웹 서비스 분석

문제에서 제공하는 url에 접속하게 되면 위와 같은 화면을 볼 수 있다. 사용자가 인삿말을 작성하면 그에 대한 응답을 출력해준다.
예를 들어서 사용자가 hello라는 요청을 보내면 응답: hello ❤️ 라고 해당 페이지에 출력되는 것을 확인할 수 있다.
엔드포인트 분석
/api
app.get('/api', (req, res) => {
if (req.ip !== '::1') return res.send('No');
const isAdmin = Number(req.query.admin);
console.log('isAdmin', isAdmin);
if (isAdmin !== 0) { // admin이면 flag 출력
return res.send(FLAG);
}
return res.send(`${req.query.msg} ❤️`);
});
req.ip로 접속한 사용자의 ip가 ::1(localhost)가 아니면 No라는 문자를 출력해준다.
그리고 isAdmin이라는 변수에 query다음으로 오는 admin 값을 저장해주고
만약 isAdmin이 0이 아니라면 flag를 출력해준다.
/greet
app.post('/greet', async (req, res) => {
const msg = String(req.body.msg);
if (msg.includes('admin') || msg.includes('\\') || msg.includes('%') || msg.includes('?') || msg.includes(';') || msg.includes('#') || msg.includes('[') || msg.includes(']')) return res.json({ result: 'Not allowed character' });
const resp = await axios.get(`http://localhost:3000/api?msg=${msg}&admin=0`);
return res.json({ result: resp.data });
});
사용자가 입력한 값을 string으로 변환하여 msg라는 변수에 저장한다.
그리고 만약 msg에 admin, \\, %, ? 등의 키워드가 포함되어 있다면 "Not allowed character" 라는 문구를 출력해준다.
그리고 localhost로 /api?msg="사용자 입력갑"&admin=0이라는 url 요청을 보내고 resp의 반환 값을 출력한다.
취약점 분석
엔드포인트 /api에선 접속자의 ip가 localhost이고, isAdmin의 값이 0이 아니어야 flag를 획득할 수 있다. 이를 통해 우리는 ssrf 취약점을 활용하여 요청을 위조해 localhost로 접속하면 flag를 획득할 수 있을 것이다.
localhost로 접속하기 위해선 msg에 들어갈 값을 변조하면 된다. 엔드포인트 /greet의 resp 변수에는 api 페이지에 localhost 권한으로 접속한 뒤의 반환 값을 읽어오도록 코딩 되어 있다. 이를 활용하여 localhost로 접속하면 될 것 같다.
익스플로잇
사용자가 입력한 msg 값을 위조하기 위해 burp suite로 요청을 보낸다.

웹 브라우저에서는 url 정규화를 진행하기 때문에 \t, \n과 같은 문자로 필터링을 우회해야한다.
msg : 1&ad\tmin=2라는 페이로드를 삽입해주면 오른쪽의 Response에 보이는 것과 같이 flag가 출력된 것을 확인할 수 있다.
'CTF & Wargame(WEB)' 카테고리의 다른 글
| level 1 XSS Filtering Bypass (1) | 2025.04.17 |
|---|---|
| Command Injection Advanced level 1 (0) | 2025.04.16 |
| session beginner (0) | 2025.04.14 |
| web-misconf-1 beginner (0) | 2025.04.14 |
| pathtraversal beginner (0) | 2025.04.14 |