• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    php escapeshellcmd多字节编码漏洞解析及延伸

    发布者: 火山休眠期 | 发布时间: 2025-6-28 22:58| 查看数: 47| 评论数: 0|帖子模式

    漏洞公告在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这个函数的,我们先来看看他的处理过程:


    /* {{{ 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手册中给出的利用例子如下:


    <?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]$Content$nbsp;echo 縗
    >  
    ?
    [loveshell@Loveshell tmp]$Content$nbsp;set|grep -i lang
    LANG=zh_CN.GB2312
    LANGVAR=en_US.UTF-8
    [loveshell@Loveshell tmp]$Content$nbsp;export LANG=zh_CN.GBK
    [loveshell@Loveshell tmp]$Content$nbsp;echo 縗

    [loveshell@Loveshell tmp]$Content$nbsp;set|grep -i lang
    LANG=zh_CN.GBK
    LANGVAR=en_US.UTF-8
    [loveshell@Loveshell tmp]$Content$nbsp;

    其中縗的编码为0xbf5c,可以看到在不设置LANG为GBK的时候縗是一个非法的gb2312编码,所以会被认为是两个字符,所以其中含有的0x5c起作用,被认为命令没结束。然后我们设置编码为GBK,縗就会被认为是一个字符来echo了。
    那我们如何来证明php的漏洞呢,拿

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

    exp.php?c=loveshell
    来源:https://www.jb51.net/hack/5427.html
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    最新评论

    浏览过的版块

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表