Permalink
Find file Copy path
1d1a4a9 Aug 30, 2018
Robert Heaton Initial commit
0 contributors

Users who have contributed to this file

155 lines (126 sloc) 4.33 KB
from twisted.internet import protocol, reactor
from twisted.internet import ssl as twisted_ssl
import dns.resolver
import netifaces as ni
# Adapted from http://stackoverflow.com/a/15645169/221061
class TCPProxyProtocol(protocol.Protocol):
"""
TCPProxyProtocol listens for TCP connections from a
client (eg. a phone) and forwards them on to a
specified destination (eg. an app's API server) over
a second TCP connection, using a ProxyToServerProtocol.
It assumes that neither leg of this trip is encrypted.
"""
def __init__(self):
self.buffer = None
self.proxy_to_server_protocol = None
def connectionMade(self):
"""
Called by twisted when a client connects to the
proxy. Makes an connection from the proxy to the
server to complete the chain.
"""
print("Connection made from CLIENT => PROXY")
proxy_to_server_factory = protocol.ClientFactory()
proxy_to_server_factory.protocol = ProxyToServerProtocol
proxy_to_server_factory.server = self
reactor.connectTCP(DST_IP, DST_PORT,
proxy_to_server_factory)
def dataReceived(self, data):
"""
Called by twisted when the proxy receives data from
the client. Sends the data on to the server.
CLIENT ===> PROXY ===> DST
"""
print("")
print("CLIENT => SERVER")
print(FORMAT_FN(data))
print("")
if self.proxy_to_server_protocol:
self.proxy_to_server_protocol.write(data)
else:
self.buffer = data
def write(self, data):
self.transport.write(data)
class ProxyToServerProtocol(protocol.Protocol):
"""
ProxyToServerProtocol connects to a server over TCP.
It sends the server data given to it by an
TCPProxyProtocol, and uses the TCPProxyProtocol to
send data that it receives back from the server on
to a client.
"""
def connectionMade(self):
"""
Called by twisted when the proxy connects to the
server. Flushes any buffered data on the proxy to
server.
"""
print("Connection made from PROXY => SERVER")
self.factory.server.proxy_to_server_protocol = self
self.write(self.factory.server.buffer)
self.factory.server.buffer = ''
def dataReceived(self, data):
"""
Called by twisted when the proxy receives data
from the server. Sends the data on to to the client.
DST ===> PROXY ===> CLIENT
"""
print("")
print("SERVER => CLIENT")
print(FORMAT_FN(data))
print("")
self.factory.server.write(data)
def write(self, data):
if data:
self.transport.write(data)
def _noop(data):
return data
def get_local_ip(iface):
ni.ifaddresses(iface)
return ni.ifaddresses(iface)[ni.AF_INET][0]['addr']
FORMAT_FN = _noop
LISTEN_PORT = 80
DST_PORT = 80
DST_HOST = "nonhttps.com"
local_ip = get_local_ip('en0')
# Look up the IP address of the target
print("Querying DNS records for %s..." % DST_HOST)
a_records = dns.resolver.query(DST_HOST, 'A')
print("Found %d A records:" % len(a_records))
for r in a_records:
print("* %s" % r.address)
print("")
assert(len(a_records) > 0)
# THe target may have multiple IP addresses - we
# simply choose the first one.
DST_IP = a_records[0].address
print("Choosing to proxy to %s" % DST_IP)
print("""
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
-#-#-#-#-#-RUNNING TCP PROXY-#-#-#-#-#-
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
Dst IP:\t%s
Dst port:\t%d
Dst hostname:\t%s
Listen port:\t%d
Local IP:\t%s
""" % (DST_IP, DST_PORT, DST_HOST, LISTEN_PORT, local_ip))
print("""
Next steps:
1. Make sure you are spoofing DNS requests from the
device you are trying to proxy request from so that they
return your local IP (%s).
2. Make sure you have set the destination and listen ports
correctly (they should generally be the same).
3. Use the device you are proxying requests from to make
requests to %s and check that they are logged in this
terminal.
4. Look at the requests, write more code to replay them,
fiddle with them, etc.
Listening for requests on %s:%d...
""" % (local_ip, DST_HOST, local_ip, LISTEN_PORT))
factory = protocol.ServerFactory()
factory.protocol = TCPProxyProtocol
reactor.listenTCP(LISTEN_PORT, factory)
reactor.run()