前言:在SQL注入讲解的前期,我们先使用最经典的sqli-lab靶场进行分析。
一、源码分析:Less-42 的注入点与堆叠点
1. 页面功能与请求链路
index.php:登录表单,POST 提交到login.php。- 请求参数:
login_userlogin_password
- 登录成功:跳转
logged-in.php。 - 登录失败:显示
../images/slap1.jpg。 - 登录后可在
logged-in.php中通过pass_change.php修改密码。
2. 关键源码解读:login.php
核心代码:
要点:
$username使用了mysqli_real_escape_string()转义。$password没有转义,直接进入 SQL。- 使用的是
mysqli_multi_query(),而不是mysqli_query(),支持一次执行多条 SQL 语句。 - 如果 SQL 出错,会通过
print_r(mysqli_error($con1))回显错误。 - 登录成功条件:第一条
SELECT能返回行,且$row[1]非空。$row[1]通常是username字段。
3. SQL 模板拆解
堆叠注入的本质:
用分号
;结束原 SQL 语句,再插入一条或多条新的 SQL 语句。
实际 SQL 结构:
SELECT*FROMusersWHEREusername='$username'andpassword='$password'注入点在$password,因为:
$password未转义且被单引号包裹;mysqli_multi_query()允许多语句。
原始模板:
WHEREusername='admin'andpassword='$password'如果$password输入:
' OR '1'='1'; UPDATE users SET password='hack123' WHERE username='admin'#则变成:
SELECT*FROMusersWHEREusername='admin'andpassword=''OR'1'='1';UPDATEusersSETpassword='hack123'WHEREusername='admin'#'第一条SELECT负责让代码判断登录成功
第二条UPDATE负责修改admin密码
4. 判断闭合与注入点
- 发现闭合方式为单引号字符串且存在报错回显。
- 输入
login_user=admin,login_password=' OR '1'='1#,注释掉后面的'。
在这一步判断时,大家会发现无论你用户名输入什么,最终登录上去的用户都是表格里的第一个用户,这是因为拼接后的判断逻辑WHERE username=‘admin’ and password=‘’ OR ‘1’=‘1’中and优先级高于or,即实际判断逻辑是这样的(username=‘admin’ and password=’’ )OR True。这就又回到文章0x0006所讲的数据库判断语句的原理,由于数据库是逐行取表中数据放入语句中匹配的,但是后面OR True的判断条件又让这条语句前件无论是否为真都能结果为真,所以实际上匹配出来的是整张users表,最后取表的第一行即第一个用户。 - 加入分号,使用UPDATE更改用户密码测试堆叠。
在测试的时候有人可能会在堆叠语句上使用sleep()进行判断,结果发现虽然语句执行了但根本没有延时。这里我们要把数据库和Web服务器区分开,在堆叠注入的内容属于非代码预期的,因而源码中大概率是没有准备接收另一条语句的执行结果,这就导致了数据库里虽然执行了sleep()但源码根本不等他,而是只需要接收前面语句的执行结果就可以接着往下运行。先前我们的时间盲注之所以能够顺利延时正是因为源码需要等待数据库执行sleep()后的结果。
5. 堆叠注入利用
5.1 插入新用户(INSERT要求知道所有列名,由于页面存在报错注入,所以也不难判断。报错注入的原理在文章0x0005中已经讲过,这里只提供判断所有列名的payload)
# 判断所有列名 login_user=admin login_password=' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=0x7573657273 and table_schema=database())),1)# # 插入新用户 login_user=admin login_password=' OR '1'='1'; INSERT INTO users(id,username,password) VALUES(100,'hack123','hack123')#5.2 删除或破坏数据
login_user=admin login_password=' OR '1'='1'; DROP TABLE users#虽然堆叠注入一般不会存在回显,但其危害从读数据扩展到改、删、建数据,具体能走多远取决于数据库用户的权限
6. 源码缺陷总结
- 使用
mysqli_multi_query()执行拼接 SQL - 数据库账号权限过大
- 登录逻辑只看第一条
SELECT是否返回行,后续语句仍可能执行
7. 与 sqli-labs 其它关卡映射
分析Less-38、Less-39、Less-43源码,尝试使用堆叠注入更换admin用户密码或者新增用户。
三、现代网站应用场景
1. 现代开发的变化、预编译覆盖不到的地方、框架 / 驱动误用
这点和文章0x0002闭合手法的情况类似,不多赘述。
2. 现代真实风险
堆叠注入一旦存在,危害通常大于普通读数据注入:
- 修改管理员密码
- 插入后门管理员
- 删除业务表
- 创建恶意存储过程
- 权限提升、横向移动
后记:堆叠注入本身就是函数或者配置上的误用,数据库允许同时执行多条语句的失误在现代网站早已少之又少,做了解即可。但这种思路是可以借鉴的,在后续讲解代码执行、命令执行的时候会有类似的操作,有助于理解。希望各位业内的老师傅能纠正文章的错误
(非商业用途,仅供交流学习,禁止转载)