Computer Security
[EN] securityvulns.ru
no-pyccku



Related information

  PHP parse_str variables overwrite

From:gmdarkfig_(at)_gmail.com <gmdarkfig_(at)_gmail.com>
Date:12.06.2007
Subject:PHP parse_str() arbitrary variable overwrite

      Title:    PHP parse_str() arbitrary variable overwrite
     Vendor:    http://www.php.net/
   Advisory:    http://www.acid-root.new.fr/advisories/14070612.txt
     Author:    DarkFig < gmdarkfig (at) gmail (dot) com >
 Written on:    2007/06/12
Released on:    2007/06/12
 Risk level:    Medium / High



[I].BACKGROUND

[Quote from php.net] PHP is a popular open-source programming
language used primarily for developing server-side applications
and dynamic web content, and more recently, other software. The
name is a recursive acronym for "PHP: Hypertext Preprocessor".
This is actually a retronym; see history of PHP.[/quote]

While I was coding the new version of phpsploitclass, I was
reading the manual of parse_url(), then I saw the parse_str()
function. I decided to see how it works. During some test that
I did, I discovered a vulnerability which can be exploited to
overwrite some variables.



[II].MANUAL

void parse_str ( string $str [, array &$arr] )

Parses str as if it were the query string passed via a URL and
sets variables in the current scope. If the second parameter arr
is present, variables are stored in this variable as array
elements instead.

Note: Support for the optional second parameter was added in
PHP 4.0.3.

Note: To get the current QUERY_STRING, you may use the variable
$_SERVER['QUERY_STRING']. Also, you may want to read the section
on variables from outside of PHP.

Note: The magic_quotes_gpc setting affects the output of this
function, as parse_str() uses the same mechanism that PHP uses
to populate the $_GET, $_POST, etc. variables.



[III].SOURCE CODE

--- ./ext/standard/string.c ---
4025. /*
4025. {{{ proto void parse_str(string encoded_string [, array result])
4026. Parses GET/POST/COOKIE data and sets global variables
4026. */
4027. PHP_FUNCTION(parse_str)
4028. {
4029.   zval **arg;
4030.   zval **arrayArg;
4031.   zval *sarg;
4032.   char *res = NULL;
4033.   int argCount;
4034.   
4035.   argCount = ZEND_NUM_ARGS();
4036.   if (argCount < 1 ||
4036.       argCount > 2 ||
4036.       zend_get_parameters_ex(argCount,&arg,&arrayArg) == FAILURE)
4036.   {
####.          /* Not enough or too many args */
4037.          WRONG_PARAM_COUNT;
4038.   }
4039.
4040.  convert_to_string_ex(arg);
4041.  sarg = *arg;
4042.  if (Z_STRVAL_P(sarg) && *Z_STRVAL_P(sarg)) {
4043.          res = estrndup(Z_STRVAL_P(sarg), Z_STRLEN_P(sarg));
4043.
####.  /* Allocate Z_STRLEN_P(sarg)+1 bytes of memory and copy
####.     Z_STRLEN_P(sarg) bytes from Z_STRVAL_P(sarg) to the
####.     newly allocated block */
4044.  }
4045.
####.  /* parse_str(argv1) */
4046.  if (argCount == 1)
4046.  {
4047.          zval tmp;
4048.          Z_ARRVAL(tmp) = EG(active_symbol_table);
4049.
####.  /* The problem is here, there is no conditions before setting
####.     the variable. If a variable already exists, it will overwrite it */
4049.
4050.          sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
4051.  }
####.  /* parse_str(argv1,argv2) */
4051.  else
4051.  {
4052.          /* Clear out the array that was passed in. */
4053.          zval_dtor(*arrayArg);
4054.          array_init(*arrayArg);
4055.          
4056.          sapi_module.treat_data(PARSE_STRING, res, *arrayArg TSRMLS_CC);
4057.  }
4058. }



[IV].EXPLANATIONS

As you can see in the manual, the user who want to use this
function is not prevented against overwriting. That's why I
think that overwriting is not wanted, they forgot to check it.
Simple proof of concept:

<?php

# ?var=new
###########
$var   = 'init';                     #
parse_str($_SERVER['QUERY_STRING']); #
print $var;                          # new

# ?array[]=new                       # Array
##############                       # (
$array = array('init');              #    [0] => init
parse_str($_SERVER['QUERY_STRING']); #    [1] => new
print_r($array);                     # )

# ?array=new
############                                # Array
$array = array('init');                     # (
parse_str($_SERVER['QUERY_STRING'],$array); #    [array] => new
print_r($array);                            # )

?>

This type of vulnerability can open a door to many vulnerabilities,
that's why it's difficult to define the risk level. Unlike extract()
there is no option such as EXTR_SKIP which will define what to do
if there is a collision. So if you want to secure your code, don't
use this function. I didn't contacted the php team but maybe they
will release a fix for this vulnerability.



[V].GREETZ

benjilenoob, ddx39, lorenzo, romano, shaka, sparah.

About | Terms of use | Privacy Policy
© SecurityVulns, 3APA3A, Vladimir Dubrovin
Nizhny Novgorod

 
 



Rating@Mail.ru
test server