Unverified Commit 5919df7e by Mariusz Kupidura Committed by GitHub

Validate exploit's setup before `run` and `check` commands (#367)

Introduce `Exploit.validate_setup` method in order to check whether
Exploit's setup is correct. In most case scanarios we will check
if `Exploit.target` is not `None`. When exploit need custom
validation logic please overwrite `validate_setup`.
parent 5fd3e7d8
...@@ -4,6 +4,7 @@ import time ...@@ -4,6 +4,7 @@ import time
from itertools import chain from itertools import chain
from weakref import WeakKeyDictionary from weakref import WeakKeyDictionary
from routersploit.exceptions import OptionValidationError
from routersploit.utils import print_status, NonStringIterable from routersploit.utils import print_status, NonStringIterable
GLOBAL_OPTS = {} GLOBAL_OPTS = {}
...@@ -133,3 +134,12 @@ class Exploit(BaseExploit): ...@@ -133,3 +134,12 @@ class Exploit(BaseExploit):
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 validate_setup(self):
""" Validate exploit's setup before `run()`
If exploit need extra validation make sure to overwrite this with
custom validation logic.
"""
if not self.target:
raise OptionValidationError("Please set target address.")
...@@ -6,7 +6,10 @@ import traceback ...@@ -6,7 +6,10 @@ import traceback
from collections import Counter from collections import Counter
from routersploit import utils from routersploit import utils
from routersploit.exceptions import RoutersploitException from routersploit.exceptions import (
RoutersploitException,
OptionValidationError,
)
from routersploit.exploits import Exploit, GLOBAL_OPTS from routersploit.exploits import Exploit, GLOBAL_OPTS
from routersploit.payloads import BasePayload from routersploit.payloads import BasePayload
from routersploit.printer import PrinterThread, printer_queue from routersploit.printer import PrinterThread, printer_queue
...@@ -328,12 +331,15 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -328,12 +331,15 @@ class RoutersploitInterpreter(BaseInterpreter):
@utils.module_required @utils.module_required
def command_run(self, *args, **kwargs): def command_run(self, *args, **kwargs):
utils.print_status("Running module...")
try: try:
self.current_module.validate_setup()
utils.print_status("Running module...")
self.current_module.run() self.current_module.run()
except KeyboardInterrupt: except KeyboardInterrupt:
utils.print_info() utils.print_info()
utils.print_error("Operation cancelled by user") utils.print_error("Operation cancelled by user")
except OptionValidationError as err:
utils.print_error(err)
except Exception: except Exception:
utils.print_error(traceback.format_exc(sys.exc_info())) utils.print_error(traceback.format_exc(sys.exc_info()))
...@@ -477,6 +483,7 @@ class RoutersploitInterpreter(BaseInterpreter): ...@@ -477,6 +483,7 @@ class RoutersploitInterpreter(BaseInterpreter):
@utils.module_required @utils.module_required
def command_check(self, *args, **kwargs): def command_check(self, *args, **kwargs):
try: try:
self.current_module.validate_setup()
result = self.current_module.check() result = self.current_module.check()
except Exception as error: except Exception as error:
utils.print_error(error) utils.print_error(error)
......
...@@ -3,6 +3,7 @@ import unittest ...@@ -3,6 +3,7 @@ import unittest
import mock import mock
from routersploit.exceptions import OptionValidationError
from routersploit.exploits import Exploit, GLOBAL_OPTS, Option from routersploit.exploits import Exploit, GLOBAL_OPTS, Option
from tests.test_case import RoutersploitTestCase from tests.test_case import RoutersploitTestCase
...@@ -95,6 +96,11 @@ class OptionTest(RoutersploitTestCase): ...@@ -95,6 +96,11 @@ class OptionTest(RoutersploitTestCase):
self.assertEqual(self.exploit_bar.options, ['paa', 'target', 'doo']) self.assertEqual(self.exploit_bar.options, ['paa', 'target', 'doo'])
self.assertEqual(self.exploit_foo.options, ['paa', 'target', 'doo']) self.assertEqual(self.exploit_foo.options, ['paa', 'target', 'doo'])
def test_validate_setup(self):
with self.assertRaises(OptionValidationError):
self.exploit_bar.target = ""
self.exploit_bar.validate_setup()
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -154,59 +154,80 @@ class RoutersploitInterpreterTest(RoutersploitTestCase): ...@@ -154,59 +154,80 @@ class RoutersploitInterpreterTest(RoutersploitTestCase):
@mock.patch('routersploit.utils.print_status') @mock.patch('routersploit.utils.print_status')
def test_command_run(self, mock_print_status): def test_command_run(self, mock_print_status):
with mock.patch.object(self.interpreter.current_module, mock_run = mock.Mock()
'run') as mock_run: mock_validate_setup = mock.Mock()
self.interpreter.command_run() self.interpreter.current_module.run = mock_run
mock_run.assert_called_once_with() self.interpreter.current_module.validate_setup = mock_validate_setup
mock_print_status.assert_called_once_with('Running module...')
self.interpreter.command_run()
mock_validate_setup.assert_called_once()
mock_run.assert_called_once_with()
mock_print_status.assert_called_once_with('Running module...')
@mock.patch('routersploit.utils.print_success') @mock.patch('routersploit.utils.print_success')
def test_command_check_target_vulnerable(self, mock_print_success): def test_command_check_target_vulnerable(self, mock_print_success):
with mock.patch.object(self.interpreter.current_module, mock_check = mock.Mock()
'check') as mock_check: mock_validate_setup = mock.Mock()
mock_check.return_value = True self.interpreter.current_module.check = mock_check
self.interpreter.command_check() self.interpreter.current_module.validate_setup = mock_validate_setup
mock_check.assert_called_once_with() mock_check.return_value = True
mock_print_success.assert_called_once_with('Target is vulnerable')
self.interpreter.command_check()
mock_validate_setup.assert_called_once()
mock_check.assert_called_once_with()
mock_print_success.assert_called_once_with('Target is vulnerable')
@mock.patch('routersploit.utils.print_error') @mock.patch('routersploit.utils.print_error')
def test_command_check_target_not_vulnerable(self, print_error): def test_command_check_target_not_vulnerable(self, print_error):
with mock.patch.object(self.interpreter.current_module, mock_check = mock.Mock()
'check') as mock_check: mock_validate_setup = mock.Mock()
mock_check.return_value = False self.interpreter.current_module.check = mock_check
self.interpreter.command_check() self.interpreter.current_module.validate_setup = mock_validate_setup
mock_check.assert_called_once_with() mock_check.return_value = False
print_error.assert_called_once_with('Target is not vulnerable')
self.interpreter.command_check()
mock_validate_setup.assert_called_once()
mock_check.assert_called_once_with()
print_error.assert_called_once_with('Target is not vulnerable')
@mock.patch('routersploit.utils.print_status') @mock.patch('routersploit.utils.print_status')
def test_command_check_target_could_not_be_verified_1(self, print_status): def test_command_check_target_could_not_be_verified_1(self, print_status):
with mock.patch.object(self.interpreter.current_module, mock_check = mock.Mock()
'check') as mock_check: mock_validate_setup = mock.Mock()
mock_check.return_value = "something" self.interpreter.current_module.check = mock_check
self.interpreter.command_check() self.interpreter.current_module.validate_setup = mock_validate_setup
mock_check.assert_called_once_with() mock_check.return_value = "something"
print_status.assert_called_once_with(
'Target could not be verified') self.interpreter.command_check()
mock_validate_setup.assert_called_once()
mock_check.assert_called_once_with()
print_status.assert_called_once_with('Target could not be verified')
@mock.patch('routersploit.utils.print_status') @mock.patch('routersploit.utils.print_status')
def test_command_check_target_could_not_be_verified_2(self, print_status): def test_command_check_target_could_not_be_verified_2(self, print_status):
with mock.patch.object(self.interpreter.current_module, mock_check = mock.Mock()
'check') as mock_check: mock_validate_setup = mock.Mock()
mock_check.return_value = None self.interpreter.current_module.check = mock_check
self.interpreter.command_check() self.interpreter.current_module.validate_setup = mock_validate_setup
mock_check.assert_called_once_with() mock_check.return_value = None
print_status.assert_called_once_with(
'Target could not be verified') self.interpreter.command_check()
mock_validate_setup.assert_called_once()
mock_check.assert_called_once_with()
print_status.assert_called_once_with('Target could not be verified')
@mock.patch('routersploit.utils.print_error') @mock.patch('routersploit.utils.print_error')
def test_command_check_not_supported_by_module(self, print_error): def test_command_check_not_supported_by_module(self, print_error):
with mock.patch.object(self.interpreter.current_module, mock_check = mock.Mock()
'check') as mock_check: mock_validate_setup = mock.Mock()
exception = NotImplementedError("Not available") self.interpreter.current_module.check = mock_check
mock_check.side_effect = exception self.interpreter.current_module.validate_setup = mock_validate_setup
self.interpreter.command_check() exception = NotImplementedError("Not available")
mock_check.assert_called_once_with() mock_check.side_effect = exception
print_error.assert_called_once_with(exception)
self.interpreter.command_check()
mock_check.assert_called_once_with()
print_error.assert_called_once_with(exception)
@mock.patch('sys.exc_info') @mock.patch('sys.exc_info')
@mock.patch('traceback.format_exc') @mock.patch('traceback.format_exc')
......
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