Skip to content

宽字符注入

宽字节注入是一个非常常见的话题,即使在PDO的保护下也有可能存在宽字节注入。
本篇文章会包括以下几点
- 宽字符注入的原理? - 几种过滤方式的实现?

宽字节注入的原理

宽字节原理十分简单,即我们经常对传入的数据进行过滤,当对单引号进行转义的时候就会造成程序自身的SQL语句的失效。 即 在 '之前添加上 \ 当发生转义之后我们通常有两种解决的方式, 1. 第一种是 转义\,即在 \之前先添加一个\使其变化为

\  -》 \\ 

从而不生效。 2. 另外一种是 使\消失,在url编码当中 '对应的编码为 %27,而\对应的编码为 %5c 如果我们能够在 '之前添加%df,即传入的数据为

index.php?id=%df'
当添加反斜杠的时候就会变成  
index.php?id=%df%5c'

恰好%df%5c在mysql当中的gbk编码当中对应的是一个特殊的中文字符,从而使得 ' 保留。 ps 这里即使不是df 只要其数据大于 128 0x81都可以 另外只要字符集当中存在 0x5c 也就是反斜杠的十六进制我们都可以试试 所以实际上 这个问题是 mysql和php的问题。
php 的 addslash会在 ' 之前添加 \
mysql 的gbk字符集当中过滤后'\正好是一个字符

如何防御

分两种情况

  1. 第一种是当前的数据库编码为gbk
1、设置mysql_charset为gbk
mysql_query("SET NAMES 'gbk'");
mysql_set_charset('gbk',$conn);

2、使用mysql_real_escape_string 
mysql_real_escape_string()

第二种是数据库编码不是gbk 设置mysql的编码格式为binary 即设置character_set_client为binary

SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary

过滤方式

magic_quote_gpc mysql_real_escape addslashes html实体编码

addslashes

在传入参数的 '' " \ NULL 之前都会加上\进行转义。 magic_quote_gpc 在 php4.0以上是默认开启的,但是在5.4之后取消了这个特性,其作用是addslashes和 stripslashes 当打开时,所有的 '(单引号),"(双引号),\(反斜线)和 NULL 字符都会被自动加上一个反斜线进行转义。 在拼接sql语句的时候是将变量放入了单引号当中,其中只要包含其中的字符都会进行转义。

mysqli_real_escape

官方文档 此函数用来对字符串当中的特殊字符进行转义,使得这个字符串变化为一个合法的SQL语句。但是要提前设置好对应的字符 转义的字符串

NUL \n \r \ ' "

需要解答的问题

Q:url_encode是每一次get请求都会发生的吗?

A:首先说明什么是url编码

只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-_.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。其他的参数都需要进行编码之后才能传入url当中。所以我们之前使用了#没有什么作用,使用代替的%23得到了结果。

ps 在mysql当中说的utf-8 一般指的是 utfbmb3 ,但是因为其不能存储一些特殊的补充字符,所以一般是使用 utfmb4 进行

Q:宽字符注入的时候会造成一个特殊字符配合'

形如 x' and 1=1; 为什么不会得到报错? 难道是过滤了?

A:确实不会有任何过滤的现象。这个需要进行试验。

Q:几种过滤的方法到底造成了什么样的不同?

A:过滤方式大致有

addslashes()
magic_quote() 
mysql_sql_real_escape()

如何进行绕过?

select * from users where username='admin\' #' and password='';

转换为

select * from users where username=char(97,100,109,105,110)#' and password='';

referer

p牛的博客

浅谈开启magic_quotes_gpc后的sql注入攻与防

Back to top