如何利用 PHP 端点来实例化任意类?

信息安全 php 注射
2021-09-07 06:10:08

PHP 允许您从变量或数组条目中实例化类,如下所示:

class Foo {}
$className = 'Foo';
new $className();
$someArray = ['class_name' => 'Foo'];
new $someArray['class_name']();

令人沮丧的是,我的一些同事——在我在多家公司从事的多个项目中——使用了这种语言特性和用户输入提供的类名,作为根据请求中指定的类型实例化几个可能的子类之一的方法。我已经看到了这些方面的代码......

new $_GET['product_type']($_GET['product_id']);

除了令人头疼的维护之外,这显然是愚蠢和危险的;你让攻击者实例化一个任意类。有多危险?有哪些攻击只使用内置的 PHP 类(因此不需要应用程序代码的详细知识),可以针对上述端点使用?

我正在寻找任何人都能想出的最恶劣的攻击,我可以用它来吓唬任何使用这种可怕反模式的未来同事。

1个回答

我不认为你可以用这段代码做任何事情。

但这并不意味着这在任何方面都是安全的。您将应用程序的控制流放弃给用户,这不是一个好主意。

例如,如果您要调用close新创建的对象,攻击者将获得 SSRF:

$obj = new $_GET['x']($_GET['y']);
$obj->close();

// SSRF: 
http://localhost/shell.php?x=SoapClient&y=http://localhost/called

或者,如果您有这样的课程,攻击者将获得会话固定:

class Session {
   function __construct($sessionId) {
       session_id($sessionId);
   }
}

// session fixation:    
http://localhost/shell.php?x=Session&y=123

或者你可能有这样的课程:

class File {
    function __construct($filename, $content) {
        $this->filename = $filename;
        $this->content = $content;
    }

    // [...]

    function save() {
        file_put_contents($this->filename, $this->content);
    }
}

假设用户应该创建的类也有一个save方法(例如,将对象保存到数据库中)。现在攻击者将执行代码。

很容易想象更多这样的场景,其中一个类的构造函数做了一些危险的事情,或者一个类的危险方法与您期望的类的安全方法同名。

您当前的代码库很可能至少允许攻击者做某事

根据您的代码保密也不是一个好主意。即使源代码以某种方式泄露,您的代码也应该是安全的。