Seccon 2017 - Man-in-the-middle on SECP384R1 (Crypto, 300)

The title give us some tips : SECP384R1 -> Ellicptic Curve

Try Connect to the server, you can find there are two dev talking.

As the title, we are asked to be the middle evil to break this conversation.

Therefore, I make a public key to build the shared key between two devices.

import hashlib 
from libnum import *
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.asymmetric import ec

private = ec.generate_private_key(ec.SECP384R1(), default_backend())
header = b'0v0\x10\x06\x07*\x86H\xce=\x02\x01\x06\x05+\x81\x04\x00"\x03b\x00\x04'
px = private.public_key().public_numbers().x
py = private.public_key().public_numbers().y
my_public = header + n2s(px)+ n2s(py)

Some useful function.

peer = []
shared_key = []

def get_pub(data):
"""
Save the key which gets from dev0 or dev1.
"""
# bytes-like to int
x = s2n(data[24 : 24 + 48])
y = s2n(data[24 + 48 :])
prime = ec.SECP384R1()
peer.append(ec.EllipticCurvePublicNumbers(x, y, prime).public_key(default_backend()))

# [KBKDF: SHA256, Encryption: AES]
def derive():
"""
We derive the shared key by tips : Key Derive Function is SHA256 and Encryption by AES (Guess the Mode is CBC and Default IV).
"""
for i in range(2):
digest = hashlib.sha256(private.exchange(ec.ECDH(), peer[i])).digest()
shared_key.append(Cipher(algorithms.AES(digest), modes.CBC(b'0'*16), default_backend()))

def crypto(cryptor, data):
buff = bytearray(1024)
length = cryptor.update_into(data, buff)
return bytes(buff[: length])

def encrypt(data,i):
return crypto(shared_key[i].encryptor(), data)

def decrypt(data,i):
return crypto(shared_key[i].decryptor(), data)

Exploit

This Question has give us a exploit.py.

That’s finish it.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "mitm.pwn.seccon.jp"
s.connect((host, 8000))

print(s.recv(len("[dev0 to dev1]:")))

########### todo ###########
data = s.recv(120)
get_pub(data)
s.send(my_public)
############################

print(s.recv(len("\n[dev1 to dev0]: OK\n")))
print(s.recv(len("[dev1 to dev0]:")))

########### todo ###########
data = s.recv(120)
get_pub(data)
s.send(my_public)
############################

print(s.recv(len("\n[dev0 to dev1]: OK\n")))
print(s.recv(len("[KBKDF: SHA256, Encryption: AES]\n")))

####### derive keys ########
derive()
############################

print(s.recv(len("[dev0 to dev1]:")))

#### Man in the middle #####
data = s.recv(256)
data = decrypt(data,0)
print(data)
ciphertext = encrypt(data,1)
s.send(ciphertext)
############################

print(s.recv(len("\n[dev1 to dev0]: OK\n")))
print(s.recv(len("[dev1 to dev0]:")))

######### Decrypt ##########
data = s.recv(256)
flag = decrypt(data,1)
print(flag)
############################

SECCON{FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFCB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF00000000000000000000000000000000000000000000000000000000}