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

发布于 2024-12-23 04:51:45 字数 3499 浏览 1 评论 0原文

编辑:在阅读了其他用户的所有输入后,我决定使用@chris建议的call_user_func_array(),这是不使用eval()的另一个原因 它比 call_user_func_array() 慢,但到目前为止,没有人能够按照我的方式利用它,如果您找到方法,请将其作为答案或评论发布:)。所以大家可以借鉴一下。 祝大家圣诞快乐!

---编辑结束---

好吧,我需要制作一个动态代码:

我得到用户输入,如 $_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->prepared 语句,

导致变量的数量是动态的($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]);

不是你所说的。

EDIT: after reading all the input from the other users, i decided, to use what @chris suggested call_user_func_array() one more reason not to use eval() its slower than call_user_func_array(), but so far, nobody was able to exploit it my way, if you find a way, please post it as answer or comment :). So everybody can learn from it.
Merry XMAS to all!

---EDIT END---

Ok i needed to make a dynamic code:

I get user input like $_POST['a'], $_POST['b']; // Depends on each query how many user input.

$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);

this input, gets passed to mysqli->prepared statements

cause the number of variables is dynamic ($input and $output);

i used the php function eval(); Now my question can this be exploited, in my code?

Just look in my function readDB2 to see how i used the eval() function (used it 3x times).

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;
}

EDIT FOR 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]););

EDIT FOR Incognito:

$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");

    ...
}

in my result

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

gets

eval("return $bind");

gets

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

not what you said.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

说不完的你爱 2024-12-30 04:51:45

您正在评估用户提交的数据,从而有效地允许攻击者执行任意代码。这绝对是您的应用程序可能存在的最严重的安全漏洞,没有之一。我的意思是。您的程序确实存在最严重的漏洞。

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

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

这行:

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

变成这样:

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

也就是说,您的原始语句的意图已无效,而是用户导致您删除了 /etc 目录。再说一次,这可能不是一个有效的示例,但这是您通过足够信任用户提交的数据将其传递给 eval 来遭受的攻击。 。

You're evaluating user-submitted data, effectively allowing attackers to execute arbitrary code. This is the absolute worst security hole your application can have, bar none. I mean that. Your programs has literally the worse vulnerability a program can have.

You're passing in $_POST['a'] as the $input parameter. The $input parameter gets treated like an array, and it's individual elements get appended to a string which is evaluated. If somebody posts executable code to your application, you could inadvertently run it.

I won't go so far as to actually post a working exploit, but suppose $_POST['a'] contained a single element, which had the string '); rmdir("/etc"); //.

This line:

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

turns into something like this:

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

That is, the intent of your original statement is nullified, and instead the user has caused you to remove your /etc directory. Again, this is probably not a working example, but this is the sort of attack you're opening yourself up to by trusting user-submitted data enough to pass it to eval.

别靠近我心 2024-12-30 04:51:45

仅供参考, 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 psuedo类型

还有,以后如果你发现自己使用eval,熟悉一下php的var_export() 函数可以帮助您构建安全字符串。但尽量不要使用 eval。

fyi, call_user_func_array() is how you call functions with unknown number of arguments.

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

array_unshift() pushes the 'sss' string element to the front of the array(we want the front because it needs to be the first argument fed to bind_param)

$callable is the callback psuedo type

also, in the future, if you find yourself using eval, familiarize yourself with php's var_export() function which can assist you with constructing safe strings. Try not to use eval though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文