XSS注入漏洞
一、反射型XSS注入
漏洞产生的原因:没有对用户提交的内容进行可靠的输入验证(没有过滤敏感字符串)。
下面编写一个存在反射型xss漏洞的网页
a、php编写xss漏洞网页
xss.php 中的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>xss</title>
<script>
function setCookie(name,value)
{
var Days = 30;
var exp = new Date();
exp.setTime(exp.getTime() + Days*24*60*60*1000);
document.cookie = name + "=" +escape(value) + ";expires=" + exp.toGMTString();
}
setCookie("xssCookie","xssValue");
</script>
</head>
<body>
<h1>反射型xss</h1>
<form action="/xss.php" method="get">
<input type="text" name = "xss1">
<input type="submit" value = "test">
</form>
</body>
</html>
<?php
error_reporting(0);
$xss = $_GET['xss1'];
if($xss !== null){
echo $xss;
}
?>
index.php 中的代码
<?php
$xss = $_GET['xss'];
if($xss !== null){
echo $xss;
}
else{
echo "failed";
}
?>
运行结果:
我们测试是否存在xss漏洞:
输入:<script>alert("存在xss注入漏洞")</script>
如果漏洞存在,结果如图所示:
b、DVWA中的反射型xss注入(中级)
方法一:大小写绕过:
方法二:双写绕过
<s<script>cript>alert("xss");</script>
解析:
大小写绕过:因为代码中用的是 str_replace函数,该函数大小写敏感,而 javascript 中 <script> 对大小写不敏感,导致可以使用大小写绕过。
双写绕过:因为代码检测的是 "<script>",把该字符串替换成空格,那么只要在 <script> 中再嵌套一个 <script> 即可
c、DVWA中的反射型xss注入(高级)
在高级模式下,使用了正则表达式,过滤掉了 js 代码(在实战中,如果大小写和双写都无法绕过,那就可以考虑是用了正则表达式)
我们可以尝试不使用 js 标签,而使用 html 标签绕过:
(使用 html 中 img 标签的 onerror 事件)
<img src=x onerror=alert('XSS');>
(onerror 事件:可以借用img标签的onerror事件,img标签支持onerror 事件,在装载文档或图像的过程中如果发生了错误,就会触发onerror事件。可以使用一张提示错误的图片代替显示不了的图片。当然也可以不显示图片,而是插入一段 js 代码)
二、存储型XSS注入
漏洞产生原因:
使用者提交的XSS代码被存储到服务器上的数据库里或页面或某个上传文件里,导致用户访问页面展示的内容时直接触发xss代码。 输入内容后直接在下方回显,回显的地方就是我们插入的内容的地方。(常出现在留言板、博客等地方)
a、DVWA存储型xss注入(低级)
Name 的编辑框长度被限制,我们就尝试 Message 的编辑框
我们可以通过检查网页的代码看看 Name 处的限制代码是不是写在前端
发现确实是写在前端的,把 maxlength="10" 删除就可以解除限制了,解除后我们再使用 Name 编辑框来注入
发现也可以成功注入。
- 使用stripslashes函数对message删除反斜杠,使用mysqli_real_escape_string函数对name、message变量中的特殊字符转义
- isset函数判断btnSign是否提交,即是否点击了Sign Guessbook按钮。
- 使用stripslashes函数删除message保存的字符串的反斜杠
- 使用mysqli_real_escape_string函数对name、message变量中的特殊字符转义
- mysqli_query函数针对数据库的查询
b、DVWA存储型xss注入(中级)
查看代码:
由:strip_tags()函数和 addslashes()函数可知,在 message 编辑框中剥去了字符串中的HTML标签和在每个双引号前添加反斜杠。
由:str_replace()函数可知,把字符串中的 <script> 替换成 空格,但是 str_replac 是大小写敏感的,因此可以用大小写绕过,也可以使用双写绕过。
c、DVWA存储型xss注入(高级)
使用html标签注入,发现成功了
代码:
由:name 处的 preg_replace()函数可知,确实使用了正则表达式
三、DOM型xss注入
漏洞产生原因:DOM型XSS漏洞是由于JavaScript代码直接操作了DOM(文档对象模型)而导致的
a、DVWA DOM型xss注入(低级)
我们尝试改写url
发现注入成功
查看代码,发现没有后端代码,那就查看前端代码
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>");
代码的一些解析:
<option> :创建选择列表
location.href :就是当前网页的地址
indexOf():返回字符串中检索指定字符第一次出现的位置
所以:document.location.href.indexOf("default=") 的作用就是检索:default= 第一次出现的位置,如果检索的字符串值没有出现,则该方法返回 -1 ,(没有是:=== -1 ; 有就是:!== -1)
decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。(使用 encodeURI() 函数可以对 URI 进行编码)
b、DVWA DOM型xss注入(中级)
发现普通注入和大小写、双写都无法绕过,尝试 <img> html 注入也无结果。
这时候就可以考虑使用闭合标签:
></select><img src = x onerror = alert("xss");> 发现使用闭合标签行得通
查看后端代码:
使用该语句然后查看前端代码的变化
这样就注入成功了
c、DVWA DOM型xss注入(高级)
普通注入、html标签注入、闭合标签都没办法实现,通过看别人写的文章发现可以用锚点(《CTF特训营》P28页提到了锚点)
锚点注入:
在URL的井号后面添加JavaScript脚本是一种称为“锚点注入”的技术,它可以实现在页面加载时执行JavaScript代码。但是,这种技术并不是所有浏览器都支持,而且也存在一些安全风险。
如果浏览器支持锚点注入,那么在URL的井号后面添加JavaScript脚本是可以运行的。例如,以下URL会在页面加载时弹出一个警告框:
http://example.com/page.html#<script>alert('Hello, world!');</script>
但是,为了保证网站的安全性,大多数现代浏览器已经禁止了锚点注入这种技术。因此,不建议在URL中使用锚点注入来执行JavaScript代码,而应该使用更安全的方法,如在HTML文档中嵌入JavaScript代码或在外部JavaScript文件中编写代码。
锚点注入是个好东西,但是只能运用在存在DOM型XSS漏洞的场景。
因为DOM型xss是不经过服务器的,其他的xss漏洞会经过服务器,可能会对 url 进行过滤
查看代码发现使用了 switch...case 构造白名单,大大提高了安全性。