[MeePwnCTF 2018] esor (easy)

2018. 7. 16. 20:10


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
        elsereturn False
    exceptreturn 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

+ Recent posts