NeSE三月升级赛WriteUp (Web)
又是一个XSS题,Docker里起了一个Web一个Bot一个Redis,Web使用Java写的,用的Eclipse的Jetty服务器,上层是Micronaut微服务框架来的,整体打包成一个JAR。 附件地址:CTF-Chal/fancy-notes.zip (github.com) 一开始还以为是Java相关的漏洞,随手看了下反编译,发现好像除了题目是Java写的之外和Java没啥关系,同理Redis也只是个用来传数据的中间媒介,似乎也利用不了什么漏洞。于是继续关注题目本身的逻辑。 先看Bot做了啥: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 const puppeteer = require("puppeteer"); const Redis = require('ioredis'); const connection = new Redis(6379, process.env.REDIS_HOST ?? "127.0.0.1"); const browser_option = { headless: true, args: [ '--no-sandbox', '--disable-gpu', '--js-flags="--noexpose_wasm --jitless"', ], executablePath: "google-chrome-stable" }; const MAIN_SITE = process.env.MAIN_SITE ?? "http://127.0.0.1:8000" const FLAG = process.env.FLAG ?? "flag{test}" const sleep = (delay) => { return new Promise((resolve) => setTimeout(resolve, delay)) } async function browse(url) { console.log(`[+] browsing ${url} started`) const browser = await puppeteer.launch(browser_option); const page = await browser.newPage(); page.on('dialog', async (dialog) => { await dialog.dismiss(); }); try { await page.goto(MAIN_SITE, { timeout: 3000, waitUntil: 'domcontentloaded' }); await sleep(1000); await page.setCookie({ name: "FLAG", value: FLAG, domain: new URL(MAIN_SITE).hostname, path: "/", secure: false, httpOnly: true }); await page.goto(url, { timeout: 3000, waitUntil: 'domcontentloaded' }); await sleep(5000); console.log(await page.cookies(MAIN_SITE)); } catch (err) { console.log(err); } finally { await page.close(); await browser.close(); } console.log(`[+] browsing ${url} finished`) } const handler = async () => { console.log('[+] Starting bot'); while (true) { console.log("[+] Working ") connection.blpop('urls', 0, async (err, message) => { try { let url = message[1]; let parsed = new URL(url); if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') { throw new Error('Invalid protocol'); } else { console.log('[+] Visiting ' + url); await browse(url); } await sleep(3000); } catch (e) { } }); await sleep(3000) } } handler(); 能看见Bot首先访问了网站的首页,然后把Flag写进了Cookie里面,加了HTTP Only(这个是重点,等会会考),然后就会访问提交给Bot的URL了。Bot是死循环从Redis里面读URL,网站里也有相关的逻辑。 ...