]> granicus.if.org Git - php/commitdiff
MFH: fixed bug #60116 (escapeshellcmd() cannot escape the characters which cause...
authorRui Hirokawa <hirokawa@php.net>
Thu, 10 Nov 2011 14:19:06 +0000 (14:19 +0000)
committerRui Hirokawa <hirokawa@php.net>
Thu, 10 Nov 2011 14:19:06 +0000 (14:19 +0000)
NEWS
ext/standard/exec.c
ext/standard/tests/general_functions/bug60116.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index ba61ca11362e1d36dd8202854d0a69eb93d74856..2cb7a5659a6f421480344c322b9c2e3f190b87e4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,8 +24,10 @@ PHP                                                                        NEWS
   . Fixed bug #60169 (Conjunction of ternary and list crashes PHP). 
     (Laruence)
   . Fixed bug #55475 (is_a() triggers autoloader, new optional 3rd argument to
-    is_a and is_subclass_of). (alan_k)    
-
+    is_a and is_subclass_of). (alan_k) 
+  . Fixed bug #60116 (escapeshellcmd() cannot escape the characters 
+     which cause shell command injection). (rui)
 - Oracle Database extension (OCI8):
   . Increased maxium Oracle error message buffer length for new 11.2.0.3 size 
     (Chris Jones)
index ac96fe68155ff38d9af560e66d1481897401621f..3b6d41167de1e0398be780f9a4a415d352ff5303 100644 (file)
 #include <unistd.h>
 #endif
 
+/* {{{ register_exec_constants
+ *  */
+void register_exec_constants(INIT_FUNC_ARGS)
+{
+    REGISTER_LONG_CONSTANT("ESCAPE_CMD_PAIR", ESCAPE_CMD_PAIR, CONST_PERSISTENT|CONST_CS);
+    REGISTER_LONG_CONSTANT("ESCAPE_CMD_END", ESCAPE_CMD_END, CONST_PERSISTENT|CONST_CS);
+    REGISTER_LONG_CONSTANT("ESCAPE_CMD_ALL", ESCAPE_CMD_ALL, CONST_PERSISTENT|CONST_CS);
+}
+/* }}} */
+
 /* {{{ php_exec
  * If type==0, only last line of output is returned (exec)
  * If type==1, all lines will be printed and last lined returned (system)
@@ -238,7 +248,7 @@ PHP_FUNCTION(passthru)
 
    *NOT* safe for binary strings
 */
-PHPAPI char *php_escape_shell_cmd(char *str)
+PHPAPI char *php_escape_shell_cmd_ex(char *str, int flag)
 {
        register int x, y, l = strlen(str);
        char *cmd;
@@ -266,14 +276,26 @@ PHPAPI char *php_escape_shell_cmd(char *str)
 #ifndef PHP_WIN32
                        case '"':
                        case '\'':
-                               if (!p && (p = memchr(str + x + 1, str[x], l - x - 1))) {
-                                       /* noop */
-                               } else if (p && *p == str[x]) {
-                                       p = NULL;
-                               } else {
+                               if (flag == ESCAPE_CMD_ALL) {
                                        cmd[y++] = '\\';
+                                       cmd[y++] = str[x];
+                               } else if (flag == ESCAPE_CMD_END) {
+                                       if ((x == 0 || x == l - 1) && (str[0] == str[l-1])) {
+                                               cmd[y++] = str[x];
+                    } else {
+                        cmd[y++] = '\\';
+                        cmd[y++] = str[x];
+                    }
+                               } else { /* ESCAPE_CMD_PAIR */
+                                       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];
                                }
-                               cmd[y++] = str[x];
                                break;
 #else
                        /* % is Windows specific for enviromental variables, ^%PATH% will 
@@ -327,6 +349,14 @@ PHPAPI char *php_escape_shell_cmd(char *str)
 }
 /* }}} */
 
+/* {{{ php_escape_shell_cmd
+ */
+PHPAPI char *php_escape_shell_cmd(char *str)
+{
+    return php_escape_shell_cmd_ex(str, ESCAPE_CMD_PAIR);
+}
+/* }}} */
+
 /* {{{ php_escape_shell_arg
  */
 PHPAPI char *php_escape_shell_arg(char *str)
@@ -397,14 +427,15 @@ PHP_FUNCTION(escapeshellcmd)
 {
        char *command;
        int command_len;
+       long flag = ESCAPE_CMD_PAIR;
        char *cmd = NULL;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &command, &command_len) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &command, &command_len, &flag) == FAILURE) {
                return;
        }
 
        if (command_len) {
-               cmd = php_escape_shell_cmd(command);
+               cmd = php_escape_shell_cmd_ex(command, flag);
                RETVAL_STRING(cmd, 0);
        } else {
                RETVAL_EMPTY_STRING();
diff --git a/ext/standard/tests/general_functions/bug60116.phpt b/ext/standard/tests/general_functions/bug60116.phpt
new file mode 100644 (file)
index 0000000..deade1e
--- /dev/null
@@ -0,0 +1,160 @@
+--TEST--
+Test escapeshellcmd() to escape the quotation
+--SKIPIF--
+<?php
+if( substr(PHP_OS, 0, 3) == 'WIN' ) {
+   die('skip...Invalid for Windows');
+}
+?>
+--FILE--
+<?php
+echo "*** Testing escapeshellcmd() escape the quotation ***\n";
+$data = array(
+       '"abc',
+       "'abc",
+       '?<>',
+       '()[]{}$',
+       '%^',
+       '#&;`|*?',
+       '~<>\\',
+       '%NOENV%',
+       "abc' 'def",
+       'abc" "def',
+       "'abc def'",
+       '"abc def"',
+);
+
+echo "case: default\n";
+
+$count = 1;
+foreach ($data AS $value) {
+       echo "-- Test " . $count++ . " --\n";
+       var_dump(escapeshellcmd($value));
+}
+
+echo "case: ESCAPE_CMD_PAIR\n";
+$count = 1;
+foreach ($data AS $value) {
+       echo "-- Test " . $count++ . " --\n";
+       var_dump(escapeshellcmd($value, ESCAPE_CMD_PAIR));
+}
+
+echo "case: ESCAPE_CMD_END\n";
+$count = 1;
+foreach ($data AS $value) {
+       echo "-- Test " . $count++ . " --\n";
+       var_dump(escapeshellcmd($value, ESCAPE_CMD_END));
+}
+
+echo "case: ESCAPE_CMD_ALL\n";
+$count = 1;
+foreach ($data AS $value) {
+       echo "-- Test " . $count++ . " --\n";
+       var_dump(escapeshellcmd($value, ESCAPE_CMD_ALL));
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+*** Testing escapeshellcmd() escape the quotation ***
+case: default
+-- Test 1 --
+string(5) "\"abc"
+-- Test 2 --
+string(5) "\'abc"
+-- Test 3 --
+string(6) "\?\<\>"
+-- Test 4 --
+string(14) "\(\)\[\]\{\}\$"
+-- Test 5 --
+string(3) "%\^"
+-- Test 6 --
+string(14) "\#\&\;\`\|\*\?"
+-- Test 7 --
+string(8) "\~\<\>\\"
+-- Test 8 --
+string(7) "%NOENV%"
+-- Test 9 --
+string(9) "abc' 'def"
+-- Test 10 --
+string(9) "abc" "def"
+-- Test 11 --
+string(9) "'abc def'"
+-- Test 12 --
+string(9) ""abc def""
+case: ESCAPE_CMD_PAIR
+-- Test 1 --
+string(5) "\"abc"
+-- Test 2 --
+string(5) "\'abc"
+-- Test 3 --
+string(6) "\?\<\>"
+-- Test 4 --
+string(14) "\(\)\[\]\{\}\$"
+-- Test 5 --
+string(3) "%\^"
+-- Test 6 --
+string(14) "\#\&\;\`\|\*\?"
+-- Test 7 --
+string(8) "\~\<\>\\"
+-- Test 8 --
+string(7) "%NOENV%"
+-- Test 9 --
+string(9) "abc' 'def"
+-- Test 10 --
+string(9) "abc" "def"
+-- Test 11 --
+string(9) "'abc def'"
+-- Test 12 --
+string(9) ""abc def""
+case: ESCAPE_CMD_END
+-- Test 1 --
+string(5) "\"abc"
+-- Test 2 --
+string(5) "\'abc"
+-- Test 3 --
+string(6) "\?\<\>"
+-- Test 4 --
+string(14) "\(\)\[\]\{\}\$"
+-- Test 5 --
+string(3) "%\^"
+-- Test 6 --
+string(14) "\#\&\;\`\|\*\?"
+-- Test 7 --
+string(8) "\~\<\>\\"
+-- Test 8 --
+string(7) "%NOENV%"
+-- Test 9 --
+string(11) "abc\' \'def"
+-- Test 10 --
+string(11) "abc\" \"def"
+-- Test 11 --
+string(9) "'abc def'"
+-- Test 12 --
+string(9) ""abc def""
+case: ESCAPE_CMD_ALL
+-- Test 1 --
+string(5) "\"abc"
+-- Test 2 --
+string(5) "\'abc"
+-- Test 3 --
+string(6) "\?\<\>"
+-- Test 4 --
+string(14) "\(\)\[\]\{\}\$"
+-- Test 5 --
+string(3) "%\^"
+-- Test 6 --
+string(14) "\#\&\;\`\|\*\?"
+-- Test 7 --
+string(8) "\~\<\>\\"
+-- Test 8 --
+string(7) "%NOENV%"
+-- Test 9 --
+string(11) "abc\' \'def"
+-- Test 10 --
+string(11) "abc\" \"def"
+-- Test 11 --
+string(11) "\'abc def\'"
+-- Test 12 --
+string(11) "\"abc def\""
+Done