一、起因
偶然间看到的一套cms系统,随手测试一波csrf,没想到失败了,于是看了一下这套cms的csrf防御代码
二、 过程
一个简单的后台页面
首先尝试添加管理员的CSRF
抓包:
明文密码传输就懒得吐槽了,虽然影响不大。主要是使用的json格式传输数据,这个格式如何构造csrf代码,以前写过一篇文章(https://www.cnpanda.net/talksafe/116.html),就不再赘述。于是构造的poc如下:
<html>
<head>
<title>This i a CSRF test!</title>
</head>
<form action="http://192.168.159.134/pagekit/index.php/api/user/1" method="post" enctype="text/plain" >
<input name='{"user":{"id":1,"username":"admin","email":"panda@cnpanda.net","url":"","registered":"2019-04-26T01:31:19+00:00","status":1,"name":"admin","login":"2019-04-26T01:54:08+00:00","permissions":null,"roles":[2,3],"data":{}},"password":"admin888"}'type='hidden'>
<input type=submit>
</form>
</html>
点击提交,结果:
重新看了下抓包的内容,发现有个X-XSRF-TOKEN,这个应该就是防止csrf攻击的头文件了,但是我们知道,并不是说只要有csrf的头文件就一定是安全的,如果头文件生成的token存在可伪造、可重用的情况,这种的头文件是没有任何作用的。
找到了防止添加管理员的csrf防御代码:
public function onRequest($event, $request)
{
$this->provider->setToken($request->get('_csrf', $request->headers->get('X-XSRF-TOKEN')));
$attributes = $request->attributes->get('_request', []);
if (isset($attributes['csrf']) && !$this->provider->validate()) {
throw new CsrfException('Invalid CSRF token.');
}
}
将请求传入函数,然后判断csrf token和系统内生成的是否一致,如果不一致,则返回Invalid CSRF token。
继续看看token是如何生成的:
public function generate()
{
return sha1($this->getSessionId().$this->getSessionToken());
}
Token的内容由两部分内容组成,一个是getSessionId()函数,一个是getSessionToken()函数。这两个函数内容如下:
protected function getSessionId()
{
if (!session_id()) {
session_start();
}
return session_id();
}
protected function getSessionToken()
{
if (!isset($_SESSION[$this->name])) {
$_SESSION[$this->name] = sha1(uniqid(rand(), true));
}
return $_SESSION[$this->name];
}
前一个函数是判断是否存在 session 如果不存在,那么返回一个session,后一个函数是利用uniqid函数基于以微秒计的当前时间,生成一个唯一的 ID,然后再进行sha1加密,最后和刚刚的session再次混合sha1加密。
至此,基本上可以说通过csrf添加管理员或修改管理员密码已经没希望了。
三、结果
漏洞挖掘并不是找一套cms就会有指定的漏洞,现在的开发已经具有了安全意识,因此对于漏洞审计者来说,不仅仅是关注研发是否对相关漏洞进行防御,更要关注防御的具体措施如何。
暂时无法评论哦~
暂无评论