Mb_ereg (I) _ replace () code injection vulnerability and its extended regular application security problems

Source: Internet
Author: User

Author: ryat # wolvez.org
Team: http://www.80vul.com
Date: 2009-04-30

Description

Mb_ereg_replace () is a function that supports multi-byte Regular Expression replacement. The function prototype is as follows:

String mb_ereg_replace (string $ pattern, string $ replacement, string $ string [, string $ option = "msr"])

When the option parameter of mb_ereg (I) _ replace () is set to e, the replacement parameter [after proper reverse reference replacement] will be executed as the php code, however, php has security risks in processing this process, which may lead to arbitrary code execution by bypassing the program's logic. In addition, programmers do not know enough about regular expression matching replacement [including preg_replace and other functions]. this vulnerability is easily caused by security restrictions.


2. Analysis

Code for mb_ereg_replace:

// Php_mbregex.c
PHP_FUNCTION (mb_ereg_replace)
{
_ Php_mb_regex_ereg_replace_exec (INTERNAL_FUNCTION_PARAM_PASSTHRU, 0 );
}
...
Static void _ php_mb_regex_ereg_replace_exec (INTERNAL_FUNCTION_PARAMETERS, OnigOptionType options)
{
...
Smart_str out_buf = {0 };
Smart_str eval_buf = {0 };
Smart_str * pbuf;
...
If (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC, "Zss | s ",
& Arg_pattern_zval,
& Replace, & replace_len,
& String, & string_len,
& Option_str, & option_str_len) = FAILURE ){
RETURN_FALSE;
}
...
Re = php_mbregex_compile_pattern (arg_pattern, arg_pattern_len, options, MBSTRG (current_mbctype), syntax TSRMLS_CC );
// Compilation mode. The compiled mode is stored in the re_pattern_buffer structure.
...
If (eval ){
Pbuf = & eval_buf;
Description = zend_make_compiled_string_description ("mbregex replace" TSRMLS_CC );
} Else {
Pbuf = & out_buf;
Description = NULL;
// * Pbuf, eval_buf, and out_buf are all smart_str structures. The structure is described as follows:
// Typedef struct {
// Char * c;
// Size_t len;
// Size_t;
//} Smart_str;
}

/* Do the actual work */
Err = 0;
Pos = string;
String_lim = (OnigUChar *) (string + string_len );
Regs = onig_region_new ();
// Allocate memory, initialize the re_registers structure, used to store the pattern matching value [num_regs members are the number of child pattern matching values, beg Members are the start bits of the pattern and subpattern matching values, and end members are the hidden bits]
While (err> = 0 ){
Err = onig_search (re, (OnigUChar *) string, (OnigUChar *) string_lim, pos, (OnigUChar *) string_lim, regs, 0 );
// Match based on the compiled Mode
...
/* Copy the part of the string before the match */
Smart_str_appendl (& out_buf, pos, (size_t) (OnigUChar *) (string + regs-> beg [0])-pos ));
// Add the part before the start of the pattern matching value [return value for function]
/* Copy replacement and backrefs */
I = 0;
P = replace;
While (I <replace_len ){
Int fwd = (int) php_mb_mbchar_bytes_ex (p, enc );
N =-1;
If (replace_len-I)> = 2 & fwd = 1 &&
P [0] ==\& & p [1]> = 0 & p [1] <= 9 ){
N = p [1]-0;
}
If (n> = 0 & n <regs-> num_regs ){
If (regs-> beg [n]> = 0 & regs-> beg [n] <regs-> end [n] & regs-> end [n] <= string_len) {
Smart_str_appendl (pbuf, string + regs-> beg [n], regs-> end [n]-regs-> beg [n]);
// If a reverse reference is used and the corresponding [sub] pattern matching value exists, call smart_str_appendl to add the [sub] mode matching value [Call memcpy to copy the value to pbuf-> c + pbuf-> len]
}
} Else {
Smart_str_appendl (pbuf, p, fwd );
P + = fwd;
I + = fwd;
}
}
...
If (eval ){
Zval v;
/* Null terminate buffer */
Smart_str_appendc (& eval_buf ,);
/* Do eval */
If (zend_eval_string (eval_buf.c, & v, description TSRMLS_CC) = FAILURE ){
Efree (description );
Php_error_docref (NULL TSRMLS_CC, E_ERROR, "Failed evaluating code: % s", PHP_EOL, eval_buf.c );
/* Zend_error () does not return in this case */
}

// If option is set to e, call zend_eval_string to process eval_buf.c, that is, pbuf-> c [compile it into opcode first, and call zend_execute to process opcode]
// The above code mb_ereg_replace does not safely process the captured sub-pattern matching value. It directly calls zend_eval_string to execute the replace value.
// This will lead to some security risks: for example, you can introduce it before closing, in addition, we can also introduce nullbyte to cut off the Code [zend_eval_string is not binary safe] :) to compare and describe this security vulnerability, we will also analyze preg_replace () the process of executing php code in/e:

// Preg_replace ()
...
If (eval ){
Eval_result_len = preg_do_eval (replace, replace_len, subject,
Offsets, count, & eval_result TSRMLS_CC );
// Call preg_do_eval in e modifier Mode
...
Static int preg_do_eval (char * eval_str, int eval_str_len, char * subject,
Int * offsets, int count, char ** result TSRMLS_DC)
{
...
Smart_str code = {0 };

Eval_str_end = eval_str + eval_str_len;
Walk = segment = eval_str;
Performance_last = 0;

While (walk <eval_str_end ){
/* If found a backreference ..*/
If (\ = * walk | $ = * walk ){
Smart_str_appendl (& code, segment, walk-segment );
If (cmd_last = \){
Code. c [code. len-1] = * walk ++;
Segment = walk;
Performance_last = 0;
Continue;
}
Segment = walk;
If (preg_get_backref (& walk, & backref )){
If (backref <count ){
/* Find the corresponding string match and substitute it
In instead of the backref */
Match = subject + offsets [backref <1];
Match_len = offsets [(backref <1) + 1]-offsets [backref <1];
If (match_len ){
Esc_match = php_addslashes_ex (match, match_len, & esc_match_len, 0, 1 TSRMLS_CC );
// If a reverse reference is used and a corresponding [sub] pattern matching value exists, php_addslashes_ex is called for the captured [sub] pattern matching value.
...
Smart_str_appendl (& code, esc_match, esc_match_len );
// Add a [sub] pattern matching Value
...
Smart_str_appendl (& code, segment, walk-segment );
Smart_str_0 (& code );

Compiled_string_description = zend_make_compiled_string_description ("regexp code" TSRMLS_CC );
/* Run the code */
If (zend_eval_string (code. c, & retval, compiled_string_description TSRMLS_CC) = FAILURE ){
Efree (compiled_string_description );
Php_error_docref (NULL TSRMLS_CC, E_ERROR, "Failed evaluating code: % s", PHP_EOL, code. c );
/* Zend_error () does not return in this case */
}
// Call zend_eval_string to process the code. cpreg_replace () function and call php_addslashes_ex for the captured pattern matching value.

Three test code:

<? Php
// Mb_ereg (

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.