{"id":598,"date":"2014-10-17T10:04:05","date_gmt":"2014-10-17T10:04:05","guid":{"rendered":"http:\/\/www.selinuxplus.com\/?p=598"},"modified":"2014-10-17T10:19:27","modified_gmt":"2014-10-17T10:19:27","slug":"%e7%94%b1bash%ef%bc%9acve-2014-6271-%e5%ad%a6%e4%b9%a0execve2","status":"publish","type":"post","link":"http:\/\/www.selinuxplus.com\/?p=598","title":{"rendered":"\u7531bash\uff1acve-2014-6271 \u5b66\u4e60execve 2"},"content":{"rendered":"<p>\u5173\u4e8ebash\u7684\u6d4b\u8bd5\u65b9\u6cd5\u5982\u4e0b\uff1a<\/p>\n<pre class=\"lang:default decode:true \" >root@localhost execve]# env x='() { :;}; echo valunerable' bash -c \"echo this is a test\"\r\nvalunerable\r\nthis is a test<\/pre>\n<p>\u6211\u4eec\u4f7f\u7528ltrace \u8ddf\u8e2a\u4e00\u4e0b<\/p>\n<pre class=\"lang:default decode:true \" >strcpy(0x1260c10, \":\")                           = 0x1260c10\r\nmalloc(16)                                       = 0x1260c30\r\nfree(0x1260a10)                                  = &lt;void&gt;\r\nfree(0x12609f0)                                  = &lt;void&gt;\r\nfree(0x1260a70)                                  = &lt;void&gt;\r\nstrcmp(\"execute-command\", \"execute-command\")     = 0\r\nfree(0x1260a40)                                  = &lt;void&gt;\r\nstrlen(\"%s%s\")                                   = 4\r\nmalloc(64)                                       = 0x1260c50\r\nstrlen(\"echo\")                                   = 4\r\nmemcpy(0x1260c50, \"echo\", 4)                     = 0x1260c50\r\nstrlen(\" \")                                      = 1\r\nmemcpy(0x1260c54, \" \", 1)                        = 0x1260c54\r\nstrlen(\"%s%s\")                                   = 4\r\nstrlen(\"valunerable\")                            = 11\r\nmemcpy(0x1260c55, \"valunerable\", 11)             = 0x1260c55\r\nstrlen(\"\")                                       = 0\r\nstrlen(\"echo valunerable\")                       = 16\r\nmalloc(17)                                       = 0x12609f0\r\nstrcpy(0x12609f0, \"echo valunerable\")            = 0x12609f0\r\nmalloc(16)                                       = 0x1260ca0\r\nstrlen(\"echo\")                                   = 4\r\nmalloc(5)                                        = 0x1260cc0\r\nstrcpy(0x1260cc0, \"echo\")                        = 0x1260cc0\r\nmalloc(16)                                       = 0x1260ce0\r\nmalloc(16)                                       = 0x1260d00\r\nstrlen(\"valunerable\")                            = 11\r\nmalloc(12)                                       = 0x1260d20\r\nstrcpy(0x1260d20, \"valunerable\")                 = 0x1260d20\r\nmalloc(16)                                       = 0x1260d40\r\n__ctype_get_mb_cur_max()                         = 6\r\nstrlen(\"echo\")                 <\/pre>\n<p>\u770b\u4e00\u4e0b\u95ee\u9898\u53d1\u751f\u7684\u7684\u539f\u56e0\uff1a        <\/p>\n<pre class=\"lang:default decode:true \" >[root@localhost bash-4.2]# vim builtins\/evalstring.c \r\nint\r\nparse_and_execute (string, from_file, flags)\r\n     char *string;\r\n     const char *from_file;\r\n     int flags;\r\n{\r\n...\r\n\r\n if (parse_command () == 0)\r\n        {\r\n          if ((flags &amp; SEVAL_PARSEONLY) || (interactive_shell == 0 &amp;&amp; read_but_dont_execute))\r\n              \u6b64\u8bed\u53e5\u6ca1\u6709\u505a\u51fd\u6570\u8fb9\u754c\u5224\u65ad\r\n            {\r\n              last_result = EXECUTION_SUCCESS;\r\n              dispose_command (global_command);\r\n              global_command = (COMMAND *)NULL;\r\n            }\r\n          else if (command = global_command)\r\n            {\r\n             \/\/\u6b64\u8bed\u53e5\u5982\u679c\u6267\u884c\uff0c\u4f20\u5165\u7684\u51fd\u6570\u5219\u4f1a\u88ab\u5f53\u4f5c\u5168\u5c40\u53d8\u91cf\uff0c\u7136\u540e\u5168\u5c40\u53d8\u91cf\u540e\u7684\u4ee3\u7801\u5219\u4f1a\u6267\u884c\u6210\u529f\r\n              struct fd_bitmap *bitmap;\r\n\r\n              bitmap = new_fd_bitmap (FD_BITMAP_SIZE);\r\n              begin_unwind_frame (\"pe_dispose\");\r\n              add_unwind_protect (dispose_fd_bitmap, bitmap);\r\n              add_unwind_protect (dispose_command, command);    \/* XXX *\/\r\n\r\n              global_command = (COMMAND *)NULL;\r\n\r\n              if ((subshell_environment &amp; SUBSHELL_COMSUB) &amp;&amp; comsub_ignore_return)\r\n                command-&gt;flags |= CMD_IGNORE_RETURN;\r\n\r\nvoid\r\ninitialize_shell_variables (env, privmode)\r\n     char **env;\r\n    create_variable_tables ();\r\n  \u4eceENV\u73af\u5883\u53d8\u91cf\u4e2d\u83b7\u53d6\u53c2\u6570\r\n  for (string_index = 0; string = env[string_index++]; )\r\n    {\r\n      char_index = 0;\r\n      name = string;\r\n      while ((c = *string++) &amp;&amp; c != '=')\r\n        ;\r\n      if (string[-1] == '=')\r\n        char_index = string - name - 1;\r\n\r\n      \/* If there are weird things in the environment, like `=xxx' or a\r\n         string without an `=', just skip them. *\/\r\n      if (char_index == 0)\r\n        continue;\r\n\r\n      \/* ASSERT(name[char_index] == '=') *\/\r\n      name[char_index] = '\\0';\r\n      \/* Now, name = env variable name, string = env variable value, and\r\n         char_index == strlen (name) *\/\r\n\r\n      temp_var = (SHELL_VAR *)NULL;\r\n\r\n      \/* If exported function, define it now.  Don't import functions from\r\n         the environment in privileged mode. *\/\r\n      if (privmode == 0 &amp;&amp; read_but_dont_execute == 0 &amp;&amp; STREQN (\"() {\", string, 4))\r\n        bash\u51fd\u6570\u7684\u5904\u7406\uff1a\r\n        {\r\n          string_length = strlen (string);\r\n          temp_string = (char *)xmalloc (3 + string_length + char_index);\r\n\r\n          strcpy (temp_string, name);\r\n          temp_string[char_index] = ' ';\r\n          strcpy (temp_string + char_index + 1, string);\r\n          \u8fd9\u91cc\u8c03\u7528\u4e86parse_and_execute \uff0c\u518d\u8c03\u7528\u4e4b\u524d\u6ca1\u6709\u5bf9temp_string \u7684\u8fb9\u754c\u8fdb\u884c\u68c0\u67e5\r\n          parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);\r\n\r\n          \/* Ancient backwards compatibility.  Old versions of bash exported\r\n             functions like name()=() {...} *\/\r\n          if (name[char_index - 1] == ')' &amp;&amp; name[char_index - 2] == '(')\r\n            name[char_index - 2] = '\\0';\r\n\r\n          if (temp_var = find_function (name))\r\n            {\r\n              VSETATTR (temp_var, (att_exported|att_imported));\r\n              array_needs_making = 1;\r\n            }\r\n           else\r\n            report_error (_(\"error importing function definition for `%s'\"), name);\r\n\r\n          \/* ( *\/\r\n          if (name[char_index - 1] == ')' &amp;&amp; name[char_index - 2] == '\\0')\r\n            name[char_index - 2] = '(';         \/* ) *\/\r\n        }\r\n<\/pre>\n<p>\u5b98\u65b9\u63d0\u4f9b\u7684\u7b2c\u4e00\u6b21patch<\/p>\n<pre class=\"lang:default decode:true \" >cat  bash-requires.patch \r\ndiff -up bash-4.1\/execute_cmd.c.requires bash-4.1\/execute_cmd.c\r\n--- bash-4.1\/execute_cmd.c.requires\t2010-08-02 17:42:41.000000000 +0200\r\n+++ bash-4.1\/execute_cmd.c\t2010-08-02 17:42:41.000000000 +0200\r\n@@ -503,6 +503,8 @@ async_redirect_stdin ()\r\n \r\n #define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0)\r\n \r\n+extern int rpm_requires;\r\n+\r\n \/* Execute the command passed in COMMAND, perhaps doing it asynchrounously.\r\n    COMMAND is exactly what read_command () places into GLOBAL_COMMAND.\r\n    ASYNCHROUNOUS, if non-zero, says to do this command in the background.\r\n@@ -534,7 +536,13 @@ execute_command_internal (command, async\r\n #else\r\n   if (breaking || continuing)\r\n     return (last_command_exit_value);\r\n-  if (command == 0 || read_but_dont_execute)\r\n+  if (command == 0 || (read_but_dont_execute &amp;&amp; !rpm_requires))\r\n+    return (EXECUTION_SUCCESS);\r\n+  if (rpm_requires &amp;&amp; command-&gt;type == cm_function_def)\/\/\u52a0\u5165\u5224\u65ad\u7c7b\u578b\r\n+    return last_command_exit_value =\r\n+      execute_intern_function (command-&gt;value.Function_def-&gt;name,\r\n+                              command-&gt;value.Function_def-&gt;command);\r\n+  if (read_but_dont_execute)\r\n     return (EXECUTION_SUCCESS);\r\n #endif<\/pre>\n<p>\u4f46\u4ea7\u751f\u4e86\u4e00\u4e2a\u65b0\u7684\u95ee\u9898\uff1a<\/p>\n<pre class=\"lang:default decode:true \" >[root@localhost ~]# env X='() { (x)=&gt;\\' bash -c \"my echo valunerable\"\r\nbash: X: line 1: syntax error near unexpected token `='\r\nbash: X: line 1: `'\r\nbash: error importing function definition for `X'\r\n[root@localhost ~]# cat my \r\nvalunerable\r\n<\/pre>\n<p>\u7531\u4e8e\u51fd\u6570\u4f53\u6ee1\u8db3() { \uff0c\u4e5f\u6ca1\u6709\u53d1\u73b0&#8221;;&#8221;,bash\u5728eval\u7684\u65f6\u5019\u9047\u5230\u8bed\u6cd5\u95ee\u9898(x)=\u88ab\u5ffd\u7565\u4e86\uff0c\u5c31\u6267\u884c>\/my echo valunerable<\/p>\n<p>\u7b2c\u4e8c\u6b21\u63d0\u4f9b\u4e86<\/p>\n<pre class=\"lang:default decode:true \" >     \/* If exported function, define it now.  Don't import functions from\r\n \t the environment in privileged mode. *\/\r\n-      if (privmode == 0 &amp;&amp; read_but_dont_execute == 0 &amp;&amp; STREQN (\"() {\", string, 4))\r\n-\t{\r\n-\t  string_length = strlen (string);\r\n-\t  temp_string = (char *)xmalloc (3 + string_length + char_index);\r\n+      if (privmode == 0 &amp;&amp; read_but_dont_execute == 0\r\n+\t  &amp;&amp; STREQN (FUNCDEF_PREFIX, name, FUNCDEF_PREFIX_LEN)\r\n+\t  &amp;&amp; STREQ (name + char_index - FUNCDEF_SUFFIX_LEN, FUNCDEF_SUFFIX)\r\n+\t  &amp;&amp; STREQN (\"() {\", string, 4)) \/\/\u589e\u52a0\u4e86\u51fd\u6570\u8fb9\u754c\u5224\u65ad\r\n+\t{\r\n+\t  size_t name_length\r\n+\t    = char_index - (FUNCDEF_PREFIX_LEN + FUNCDEF_SUFFIX_LEN);\r\n+\t  char *temp_name = name + FUNCDEF_PREFIX_LEN;\r\n+\t  \/* Temporarily remove the suffix. *\/\r\n+\t  temp_name[name_length] = '\\0';\r\n \r\n-\t  strcpy (temp_string, name);\r\n-\t  temp_string[char_index] = ' ';\r\n-\t  strcpy (temp_string + char_index + 1, string);\r\n+\t  string_length = strlen (string);\r\n+\t  temp_string = (char *)xmalloc (name_length + 1 + string_length + 1);\r\n+\t  memcpy (temp_string, temp_name, name_length);\r\n+\t  temp_string[name_length] = ' ';\r\n+\t  memcpy (temp_string + name_length + 1, string, string_length + 1);\r\n \r\n \t  \/* Don't import function names that are invalid identifiers from the\r\n \t     environment, though we still allow them to be defined as shell\r\n\t     variables. *\/\r\n-\t  if (legal_identifier (name))\r\n-\t    parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);\r\n+\t  if (legal_identifier (temp_name))\r\n+\t    parse_and_execute (temp_string, temp_name,\r\n+\t\t\t       SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);\r\n \r\n-\t  if (temp_var = find_function (name))\r\n+\t  if (temp_var = find_function (temp_name))\r\n \t    {\r\n \t      VSETATTR (temp_var, (att_exported|att_imported));\r\n \t      array_needs_making = 1;\r\n \t    }\r\n \t  else\r\n \t    report_error (_(\"error importing function definition for `%s'\"), name);\r\n+\r\n+\t  \/* Restore the original suffix. *\/\r\n+\t  temp_name[name_length] = FUNCDEF_SUFFIX[0];\r\n \t}\r\n #if defined (ARRAY_VARS)\r\n #  if 0\r\n@@ -2537,7 +2557,7 @@\r\n   var-&gt;context = variable_context;\t\/* XXX *\/\r\n \r\n   INVALIDATE_EXPORTSTR (var);\r\n-  var-&gt;exportstr = mk_env_string (name, value);\r\n+  var-&gt;exportstr = mk_env_string (name, value, 0);\r\n \r\n   array_needs_making = 1;\r\n \r\n@@ -3388,22 +3408,43 @@\r\n \/*\t\t\t\t\t\t\t\t    *\/\r\n \/* **************************************************************** *\/\r\n \r\n+\/* Returns the string NAME=VALUE if !FUNCTIONP or if VALUE == NULL (in\r\n+   which case it is treated as empty).  Otherwise, decorate NAME with\r\n+   FUNCDEF_PREFIX and FUNCDEF_SUFFIX, and return a string of the form\r\n+   FUNCDEF_PREFIX NAME FUNCDEF_SUFFIX = VALUE (without spaces).  *\/\r\n\/\/\u589e\u52a0\u4e86\u5bf9\u51fd\u6570\u7684\u5224\u65ad\r\n static inline char *\r\n-mk_env_string (name, value)\r\n+mk_env_string (name, value, functionp)\r\n      const char *name, *value;\r\n+     int functionp;\r\n {\r\n-  int name_len, value_len;\r\n-  char\t*p;\r\n+  size_t name_len, value_len;\r\n+  char *p, *q;\r\n \r\n   name_len = strlen (name);\r\n   value_len = STRLEN (value);\r\n-  p = (char *)xmalloc (2 + name_len + value_len);\r\n-  strcpy (p, name);\r\n-  p[name_len] = '=';\r\n+  if (functionp &amp;&amp; value != NULL)\r\n+    {\r\n+      p = (char *)xmalloc (FUNCDEF_PREFIX_LEN + name_len + FUNCDEF_SUFFIX_LEN\r\n+\t\t\t   + 1 + value_len + 1);\r\n+      q = p;\r\n+      memcpy (q, FUNCDEF_PREFIX, FUNCDEF_PREFIX_LEN);\r\n+      q += FUNCDEF_PREFIX_LEN;\r\n+      memcpy (q, name, name_len);\r\n+      q += name_len;\r\n+      memcpy (q, FUNCDEF_SUFFIX, FUNCDEF_SUFFIX_LEN);\r\n+      q += FUNCDEF_SUFFIX_LEN;\r\n+    }\r\n+  else\r\n+    {\r\n+      p = (char *)xmalloc (name_len + 1 + value_len + 1);\r\n+      memcpy (p, name, name_len);\r\n+      q = p + name_len;\r\n+    }\r\n+  q[0] = '=';\r\n   if (value &amp;&amp; *value)\r\n-    strcpy (p + name_len + 1, value);\r\n+    memcpy (q + 1, value, value_len + 1);\r\n   else\r\n-    p[name_len + 1] = '\\0';\r\n+    q[1] = '\\0';\r\n   return (p);\r\n }\r\n\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u5173\u4e8ebash\u7684\u6d4b\u8bd5\u65b9\u6cd5\u5982\u4e0b\uff1a root@local&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[100,4,103,5],"tags":[17,128,129],"_links":{"self":[{"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/posts\/598"}],"collection":[{"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=598"}],"version-history":[{"count":4,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/posts\/598\/revisions"}],"predecessor-version":[{"id":646,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=\/wp\/v2\/posts\/598\/revisions\/646"}],"wp:attachment":[{"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=598"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=598"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.selinuxplus.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}