session 在 Joomla 中的处理有一些的问题,它会把没有通过验证的用户名和密码存储在 _session
表中
在登陆过程中,会有一个 303 的跳转,这个 303 是先把用户的输入存在数据库中,再从数据库中读取、对比,即先执行 write
函数在执行 read
函数
而且它的 csrf token 也在前端页面中
这两个函数位于 libraries/joomla/session/storage/database.php
中,内容如下:
可以看到,它在写入的过程中将 \x00*\x00
替换为 \0\0\0
,因为 MySQL 中不能存储 NULL
,而 protected
变量序列化后带有 \x00*\x00
在读取过程中会重新把 \0\0\0
替换为 \x00*\x00
以便反序列化,但是这个替换将 3 字节的内容替换为 6 字节
如果提交的 username
为 per\0\0\0i0d
,那么在 read
时返回的数据就是 s:8:s:"username";s:12:"perNNNi0d"
N 代表 NULL,替换的大小为 9 字节,但是声明的是 12 字节,那么这将是一个无效的对象
那么就可以利用这个溢出来构造"特殊"的代码
值得一提的是,在进行 replace
后,反序列化时 username
会按照 54 的长度读取,读取到 password
字段处,以其结尾的 ;
作为结尾,而 password
字段的内容就逃逸出来,直接进行反序列化了。
思路
\0\0\0
溢出,来逃逸密码 value在数据库中
s:8:s:"username";s:54:"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";s:8:"password";s:6:"123456"
s:8:s:"username";s:54:"NNNNNNNNNNNNNNNNNNNNNNNNNNN";s:8:"password";s:6:"123456"
```
## POP 链的构造
- 接下来就是 POP 链的构造
- 在 `libraries/joomla/database/driver/mysqli.php` 中的 `__destruct()` 触发 `disconnect()` 函数,对 `disconnectHandlers` 数组中的每个值,都会执行 `call_user_func_array()` ,并将 `&$this` 作为参数引用,但是不能控制参数,利用条件是 `$this->connection` 为 `true`
```php
public function __destruct()
{
$this->disconnect();
}
public function disconnect()
{
// Close the connection.
if ($this->connection)
{
foreach ($this->disconnectHandlers as $h)
{
call_user_func_array($h, array( &$this));
}
mysqli_close($this->connection);
}
$this->connection = null;
}
但是在 libraries/simplepie/simplepie.php
中又有可以利用的,这里的函数和参数值都在我们的控制之下
这条语句执行的条件是 $this->cache
必须为 true
,$parsed_feed_url['scheme']
不为空
根据这些信息就能够构造出反序列化链了,如下图,可以很清晰看出构造方式
如果 zopatkgieeqqmifstiih
出现在返回页面就可以判断存在该漏洞