2

I was reading about the create_function, that will be DEPRECATED on PHP 7.2, that is prone to php command injection. I started to play with it and created an example.

The code below should return the lowercase version of each string in the array.

My question is, Why using 'array_walk_recursive' function seems to fix the code injection in this case?

Legit use of the function

<?
$arr = ['HELLO'];

array_walk_recursive(
    $arr,
    create_function('&$value, $key', '$value = strtolower($value);')
);
print_r($arr);
?>

Array
(
    [0] => hello
)

Trying to Inject command but the PHP code is not evaluated. A string is returned

<?
$arr = ['PHPINFO();']; 
array_walk_recursive(
    $arr,
    create_function('&$value, $key', '$value = strtolower($value);')
);
print_r($arr);
?>

Array (
    [0] => phpinfo(); 
)

Trying to put the phpinfo() inside create_function

(Note that phpinfo ran. The warning is from a php sandbox)

<?
$arr = ['anything'];
array_walk_recursive(
    $arr,
    create_function(
        '&$value, $key',
        'phpinfo(); $value = strtolower($value);'
    )
);
print_r($arr);
?>
*<b>Warning</b>:  phpinfo() has been disabled for security reasons in <b>[...][...](32) : runtime-created function</b> on line <b>1</b><br />
Array
(
    [0] => anything
)*
1

Why using 'array_walk_recursive' function seems to fix the code injection in this case?

It's not array_walk_recursive that is fixing the issue. The problem is that there is no issue in the first place.

You can't use the create_function functions arguments for code injection, as those are treated as variable strings, and can't be used to break out of the current context.

The injected parameter would need to come from outside. For example:

<?php
$arr = ['a' => 'b', 'c' => 'D']; 
$func = $_GET['x']; /// eg x=strtolower
array_walk_recursive(
    $arr,
    create_function('&$value, $key', '$value = ' . $func . '($value);')
);
print_r($arr);
?>

Now you could gain code execution:

x=strtolower($value);phpinfo();

Detailed explanation

<?php // I would suggest to copy-paste the below code to somewhere that supports syntax-highlighting, it helps in understanding the issue
$arr = ['a' => 'b', 'c' => 'D']; 
$func = $_GET['x']; /// eg x=strtolower
array_walk_recursive( // apply the function created below to all array elements
    $arr,
    create_function(                      // creating a new function
        '&$value, $key',                  // arguments for the function
        '$value = ' . $func . '($value);' // the function itself.
            // function uses $func from outside this string context (this is the essential part). 
            // $value is the value from the previous parameter. It is just a string here. 
    )
);
print_r($arr);
?>

When this is called with x=strtolower($value);phpinfo();, the function that create_function creates from the given string is basically:

function (&$value, $key) {
    $value = strtolower($value);phpinfo();
}

And then this function is called for each array entry. We can see how this will lead to code execution.

If we compare that to the code from the OP, the function that is created would be:

function (&$value, $key) {
    $value = strtolower($value);
}

There is no code execution in this function, as no value from outside was used in the string that created the function.

  • Could you maybe comment your code to explain what it's doing differently so it's easier to understand what OP misunderstanding in the first place was? – Tom K. Nov 20 '18 at 14:13
  • @TomK. There isn't that much to comment, but I tried to go a bit more into depth. I hope it's clearer now. – tim Nov 20 '18 at 14:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.