整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

从JS文件中发现「认证绕过」漏洞

从JS文件中发现「认证绕过」漏洞

译:h4d35

预估稿费:120RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

前言


本篇文章主要介绍了在一次漏洞悬赏项目中如何利用配置错误挖到一个认证绕过漏洞。

从JS文件中发现认证绕过漏洞


本文内容源自一个私有漏洞赏金计划。在这个漏洞计划中,接受的漏洞范围限于目标网站少数几个公开的功能。基于前期发现的问题(当我被邀请进这个计划时,其他人一共提交了5个漏洞),似乎很难再挖到新的漏洞。同时,在赏金详情中提到了这样一句话:

如果你成功进入管理页面,请立即报告,请勿在/admin中进行进一步的测试。

然而,目标网站中存在一个仅限于未认证和未经授权的用户访问的管理页面。当我们访问/login或/admin时会跳转到https://bountysite.com/admin/dashboard?redirect=/。

对登录页面进行暴力破解也许是一个可行方案,但是我并不喜欢这种方式。看一下网页源码,没什么有用的内容。于是我开始查看目标网站的结构。似乎目标网站的JS文件都放在少数几个文件夹中,如/lib、/js、/application等。

有意思!

祭出神器BurpSuite,使用Intruder跑一下看能否在上述文件夹中找到任何可访问的JS文件。将攻击点设置为https://bountysite.com/admin/dashboard/js/*attack*.js。注意,不要忘记.js扩展名,这样如果文件能够访问则返回200响应。确实有意思!因为我找到了一些可访问的JS文件,其中一个文件是/login.js。

访问这个JS文件https://bountysite.com/admin/dashboard/js/login.js,请求被重定向至管理页面:) 。但是,我并没有查看该文件的权限,只能看到部分接口信息。

但是我并没有就此止步。这看起来很奇怪,为什么我访问一个.js文件却被作为HTML加载了呢?经过一番探查,终于发现,我能够访问管理页面的原因在于*login*。是的,只要在请求路径/dashboard/后的字符串中含有*login*(除了'login',这只会使我回到登录页面),请求就会跳转到这个管理接口,但是却没有正确的授权。

我继续对这个受限的管理接口进行了进一步的测试。再一次查看了页面源码,试着搞清楚网站结构。在这个管理接口中,有其他一些JS文件能够帮助我理解管理员是如何执行操作的。一些管理操作需要一个有效的令牌。我试着使用从一个JS文件中泄露的令牌执行相关管理操作,然并卵。请求还是被重定向到了登录页面。我发现另外一个真实存在的路径中也部署了一些内容,那就是/dashboard/controllers/*.php。

再一次祭出BurpSuite,使用Intruder检查一下是否存在可以从此处访问的其他任何路径。第二次Intruder的结果是,我发现几乎不存在其他无需授权即可访问的路径。这是基于服务器返回的500或者200响应得出的结论。

回到我在上一步侦察中了解到的网站结构中,我发现这些路径是在/controllers中定义的,通过/dashboard/*here*/进行访问。但是直接访问这些路径会跳转到登录页面,似乎网站对Session检查得还挺严格。此时我又累又困,几乎都打算放弃了,但是我想最后再试一把。如果我利用与访问管理页面相同的方法去执行这些管理操作会怎么样呢?很有趣,高潮来了:) 我能够做到这一点。

通过访问/dashboard/photography/loginx,请求跳转到了Admin Photography页面,并且拥有完整的权限!

从这里开始,我能够执行和访问/dashboard/*路径下的所有操作和目录,这些地方充满了诸如SQL注入、XSS、文件上传、公开重定向等漏洞。但是,我没有继续深入测试,因为这些都不在赏金计划之内,根据计划要求,一旦突破管理授权限制,应立即报告问题。此外,根据管理页面显示的调试错误信息可知,我之所以能够访问到管理页面,是因为应用程序在/dashboard/controllers/*文件中存在错误配置。期望达到的效果是:只要请求链接中出现*login*,就重定向至主登录页面,然而,实际情况并不如人所愿。

后记


总之,这是有趣的一天!我拿到了这个漏洞赏金计划最大金额的奖励。

PHP中,要跳过HTTPS的验证,可以使用cURL库的CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST选项。这些选项允许你禁用对SSL证书的验证。请注意,禁用SSL验证可能会导致安全风险,因为它无法验证服务器的身份。这种方法仅适用于测试环境或在你确信目标服务器是可信的情况下使用。

下面是一个示例代码,展示了如何在PHP中模拟登录时跳过HTTPS验证:

<?php

// 登录表单的URL

$login_url='https://example.com/login';

// 登录后要抓取的页面URL

$target_url='https://example.com/data';

// 登录表单的用户名和密码

$username='your_username';

$password='your_password';

// 创建POST请求的数据

$post_data=array(

$username_field=> $username,

$password_field=> $password

);

// 初始化cURL会话

$ch=curl_init();

// 设置cURL选项

curl_setopt($ch, CURLOPT_URL, $login_url);

curl_setopt($ch, CURLOPT_POST, true);

curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// 禁用SSL验证

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// 发送登录请求

$result=curl_exec($ch);

// 检查是否登录成功

if ($result !==false) {

// 登录成功,继续抓取登录后的页面数据

// 设置抓取目标页面的URL

curl_setopt($ch, CURLOPT_URL, $target_url);

// 发送抓取请求

$data=curl_exec($ch);

// 处理抓取到的数据

if ($data !==false) {

// 在这里可以对抓取到的数据进行处理,例如解析HTML、提取信息等

echo $data;

} else {

// 抓取失败

echo 'Failed to fetch data.';

}

} else {

// 登录失败

echo 'Login failed.';

}

// 关闭cURL会话

curl_close($ch);

?>


在代码中,使用curl_setopt()函数来设置CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST选项为false,从而禁用了SSL验证。

请注意,在实际生产环境中,强烈建议不要禁用SSL验证,以确保通信的安全性。只有在开发和测试阶段,或者在你确信目标服务器是可信的情况下,才应该考虑禁用SSL验证.

让我们看看如下这个web应用示例:

<html>
 <meta http?equiv="Content?Security?Policy"
 content="script?src 'nonce?...' 'unsafe?eval'">
 <div id="template_target"></div>
 <script type="application/template" id="template">
 Hello World! 1 + 1={{ 1 + 1 }}
 </script>
 Your search is <?php echo $_GET['q']; ?>
 <script nonce="...">
 let template=document.getElementById('template');
 template_target.innerHTML=template.innerText.replace(/{{(.?)}}/g,eval)
 </script>
</html>

以上这段简单的HTML代码可能反映了现在渗透测试人员经常碰到的模板化Web应用。某些模板内容存储在Web页面中,然后再转换为HTML代码的一部分。上段代码中含有id为template的HTML元素内容先被读取,然后再执行{{}}括号内的内容,最后在某个单独HTML元素中呈现出来。

Hello World! 1 + 1=2
Your search is ........... 

其次,这段代码应用程序会在页面上打印URL中的参数值。这显而易见是一个XSS漏洞,但由于CSP(内容安全策略)的存在,攻击者并不能直接执行javascript。虽然直接运行javascript的路被堵死,但是我们可以找到其他绕过方法。

乍一看,貌似eval函数是一个可以利用的点,我们或许可以直接插入某些特制代码,让eval函数去执行。

为了实现这点,我们必须插入HTML元素中id为template的代码。但在我们插入语句的前面已有id为template的HTML元素,而document.getElementById('template')只会去获取第一个HTML元素,并不是我们所输入的语句。

此刻,我们需要换个角度,看看浏览器是否能出现“意外”,以前就出现过很多浏览器的异常解析所导致的XSS攻击。我把所有能使用的tag都收集起来进行测试,看看是否有惊喜。测试代码如下:

<div id="template">First Tag</div>
 {% for tag in tag_list %}
 <{{tag}} id="template">{{tag}}</{{tag}}>
 {% endfor %}
<script>console.log(document.getElementById('template'));</script>

当程序运行完毕时,我得到一个奇怪的结果:当轮到<html>时,页面结构似乎发生了大变,此时已不再是<div>排在前面。让我们看下当插入<html id="template">时的变化:

此时<html>已排在文档顶部(在我所测试的所有浏览器中都是如此!),现在getElementById('template')将获取<html>中的恶意数据,而不是<div>的内容。

只需简单的?q=<html id="template">{{ alert("xss") }}</html>就可进行攻击

最终,由于浏览器这个“莫名其妙”的特性,我们绕过了CSP成功进行了XSS攻击!

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场

来源:https://nosec.org/home/detail/2860.html

原文:https://pagedout.institute/download/PagedOut_001_beta1.pdf(该PDF文档的第62页

白帽汇从事信息安全,专注于安全大数据、企业威胁情报。

公司产品:FOFA-网络空间安全搜索引擎、FOEYE-网络空间检索系统、NOSEC-安全讯息平台。

为您提供:网络空间测绘、企业资产收集、企业威胁情报、应急响应服务。