From 37bf68869fd05e6bd0c181958326b7e2fc828be3 Mon Sep 17 00:00:00 2001 From: Adam Cammack Date: Tue, 16 Jan 2018 20:59:27 -0600 Subject: [PATCH] Add scanner for the open proxy from 'SharknAT&To' --- .../external/python/metasploit/sonar.py | 99 +++++++++++++++++++ .../scanner/wproxy/att_open_proxy.py | 39 ++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/msf/core/modules/external/python/metasploit/sonar.py create mode 100755 modules/auxiliary/scanner/wproxy/att_open_proxy.py diff --git a/lib/msf/core/modules/external/python/metasploit/sonar.py b/lib/msf/core/modules/external/python/metasploit/sonar.py new file mode 100644 index 0000000000..428c144ed5 --- /dev/null +++ b/lib/msf/core/modules/external/python/metasploit/sonar.py @@ -0,0 +1,99 @@ +import socket, re, functools +import asyncio + +from metasploit import module +from async_timeout import timeout + + +def make_study(payload='', pattern='', onmatch=None, connect_timeout=3, read_timeout=10): + return lambda args: start_study(payload, pattern, args, onmatch, connect_timeout=connect_timeout, read_timeout=read_timeout) + + +def start_study(payload, pattern, args, onmatch, **timeouts): + loop = asyncio.get_event_loop() + loop.run_until_complete(run_study(payload, pattern, args, onmatch, **timeouts)) + + +async def run_study(payload, pattern, args, onmatch, **timeouts): + runs = [study_host(host, int(args['rport']), payload, **timeouts) for host in args['rhosts']] + async for (target, res) in Study(runs): + if isinstance(res, Exception): + module.log('{}:{} - Error connecting: {}'.format(*target, res), level='error') + elif res and re.search(pattern, res): + module.log('{}:{} - Matches'.format(*target), level='good') + module.log('{}:{} - Matches with: {}'.format(*target, res), level='debug') + onmatch(target, res) + else: + module.log('{}:{} - Does not match'.format(*target), level='info') + module.log('{}:{} - Does not match with: {}'.format(*target, res), level='debug') + + +class Study: + def __init__(self, runs): + self.queue = asyncio.queues.Queue() + self.total = len(runs) + self.done = 0 + + for r in runs: + f = asyncio.ensure_future(r) + args = r.cr_frame.f_locals + target = (args['host'], args['port']) + f.add_done_callback(functools.partial(self.__queue_result, target)) + + + def __queue_result(self, target, f): + res = None + + try: + res = f.result() + except Exception as e: + res = e + + self.queue.put_nowait((target, res)) + + + async def __aiter__(self): + return self + + + async def __anext__(self): + if self.done == self.total: + raise StopAsyncIteration + + res = await self.queue.get() + self.done += 1 + return res + + +async def study_host(host, port, payload, connect_timeout, read_timeout): + r = None + w = None + buf = bytearray() + + async with timeout(connect_timeout): + r, w = await asyncio.open_connection(host, port) + remote = w.get_extra_info('peername') + if remote[0] == host: + module.log('{}:{} - Connected'.format(host, port), level='debug') + else: + module.log('{}({}):{} - Connected'.format(host, *remote), level='debug') + w.write(payload) + await w.drain() + + try: + async with timeout(read_timeout): + while len(buf) < 4096: + data = await r.read(4096) + if data: + module.log('{}:{} - Received {} bytes'.format(host, port, len(data)), level='debug') + buf.extend(data) + else: + break + except asyncio.TimeoutError: + if buf: + pass + else: + raise + + w.close() + return buf diff --git a/modules/auxiliary/scanner/wproxy/att_open_proxy.py b/modules/auxiliary/scanner/wproxy/att_open_proxy.py new file mode 100755 index 0000000000..de98e1cc7a --- /dev/null +++ b/modules/auxiliary/scanner/wproxy/att_open_proxy.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +from metasploit import module, sonar + + +metadata = { + 'name': 'Open WAN-to-LAN proxy on AT&T routers', + 'description': ''' + The Arris NVG589 and NVG599 routers configured with AT&T U-verse + firmware 9.2.2h0d83 expose an un-authenticated proxy that allows + connecting from WAN to LAN by MAC address. + ''', + 'authors': [ + 'Joseph Hutchins' # Initial disclosure + 'Jon Hart ', # Dummy payload and response pattern + 'Adam Cammack ' # Metasploit module + ], + 'date': '2017-08-31', + 'references': [ + {'type': 'cve', 'ref': '2017-14117'}, + {'type': 'url', 'ref': 'https://www.nomotion.net/blog/sharknatto/'}, + {'type': 'url', 'ref': 'https://blog.rapid7.com/2017/09/07/measuring-sharknat-to-exposures/#vulnerability5port49152tcpexposure'}, + {'type': 'aka', 'ref': 'SharknAT&To'}, + {'type': 'aka', 'ref': 'sharknatto'} + ], + 'type': 'scanner.multi', + 'options': { + 'rhosts': {'type': 'address_range', 'description': 'The target address', 'required': True, 'default': None}, + 'rport': {'type': 'port', 'description': 'The target port', 'required': True, 'default': 49152}, + }, + } + + +def report_wproxy(target, response): + module.report_vuln(target[0], 'wproxy', port=target[0]) + + +if __name__ == "__main__": + module.run(metadata, sonar.make_study(payload = b'\x2a\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00', pattern = b'^\\*\xce.{3}$', onmatch = report_wproxy))