$ pip install git+https://github.com/threat9/threat9-test-bed.git
HttpServiceMock
is a flask
application that allows for adding
unittests.mock
as view functions. This gives us ability to setup dummy
http services on demand for testing purposes.
from threat9_test_bed.service_mocks import HttpServiceMock
from foo import ExploitUnderTest
def test_exploit():
with HttpServiceMock("localhost", 8080) as target:
cgi_mock = target.get_route_mock("/cgi-bin/cgiSrv.cgi",
methods=["POST"])
cgi_mock.return_value = 'foo status="doing" bar'
check_mock = target.get_route_mock("/routersploit.check",
methods=["GET", "POST"])
check_mock.return_value = 'root'
exploit = ExploitUnderTest(f'http://{target.host}', target.port)
assert exploit.check() is True
cgi_mock.assert_called_once()
assert check_mock.call_count == 2
It is very convenient to use py.test
library and it's fixture abilities.
Such fixture will perform setup and teardown automatically before each test.
All we have to do is to pass target
as the test argument.
import pytest
from threat9_test_bed.service_mocks import HttpServiceMock
from foo import ExploitUnderTest
@pytest.fixture
def target():
with HttpServiceMock("localhost", 8080) as target_:
yield target_
def test_exploit(target):
cgi_mock = target.get_route_mock("/cgi-bin/cgiSrv.cgi",
methods=["POST"])
cgi_mock.return_value = 'foo status="doing" bar'
check_mock = target.get_route_mock("/routersploit.check",
methods=["GET", "POST"])
check_mock.return_value = 'root'
exploit = ExploitUnderTest(f'http://{target.host}', target.port)
assert exploit.check() is True
cgi_mock.assert_called_once()
assert check_mock.call_count == 2
You can serve HttpScenarioService
using adhoc SSL certificate by setting
ssl
keyword argument to True
:
from threat9_test_bed.service_mocks import HttpServiceMock
@pytest.fixture
def trash_target():
with HttpServiceMock("127.0.0.1", 0, ssl=True) as http_service:
yield http_service
HttpScenarioService
allows for creating test utilities using pre-defined
scenarios
import pytest
from threat9_test_bed.scenarios import HttpScenario
from threat9_test_bed.service_mocks import HttpScenarioService
@pytest.fixture(scope="session")
def empty_target():
with HttpScenarioService("127.0.0.1", 8081,
HttpScenario.EMPTY_RESPONSE) as http_service:
yield http_service
@pytest.fixture(scope="session")
def trash_target():
with HttpScenarioService("127.0.0.1", 8082,
HttpScenario.TRASH) as http_service:
yield http_service
You can serve HttpScenarioService
using adhoc SSL certificate by setting
ssl
keyword argument to True
:
from threat9_test_bed.service_mocks import HttpScenarioService
@pytest.fixture(scope="session")
def trash_target():
with HttpScenarioService("127.0.0.1", 8443, HttpScenario.TRASH,
ssl=True) as http_service:
yield http_service
TelnetServiceMock
allows for creating test utilities using pre-defined
scenarios as well as attaching unittests.mock
as command handlers. This gives us ability to setup dummy telnet service
on demand for testing purposes.
from telnetlib import Telnet
import pytest
from threat9_test_bed.service_mocks.telnet_service_mock import TelnetServiceMock
from threat9_test_bed.scenarios import TelnetScenarios
@pytest.fixture
def generic_target():
with TelnetServiceMock("127.0.0.1", 8023,
TelnetScenarios.AUTHORIZED) as telnet_service:
yield telnet_service
def test_telnet(generic_target):
command_mock = target.get_command_mock("scoobeedoobeedoo")
command_mock.return_value = "Where are you?"
tn = Telnet(target.host, target.port, timeout=5)
tn.expect([b"Login: ", b"login: "], 5)
tn.write(b"admin" + b"\r\n")
tn.expect([b"Password: ", b"password"], 5)
tn.write(b"admin" + b"\r\n")
tn.expect([b"admin@target:~$"], 5)
tn.write(b"scoobeedoobeedoo" + b"\r\n")
_, match_object, _ = tn.expect([b"Where are you?"], 5)
tn.close()
assert match_object
To avoid port
collison during tests you can tell test utilities to set
it for you by passing 0
@pytest.fixture(scope="session")
def trash_target():
with HttpScenarioService("127.0.0.1", 0,
HttpScenario.TRASH) as http_service:
yield http_service
$ test-bed http
Scenario | Behavior |
---|---|
EMPTY_RESPONSE |
returns empty response with 200 status code |
TRASH |
returns 100 characters long gibberish with 200 status code |
NOT_FOUND |
returns 404 status code |
FOUND |
returns OK with 200 status code |
REDIRECT |
redirects you with 302 status code |
TIMEOUT |
sleep the server for 1 hour which effectively times out the request |
ERROR |
returns 500 status code |
$ test-bed http --scenario TRASH
$ test-bed https
Scenario | Behavior |
---|---|
EMPTY_RESPONSE |
returns empty response with 200 status code |
TRASH |
returns 100 characters long gibberish with 200 status code |
NOT_FOUND |
returns 404 status code |
FOUND |
returns OK with 200 status code |
REDIRECT |
redirects you with 302 status code |
TIMEOUT |
sleep the server for 1 hour which effectively times out the request |
ERROR |
returns 500 status code |
$ test-bed https --scenario FOUND
After successful authorization elnet service responds with random Lorem ipsum... for every command
$ test-bed telnet
Scenario | Behavior |
---|---|
AUTHORIZED |
Any authorization attempt ends with success |
NOT_AUTHORIZED |
Every authorization attempt ends with failure |
GENERIC |
Authorization using admin/admin credentials |
TIMEOUT |
Server hangs as soon as client has been connected |
$ test-bed telnet --scenario GENERIC
I can't start my
https
service on port 443 due toPermissionError
Running services on it's default port may need extra privileges thus
prepending command with sudo
should do the trick e.g.
$ sudo test-bed https --scenario TRASH --port 443
[2017-09-16 12:51:18,137: INFO/werkzeug] * Running on https://127.0.0.1:443/ (Press CTRL+C to quit)
This solution can be applied to other services and it's default ports as well.