快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

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

  /* {{{ 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编码会被认为是一个字符。

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论