compress
이번 문제는 그냥 암호화된 문자열하고 인코드 하는 파이썬 코드를 던져줬네요
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import md5 def encode(input_string): print "Input : %s" % input_string h = md5.md5(input_string[:4]).hexdigest() table = { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9, 'j': 0 } out = "" prev = "" stage1 = [] stage2 = [] stage3 = "" passbyte = -1 for ch in input_string: if ch in table.keys(): stage1.append(table[ch]) else: stage1.append(ch) for index, ch in enumerate(stage1): if len(stage1) <= index + 1: if index != passbyte: stage2.append(ch) break if passbyte != -1 and passbyte == index: continue if type(ch) == int and type(stage1[index+1])==int: tmp = ch << 4 tmp |= stage1[index+1] stage2.append(tmp) passbyte = index+1 else: stage2.append(ch) for ch in stage2: if type(ch) == int: stage3 += chr(ch) else: stage3 += ch for index, ch in enumerate(stage3): if index >= len(h): choice = 0 else: choice = index out += chr(ch ^ h[choice]) return repr(out) encoded = "~u/\x15mK\x11N`[^\x13E2JKj0K;3^D3\x18\x15g\xbc\\Gb\x14T\x19E" encode(st) | cs |
먼저 간략하게 이 코드가 뭘 하는지 적어보자면
1. 문자열을 입력받는다.
2. 문자열 앞 4글자의 md5 해쉬값을 h 에 저장함.
3. Stage 1 에선 위에 table 을 가지고 치환 작업을 한다. 그리고 그 치환한 문자들을 stage1 에 저장. ex ) asdf 면 1s46 으로
4. Stage 2 에선 stage1 에 저장된 문자열 중 숫자가 연속으로 이어져 있는 것을 16진수 를 사용해 하나로 합친다.
그리고 stege2 에 저장한다. ex) asdf -> 1s46 -> 1 s 70 // 46 은 0x46 -> 70
5. Stage 3 에선 stage2 에 있는 int 형 값들을 chr 를 통해서 문자로 바꾼다.
6. 그리고 위에 구해놨던, h 에 저장했던 값과 1대1 로 xor 을 진행한다.
7. 끗!
매우 간단한 암호화 과정이지만 하나 걸리는 점은 md5 해쉬한 값하고 진행한다는 점
하지만 다행이 문제가 안되는게 4자리 문자의 해쉬 값이다. 게다가 추측을 하자면 숫자는 정답에 들어갈 수 없으므로
즉 해봤자 대문자, 소문자로 이뤄진 4자리 문자다.
% ( table 에서 숫자로 치환을 하는 과정이 있어서 만약 답에 숫자가 들어가면 문제가 생길 수 있으니까 ㅇㅇ )
이 부분은 brute-force 로 돌려 보다보면 알 수 있다. 대략적인 코드는 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from md5 import * def encode(input_string): ...skip... charset = [a-z,A-Z] for a in charset: for b in charset: for c in charset: for d in charset: tmp = a tmp += b tmp += c tmp += d enc = encode(tmp) if enc == "~u/" or enc == "~u/\x15": print tmp encode(st) | cs |
대략적으로 이런 코드를 돌리면 구할 수 있다. ( ~u/\x15 는 주어진 encoded 앞자리 4 개 데이터다 )
그럼 'FLag' 란 문자가 나올 거다.
그럼 역연산을 위해 먼저 'FLag' 의 md5 값과 encoded 데이터를 xor 해 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from md5 import * def decode(key, encoded): decoded = "" print "Encoded : %s" % encoded h = md5(key).hexdigest() for idx, ch in enumerate(encoded): if idx >= len(h): choice = 0 else: choice = idx decoded += chr(ord(ch)^ord(h[choice])) print "Decoded : %s" % repr(decoded) encoded = "~u/\x15mK\x11N`[^\x13E2JKj0K;3^D3\x18\x15g\xbc\\Gb\x14T\x19E" decode("FLag", encoded) | cs |
그럼 아래같은 결과가 나온다.
1 2 | Encoded : ~u/mKN`[^E2JKj0K;3^D3gᄐ\GbTE Decoded : 'FL\x17 \ts {\x03ompr\x05ss_\ts_\x01lw\x01ys_\x85lp\x06ul!}' | cs |
뭐 완벽히 복원해 주는 코드를 짜도 되긴 하는데 저 정도면 그냥 나온 결과만 보고 바로 답을 맞춰 볼 수 있을거 같다.
1 2 | \x17 -> ag \x03 -> c \x05 -> e \x01 -> a \x85 -> he \x06 -> f | cs |
FLag is {compress_is_always_helpful!}
'CTFs > CodaGate PreQual 2016' 카테고리의 다른 글
[Codegate 2016] pwnable : Fl0ppy (0) | 2016.08.27 |
---|---|
[Codegate 2016] pwnable : Manager (0) | 2016.08.27 |
[Codegate 2016] pwnable : WaterMelon (0) | 2016.08.27 |