ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CISP-PTE SQL注入题解密:判断类型与手工利用全流程

2026/9/28 7:17:22 拓冰建站 浏览量
CISP-PTE SQL注入题解密:判断类型与手工利用全流程 1. CISP-PTE的SQL注入题到底在考什么第一次接触CISP-PTE的SQL注入题时我犯过一个典型的错误拿到一个看起来像是注入点的URL直接就把sqlmap挂上去跑。结果问题倒是跑出来了但数据量一大加上题目环境本身做了不少限制跑完全部数据花了快四十分钟后面的题差点没时间做。考完回顾了一下才发现CISP-PTE的SQL注入考点重点不在于能不能注入而在于能不能高效、准确地拿到你想要的那条数据。CISP-PTE是注册渗透测试工程师方向的认证考试考试形式是机考给你一个模拟的真实Web环境一个IP、一个域名你需要通过Web漏洞利用最终拿到提交点要求的Flag文本。SQL注入是其中分值很重的一个专项题型也是我认为整个考试中最有规律可循的一类题。它不像上传、命令执行那样需要碰运气猜路径也不像代码审计那样需要大量阅读源码。只要你对注入的分类、判型、手工利用链路足够熟哪怕完全不依赖sqlmap也能在十分钟内拿下一道完整的注入题。我在备考和实际考试中反复验证过这样一件事SQL注入题在CISP-PTE里常见的出法就三类——联合查询拿数据、报错信息直接泄露、以及盲注逐位猜解。前两类占了大头盲注偶尔出现但没那么难只是需要脚本辅助。这篇内容我就围绕考试环境里最实用的SQL注入打法来展开把我在SQLi-Labs、DVWA、Pikachu、CTFHUB这些靶场里反复刷出来的经验和踩过的坑一次性梳理清楚给准备考CISP-PTE或者正在学渗透测试的朋友做个完整参考。先说清楚一件事CISP-PTE考的是授权环境下的渗透测试能力所有题目都是在官方指定的仿真靶场里进行你做的任何操作都限定在考试平台内。这篇文章里讲的所有SQL注入手法也都只适用于你自己搭的靶场、CTF比赛平台或拿到了书面授权的测试环境。千万不要拿去测未经授权的网站这是底线问题。2. 建立自己的注入类型判断框架2.1 一条查询语句是怎么被拆出漏洞的SQL注入的本质是开发者把用户输入直接拼接进了SQL查询语句。我打一个最简单的比方数据库本来只想执行查找id为1的用户这个动作但你在id参数里传入了别的内容于是这条语句的语义被改变了变成了查找id为1的用户顺便再执行一段你输入的SQL。以PHPMySQL最常见的代码为例?php $id $_GET[id]; $sql SELECT * FROM users WHERE id $id; $result mysqli_query($conn, $sql); ?这里$_GET[id]拿到的值直接就拼到了SQL里没有任何类型转换、转义或过滤。你在URL里传?id1 and 11查询就变成SELECT * FROM users WHERE id 1 and 11因为11恒为真所以返回结果跟id1完全一样。你传?id1 and 12条件永远为假页面就什么都不返回。这一个正常/异常的差异就是判断注入点的依据。我在自己的学习笔记里把SQL注入的判定框架分成两条线第一条线判断注入点类型第二条线选择合适的注入手法。类型判断错了后面全是无用功。比如你拿字符型的输入去跑数字型的联合查询字段数对了也可能半天找不到回显点。2.2 联合、报错、布尔、时间四条路怎么选进入实战之前需要建立一张决策表。我自己在靶场里刷题时每拿到一个疑似注入点先问三个问题页面有没有直接的回显位置报错信息会不会展示到页面上页面响应时间能不能被控制根据三个问题的不同答案选择的利用技术完全不同。用一张表格把四种主流注入类型的适用条件列出来注入类型适用条件核心特征获取数据的方式联合查询页面有明确回显位置UNION SELECT能控制显示的内容直接查询并输出结果报错注入数据库错误信息回显到页面UPDATEXML/EXTRACTVALUE抛错携带数据从报错信息里读取拼接内容布尔盲注页面无回显、无报错但响应内容有差异条件真/假返回不同页面逐位判断ASCII码时间盲注页面无回显、无报错且内容无差异sleep()控制响应延时通过响应时间判断ASCII码这个表看起来简单但在考场上很多人会卡在第一步明明有回显却非要用盲注脚本去慢慢猜。反过来没有回显的界面又有人非要用union硬怼结果字段数试了半天都没反应。所以我的习惯是拿到注入点后先做一次最简单的and 11/and 12测试观察页面差异再决定走哪条路。2.3 顺手把堆叠注入和宽字节注入也理清楚考试的高频考点除了上面四种还会偶尔涉及堆叠注入和宽字节注入。堆叠注入的原理是在一条语句结束后用分号;分隔接着执行第二条SQL语句。PHP的mysqli_multi_query这类函数允许执行多条语句时才会生效但实际环境中很多开发者用PDO的预处理查询堆叠注入往往打不通。我刷SQLi-Labs的Less-23之后专门总结过只有当你发现后端能执行多条语句且错误信息不会把后续语句的报错暴露给你时才考虑用堆叠注入。宽字节注入主要对付的是GBK编码环境的转义绕过。在PHP的老版本环境中开发者会用addslashes()对单引号加反斜杠转义而%bf%27这种组合在GBK编码下%bf%5c会被当成一个正常的汉字字符反斜杠被吃掉单引号就逃逸了出来。这个在真实考试里出现频率不高但Pikachu靶场里有一个专门的宽字节注入关卡顺手刷一遍能加深对编码处理的理解。3. 手工注入的全流程从识别注入点到完整脱库3.1 判断注入点的两种最稳姿势我个人习惯判断注入点从来不用单引号直接去炸。虽然这个方式在很多靶场里能立刻触发数据库报错但在CISP-PTE考试环境里一旦报错信息被WAF拦截或者被程序吞掉你能拿到的信息很少。我的标准操作是先构造一个恒等式和一个恒假式放在同一个参数里对比页面输出。假设目标URL是http://192.168.x.x/sqli/example.php?id1第一步访问id1 and 11页面正常返回和id1的内容完全一致。 第二步访问id1 and 12页面返回空内容、或者长度明显减少。两次结果有差异这个参数基本就是注入点。多花这几秒钟换来的是极高的确定性。然后我再用order by去猜字段数确认是数字型还是字符型。字符型的判断方式是在参数后加单引号如果页面报错再尝试id1 and 11能正常返回那说明单引号是闭合条件的一部分你注入的SQL必须保证引号配对否则语法永远不通。3.2 联合查询在考试里的标准四步考试里最舒服的题就是页面有直接回显位置的联合查询注入。刷SQLi-Labs前面十关的时候这套流程我练到闭着眼都能写出来分四步第一步用ORDER BY确定字段数。?id1 order by 3 ?id1 order by 4当order by 3正常而order by 4报错说明查询结果集只有3列。注意这里不能直接从1开始慢慢试浪费时间。我一般都从5开始试探如果正常就翻倍异常时再在附近细查。第二步用UNION SELECT找回显位置。?id-1 union select 1,2,3这里很多新手会疑惑为什么是-1。原因很简单要让前面那条查询不返回任何结果后面的UNION SELECT内容才能显示到页面上。如果原查询返回了一行UNION的结果会从第二行开始显示有些页面只渲染第一行你就看不到你要的内容。传-1让原查询查无此人联合查询的结果就直接成为第一行展示出来。然后在页面里找到数字1、2、3分别落在什么位置哪个位置显示在页面上那就是你的回显位。第三步查询库名和表名。?id-1 union select 1,2,database() ?id-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schemadatabase()group_concat是MySQL里特别实用的函数可以把查询的多行结果合并成一行用逗号分隔特别适合注入场景下数据回显位置有限的情况。有些版本过滤了group_concat那可以用concat_ws去替代。第四步逐个表查字段、抽数据。?id-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_nameusers ?id-1 union select 1,2,group_concat(username,0x7e,password) from users0x7e是波浪号~的十六进制表示用来在拼接字段中间加一个分隔符方便你一眼看出每个字段的边界。如果代码里过滤了单引号你写table_nameusers会直接报错这时可以考虑用十六进制写法table_name0x7573657273这是我在CTFHUB的SQL注入关卡里练出来的技巧。3.3 报错注入一条报错信息就能解决问题很多场景下页面没有回显位置但数据库的报错信息会直接被打印到页面上这时候联合查询大概率发挥不了作用报错注入才是主角。我在考场上用得最顺的报错注入函数有两个updatexml和extractvalue。这两个都是MySQL里处理XML数据的函数当传入的XPath表达式格式错误时会把参数内容回显到错误信息里。一次标准的报错注入长这样?id1 and updatexml(1,concat(0x7e,(select database()),0x7e),1)原理是updatexml的第二个参数期望是一个合法的XPath路径但concat()出来的结果带上了波浪号~0x7e不符合XPath格式于是MySQL报错并把完整的字符串显示出来。波浪号在这里不是必须的但加上它能把你的数据和其他报错信息区隔开读取的时候不会看花眼。注意updatexml报错信息最长只显示32个字符。如果你的查询结果超过32个字符比如group_concat了一批表名报错内容会被截断。所以遇到数据量大的场景要用substr()或者mid()把结果切分成多段一段段取。我在SQLi-Labs的Less-17里就踩过这个坑直接查select group_concat(column_name) from information_schema.columns报错信息只显示了一半还以为出错了最后才发现是长度截断的问题。报错注入的另外一条思路是用extractvalue?id1 and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schemadatabase() limit 0,1),0x7e))extractvalue的报错同样限制在32字符用法和updatexml几乎一致。考试中两个函数不一定都可用有的环境禁了一个两个都掌握会更稳。3.4 盲注的脚本思路别傻傻地手工猜布尔盲注和时间盲注在考试里属于不上手不知道一上手就烦的题型。手工逐个字符去猜库名、表名、数据速度太慢也容易出低级错误。我的做法是写一个非常简单的Python脚本自己控制请求的发送和条件判断。完全不需要什么复杂框架用requests库就够。以布尔盲注为例我用substr加ascii逐位判断。判断第一个字符的脚本逻辑大致如下import requests url http://192.168.x.x/sqli/blind.php payload 1 and ascii(substr(database(),{pos},1)){mid} -- -然后对每个位置做二分查找1到128之间猜平均7次请求能确定一个字符。整个库名如果8个字符大约56次请求就能出结果。用二分法比从1到127逐一遍历快太多这点在考试时间紧张时非常关键。我在自己练CTFHUB的布尔盲注关卡时从线性遍历改成二分法之后速度提升大约十倍。时间盲注的唯一区别是判断条件从页面内容差异变成了响应时长差异。构造方式?id1 and if(ascii(substr(database(),1,1))100,sleep(3),0)如果条件成立页面会延迟3秒才返回不成立则几乎瞬间返回。这种注入在考场里最耗时间所以我通常把它作为最后手段。先用浏览器插件或Burp的响应时间统计功能辅助判断脚本思路和布尔盲注完全一致只是判定标准从内容成了时间阈值。4. 万能密码这类绕过题核心是理解逻辑闭合4.1 为什么or 11能绕过登录热搜词里SQL注入万能密码绕过出现频率很高这确实是考试里容易考到的一个小点更准确地说它的本质是登录场景下的SQL注入利用。很多老系统后台登录代码写得很随意$sql SELECT * FROM users WHERE username$_POST[user] AND password$_POST[pass];你在用户名框输入admin or 11 -- -拼接后的SQL变成SELECT * FROM users WHERE usernameadmin or 11 -- - AND password-- -后面被注释掉or 11让整个条件恒为真于是查询返回了第一条用户数据登录直接被绕过。万能密码不是真的万能它只是通过闭合单引号改变了原始SQL的判定逻辑。理解这一点比背几个密码公式重要因为考试里改一个过滤规则背的公式可能就失效了。常见变形还有 or 11 # or 11 -- - or aa admin --MySQL注释符有三种#、--后面必须跟空格、/* */。Sqli-Labs里很多关卡会在SQL末尾再加一段代码来干扰理解注释符的闭合规则就能轻松绕过。4.2 等价替换WAF拦截时的保命手段考试环境中可能会有简单的过滤逻辑比如直接替换掉or、and、union等关键字或者把空格替换为空。遇到这种情况等价替换的思路就非常重要。我把实践中验证过有效的替换表整理出来原始写法替换方案适用场景空格/**/、%09、%0a空格被过滤时like、、regexp等号被过滤时orunion selectunion/*!50000select*/select关键字被过滤时substr()mid()、left()函数被过滤时database()schema()函数被过滤时比如SQLi-Labs的Less-26空格和注释符都被过滤了我当时的解法是用%0a换行符替代空格用||替代or再加上/反斜杠来绕过分词组合起来一个布尔型盲注的判断就能正常执行。这类考点的核心逻辑是过滤规则永远是黑名单式的总有你想象不到的合法SQL写法能绕过它。4.3 一次完整的绕过场景复盘我自己在Pikachu靶场里遇到过这样一个登录注入题用户名输入框做了过滤把or和and直接替换为空但没有做递归过滤。这意味着我输入oorr时替换机制把中间的or去掉剩下的刚好是or。构造万能密码时我就用了这个方法admin oorr 11替换后变成admin or 11成功执行。这个过滤不递归的漏洞在实际测试里非常常见也经常出现在CTF比赛里。CISP-PTE考试如果加入WAF考点大概率也是这种单层替换而不是企业级的复杂过滤规则。掌握了递归思想很多过滤就能优雅绕过。5. 靶场训练路线从SQLi-Labs一路打到CTFHUB5.1 SQLi-Labs前22关的刷法建议SQLi-Labs是SQL注入类的经典靶场我自己完整刷过一遍其中前22关是最核心的入门路径。这一段的练习价值在于把所有注入类型都覆盖到了而且每一关的SQL代码都能打开看你能精确知道后端是怎么处理的这对建立注入点和SQL语义的映射关系极其有帮助。我的建议是不要跳着刷按顺序来。Less-1到Less-4覆盖数字型和字符型的联合查询Less-5到Less-6是报错型和双查询Less-7到Less-10进入布尔盲注Less-11到Less-16转向POST型注入Less-17是报错型的数据更新场景Less-18到Less-22是请求头注入。每一关都要手工做一遍不用sqlmap。我个人的体会是前10关手工做完你对联合查询和报错注入的肌肉记忆基本就形成了后面再看代码审计题目会顺畅得多。5.2 DVWA和Pikachu的差异化补充DVWA的SQL Injection模块一共四档low、medium、high、impossible。low就是最原始的注入和SQLi-Labs的Less-1很像。medium级别开始对用户输入做转义这时候你需要把输入交给Burp抓包通过POST请求重放来绕过前端的限制。看到没有DVWA最大的价值在于它刻意模拟了开发者试图防御但防得不够好的真实场景你可以通过代码审计了解不同安全级别下的防御方式。Pikachu靶场我在CISP-PTE备考的后期才认真刷它跟SQLi-Labs最大的不同是覆盖面更广包含了搜索型注入、insert/update注入、delete注入以及宽字节注入。Search型注入的核心是输入的内容被包含在LIKE运算符里判断闭合方式时要用%去配对。举个例子搜索框提交helloSQL可能是where name like %hello%你要闭合的是两个%。这类平时刷得少的场景在考试里一旦碰上会慌Pikachu能补齐这些短板。5.3 CTFHUB技能树的SQL注入专项怎么针对性练CTFHUB是CTF选手常用的在线训练平台它的技能树里SQL注入模块设计得很有层次而且更贴近CTF和渗透测试的实际出题风格。我的用法是在SQLi-Labs刷完基础后把所有SQL注入关卡当成一次模拟考从整数型注入开始到字符型注入、报错注入、布尔盲注、时间盲注再到MySQL结构、Cookie注入、UA注入、Referer注入。其中Cookie注入、UA注入和Referer注入是考试里比较容易忽略的点。很多注入点不在URL参数里而在请求头里。你用浏览器直接访问时看不到任何注入迹象但用Burp抓包把User-Agent字段改成 and 11 -- -响应内容就会出现差异。CTFHUB的这类题目逼你养成每个请求头都值得测一遍的习惯这在CISP-PTE考试中可能是救命技能。5.4 SQL Server 2008注入的小补课热搜词里出现了SQL Server 2008注入这类和MySQL注入最大的区别在于系统库结构完全不同。MySQL查库名用information_schema.schemataSQL Server用的也是information_schema但没有limit要用top或者where条件来逐行取数据。除此之外SQL Server的典型特征是用version获取数据库版本用db_name()获取当前库名。考试中如果给的靶场是SQL Server数据库习惯MySQL的联合查询思路后很容易掉链子。我的经验是先看页面底层提示或注入失败的报错格式判断数据库类型再切换对应的系统表和函数。6. 进考场前必须想清楚的几件事6.1 sqlmap和手工的界限我见过不少备考的人陷入一个误区认为考试必须全程手工sqlmap用了算作弊。其实不然。CISP-PTE是渗透测试能力的考核你用工具说明你掌握工具的用法这完全符合一个渗透测试工程师的真实工作方式。问题的关键只在于你要能判断什么情况下工具比手工高效什么情况下工具反而误事。我的个人原则是拿到注入题先手工确认注入点和类型再决定要不要交给sqlmap。对于联合查询和报错注入这种简单场景手工通常比sqlmap快得多因为你不需要等它跑探测流程。对盲注这种重复性劳动sqlmap是很好的生产力工具前提是你得熟悉参数尤其是--level和--risk。很多默认跑不出来的注入点把--level提到3以上就能识别出来。但注意考试环境中如果加了很多过滤条件sqlmap默认的payload库可能绕不过去这时候就需要--tamper参数配合脚本绕过。我备考后期把常用tamper脚本如space2comment、between等都过了一遍考场上确实能派上用场。6.2 做题顺序与时间分配的真实建议CISP-PTE考试是综合题型SQL注入只是其中一部分。我的战术是开考后先花几分钟把整个平台翻一遍明确哪些题能一眼看出类型先把最确定的SQL注入题做掉拿稳分再去碰需要猜解的题目。因为SQL注入在所有Web漏洞题型里是最有手就行的题型只要找到注入点拿到Flag的概率很高。具体到一道SQL注入题我的时间分配大概是前3分钟判断注入点和类型中间10到15分钟完成数据获取和Flag提交如果超过20分钟还没拿到结果果断换思路。实际考试中我遇到过前端WAF拦截导致payload一直打不进去的情况当时的选择是立刻切到Burp重放请求把payload做一次URL编码瞬间就通了。这类换一个发送通道的思路比盲目改payload更高效。最后一个建议考试环境里的Flag提交格式通常是页面上给一个输入框你必须把查询出来的完整数据按指定格式填进去。很多人拿到库名、表名甚至密码字段了却因为格式不对扣分。我的做法是进入命令行环境后把每一步查询结果截图保存最后对照提交要求逐字填写确保不出低级错误。这种考场上不犯错的能力比多会一两个技巧更实际。SQL注入这门课说穿了就是对SQL语义的精确控制。你越是理解后端查询语句原本长什么样就越容易构造出让它失控的payload。备考阶段我反复刷SQLi-Labs和CTFHUB的体会是做题数量不是关键关键是每一道题都尽量手工分析一遍不碰sqlmap。等到考场上你发现自己脑子里已经有一套判断流程在自动运转时分数自然就到了。