[MeePwnCTF 2018] esor (easy)
Howdy, howdy ...
python소스가 하나 주어지고, nc를 통해 서버에 접속하면 encrypt된 data를 요청할 수 있다.
주어진 소스 파일은 아래와 같다.
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | #!/usr/bin/python2 from Crypto.Cipher import AES import hmac, hashlib import os import sys menu = """Choose one: 1. encrypt data 2. decrypt data 3. quit """ class Unbuffered(object): def __init__(self, stream): self.stream = stream def write(self, data): self.stream.write(data) self.stream.flush() def __getattr__(self, attr): return getattr(self.stream, attr) sys.stdout = Unbuffered(sys.stdout) sys.stderr = None encrypt_key = '\xff' * 32 secret = 'MeePwnCTF{#flag_here#}' hmac_secret = '' blocksize = 16 hmac_size = 20 def pad(msg): padlen = blocksize - (len(msg) % blocksize) - 1 return os.urandom(padlen) + chr(padlen) def unpad(msg): return msg[:-(ord(msg[-1]) + 1)] def compute_hmac(msg): return hmac.new(hmac_secret, msg, digestmod=hashlib.sha1).digest() def encrypt(prefix='', suffix=''): _enc = prefix + secret + suffix _enc+= compute_hmac(_enc) _enc+= pad(_enc) iv = os.urandom(16) _aes = AES.new(encrypt_key, AES.MODE_CBC, iv) return (iv + _aes.encrypt(_enc)).encode('hex') def decrypt(data): data = data.decode('hex') try: iv = data[:blocksize] _aes = AES.new(encrypt_key, AES.MODE_CBC, iv) data = _aes.decrypt(data[blocksize:]) data = unpad(data) plaintext = data[:-hmac_size] mac = data[-hmac_size:] if mac == compute_hmac(plaintext): print(plaintext) return True else: return False except: return False print """Welcome to our super secure enc/dec server. We use hmac, so, plz don't hack us (and you can't). Thanks.""" while True: choice = int(raw_input(menu)) if choice == 1: _pre = raw_input('prefix: ') _suf = raw_input('suffix: ') print encrypt(prefix=_pre, suffix=_suf) elif choice == 2: _data = raw_input('data: ') if decrypt(_data): print 'OK' else: print 'KO' elif choice == 3: sys.exit(0) else: choice = int(raw_input(menu)) | cs |
encrypt함수는 _enc = prefix + secret + suffix 로 사용자로부터 입력받은 prefix와 suffix를 flag의 앞과 뒤에 붙여 암호화하게 된다.
AES.CBC모드로 암호화하기 때문에 iv값이 필요하게 된다.
뭐.. 분석을 하면 좀 길어진다. 그러나 실제 문제를 풀때는 분석이 필요없었다;;
출제자의 실수인지, 서버에서 사용하는 키값과 주어진 소스파일의 키값이 같았다.
즉 '\xff' * 32가 키값인것이다. 그래서 그냥 서버에서 주는 data값을 주어진 소스파일의 decrypt함수로 돌리면 flag가 나온다.
MeePwnCTF{pooDL3-this-is-la-vie-en-rose-P00dle!}
플래그 내용에 Poodle이란 단어가 들어가 있는데, Poople attack이라고 구글에 검색하면 아래와 같이 나온다.
The POODLE attack (which stands for "Padding Oracle On Downgraded Legacy Encryption") is a man-in-the-middle exploit which takes advantage of Internet and security software clients' fallback to SSL 3.0. |
원래는 이 POODLE attack을 통해 푸는 문제인것같다. 하지만 출제자의 실수로.... (대회가 끝난 시점인 현재 130명이나 풀었다...)
대회가 끝나고 다시 서버에서 주어진 data를 주어진 소스파일로 decrypt하려 했더니, 실패하였다.
아마 대회중간에 키 값이 잘못된걸 알아차리고 바꾼것같은데;; 운좋게 푼사람들은 몰라도... 못푼사람들은 ㅠㅠ
일단 대회당시에는 이렇게 풀수있었다.
다음 포스팅에서는 Poople attack으로 푸는 방법으로 다시 써보겠다.
'Write-up > Crypto' 카테고리의 다른 글
[ISITDTU 2018] Baby Write-up (0) | 2018.07.30 |
---|---|
[MeePwnCTF 2018] bazik (0) | 2018.07.25 |
[MeePwnCTF 2018] esor (hard) (0) | 2018.07.16 |
[MeePwnCTF 2018] ezchallz (0) | 2018.07.16 |
[UIUCTF 2018] Hastad (0) | 2018.06.02 |