summaryrefslogtreecommitdiffstats
path: root/docs/writeups/Meepwn_2018/Esor.txt
blob: 33a88811fdddb0b8a944ff9666ff7ba20a08cfad (plain) (blame)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
We are given source code for a python program.  This program is for a hosted
encryption/decryption server running on a remote port.  The remote service is
running this program verbatim except that the flag is censored in our copy.

Encrypt asks for a prefix and suffix and concatenates these around the flag
(called secret).  This is what gets encrypted and hmac'd.  The encrypted blob is
delivered to us, cool.  This part must be done on the remote server since it is
the only one who knows the secret (flag).

The decrypt function doesn't actually show the original plaintext to us, it just
performs decryption in the background and reports whether the hmac is valid or
not, so we cannot use the server.  Fortunately our client has access to all key
and cipher algorithm information and can accept the data we just got from the
server.

We just need to modify our local copy to print() the plaintext during decryption
verification.  When you run locally and attempt to decrypt the data returned by
the server, you should see the flag surrounded by your prefix and suffix.  If
you used empty strings for the prefix and suffix, then just the flag itself
should appear.

MeePwnCTF{pooDL3-this-is-la-vie-en-rose-P00dle!}

--

#!/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): 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))