尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Hack World 1靶场实战:SQL注入布尔盲注手工与自动化脚本
SQL注入到现在还是每个搞Web安全的人绕不开的一课。Hack World 1这个靶场题目特别适合用来练布尔盲注手工利用——它把过滤规则藏得恰到好处既不会让你一眼就猜完又不会难到无从下手。题目页面很简单一个输入框一个提交按钮后端把输入拼进SQL查一张表页面根据查询结果返回两种完全不同的内容。你要做的是在不能直接看到查询结果的前提下把flag表里的flag一个字符一个字符地挖出来。这篇文章不打算只贴最终payload而是把从探测注入点、理解过滤器、构造布尔条件到最终落地成自动脚本的整个过程重新走一遍。适合刚学完SQL注入基础、但还没系统做过盲注题的人也适合那些已经会跑sqlmap、但想知道手工注入到底在干什么的读者。1. 先弄清楚题目到底在考什么1.1 关卡的基本设定进入Hack World 1之后页面上只有一个 id 输入框没有明显源码。根据题目描述后台大概是这种逻辑拿到 id 参数后拼进一条 SQL例如select * from table where id xxx然后把查询结果渲染到页面。这种“详情页”模式在业务系统里非常常见所以很多注入题的入口都长这样。关键信息在页面的反馈里。我输入 1、2、3页面返回正常内容输入其他数字、字母、符号页面返回另一句固定提示。换句话说这条 SQL 在“查到了”和“没查到”两种结果下页面正文完全不一样。这是一个非常重要的信号我们不需要把数据直接显示出来只要能精确控制“真/假”两个状态就能隔空读出数据。这就是布尔盲注的基本前提。很多初学者一上来就想着 union select、报错注入看到页面没有任何报错回显就放弃了。这里想强调一个经验对盲注来说页面“不报错”反而是好消息。它说明后端对异常做了兜底没有把 SQL 错误直接抛到前端。我们只需要用布尔条件去制造页面差异不需要依赖报错信息。1.2 手动探测注入点先做最小验证。我直接提交1^0和1^1。结果很干净1^0返回正常页1^1返回异常提示。输入实际计算出来的 id页面状态1^01正常1^10异常提示1^23正常看到这个结果基本可以断定注入点存在而且 id 参数最终出现在数字上下文而不是字符串上下文。1^0在 SQL 里是“1 异或 0”结果为 1查得到1^1的结果是 0查不到。这和我后面要用的注入公式完全一致1^(条件)。这里有一个关键映射关系建议现在就记住后面写脚本时还会用到条件为真时1^(条件)的结果是 0页面返回异常提示条件为假时结果是 1页面返回正常内容。这个映射容易搞反。我见过不少人第一遍写自动化脚本时栽在这里最后输出的内容完全不可读回头排查才发现是“真/假状态”和“页面特征”对应错了。还有一种常见的确认注入点方式是提交1 and 11但这种写法在这个题目里大概率会被拦因为它触碰了过滤规则。先接受“有过滤”这个前提我们接着拆过滤器。2. 过滤器拆解为什么不能直接写 and 和空格2.1 空格过滤以及它的替代品我测试过程中提交了1 and 11这类 SQL 注入最常见的 payload页面没有返回预期的正常状态。再试1 or 11同样不行。这里就涉及 Hack World 1 的第一个经典过滤规则过滤空格。当过滤器发现输入里包含空格会直接把它删掉。SQL 语句里一旦没了空格很多表达式就没法写。常见的绕过手法是把空格换成/**/这是 MySQL 的注释符但在这里可以充当词与词之间的分隔还可以用括号来强行分隔。比如select(flag)from(flag)在 MySQL 里完全合法因为 select 和后续表达式之间、from 和表名之间都用括号做了“隐式分隔”。我实际在这道题里用的所有 payload不管是子查询还是条件判断都写成无空格版本比如(select(flag)from(flag))。换成select/**/flag/**/from/**/flag也有效。两种都能用我更推荐括号写法因为它短而且和函数嵌套的结构天然契合不容易在复杂嵌套里多写、漏写。注意空格过滤后别只想着用/**/还要确认目标环境是否连注释符也过滤了。这就是为什么括号法更稳妥——它不依赖注释符。2.2 为什么 or 和 and 会被重点盯防第二个特征是过滤了or和and这两个关键字。注意这里不是只过滤单独的“and”单词而是把输入里的“or”和“and”作为子串处理。比如写一个information_schema里面包含or过滤器会把这一小段删掉结果语句就变成infmation_schema直接语法错误。这也是很多人卡住的地方payload 看上去没问题但语句里藏了个“or”子串被悄悄改写了。那为什么不直接放弃 or/and因为布尔盲注本身非常依赖 and/or 来拼接条件。你有两种绕法第一使用||、这类逻辑运算符替代。这在很多 MySQL 版本里能用但如果你要在复杂子查询里嵌套多层条件写起来容易乱。第二也是最推荐的方式——不用 or/and改用异或。异或在布尔盲注里有个天然优势1^011^10。一个运算就能完成条件判断完全不需要写 and/or。Hack World 1 的过滤器堵死了最常见的路但位运算这条路它没堵。于是整道题就从“猜过滤”变成了“顺着过滤器的盲区搭信道”。我尝试过111的方式也能用一段时间但一旦条件复杂起来就会踩到关键字过滤的坑。而异或方式因为写法极简反而最适合长期稳定使用。2.3 其他隐蔽的过滤点Hack World 1 的过滤不是只有空格和 or/and。不同版本可能还会过滤掉union、select、、之类的东西。所以如果你想复用这套打法去打其他题目建议先做一轮基础 fuzz把空格、注释符、常见运算符、常见函数名分别丢进参数观察页面反应整理一张“什么能用、什么不能用”的小表。这一步花不了多少时间但收益很大。我当时拿到的过滤器画像大致是空格废了、or/and 废了、双写绕过有时会生效。例如把or写成oorr让过滤器删掉中间的or剩下来的还是or。不过在 Hack World 1 里我没有依赖双写因为异或链路已经够用。万一以后遇到更严格的过滤器还可以继续用大小写混写、内联注释、十六进制编码等方法去绕。3. 手注全过程从长度到完整 flag3.1 用长度函数确认目标范围在已知表结构的情况下也就是已知 flag 表和 flag 字段第一步先读长度。payload 是1^(length((select(flag)from(flag)))10)执行逻辑是这样的先执行子查询(select(flag)from(flag))取出 flag 字符串再用length()拿到长度和 10 比较得到一个布尔值也就是 0 或 1。这个 0 或 1 再和前面的 1 异或产生最终传给 id 的数值。如果题目设置的 flag 长度正好是 10页面就会走到异常页不是 10页面就返回正常页。判断长度有两种做法一种是逐个去试从1一直试到100另一种更省事先用范围判断比如length(...)20看看页面是正常还是异常再用二分法把长度范围快速切小。我当时写了一个小循环去测拿到具体长度后才开始下一步。这一步很重要因为后面的逐字符提取要循环很多次长度没搞对循环次数就不够。3.2 逐字符提取的原理确定长度以后核心就是“取一个字符、比一次 ASCII、看一次响应”。payload 长这样1^(ascii(substr((select(flag)from(flag)),1,1))102)substr()从目标字符串里取出第 1 个字符ascii()把它变成数字再和一个猜测值比较。这个 102 对应字符f。如果页面对应条件为真的状态说明第 1 个字符确实是f。这里有个细节我直接用了等号比较。等号在 MySQL 里可以正常工作但如果过滤器把等号也过滤了就要换用、、like这些替代。Hack World 1 里等号能用我就没有自找麻烦。3.3 手工二分加速如果一位一位用 ASCII 码去暴力猜每个字符平均要试几十次一个 30 位的 flag 要试上千次手工逐个试会非常消磨耐心。实际手工过程中我更推荐二分法先问ascii(...)100根据结果缩小范围。比如响应为真说明字符在 100 到 127 之间接着问110继续往下折半。这样做一轮大概只需要 7 到 10 次请求就能确定一个字符。手工操作时最好建一个表格把每个位置的尝试记录、当前区间、最终字符记下来。别小看这个习惯后面写脚本时二分法的代码就是这个逻辑的自动化版本。手工跑一遍的好处是你会确切知道每个响应对应的布尔值是什么不会在脚本阶段把“正常页/异常页”的判定写反。3.4 手工提取的完整经验手工把完整 flag 挖出来后你会发现整个过程就是一个机械重复改序号、改猜测值、看响应。这个“重复”恰恰是应该写脚本的信号。但我不建议一上来就自动化因为手工注一遍能帮你建立对响应判断、payload 结构、过滤器误伤这些细节的直觉。等你手注完整拿下一道题再写脚本去刷同一类题效率和质量都会高很多。4. 把重复劳动交给脚本4.1 脚本的整体思路拿到一条手工可用的 payload 后写脚本就水到渠成。我习惯用 Python 的 requests 库发请求因为它简单、生态好。脚本要做三件事构造 payload 并发送请求根据页面返回的正文识别真/假响应对每个字符位置做二分搜索拼出 flag。判定真/假这一步是脚本最容易出错的地方。不要用“页面是否包含某个字符串”这种模糊判断要选一段区分度最高的正文片段。我通常在发包后先打印两三次响应肉眼确认两段正文的特征再用in判断。确认“条件为真”对应的页面到底是什么。因为我前面用的公式是1^(条件)条件为真时 id 被算成 0所以脚本里的“真”往往要匹配异常页面的特征而不是正常页面。4.2 可以直接照着改的 Python 示例下面是一个可直接修改目标地址后运行的示例脚本。它用二分法猜测每个位置字符的 ASCII 码import requests url http://目标地址/ param_name id # 根据实际参数名调整 true_marker 异常页独有特征文字 # 替换为你观察到的特征 headers { User-Agent: Mozilla/5.0 } def is_true(payload): # 根据题目实际情况可能是 get 或 post r requests.post(url, data{param_name: payload}, headersheaders, timeout10) return true_marker in r.text def get_length(): # 逐个搜索 flag 长度 for n in range(1, 100): payload f1^(length((select(flag)from(flag))){n}) if is_true(payload): return n return -1 def get_char(pos): lo, hi 32, 126 while lo hi: mid (lo hi) // 2 # 判断 ascii 是否大于 mid payload f1^(ascii(substr((select(flag)from(flag)),{pos},1)){mid}) if is_true(payload): lo mid 1 else: hi mid return chr(lo) length get_length() print(fflag length: {length}) flag for i in range(1, length 1): c get_char(i) flag c print(fposition {i}: {c}) print(flag) print(final:, flag)4.3 脚本运行效果与调整点第一次跑这个脚本建议在循环里加个print(payload)方便出问题时中止调试。实际运行中脚本大概会发几十到几百个请求根据平台网速和限流情况可能需要几分钟。如果目标平台有请求频率限制可以在循环里加time.sleep(0.2)避免访问过于密集。还有一点注释里我写了“目标地址”占位实际操作时不要忘记替换成你的靶场地址并且确认请求方式是 GET 还是 POST。有些题目虽然表单看起来是 POST但后端处理的可能是 GET 参数发包方向错了脚本会一直拿不到正确响应。二分法代码看起来短但它依赖前面说的is_true映射。如果条件为真时id 是 0页面是异常页那true_marker就一定要填异常页的特征。这个映射关系在脚本里写错整个输出都会乱掉。5. 实战中常见的坑和排查方法5.1 布尔判断反了导致输出乱码我第一次写自动化脚本时把“正常页”和“异常页”的判定写反了。现象是脚本很快跑完但最终输出是一串完全没规律的内容。排查方法很简单找一个已知字符比如 flag 的第一个字符手工提交1^(ascii(substr((select(flag)from(flag)),1,1))102)先确认这个 payload 到底返回哪个页面再回头改脚本里的true_marker。5.2 空格过滤把 payload 整个搞废有时候 payload 本身没问题但一提交就被过滤。比如你想在某个子句里加空格结果空格被删整个语法全乱。处理建议是坚持写“无空格版”payload或者准备一个工具函数把所有空格统一替换成/**/。另外注意在复杂嵌套里注释符也可能被过滤所以我的主推方案始终是括号法。5.3 循环到了结尾还在继续猜flag 通常以特定格式结尾比如}或者某个固定标志。如果脚本按长度循环完但最后一个字符怎么都不对可能是长度计算错了。建议先用脚本打印长度再人工验证一下分别提交length(...)N和length(...)N1看结果是否一致。两边都符合预期才说明长度判断是对的。5.4 超时、限流和网络波动在靶场练习时平台可能存在限流。脚本发太快可能在某个请求开始超时导致整个二分流程卡住。解决方案是加超时重试、控制请求间隔、限制并发。另外可以在脚本里加一个“连续三次超时就退出”的保护避免无意义等待。网络波动这件事容易被新手忽略因为你本地看到的页面和脚本请求之间可能有 CDN 缓存或代理干扰必要时把 headers 补全一点模拟真实浏览器行为。5.5 过滤规则变化导致 payload 失效有些练习平台会在同一关卡里随机变化过滤规则上一分钟还能用的 payload下一分钟可能不行了。遇到这种情况先别急着改脚本重新做一轮输入 fuzz把当前过滤规则摸清楚再调整 payload。我的经验是把“探测过滤规则”这个过程也脚本化以后遇到不同靶场就能更快定位。5.6 一个容易被忽略的细节字符集题目里的 flag 不一定全是可打印 ASCII 字符。如果脚本只搜 32 到 126 这个区间遇到特殊符号或非标准格式就会漏。做二分搜索之前可以先用length确认总长度再观察最后一个字符是不是}如果不是就要扩展搜索范围比如包含中文字符或更多特殊符号。CTF 里大部分 flag 是 ASCII但扩展一下思路没坏处。6. 这套方法还能怎么用6.1 迁移到时间盲注如果目标平台没有响应差异不管条件真假页面都一样布尔盲注的“信道”就失效了。这时候可以考虑时间盲注把“条件真/假”转换成“延时/不延时”用sleep()或benchmark()制造可观测的时间差。整体的二分思路不用变只需把判断函数从“看页面内容”改成“看请求耗时”。6.2 迁移到其他过滤规则Hack World 1 只是一个小样本。我建议学完这道题后去合规的实验环境多做一些带不同过滤规则的同类题比如过滤了更多关键字的、把查询结果反射出来的、甚至要求写完整 SQL 语句的。每次换一种规则就多一次绕过的经验。把常用的绕过技术按“空格、关键字、函数、符号”四类记下来做题时能很快对号入座。我在实际练习中发现的另一个小技巧是所有盲注题都可以抽象成同一个流程——确认注入点、寻找条件为真时的页面差异、设计可二分查询的 payload、写脚本提取。Hack World 1 只是把这个流程放在了一个过滤规则不算极端的环境里。等你哪天遇到一个没有回显、没有报错、页面响应几乎一模一样的目标时这套“找信道、确认响应、慢速提取”的节奏会帮上大忙。最后分享一个经验把二分法的边界条件和响应特征常量最先写好之后换题目只需要改目标地址和过滤规则脚本不用重写。
RELATED

相关推荐

Mac上Homebrew换源全攻略:解决brew install卡顿与更新失败

Mac上Homebrew换源全攻略:解决brew install卡顿与更新失败

Homebrew在Mac上几乎成了开发者的标配,装个nginx、wget、ffmpeg都得靠它。但有个问题大家迟早会遇到:brew install啥都挺顺,偏偏卡在Updating Homebrew和fetching的环节上,一卡就是十几分钟,最后还可能直接报错失败。这…

📅 2026/10/21 17:31:29
任务编排系统规划器设计:状态空间建模与搜索策略全解析

任务编排系统规划器设计:状态空间建模与搜索策略全解析

接手任务编排系统设计时,最让我纠结的不是执行器怎么做、接口怎么定,而是规划器(Planner)这一块到底怎么设计。原因很简单:执行器、监控器这些模块的逻辑相对确定,输入输出一目了然,但规划器不一…

📅 2026/10/21 17:31:29
dhtmlxGantt甘特图组件库详解:从基础配置到二次开发实战

dhtmlxGantt甘特图组件库详解:从基础配置到二次开发实战

简介:一份面向任务调度与项目管理场景的 dhtmlxGantt 甘特图资源包,兼顾最新版与 4.0 版本,适合需要实现任务拖拽、分组、超期警示染色、数据导出以及万条级记录快速加载的中高级前端开发者。资源共 609 个文件、4.84MB,以 JS 核心…

📅 2026/10/21 17:26:28
MORE NEWS

更多资讯

📰

Fluent多相流模型选型与设定避坑指南:VOF、Mixture、Eulerian实战

简介:这份PDF资料面向CFD仿真初学者与工程技术人员,系统梳理Fluent中多相流模型的选择逻辑与设定方法,帮助解决气-液、气-固、液-固等流动场景下模型选型困难的问题。内容从多相流分类入手,覆盖气泡流、液滴流、活塞流、分层自由面…

📰

自动驾驶全栈技术解析:算法、通信与服务器三层架构

第一次接触自动驾驶的时候,我犯过一个很典型的错误:一头扎进感知算法,翻来覆去调检测模型参数,觉得只要让车“看清世界”就够了。结果在仿真器里跑得顺风顺水的路径规划,一旦接上真实那套通信基设和计算平台&#xff0…

📰

SystemVerilog OOP核心:类、对象、封装、继承与多态详解

1. 为什么验证工程师绕不开OOP这套东西刚入行做数字验证那会儿,我最怕看到别人写的测试平台代码。倒不是看不懂initial块和always块,而是那些满屏的class、extends、virtual关键字,看着就头大。后来被项目逼着啃了几个月,才慢慢品…

📰

uni-app小程序表单重复提交的定位与双层防护实践

很多项目里都有这样一个瞬间:用户在下单页填完信息,点了一下提交按钮,网络一卡,页面没立刻反应,他又点了一下。一秒钟后,两条几乎相同的订单落库。这类问题放在 uni-app 小程序里有统一说法,叫表…

📰

JDK源码阅读环境搭建:IDEA导入与断点调试完整指南

1. 为什么还要折腾JDK源码阅读这件事 刚入行那会儿,我也觉得看JDK源码是件挺“自虐”的事——平时写业务代码, ArrayList 、 HashMap 、 ConcurrentHashMap 拿来就用,谁没事去翻底层怎么实现的。直到有一次线上出问题,一个看…

📰

深入解析TEE可信执行环境:从TrustZone架构到OP-TEE应用开发实战

1. 为什么现在要啃TEE这块硬骨头手机里的指纹支付、人脸识别、网银密钥,这些敏感操作你以为是App自己在扛?其实背后站着一个几乎不露脸的“安全屋”——TEE(可信执行环境)。这两年Android生态里,TEE已经从厂商的私有后…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬