Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:17245
HistoryJun 12, 2007 - 12:00 a.m.

PHP parse_str() arbitrary variable overwrite

2007-06-1200:00:00
vulners.com
151
   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.