免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

sqli-labs Less-55通关详解:从数字型注入到堆叠注入创建用户

sqli-labs Less-55通关详解:从数字型注入到堆叠注入创建用户 sqli-labs做到Less-55这一关跟我之前写Less-1到Less-4联合注入笔记时的玩法完全不是一个路子。前面那些关卡把payload塞进去之后只要盯着页面的回显数据就行Less-55的目标不再是查数据而是往数据库里写一个操作——创建一个新用户。这个转变如果没想明白很容易卡在第一步注入点明明找到了payload也带进去了页面却始终不给你想要的反馈。很多人上来就复用union select的老套路在Less-55上折腾大半天最后发现方向压根就错了。这篇我按自己实际通关的顺序把这个关卡从探测、闭合方式判断到最终执行CREATE USER语句的完整链路拆开讲。里面既有我反复试错撞出来的坑也有怎么快速判断当前环境到底支不支持堆叠注入的土办法。适合正在刷sqli-labs、想搞懂Less-54到Less-56这几个堆叠注入关卡的人参考。1. 关卡定位与终极目标解析1.1 Less-55在sqli-labs里的位置sqli-labs这套靶场刷到后面关卡难度是明显分层的。Less-1到Less-4是基础的联合查询注入Less-5到Less-10开始进入盲注Less-11到Less-22换成了POST注入和Cookie注入Less-23到Less-31又是各种闭合方式变体Less-32到Less-37开始处理宽字节和转义绕过。到了Less-38以后脚本开始引入一个全新的知识点堆叠注入Stacked Queries。Less-54、Less-55、Less-56这连续三关是专门为堆叠注入设计的挑战关卡。Less-55刚好夹在中间闭合方式跟Less-54不一样又比Less-56简单。它是数字型参数注入不需要用引号去闭合前面的SQL语句Less-56则换成了单引号加括号的闭合方式难度高一点。Less-55之所以值得单独写一篇是因为它的终极目标非常典型不是让你读数据而是让你利用堆叠注入创建一个数据库用户。这个目标一旦达成就意味着你已经从一个只会查询的注入者升级成能在目标数据库里执行写操作的人了。1.2 为什么这关的目标变成了创建用户看Less-55页面顶部的挑战提示会发现自己面对的不再是单纯找flag、拿密码之类的常规任务。关卡设计了一个十四步的进度挑战从最基础的探测注入点开始一步步引导你完成信息收集、数据枚举、权限确认最后一步是往数据库里创建一个新用户。当时我第一次看到这个目标第一反应是创建用户我注入的目标难道不是拿数据吗后来想明白了这正是Less-54到Less-56这一组的教学目的普通注入能读到的数据再多也只是看而堆叠注入允许你执行完整的第二条SQL语句意味着你可以做更多事情比如修改表、删数据甚至创建账号。创建用户这个动作选得很有讲究。CREATE USER执行成功之后你可以用这个新账号去登录MySQL、登录靶场页面形成一条完整的证据链——注入不止能看还能操作。这也是挑战要求你做到第14步的最终原因。1.3 堆叠注入到底解决了什么问题要理解Less-55为什么难住一批人得先搞清联合注入和堆叠注入的本质区别。联合注入UNION注入的原理是把你注入的内容和原SQL的SELECT结果合并成一个结果集返回。它有个硬性限制你拼接的那部分必须是查询语句还得跟前面的列数、数据类型对齐。SELECT之后的东西本质上都是在读。堆叠注入的原理完全不同。它利用的是数据库驱动支持多语句执行这一特性在参数里塞入一个分号把原SQL语句截断然后分号后面跟一条完全独立的SQL语句。分号后的语句可以是SELECT、INSERT、UPDATE、DELETE也可以是CREATE USER这种DDL语句。我用一个比较土的理解方式UNION注入相当于你给前台打电话让前台顺便把档案室的一份资料拍给你堆叠注入相当于你打电话的同时按了一下分机号让另一个办公室里的人直接帮你签了个字。这两个动作的权限等级是不一样的。Less-55的关卡源码用的就是支持多语句的执行函数所以分号后面才能接CREATE USER。如果你用Less-1那套union思路来打Less-55最多只能把原查询的数据换成别的内容永远执行不了创建用户这就是一堆人卡关的根因。2. 开局三分钟探测注入类型、闭合方式与可堆叠性2.1 第一步基础请求与单引号试探进了Less-55URL结构跟前面关卡一样还是?id1这种传参方式。我先按惯例丢了个?id1过去页面正常返回了用户数据回显内容跟之前关卡一样展示用户名和密码字段。接下来是每个注入关卡都绕不开的试探把参数改成?id1。这里我观察到一个很重要的情况——页面没有报出明显的SQL语法错误而是直接不再显示正常数据。这说明参数很可能没有用单引号包裹或者引号被过滤了。对比一下Less-54的表现。Less-54是标准的字符型闭合输入1之后页面会直接甩出SQL语法错误把拼接后的SQL片段露出来。Less-55只回显消失、不报错这个差异本身就是线索它大概率是数字型注入不需要引号闭合。2.2 第二步数字型注入的完整判定链为了坐实这个判断我用了一组经典的判定请求?id1 and 11页面正常返回?id1 and 12页面空白无数据返回?id1 and 11如果报错或异常说明前面不是字符闭合实际打下来and 11正常、and 12无双显这就已经能断定是数字型注入了。数字型注入的本质是参数值直接参与数值运算SQL语句里没有引号包裹所以你可以直接拿空格和关键字去拼接不需要考虑闭合和转义。在这个环节我犯过一次马虎——直接跳到堆叠payload没先确认闭合方式。结果在Less-56那种单引号加括号的关里吃了亏后面会细说。Less-55这里确认完数字型后面构造payload就清爽很多。2.3 第三步确认底层是否支持多语句执行这是Less-55能不能玩起来的关键一步。堆叠注入能不能成立不取决于前端传参而取决于数据库驱动是否允许一条请求里执行多条SQL语句。验证方法很简单构造一个含分号的后半句看它有没有被执行。比如http://127.0.0.1/sqli-labs/Less-55/?id1;show databases;如果页面在正常返回用户数据的同时底部或某处多出了一些输出或者报错信息里包含了show databases相关内容说明分号后面的语句被数据库执行了。Less-55这里后端用的是能够执行多语句的查询函数所以这条show databases是能产生反应的。这一步极容易忽略。很多人知道Less-55要用堆叠注入一上来就丢CREATE USER的payload结果没反应就懵了。先拿一个无副作用的show databases去试堆叠通道通不通后面再上真正的攻坚payload这个顺序在实战里也是好习惯。3. 核心payload一条语句打通创建用户3.1 CREATE USER语法回顾创建用户的SQL标准语法是这样的CREATE USER 用户名主机 IDENTIFIED BY 密码;主机部分可以写localhost也可以写%表示任意主机。靶场环境里通常用localhost就够了当然用%也无所谓只要能创建成功就满足通关条件。我把这条语句跟前面的注入点拼在一起原SQL大概是这样的形态SELECT * FROM users WHERE id1 LIMIT 0,1我的目标是把分号后面的语句塞进去同时把原SQL末尾的LIMIT 0,1处理掉。最常用的做法是在分号后面用--注释掉剩余SQLSELECT * FROM users WHERE id1;CREATE USER less55localhost IDENTIFIED BY less55;-- LIMIT 0,1放浏览器里完整请求就是http://127.0.0.1/sqli-labs/Less-55/?id1;CREATE USER less55localhost IDENTIFIED BY less55;--一句话解释这个payload的生效过程数据库先执行第一句SELECT然后忽略分号继续执行第二句CREATE USER再因为--注释符把后面跟上来的LIMIT 0,1整个吞掉。三个环节缺一个都不行。3.2 构造可以被完整传递的URL细节这里有个容易翻车的点网上很多wp写payload时都不强调URL里直接写空格、单引号浏览器和服务器处理时可能有编码问题。我实际提交时把URL里的空格都处理成了或者直接保留原始空格也行但更稳的写法是用浏览器的地址栏输入让浏览器自动编码。单引号不需要额外转义直接保留。分号必须是英文分号。如果MySQL版本较新CREATE USER对密码规则敏感可以换一个简单密码比如123456避免因为密码策略太严导致创建失败。靶场环境一般是MySQL 5.x对密码策略没那么苛刻。完整可用的例子http://127.0.0.1/sqli-labs/Less-55/?id1;create user less55localhost identified by 123456;--这里create user小写也没问题MySQL关键字不区分大小写。用户名分两段写和写一个整体都可行我自己的习惯是带上引号跟标准语法对齐免得到时候手滑。3.3 提交后的回显与验证方法提交之后页面如果有类似创建成功的提示那当然最直观。但更可靠的办法是绕过页面直接从MySQL层面验证打开命令行进入MySQLmysql -uroot -p查询用户表SELECT user, host FROM mysql.user WHERE user less55;如果看到less55的记录存在说明创建成功。同时你还可以回到浏览器在Less-55页面用新创建的用户去登录验证这个用户是真实可用的。这一整套验证把注入点存在、堆叠生效、写操作成功三个环节全部闭环了。4. 十四步挑战的通关路线按阶段拆解操作重点4.1 信息收集期的三条关键线索Less-55页面的挑战进度条把目标拆成了十四个小步骤前几步基本都在信息收集。我没法把每一行页面提示原样背给你但操作逻辑是固定的先确认注入存在再确认注入类型然后开始找库、找表、找列。我实际打的时候信息收集主要靠三条线索注入点在id参数数字型不需要闭合当前连接数据库的账号是高权限可以通过select current_user()或select version()确认目标库是security表是users字段是id、username、password这三条线索到位后十四步挑战的前半段基本就推完了。中间有些步骤要求你找到下一步的线索页面上的提示会变但底子就是常规SQL查询。4.2 注入点利用从查转型到写挑战进行到中后段页面会开始引导你关注更高级的操作——不只是读取表里的数据而是思考在数据库里还能做什么。我个人理解这一段的关卡设计意图是逼你转变思路。如果你一直用UNION注入的思路会发现到了这一阶段怎么都进展不下去UNION不能创建用户、不能改数据、不能删表。只有当你意识到分号后面可以接完整语句时瓶颈才被打破。从操作层面来说你在前面信息收集时已经确认了高权限账号和堆叠通道那么这一步的payload就是水到渠成的事构造一条带分号的CREATE USER语句把它放进参数里。这也是十四步挑战里最关键的转折点。4.3 挑战结束判定与常见误判很多新手卡在最后一步不是payload不对而是不知道算没算通关。Less-55的挑战结束判定其实很明确当页面确认创建用户成功或者后续步骤让你用新用户登录靶场并给出通过提示就说明大功告成。我自己的经验是别光看页面有没有报错——只要MySQL里能查到新用户你手的操作已经生效了页面的反馈有时会因为编码、回显机制不全而不显示这时候去数据库层面验证是最靠谱的。还有一种常见误判是页面上看到SQL语法报错就以为自己把整个挑战搞砸了。实际上堆叠注入的报错很多时候出现在第一个SELECT上比如你注释没写对导致原SQL尾部多出一截内容。这种情况下CREATE USER未必失败MySQL的多语句执行是逐条解析执行的前半段报错不影响后半段结果。所以看到报错先别慌先验证目标用户存不存在再回来看语法问题。5. 实战中容易踩的坑五类高发问题的完整排查链路5.1 引号、分号与URL编码的三重陷阱堆叠注入的payload里既有单引号又有分号还有空格和注释符这几个字符在URL传输中各有各的脾气。第一个坑是单引号。CREATE USER less55localhost这里面的单引号是SQL字符串的界定符必须原样传给后端。如果你在某层代理或WAF环境里单引号可能被转义或拦截但Less-55本地靶场通常没这问题。第二个坑是分号。有些网络中间件或Web容器会对请求里的分号做处理。如果发现payload提交后数据库没有反应可以试着把分号做URL编码写成%3B或者检查是不是被浏览器自动转成了别的字符。第三个坑是注释符。--是URL里最常用的注释写法因为在URL解码后会被当作空格。MySQL要求--后面至少跟一个空格才生效所以--能用--单独用反而可能失效。如果你换用#注释记得URL编码成%23。5.2 有回显但没生效先分清报错来源有一次我把payload粘到地址栏页面出现了一长串SQL语法错误。我的第一反应是完了堆叠没生效。后来仔细一看报错信息报的是第一句SELECT的语法错误不是CREATE USER的问题。这个现象很重要当后端开启错误回显时MySQL会把SQL错误直接打到页面上。报错来源不同处理方式完全不一样报错位置在LIMIT附近多半是注释没生效原SQL尾巴没被吞掉报错位置在CREATE USER附近通常是语法写错了报错位置在WHERE附近可能是闭合方式判断错了正确做法是先在本地命令行里手敲一遍完整SQL确认语法能过再回来调URL的编码和注释写法。这能省掉一大半瞎试的时间。5.3 权限不足时报错的处理策略如果目标连接数据库的账号权限不够CREATE USER会直接甩一个权限拒绝错误ERROR 1227 (42000): Access denied; you need (at least one of) the CREATE USER privilege(s) for this operation。Less-55默认配置用的是root账号连接数据库所以正常情况下你不需要处理权限问题。但如果你自己改了靶场配置或者在后端加了独立账号就会遇到这个报错。这时候的排查方向是确认当前数据库连接账号权限SELECT user(), current_user();确认是否有权限可以用SHOW GRANTS FOR current_user()查看授权列表如果权限确实不够只能换个有权限的连接账号或者考虑用GRANT类的操作绕过——但这已经超出Less-55本来的教学范围了我的建议是新手阶段别在权限问题上死磕先把环境恢复成默认配置把Less-55的本体知识学明白再谈扩展。5.4 是否支持堆叠的快速验证法这个坑我在前面提过一次但值得单独说。有些环境你payload写得很完美执行了却没效果原因是后端压根没有开启多语句执行。PHP里用mysqli_query()和mysqli_multi_query()的效果完全不同只有后者才支持分号分隔的多条SQL。快速验证法很简单提交这样一条请求http://127.0.0.1/sqli-labs/Less-55/?id1;select sleep(3);--如果页面明显卡了3秒才加载说明sleep(3)被执行了堆叠通道是通的。如果页面瞬间返回且没有其他变化说明后半句根本没执行那就要怀疑后端是不是不支持多语句。用sleep()验证堆叠有两个好处一是无副作用不会改动任何数据二是时间差非常直观不像show databases那样还需要在回显里找输出位置。我把这招称为时间盲探堆叠在真实授权测试里也很实用。5.5 完整排查链路复盘把上面几种坑串成一套排查流程遇到问题照这个顺序走确认请求原样到达浏览器F12看Network面板检查实际发送的URL里分号、单引号、空格是否被正确编码确认堆叠通道存在丢sleep(3)看有没有时间延迟确认闭合方式用and 11、and 12验证数字型注入在命令行模拟执行完整SQL把payload拼到源语句里在MySQL里手跑一遍看语法是否通过确认权限等级如果命令行都报权限错误说明不是注入语法问题是账号权限问题确认执行函数如果sleep没反应同时SQL语法无误检查后端代码确认是否用了多语句执行函数这套链路是我在Less-55上反复试错后总结出来的。按这个顺序排查基本十几分钟内能定位问题比无头苍蝇式乱试payload高效太多。6. 把Less-55放进整个系列里看从54到56的梯队差异与防御视角6.1 Less-54、55、56三个关卡的核心差异这三个关卡表面上是同一种堆叠注入玩法但闭合方式不同导致实际操作手感和踩坑点都不一样。我把它们整理成一张对照表关卡闭合方式核心考察点典型误区Less-54单引号闭合字符型堆叠先闭合再堆叠忽略单引号闭合直接堆叠报错Less-55数字型无闭合快速识别无引号直接堆叠套用union老套路卡在查不出结果Less-56单引号加括号闭合方式更隐蔽需要精确构造只闭合单引号漏掉右括号打Less-55形成的肌肉记忆在Less-56上不一定好使。Less-56的SQL长这样SELECT * FROM users WHERE id($id) LIMIT 0,1你需要先把它闭合完整再堆叠。比如?id);CREATE USER less56localhost IDENTIFIED BY 123456;--我自己的体会是Less-54到56这一组关卡真正想训练的能力是快速识别闭合结构。Less-55在这个梯队里是最友好的因为没有引号和括号适合作为理解堆叠注入的切入点。6.2 堆叠注入为什么在真实场景里威胁更大Less-55只是用CREATE USER演示了堆叠注入的能力但它的潜力远不止于此。分号后面能接的语句决定了影响范围接UPDATE可以篡改数据接DELETE可以删库炸表接DROP TABLE可以清空业务表接CREATE USER或GRANT可以直接在数据库里留后门账号这些操作有一个共同特点不再依赖回显。传统UNION注入受限于回显位置堆叠注入则是执行即可即使页面完全无回显SQL也照样跑了。所以在真实授权测试里一旦确认堆叠注入存在危险等级就要立刻上调。不过要强调一点这些操作必须只在你拥有合法授权的测试环境中进行。sqli-labs本身就是专门的练习靶场在本地搭一个、拿自己的环境练手是安全且正当的学习方式。6.3 防御视角参数化查询与最小权限Less-55通关之后站在蓝队视角回看这个漏洞修复方式其实不复杂。问题是很多老系统到现在还在用字符串拼接SQL。参数化查询是最彻底的修复方式。用PHP的PDO举例如下$stmt $pdo-prepare(SELECT * FROM users WHERE id ? LIMIT 0,1); $stmt-execute([$_GET[id]]);参数化查询的原理是让数据库把参数值当作纯数据来处理永远不参与SQL语法解析。这样无论你传什么分号、单引号、关键字都只是字符串的一部分不可能被解释成第二条SQL语句。另外还要配合最小权限原则。例如业务接口连数据库的账号只授予SELECT权限即使注入点存在攻击者也执行不了CREATE USER。很多老系统图省事直接用root连接业务库等于把所有权限都摆上了台面这跟把家门钥匙放门口是一个道理。Less-55这关教你的不只是注入手法更是防御的底线永远不要相信用户输入永远不要用高权限账号跑业务查询。最后分享一个我刷Less-55时的真实体会这关的难点不在payload有多复杂而在于能不能及时从读数据切换到写操作的思路上来。我见过不少朋友卡在这里并不是不会SQL而是被前面Less-1到Less-53的查询型注入固化了思维见到注入点就下意识拉union。如果你也是这种情况试着把Less-55当成一个分水岭——越过它你对SQL注入的理解会从读取数据真正进阶到数据库操作层面后面的Less-56、Less-57甚至更进阶的挑战都会顺很多。
返回列表