class SocksProxyConnection: """ Generic asynchronous TCP socket class, nothing SMB related. Creates the connection and channels incoming/outgoing bytes via asynchonous queues. """ def __init__(self, target=None, socket=None): self.target = target self.socket = socket #for future, if we want a custom soscket self.client = None self.proxy_task = None self.out_queue = None #asyncio.Queue() self.in_queue = None #asyncio.Queue() async def disconnect(self): """ Disconnects from the socket. Stops the reader and writer streams. """ self.proxy_task.cancel() async def connect(self): self.out_queue = asyncio.Queue() self.in_queue = asyncio.Queue() comms = SocksQueueComms(self.out_queue, self.in_queue) self.target.proxy.target.endpoint_ip = self.target.ip self.target.proxy.target.endpoint_port = int(self.target.port) self.client = SOCKSClient(comms, self.target.proxy.target, self.target.proxy.auth) self.proxy_task = asyncio.create_task(self.client.run()) return
class AIOKerberosClientSocksSocket: def __init__(self, target): self.target = target self.out_queue = None self.in_queue = None self.proxy_client = None self.proxy_task = None def get_addr_str(self): return '%s:%d' % (self.target.ip, self.target.port) async def sendrecv(self, data): self.out_queue = asyncio.Queue() self.in_queue = asyncio.Queue() comms = SocksQueueComms(self.out_queue, self.in_queue) self.client = SOCKSClient(comms, self.target.proxy.target) self.proxy_task = asyncio.create_task(self.client.run()) length = len(data).to_bytes(4, byteorder = 'big', signed = False) await self.out_queue.put(length+data) resp_data = b'' resp_data_len = -1 while True: data, err = await self.in_queue.get() if data is None: break if err is not None: raise err resp_data += data if resp_data_len == -1: if len(resp_data) > 4: resp_data_len = int.from_bytes(resp_data[:4], byteorder = 'big', signed = False) if resp_data_len == 0: raise Exception('Returned data length is 0! This means the server did not understand our message') if resp_data_len != -1: if len(resp_data) == resp_data_len + 4: resp_data = resp_data[4:] break elif len(resp_data) > resp_data_len + 4: raise Exception('Got too much data somehow') else: continue await self.out_queue.put(None) if resp_data == b'': raise Exception('Connection returned no data!') krb_message = KerberosResponse.load(resp_data) return krb_message def __str__(self): t = '===AIOKerberosClientProxySocket AIO===\r\n' t += 'target: %s\r\n' % self.target return t
def main(): import argparse parser = argparse.ArgumentParser(description='Transparent TCP tunnel for SOCKS unaware clients.') parser.add_argument('proxy_connection_string', help='connection string decribing the socks5 proxy server connection properties') parser.add_argument('dst_ip', help='IP address of the desination server') parser.add_argument('dst_port', type = int, help='port number of the desination service') parser.add_argument('-l', '--listen-ip', default = '127.0.0.1', help='Listener IP address to bind to') parser.add_argument('-p', '--listen-port', type = int, default = 11111, help='Listener port number to bind to') parser.add_argument('-t', '--timeout', type = int, default = None, help='Endpoint timeout') parser.add_argument('-v', '--verbose', action='count', default=0) args = parser.parse_args() if args.verbose >=1: logger.setLevel(logging.DEBUG) elif args.verbose > 2: logger.setLevel(1) comms = SocksLitenerComms(args.listen_ip, args.listen_port) url = SocksClientURL.from_url(args.proxy_connection_string) url.endpoint_ip = args.dst_ip url.endpoint_port = args.dst_port url.endpoint_timeout = args.timeout target = url.get_target() credentials = url.get_creds() if args.verbose >=1: print(str(target)) print(__banner__) layout = """Connection layout CLIENT --->| CLIENT --->|(LISTENER) %s:%s |--->| (%s) %s:%s |--->| (FINAL DST) %s:%s CLIENT --->| """ % (args.listen_ip, args.listen_port, target.version.name.upper() ,target.server_ip, target.server_port, args.dst_ip, args.dst_port) print(layout) client = SOCKSClient(comms, target, credentials) print('Waiting for incoming connections') asyncio.run(client.run())
class RDNS: def __init__(self, server = '8.8.8.8', protocol = 'TCP', cache = True, timeout = 1, proxy:List[str] = None): self.server = server self.protocol = protocol self.port = 53 self.cache = {} self.timeout = timeout self.proxy:List[str] = proxy self.proxyobj = None self.proxy_task = None self.in_q = None self.out_q = None async def setup(self): try: if self.proxy is None: # no need for additional setup return None, None self.in_q = asyncio.Queue() self.out_q = asyncio.Queue() comms = SocksQueueComms(self.in_q, self.out_q) proxies = SocksClientURL.from_urls(self.proxy, self.server, self.port) self.proxyobj = SOCKSClient(comms, proxies) self.proxy_task = asyncio.create_task(self.proxyobj.run()) return None, None except Exception as e: return None, e async def lookup(self, hostname, dnstype = DNSType.A): _, err = await self.setup() if err is not None: return None, err try: question = DNSQuestion.construct(str(hostname), dnstype, DNSClass.IN, qu = False) if self.proxyobj is None: if self.protocol == 'TCP': reader, writer = await asyncio.wait_for(asyncio.open_connection(self.server, self.port), self.timeout) packet = DNSPacket.construct( TID = os.urandom(2), flags = DNSFlags.RD, response = DNSResponse.REQUEST, opcode = DNSOpcode.QUERY, rcode = DNSResponseCode.NOERR, questions= [question], proto = socket.SOCK_STREAM ) writer.write(packet.to_bytes()) await writer.drain() data = await DNSPacket.from_streamreader(reader, proto = socket.SOCK_STREAM) writer.close() return data.Answers[0].ipaddress, None else: raise NotImplementedError() else: if self.protocol == 'TCP': packet = DNSPacket.construct( TID = os.urandom(2), flags = DNSFlags.RD, response = DNSResponse.REQUEST, opcode = DNSOpcode.QUERY, rcode = DNSResponseCode.NOERR, questions= [question], proto = socket.SOCK_STREAM ) await self.in_q.put(packet.to_bytes()) x = await DNSPacket.from_queue(self.out_q, b'', proto = socket.SOCK_STREAM) packet, rem = x if len(packet.Answers) == 0: raise Exception("No answer found in packet") return packet.Answers[0].ipaddress, None else: raise NotImplementedError() except Exception as e: return None, e finally: if self.proxyobj is not None: await self.proxyobj.terminate() async def resolve(self, ip): try: if ip in self.cache: return self.cache[ip] ip = ipaddress.ip_address(ip).reverse_pointer tid = os.urandom(2) question = DNSQuestion.construct(ip, DNSType.PTR, DNSClass.IN, qu = False) if self.protocol == 'TCP': reader, writer = await asyncio.wait_for(asyncio.open_connection(self.server, self.port), self.timeout) packet = DNSPacket.construct( TID = tid, flags = DNSFlags.RD, response = DNSResponse.REQUEST, opcode = DNSOpcode.QUERY, rcode = DNSResponseCode.NOERR, questions= [question], proto = socket.SOCK_STREAM ) writer.write(packet.to_bytes()) await writer.drain() data = await DNSPacket.from_streamreader(reader, proto = socket.SOCK_STREAM) self.cache[ip] = data.Answers[0].domainname writer.close() return data.Answers[0].domainname, None else: cli = UDPClient((self.server, self.port)) packet = DNSPacket.construct( TID = tid, flags = DNSFlags.RD, response = DNSResponse.REQUEST, opcode = DNSOpcode.QUERY, rcode = DNSResponseCode.NOERR, questions= [question], proto = socket.SOCK_DGRAM ) reader, writer = await cli.run(packet.to_bytes()) data = await DNSPacket.from_streamreader(reader) self.cache[ip] = data.Answers[0].domainname return data.Answers[0].domainname, None except Exception as e: return None, e finally: if self.proxyobj is not None: await self.proxyobj.terminate()
class SocksProxyConnection: """ Generic asynchronous TCP socket class, nothing SMB related. Creates the connection and channels incoming/outgoing bytes via asynchonous queues. """ def __init__(self, target): self.target = target self.client = None self.proxy_task = None self.handle_in_task = None self.out_queue = None #asyncio.Queue() self.in_queue = None #asyncio.Queue() self.proxy_in_queue = None #asyncio.Queue() self.is_plain_msg = True async def disconnect(self): """ Disconnects from the socket. Stops the reader and writer streams. """ self.proxy_task.cancel() self.handle_in_task.cancel() def get_peer_certificate(self): raise Exception( 'Not yet implemented! SSL implementation on socks is missing!') return self.writer.get_extra_info('socket').getpeercert(True) def get_one_message(self, data): if len(data) < 6: return None if self.is_plain_msg is True: dl = calcualte_length(data[:6]) else: dl = int.from_bytes(data[:4], byteorder='big', signed=False) dl = dl + 4 #print(dl) if len(data) >= dl: return data[:dl] async def handle_in_q(self): try: data = b'' while True: while True: msg_data = self.get_one_message(data) if msg_data is None: break await self.in_queue.put((msg_data, None)) data = data[len(msg_data):] temp, err = await self.proxy_in_queue.get() #print(temp) if err is not None: raise err if temp == b'' or temp is None: logger.debug('Server finished!') return data += temp continue except asyncio.CancelledError: return except Exception as e: logger.exception('handle_in_q') await self.in_queue.put((None, e)) finally: self.proxy_task.cancel() async def run(self): """ """ try: self.out_queue = asyncio.Queue() self.in_queue = asyncio.Queue() self.proxy_in_queue = asyncio.Queue() comms = SocksQueueComms(self.out_queue, self.proxy_in_queue) self.target.proxy.target.endpoint_ip = self.target.host self.target.proxy.target.endpoint_port = int(self.target.port) self.client = SOCKSClient(comms, self.target.proxy.target, self.target.proxy.auth) self.proxy_task = asyncio.create_task(self.client.run()) self.handle_in_task = asyncio.create_task(self.handle_in_q()) return True, None except Exception as e: return False, e