利用GBK双字节编码突破PHP单引号转义限制进行SQL注入

本文介绍了一种利用GBK双字节编码特性绕过PHP单引号转义的方法,实现SQL注入攻击。通过特定的编码序列使PHP的magic_quotes_gpc设置失效,从而使原本被转义的单引号能够正常用于SQL注入。

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

利用GBK双字节编码突破PHP单引号转义限制进行SQL注入

今天看了黑防2009精华本下册《双字节编码:PHP的隐形杀手》一文,深受启发。

当php.ini中magic_quotes_gpc被设置为on时,提交的参数会被转义,例如,单引号会被转义成了'。一下子截断了字符型注入的路。

GBK双字节编码:一个汉字用两个字节表示,首字节对应0x81-0xFE,尾字节对应0x40-0xFE(除0x7F),刚好涵盖了对应的编码0x5C。

0xD5 0x5C 对应了汉字“誠”,于是 %d5%5c  经URL解码后为“誠”。

当我们提交参数 %d5' ,经浏览器URL编码后为%d5%27,再经PHP URL解码后为 0xd50x27,再经PHP转义后为0xd50x5c0x27,即就是在0x27(')之前插入了转义符0x5c(\)。当MySQL采用GBK编码连 接时,0xd50x5c0x27 这一字节序列就被MySQL作为GBK编码理解:誠'。

这样就吃掉了PHP的转义符,从而突破了单引号转义的限制。


本地测试如下:


测试脚本index.php如下:

  1. <?php  
  2. $conn=0;  
  3. $conn = mysql_connect("localhost","root","see2006");  
  4. if (!$conn)  
  5. {  
  6.   die("不能打开数据库连接,错误: " . mysql_error());  
  7. }  
  8.   
  9. // 选择数据库  
  10. mysql_select_db("test"$conn);  
  11.   
  12. // 设置mysql数据库输出数据的字符集  
  13. mysql_query("set names 'gbk'");  
  14.   
  15. $sql="select * from  news where content like '%".$_REQUEST['k']."%'";  
  16. echo "当前sql语句:".$sql."<br/><br/>";  
  17.   
  18. $result=mysql_query($sql,$conn);  
  19.   
  20. if(!$result)  
  21.   echo mysql_error();  
  22.   
  23. while($result && $row=mysql_fetch_array($result))  
  24. {  
  25.    echo "$row[title]<br/>";  
  26. }  
  27. ?>  





搜索关键字为空,显示所有条目

18_233143_nkcq.gif


单引号被PHP自动转义

18_233207_zwo3PHP.gif


利用双字节编码绕过PHP转义,SQL语句出错

18_233221_he7lPHPSQL.gif


利用#注释之后的SQL语句,语法正确

18_233242_da3gSQL.gif


union猜字段数目和可显示字段的位置

18_233259_c02funion.gif


union查看当前用户

18_233321_gd7kunion.gif


union查看当前数据库名

18_233401_xum1union.gif


union查看test数据库表名

18_233422_xum2uniontest.gif


union查看user表的name字段值

18_233440_kh0nunionusername.gif


union查看user表的pass字段值

18_233508_sphwunionuserpass.gif

转载于:https://www.cnblogs.com/kangwang1988/archive/2011/04/20/2023043.html

<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、付费专栏及课程。

余额充值