CTF

[IrisCTF] Political

Wermut 2025. 2. 27. 01:13

 

political.tar.gz
0.00MB

 

 

 


 

문제 페이지

 

문제에 접근하면 토큰을 주고 있음을 알 수 있다.

문제만으론 더 분석할 수 없어 코드를 바로 확인해 보았다.

 

# chal.py

from flask import Flask, request, send_file
import secrets

app = Flask(__name__)
FLAG = "irisctf{testflag}"
ADMIN = "redacted"

valid_tokens = {}

@app.route("/")
def index():
    return send_file("index.html")

@app.route("/giveflag")
def hello_world():
    if "token" not in request.args or "admin" not in request.cookies:
        return "Who are you?"

    token = request.args["token"]
    admin = request.cookies["admin"]
    if token not in valid_tokens or admin != ADMIN:
        return "Why are you?"

    valid_tokens[token] = True
    return "GG"

@app.route("/token")
def tok():
    token = secrets.token_hex(16)
    valid_tokens[token] = False
    return token

@app.route("/redeem", methods=["POST"])
def redeem():
    if "token" not in request.form:
        return "Give me token"

    token = request.form["token"]
    if token not in valid_tokens or valid_tokens[token] != True:
        return "Nice try."

    return FLAG

 

코드는 간단한데, 공격을 위해선 다음과 같은 절차를 따라야 했다.

 

  1.  ADMIN 쿠키와 token 값을 가진 상태로 /giveflag 경로로 접근해 valid_tokens[token] 값을 True로 설정
  2.  redeem 경로로 이전의 token 값을 가진 상태로 접근, flag 출력                                                                                                                                                                                              

하지만 ADMIN 값을 안다는 것이 불가능하기 때문에 위 코드만 보고는 문제를 푸는 것이 불가능하다.

 

 

문제를 다시 보면 일반적인 웹 문제와 달리 nc로 접근 가능함을 알 수 있는데

접근해 보면 bot이 작동하고 있음을 알 수 있다.

 

// /bot/bot.js

const puppeteer = require('puppeteer');
const fs = require('fs');
const net = require('net');

const BOT_TIMEOUT = process.env.BOT_TIMEOUT || 2*1000;

const puppeter_args = {};

(async function(){
  const browser = await puppeteer.launch(puppeter_args);

  function ask_for_url(socket) {
      socket.state = 'URL';
      socket.write('Please send me a URL to open.\n');
  }

  async function load_url(socket, data) {
    let url = data.toString().trim();
    console.log(`checking url: ${url}`);
    // replace with your server as needed
    if (!url.startsWith('http://localhost:1337/') && !url.startsWith('https://localhost:1337/')) {
      socket.state = 'ERROR';
      socket.write('Invalid URL (must start with http:// or https://).\n');
      socket.destroy();
      return;
    }
    socket.state = 'LOADED';
    let cookie = JSON.parse(fs.readFileSync('/home/user/cookie'));

    const context = await browser.createBrowserContext();
    const page = await context.newPage();
    await page.setJavaScriptEnabled(false);
    await page.setCookie(cookie);
    socket.write(`Loading page ${url}.\n`);
    setTimeout(()=>{
      try {
        context.close();
        socket.write('timeout\n');
        socket.destroy();
      } catch (err) {
        console.log(`err: ${err}`);
      }
    }, BOT_TIMEOUT);
    await page.goto(url);
  }

  var server = net.createServer();
  server.listen(1338);
  console.log('listening on port 1338');

  server.on('connection', socket=>{
    socket.on('data', data=>{
      try {
        if (socket.state == 'URL') {
          load_url(socket, data);
        }
      } catch (err) {
        console.log(`err: ${err}`);
      }
    });

    try {
      ask_for_url(socket);
    } catch (err) {
      console.log(`err: ${err}`);
    }
  });
})();

 

bot의 코드인데 이 봇은 ADMIN 쿠키를 가진 상태로 사용자가 입력한 URL로 접근한다.

즉, bot이 token 값을 가진 채로 /giveflag 경로로 접근하게 된다면 이후 사용자가 /redeem 경로로 접근했을 때

 flag를 얻을 수 있을 것이다.

 

다만 문제의 이름에서 예고하듯 봇에게 입력 가능한 url은 제한되어 있다.

 

// /bot/policy.json

{
	"URLBlocklist": ["*/giveflag", "*?token=*"]
}

 

해당되는 문자열의 일부를 url 인코딩하여 값을 넘겨주면 정상적으로 bot이 해당 url로 접근 가능하다.

 

bot이 /giveflag 경로로 접근한 모습

 

이제 /redeem 경로로 접근하면 flag를 얻을 수 있다.

 

 

 

flag: irisctf{flag_blocked_by_admin}

'CTF' 카테고리의 다른 글

[ISITDTU CTF] Another one Write-Up  (0) 2025.02.27
[hkcert] Custom-Web-Server(1) Write Up  (0) 2025.02.27
[hkcert] Mystiz's Mini CTF (2) Write Up  (0) 2025.02.27
[IrisCTF] Password Manager  (0) 2025.02.27
[SSUCTF] hellOphp  (0) 2025.02.27