前置知识点:session
当我们访问一个网站, PHP 发现你是新用户,就会给你创建一个 Session 文件, 用来存储用户登录信息、状态等,比如:
sess_cy
(文件名格式是 sess_+PHPSESSID 的值)
文件默认存在 /tmp/ 目录下,也可以通过 php.ini 的 session.save_path 配置改位置。
然后服务器响应时会告诉浏览器:
1 | Set-Cookie: PHPSESSID=cy |
浏览器记住了,所以后面每次访问,服务器都会自动在每次请求里带上:
1 | Cookie: PHPSESSID=cy |
这样服务器就知道你是谁,对应哪个 session 文件。
所以 cookie 是服务器让浏览器带的,浏览器只是听话地照做而已。
隐藏功能:上传进度记录(upload_progress)
这个功能默认是关闭的,但如果管理员打开了这些设置:
1 | session.upload_progress.enabled = on //enabled=on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ; |
那 PHP 会在用户上传文件的时候,自动把上传进度(上传了多少、文件名是啥等)写进 session 文件里。
而你可以通过设置一个 POST 参数:
1 | PHP_SESSION_UPLOAD_PROGRESS = 你想写入session文件的内容 |
这样,PHP 就会把你这段值写入 session 文件里。
比如,我们在cookie里设置PHPSESSID=AndyNoel,就会在服务器/tmp
目录下或者/var/lib/php/sessions/
目录下创建一个文件:sess_AndyNoel。即便没有设置自动初始化session,php也会产生session,并生成一个键值,这个键值由ini.get("session.upload_progress.prefix")
+我们构造的session.upload_progress.name
值组成,最后被一起写入sess_文件里。
回到题目
一进去是这样,很容易能猜出来 QAQ 是参数吧?
经过测试,过滤了
1 | . : php flag data log |
基本上杀死了伪协议和日志文件
那么我们可以通过 QAQ 这个上传接口,构造特殊的 POST 请求,让 PHP 自动写入木马。
根据 PHP 的配置,当session.upload_progress.enabled = On 的时候,如果满足下面两个条件:
- 请求里有参数名是:
PHP_SESSION_UPLOAD_PROGRESS
- 请求里真的上传了文件
那么 PHP 会把上传过程的信息,自动写进当前用户的 session 文件, 但是当文件上传完毕之后,PHP 会自动删除 session 里的上传进度信息,所以我们要利用请求还没响应,session 还没被清理这个时间差,抢先包含 sess 文件执行。
我们的思路大概是:
上传文件 ➜ 写入 session 文件 ➜ include sess 文件 ➜ 远程执行命令
那么我们写脚本的思路就是,先随便上传一个文件,再在请求头PHP_SESSION_UPLOAD_PROGRESS
写自己的一句话木马,在 cookie 里面写 session 参数,对应访问时候的文件名。
1 | import requests |
这是上传文件,让 PHP 写入对应的 session 文件。
接下来我们写向对于知道路径的 PHP 文件发请求的函数:
1 | def read(session): |
最后写
1 | if __name__ == '__main__': |
总结:session 文件包含的利用条件
- 存在文件包含漏洞
- 知道session文件存放路径,可以尝试默认路径
- 具有读取和写入session文件的权限