-
Notifications
You must be signed in to change notification settings - Fork 1
/
tcp-proxy.py
155 lines (123 loc) · 5.36 KB
/
tcp-proxy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import sys
import socket
import threading
HEX_FILTER = "".join([(len(repr(chr(i))) == 3) and chr(i) or "." for i in range(256)])
# for each integer in the range of 0 to 255, if the length of the corresponding
# character equals 3, we get the character (chr(i)). Otherwise, we get a dot (.)
def hexdump(src, length=16, show=True):
if isinstance(src, bytes):
src = src.decode()
results = list() # creating an empty list object
for i in range(0, len(src), length):
word = str(src[i : i + length])
printable = word.translate(HEX_FILTER) # mapping the cahars
hexa = " ".join(
[f"{ord(c):02x}" for c in word]
) # read 1 char at time, convert it to ASCII and then print it as 2 digit hex number
hex_width = length * 3
results.append(
f"{i:04x} {hexa:<{hex_width}} {printable} "
) # hex width used for text_aligning to the left
if show:
for line in results:
print(line)
else:
return results
def receive_from(connection): # connection is socket object
buffer = b""
connection.settimeout(15) # setting a timeout
try:
while True: # set up a loop for reading messages
data = connection.recv(4096)
if not data: # loop breaks if there is no more data to read
break
buffer += data
except Exception as e:
pass
return buffer
# Modifying the response and request, INTERCEPTOR
def request_handler(buffer): # buffer is in bytes format
# perform packet modifications
return buffer
def response_handler(buffer): # buffer is in bytes format
# perform packet modifications
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# creating a socket object
remote_socket.connect((remote_host, remote_port)) # connecting the remote socket
# check to make sure we don’t need to first initiate a connection to the remote side
if receive_first:
remote_buffer = receive_from(remote_socket)
# receive from accepts socket object and returns buffer variable in bytes
hexdump(remote_buffer) # dump the contents of the packet
remote_buffer = response_handler(remote_buffer)
if len(remote_buffer):
print(f"[<==] Sending {len(remote_buffer)} bytes to localhost.")
client_socket.send(remote_buffer)
# receiving message from local host, modify it and send it to remote host
# then receive message from the remote host, modify it and send it to the local host
# if there is no data end the connections
while True: # maintaining the communication
local_buffer = receive_from(
client_socket
) # receiving the generated by localhost
if len(local_buffer):
print(f"[==>] Received {len(local_buffer)} bytes from localhost.")
hexdump(local_buffer)
local_buffer = request_handler(local_buffer) # modifies the request
remote_socket.send(local_buffer)
print("[==>] Sent to remote.")
remote_buffer = receive_from(
remote_socket
) # receiving the response generated by remote host
if len(remote_buffer):
print(f"[==>] Received {len(remote_buffer)} bytes from remote host.")
hexdump(remote_buffer)
remote_buffer = response_handler(remote_buffer)
client_socket.send(remote_buffer)
print("[<==] Sent to localhost.")
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print("[*] No more data. Closing connections.")
break
def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host, local_port)) # turning a socket into server
except Exception as e:
print(f"problem on bind: {e}")
print(f"[!!] Failed to listen on {local_host}:{local_port}")
print("[!!] Check for other listening sockets or correct permissions.")
sys.exit(0)
print(f"[*] Listening on {local_host}:{local_port}")
server.listen(5) # starts listening
while True:
client_socket, addr = server.accept()
# print out the local connection information
print(f"Recevied incoming connection from {addr[0]}:{addr[1]}")
# start a thread to talk to the remote host
proxy_thread = threading.Thread(
target=proxy_handler,
args=(client_socket, remote_host, remote_port, receive_first),
)
proxy_thread.start()
def main():
if len(sys.argv[1:]) != 5:
print("Usage: ./proxy.py [localhost] [localport]", end="")
print("[remotehost] [remoteport] [receive_first]")
print("Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
sys.exit(0)
local_host = sys.argv[1]
local_port = int(sys.argv[2])
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
server_loop(local_host, local_port, remote_host, remote_port, receive_first)
if __name__ == "__main__":
main()