PHP eval()在我的代码中可以利用吗? (动态参数)

时间:2011-12-25 15:08:04

标签: php mysqli eval prepared-statement

编辑:在阅读了其他用户的所有输入后,我决定使用@chris建议 call_user_func_array()的另一个理由,不要使用 eval() call_user_func_array()慢,但到目前为止,没有人能够以我的方式利用它,如果你找到方法,请将其发布为答案或评论:)。所以每个人都可以从中学习。 Merry XMAS给所有人!

---编辑结束---

好的,我需要制作动态代码:

我得到的用户输入如 $ _ POST ['a'],$ _POST ['b']; //取决于每个查询有多少用户输入。

$sql = "SELECT 1, 2, 3 FROM x WHERE b = ? AND a = ? LIMIT 10"; // SQL STATEMENT
$input = array($_POST['a'], $_POST['b']);
$output = 3; // Number of variables need for 1, 2, 3
$data = readDB2($sql, $input, $output);
var_dump($data);

此输入,传递给mysqli->预处理语句

导致变量数量是动态的($ input和$ output);

我使用了php函数eval();现在我的问题可以在我的代码中被利用了吗?

只需查看我的函数readDB2,看看我如何使用eval()函数(使用它3次)。

public function readDB2($sql, $input, $output1) {

    $stmt = $this->mysqli->prepare($sql);
    if(!empty($input) && is_array($input)) {
        $sp = "";
        $data = "";
        $inputn = count($input) - 1;
        for($i = 0; $i <= $inputn; $i++) {
            if($i !== $inputn) {
                $data .= '$input[' . $i . "],";
            } else {
                $data .= '$input[' . $i . "]";
            }
            $sp .= "s";
        }
        $bind = '$stmt->bind_param(\''. $sp . '\',' . $data . ');';
        eval("return $bind");
    }
    if (!$stmt) {throw new Exception($this->mysqli->error);}
    $stmt->execute();
    if (!$stmt) {throw new Exception($this->mysqli->error);}
    $stmt->store_result();
    $checker = $stmt->num_rows;
    if($checker !== 0) {
        if(!empty($output1)) {
            $out = "";
            for($i = 1; $i <= $output1; $i++) {
                if($i !== $output1) {
                    $out .= '$out' . $i . ",";
                } else {
                    $out .= '$out' . $i;
                }
            }
            $res = '$stmt->bind_result(' . $out . ');';
            eval("return $res");

            $vars = "array(" . $out . ");";

            while ($stmt->fetch()) {
                $results[] = eval("return $vars");
            }

        }
    } else {
        $results = "NO RESULTS";
    }
    $stmt->fetch();
    $stmt->close();

    $this->results = array('num_rows' => $checker, $results);

    return $this->results;
}

为meagar编辑

$bind = '$stmt->bind_param(\''. $sp . '\',' . $data . ');'; 
==
$bind = '$stmt->bind_param('ss', $input[0], $input[1]);); 
OR and so on
$bind = '$stmt->bind_param('sss', $input[0], $input[1], $input[2]););

编辑隐身:

$input = array($_POST['pwnd']);

$data = readDB2($sql, $input, $output) {

public function readDB2($sql, $input, $output) {
    ...
    $inputn = count($input) - 1;
    for($i = 0; $i <= $inputn; $i++) {
            if($i !== $inputn) {
                $data .= '$input[' . $i . "],";
            } else {
                $data .= '$input[' . $i . "]";
            }
            $sp .= "s";
        }
        $bind = '$stmt->bind_param(\''. $sp . '\',' . $data . ');';
        eval("return $bind");

    ...
}

在我的结果中

$bind = '$stmt->bind_param(\''. $sp . '\',' . $data . ');';

获取

eval("return $bind");

$stmt->bind_param('s', $input[0]);

不是你说的。

2 个答案:

答案 0 :(得分:4)

您正在评估用户提交的数据,有效地允许攻击者执行任意代码。这是您的应用程序可以拥有的绝对最严重的安全漏洞,没有。我的意思是。你的程序实际上是程序可能带来的更糟糕的漏洞。

您正在传递$_POST['a']作为$input参数。 $input参数被视为一个数组,它的各个元素被附加到一个被评估的字符串。如果有人将可执行代码发布到您的应用程序,您可能会无意中运行它。

我不会实际发布一个有效的漏洞,但假设$_POST['a']包含一个元素,其中包含字符串'); rmdir("/etc"); //

这一行:

    $bind = '$stmt->bind_param(\''. $sp . '\',' . $data . ');';

变成这样的东西:

    $stmt->bind_param(''); rmdir("/etc"); //);';

也就是说,原始语句的意图无效,而是用户导致您删除了/etc目录。同样,这可能不是一个工作示例,但这是您通过信任用户提交的数据足以将其传递给eval而打开的攻击类型。

答案 1 :(得分:2)

fyi,call_user_func_array()是如何调用具有未知数量参数的函数。

array_unshift($input, str_repeat('s', count($input)));
$callable = array($stmt, 'bind_param');
call_user_func_array($callable, $input);

array_unshift()将'sss'字符串元素推送到数组的前面(我们想要前面因为它需要是第一个输入bind_param的参数)

$ callable是callback伪造类型

此外,如果您发现自己使用eval,请熟悉php的var_export()函数,它可以帮助您构建安全字符串。尽量不要使用eval。