🛡 SQLi 注入大全
已掌握 0/46
首页 › 阶段 1 · 入门与探测

入门 · 认识注入与定位输入面

先搞懂注入是什么、怎么判定注入成立、再判断是哪一种类型

当前位置…
总

总纲 · 认识与定位

先搞懂 SQL 注入是什么、注入成立的根因,以及本手册的安全边界与阅读方法。

总纲 › 概念

什么是 SQL 注入 基础

把用户输入当成了 SQL 代码来执行

用户输入被拼接进 SQL 语句并执行,就造成注入。
核心:输入被当作“代码”而不是“数据”来解析。

# 正常
SELECT * FROM users WHERE id=350
# 注入:350 本身无含义,但 350 OR 1=1 把查询条件整段改写
SELECT * FROM users WHERE id=350 OR 1=1 # 永远为真 → 返回全部
一句话

没有正确转义/参数化,输入直接进 SQL,就会被“读出代码的含义”。

📝 逐段拆解 · 拿到后往哪深挖
术语 / 片段含义深挖 / 下一步 →
350 OR 1=1用恒真条件改写 WHERE 条件若返回全部用户 → 注入成立,可进 UNION 或 布尔
OR 1=1逻辑或 + 永真配合 AND/OR 测两种状态,见 真值判定
总纲 › 原理

注入原理与闭合 闭环

先闭合 → 再扩展 → 后注释

任何形式的 SQL 注入,都围绕三个动作:

  • 闭合:用一个 ' 把原字符串引号“关掉”
  • 扩展:加上自己的永真/子查询/UNION
  • 注释:用 -- - 或 # 把后面不要的代码吃掉
数量型 vs 字符串型(决定性差异)
?id=350-- -                        # 数字型:直接拼,不用引号
?name='woodpecker'-- -          # 字符串型:需先闭合引号
?name=woodpecker' OR '1'='1'-- -    # 恒真,绕开原条件
完整拼接出的 SQL
实际参与判断的部分
    注意:数字型和字符串型的唯一区别就在引号和注释。拿 ' 和 -- - 各试一次,“听响”最快。
    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    '单引号 = 闭合符喂一个能报错/变色/卡顿的单引号,基本就是字符串型
    -- -行末注释把后面 AND status=1 之类条件吃掉,让注入的部分独立生效
    OR '1'='1'恒真条件始终为真 → 绕过原 where 的条件判断
    350 数字型不带引号直接拼接若 350-1 内容变化 → 数字型,直入 UNION 不用闭合
    总纲 › 红线

    安全红线与授权 守则

    只在有权限的环境里动手

    这份手册用于攻防教学与授权靶场(CTF、HBC、自建 CTFd、本地靶场)。

    ⚠ 责任声明:任何时候都不对未经授权的系统发起注入测试。hbc.haobachang.com 仅作演示参照,请在你导师/厂商批准、或你自有的靶场里演练。
    提示/要点:授权原则:①你拥有它;②书面/明确授权;③CTF 或培训靶场本身就允许解题。三选一才动手。
    总纲 › 阅读

    这本手册怎么读 导航

    分页串线,不留盲点

    本手册已拆为 6 个主题页,按阶段递进:

    • 入门·探测(本页 ← 你现在在这):判定有没有注入、是哪种
    • 招式库:UNION / 报错 / 布尔 / 时间 / 堆叠,每种都配逐段拆解表
    • 场景注入:GET/POST/Header/Cookie/搜索/登录/特殊位,选一个输入面就够了
    • 绕过:被 WAF 或过滤拦截时怎么换写法
    • 跨库:MySQL/MSSQL/PG/Oracle/SQLite 方言
    • 深水区·实战:读/写文件、提权、命令执行、最终决策图

    用法:顶部标签切页;每节可 “✓ 标记已掌握”跨页留存进度;每个 payload 可一键复制;每个代码块下都有一张详注表,解释每个函数/片段含义与拿到后往哪深挖。

    探

    ①/② 探测 · 先确认“有没有”+“是哪型”

    面对未知输入面:找全参数 → 五连问判型 → 落到具体招式。

    探测 › 输入面

    输入面清单(在哪里注入) 找面

    先想清楚“哪些参数能碰”

    注入必须落在被拼进 SQL 的输入点。列一张清单,越全越好:

    常见输入点(从最常见到最冷门)
    GET:   ?id= / ?page= / ?type= / ?log= / ?uid=
    POST: 表单字段 / JSON body / 搜索框 / 登录框
    Header: User-Agent / Referer / Cookie / X-Forwarded-For
    其他: 排序字段 ORDER 后的列 / 分页 LIMIT 的数字
    隐藏: APIs 的 id、debug 参数、Batch 批量参数
    思路

    值像“标识或数字”的越可疑(id/page/uid)。先每个参数随手一个 ',看谁来“报错”。

    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    GET ?id=?page=URL 查询串参数最最常见的注入面,见 GET
    POST 表单/JSON请求体字段登录/搜索/提交多在此,见 POST
    Header: UA/Referer/XFF请求头参数写日志/取真实 IP 的隐藏面,见 Header
    Cookie会话标识可绕过 URL/body 过滤,见 Cookie
    ORDER/LIMIT 数字排序/分页位窄但常见,见 特殊位
    探测 › 第1问

    判断闭合方式 闭合

    先知道它是“带引号拼”还是“裸拼”

    第一步永远先判字符型还是数字型(即要不要闭合引号)。

    试探序列(逐个试,看谁有反应)
    ?id=350          # 基准:正常页面
    ?id=350-1        # 若内容从 id=350 变 id=349 → 数字型直拼
    ?id=350'         # 若报错(有闭合的单引号) → 字符型
    ?id=350' AND '1'='1  # 字符串恒真:内容变多=闭合成功
    判定

    ①变了 → 数字型;②③④对单引号有反应 → 字符型。数字型可直接 UNION,字符型先记下闭合符。

    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    350-1数字参与运算内容跟着变 → 数字型,字段直接拼在数字位置
    350'在数字后加单引号报错 → 有人把 id 当字符串拼了,需要闭合
    350' AND '1'='1闭合 + 恒真内容变多/正常 → 单引号闭合成功,可在此扩展
    探测 › 第2问

    真值判定(布尔) 布尔

    用“对/错”确认注入成立

    最可靠的确认:让条件

    真→正常、假→空/少记录,看两态分不分明。

    AND 1=1 / AND 1=2 对比
    ?id=350 AND 1=1-- -   # 真:内容不变
    ?id=350 AND 1=2-- -   # 假:内容变空/变少/报错
    判定

    两态分明 → 注入成立,且可直接走布尔盲注。若输入被过滤(and/or),见关键字绕过。

    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    AND 1=1恒真:原逻辑不变第一种状态=页面 A
    AND 1=2恒假:条件被冲掉第二种状态=页面 B;两态分得开 → 可当信道
    两态信道真/假 → 0/1这正是盲注逐位猜数据的原理,见 布尔盲注
    探测 › 第3问

    时间判定 时间

    用“快不快”做信号(内容恒定时)

    当页面内容永远一样、布尔分不出来时,用延迟当信号:真→睡 3 秒,假→秒回。

    SLEEP 探测
    ?id=350 AND SLEEP(3)-- -   # 卡了≈3秒 → 注入成立
    ?id=350 AND IF(1=1,SLEEP(3),0)-- -
    推论

    能睡 → 注入成立,可走时间盲注。注意有些 WAF 对 SLEEP 敏感,见WAF 规避。

    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    SLEEP(3)让查询卡住 N 秒时间盲注的信号:真→卡、假→秒回
    IF(cond,a,b)条件表达式,真返 a 假返 b把"是不是"编码成能区分的差异
    AND SLEEP(3)延迟作为判断载体真→睡、假→秒回,用计时差异当信道
    探测 › 第4问

    报错诱导 报错

    让数据库把信息读进报错里

    如果页面把数据库错误原样显示,就能让查询结果通过报错传出来。

    诱导一个必然出错的表达式
    ?id=350 AND UPDATEXML(1,CONCAT(0x7e,(SELECT version()),0x7e),1)-- -
    # 输出类似: XPATH syntax error: ~8.0.33~
    判定

    报错里带出 ~值~ → 注入成立,走报错注入。若“页面不报错但有变化”→ 回到布尔/时间。

    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    UPDATEXML()/EXTRACTVALUE()MySQL 报错函数单次约 32 字符,超长用 mid() 分段
    0x7e字符 ~ 的十六进制包住值,让回显一眼看清边界
    version()数据库版本号定版本 → 决定 information_schema 有无、报错函数/UDF 是否可行
    CONCAT(0x7e,..,0x7e)把子查询值包进 ~ ~ 中间让值在报错里显眼可见,一眼看清边界
    探测 › 第5问

    数据库指纹 指纹

    先认库再选 payload

    不同数据库的语法、注释符、系统表都不一样。五问里顺手把库认出来。

    一句话指纹(看报错/版本函数)
    MySQL:   version()  报错常带 MySQL/x'  -- 注释是 --空格 或 #
    MSSQL: @@version / CONVERT(int,..) 报错
    PG: PG_SLEEP() / CAST(x AS int) 报错
    Oracle: || 拼接 / FROM dual
    SQLite: sqlite_master / 报错里带 SQLite
    提示/要点:认错库=白干。判注入成功后,先花 30 秒确认是哪家,再带上跨库页的 payload。
    📝 逐段拆解 · 拿到后往哪深挖
    术语 / 片段含义深挖 / 下一步 →
    version()版本 + 平台进 MySQL 用;看是否能 UDF
    @@versionMSSQL 版全局变量在 MSSQL 方言里万能,见 MSSQL
    PG_SLEEP() / CAST(.. AS int)PostgreSQL 时间/报错指纹认准是 PG 再去套 PG 注入语法
    FROM dualOracle 虚表Oracle 查询必须带 FROM,目睹它→基本是 Oracle
    探测 › 汇总

    五连问总决策 决策

    一串反馈,落到一页招式

    把五个探测反馈对应到主攻招式:

    反馈主攻招式进哪一页
    回显(ORDER BY+UNION 有数)UNION 联合注入招式库
    报错带 ~值~报错注入招式库
    真假两态分明布尔盲注招式库
    能睡几秒时间盲注招式库
    ; 能跑多条堆叠注入招式库
    输入被过滤/WAF先绕过再打绕过