[Dreamhack] random-test 풀이

서승기·2026년 7월 30일

Dreamhack

목록 보기
3/5

웹해킹의 매우 기초적인 문제인데, 나는 이제껏 쉬운 문제들만 풀어왔음을 깨닫게 해주는 문제였다.

우선 문제 파일 열어서 코드 빠르게 확인해보았다.

#!/usr/bin/python3
from flask import Flask, request, render_template
import string
import random

app = Flask(__name__)

try:
    FLAG = open("./flag.txt", "r").read()       # flag is here!
except:
    FLAG = "[**FLAG**]"


rand_str = ""
alphanumeric = string.ascii_lowercase + string.digits
for i in range(4):
    rand_str += str(random.choice(alphanumeric))

rand_num = random.randint(100, 200)


@app.route("/", methods = ["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("index.html")
    else:
        locker_num = request.form.get("locker_num", "")
        password = request.form.get("password", "")

        if locker_num != "" and rand_str[0:len(locker_num)] == locker_num:
            if locker_num == rand_str and password == str(rand_num):
                return render_template("index.html", result = "FLAG:" + FLAG)
            return render_template("index.html", result = "Good")
        else: 
            return render_template("index.html", result = "Wrong!")
            
            
app.run(host="0.0.0.0", port=8000)

지금까지의 웹과는 조금 다르다.

문제를 처음 봤을때, 이전 처럼 FLAG가 나타나는 취약점이 있지 않을까, 숨겨진 FLAG의 암호 힌트가 코드 내에 숨겨져 있는게 아닌가 하며 폴더 전체 검색으로 키워드를 찾아다녔다.

내가 놓친 FLAG의 힌트가 있는지 찾으며 돌아다녀보았다...

몇분 동안 찾아본 결과 접근법이 잘못되었다는 것을 깨닫고 제대로 문제를 파악해보기로 하였다.

일단 FLAG를 뱉어내는 조건을 먼저 확인해보자

  if locker_num != "" and rand_str[0:len(locker_num)] == locker_num:
            if locker_num == rand_str and password == str(rand_num):
                return render_template("index.html", result = "FLAG:" + FLAG)
            return render_template("index.html", result = "Good")
        else: 
            return render_template("index.html", result = "Wrong!")

이 코드에 FLAG를 주는 조건이 적혀있다. 해석해보자면
첫번째 if 문은 다음과 같다.

정답 문자열rand_str의 맨 앞부분을 내가 입력한 글자 수len(locker_num)만큼만 잘라서 내가 입력한 값과 똑같은지 비교해라

True라면 두번째 조건문으로 간다.

너가 입력한 사물함 번호랑 자물쇠 번호가 맞으면 FLAG를 줄거다.
False라면 "Good" 이라는 문자열을 출력하겠다고 한다.

그 무엇도 아니면 "Wrong!"을 출력한다고 한다.

오키, 그럼 정답문자열 rand_str은 어떻게 만들어지지?

rand_str = ""
alphanumeric = string.ascii_lowercase + string.digits
for i in range(4):
    rand_str += str(random.choice(alphanumeric))

rand_num = random.randint(100, 200)

여기서 확인할 수 있다.

일단 rand_str은 4글자이고, string.ascii_lowercasestring.digits 을 더한 alphanumeric중에서 랜덤하게 하나씩 골라 만들어진 4글자 문자열임을 알 수 있었다.

rand_num은 100이상 200이하 정수임을 알 수 있었다. 다만

string.ascii_lowercasestring.digits 가 뭐지?

이렇다고 한다.
alphanumericabcdefghijklmnopqrstuvwxyz0123456789라는 문자열이였음을 알 수 있었다.

즉. 사물함 번호는 영어 소문자 + 숫자가 포함된 랜덤문자열 4글자, 자물쇠 번호는 100에서 200사이의 번호 임을 알 수 있었다.

근데. 사실 문제 설명에서도 알려주고 있던 내용이었다.,

자 이제 그럼 이 문제를 어떻게 풀 수 있을까?
처음부터 범위가 좁은 조건이 있으면 의심을 해봐야 하는 것이 있었다.

그렇다. 풀이법은 브루트 포스였다.

하지만 이제껏 툴이라고는 Vscode 랑 브라우저에서 마우스 클릭만 해오던 내가 어떻게 해야할지 감도 잡히지 않았다.

검색해보니, Proxy 툴로 입력을 찾고 brute force 공격을 해줄 수 있는 툴이 있다고 하여서 다운로드 받았다.

https://portswigger.net/burp/downloads

바로 Burp Suite

Community Edition으로 다운로드 받아도 충분히 할만한건 다 할 수 있다고 해서 다운로드 받고 실행해보았다.

진짜 하나도 모르겠었지만, 간단하게 요약하면 프록시라고 해서 내가 사이트로 보낸 입력을 Proxy가 대신 보내주고, 그 응답을 Proxy가 가로채서 그 응답이 나한테 바로 전달되지 않고 Proxy를 통해서 볼 수 있었다.

그냥 중간 대행자 역할을 해준다고 보면 된다.

그렇다면 이제 이 Burp Suite를 통해서 문제를 풀어보자.

여기 Open Browser를 열어 크롬창을 열어주자

그럼 이런 창이 하나 뜨는데, 여기에 우리가 드림핵에서 서버를 실행하면 주는 링크를 여기에 넣고 접속하면 된다.

그럼 이제부터 Proxy가 대행자의 역할로 사이트에 대신 접속해주고 우린 그걸 전달받아 확인할 수 있다.


잘 접속 했다. 이제 Proxy를 통해 신호를 가로채보자.


Proxy 탭에서 Intercept on 버튼을 눌러 인터셉트를 활성화 하자.

이제 서버에서 우리 한테 보내는 신호를 Proxy가 가로채갈 것이다.

그럼 우리가 보고있는 브라우저 창은 렉이 걸린 것처럼 신호를 대기하는 상태가 될 것이다.

아무런 값만 먼저 넣어보고 제출 해보자.

좋다. 우리가 제출 버튼을 눌러 사이트에게 보낸 Request가 잡혔다.

저기 HTTP 프로토콜의 마지막줄 content 내용에 우리가 적은 abcd와 132가 적혀있는 것을 볼 수 있다.

그럼 우린 저 칸에 처음부터 끝까지 내용을 적어서 제출해, FLAG를 얻어낼 수 있을 것이다.

Proxy 옆에 있는 Intruder에 들어가보자.

그리고 이렇게 locker_num에 커서를 놓고 Add 버튼을 눌러 저 문양을 저 칸에 추가해준다.
(이 공간에다 순차적 대입을 할 것이다. 라는 포지션을 잡는 것이다.)

그리고 오른쪽 탭에서 Payload type: 을 Brute forcer 로 변경해주고,

아래 Min length, Max length를 1로 해주자.

한글자씩 적어넣어서 Good의 표시를 매개로 하여 암호를 알아낼 것이다.

그리고 여기 오른쪽 탭에 있는 Settings 버튼을 누르고 Grep - Match 탭에 들어간다.

Enter a new Item 칸에 Good 이라고 적고 Add를 누른다.

Good 이 잘 들어갔음을 확인할 수 있다.

이제 주황색의 Start Attack 버튼을 클릭해 한글자씩 요청을 넣어보자.


이렇게 쭉 요청이 들어가는 것을 볼 수 있다.

이중에서 딱 한가지

Grep에서 우리가 지정한 Good을 인식한 글자가 무엇인지 확인해보자.

r 이였다, 이제 r이 번호의 첫글자임을 알아냈다.

이제 찾아낸 한글자는 고정으로 넣어두고 그 뒤의 두번째 글자도 대입해서 찾아보자.

이 과정을 3번만 반복하면 된다.

Min length , Max length를 3으로 해서 나머지를 찾는다면 한번에 찾을 수 있겠지만, 오래걸릴 것이다.

rjuq임을 알아냈다.

Password는 100번만 숫자로 대입해보면 되니, 한번에 해보자.


이젠 password에 Add를 통해 포지션을 추가하고

Payload 타입을 Numbers 로 변경해주자.

From: 에는 100을 To: 에는 200을 적어주자.

마지막으로 Settings 탭에서 Add를 누르고 DH를 입력해 Flag를 잡아낼 수 있도록 하자

이제 시행해보자

여러 대입중 한곳에서 DH를 인식했다는 표시를 발견했다.

그 숫자는 바로 107!

모든 비밀번호를 알아내는데에 성공했다.

사물함 번호 제대로 적었는데, 제출 버튼을 눌러도 응답이 없다면 Intercept 가 On 되어있는지 확인해보자.

이렇게 직접 툴을 통해서 Brute Force를 실행해보는 방법을 알아보았다.

profile
여러가지 공부하는 Velog

0개의 댓글