import asyncio
import struct
# Asetukset
LISTEN_HOST = '0.0.0.0'
LISTEN_PORT = 5901
UPSTREAM_HOST = '127.0.0.1'
UPSTREAM_PORT = 5900
class VNCProxy:
async def start(self):
server = await asyncio.start_server(self.handle_client, LISTEN_HOST,
LISTEN_PORT)
print(f"[*] VNC Proxy kuuntelee {LISTEN_HOST}:{LISTEN_PORT}")
async with server:
await server.serve_forever()
async def handle_client(self, client_reader, client_writer):
print("[+] Uusi VNC-asiakas yhdistetty proxyyn")
try:
target_reader, target_writer = await asyncio.open_connection(UPSTRE
AM_HOST, UPSTREAM_PORT)
except Exception as e:
print(f"[-] Ei yhteyttC$ VNC-palvelimeen: {e}")
client_writer.close()
return
# Kaksi asynkronista putkea:
# 1. Palvelimelta asiakkaalle (puhdas pass-through)
# 2. Asiakkaalta palvelimelle (tC$ssC$ tapahtuu sieppaus)
task1 = asyncio.create_task(self.server_to_client(target_reader,
client_writer))
task2 = asyncio.create_task(self.client_to_server(client_reader,
target_writer))
await asyncio.gather(task1, task2)
async def server_to_client(self, target_reader, client_writer):
try:
while True:
data = await target_reader.read(4096)
if not data:
break
client_writer.write(data)
await client_writer.drain()
except asyncio.IncompleteReadError:
pass
async def client_to_server(self, client_reader, target_writer):
try:
# 1. VAIHE: RFB KC$ttely (Handshake)
# Yksinkertaistettu ohitus: luetaan protokollaversio (12 tavua) ja
ClientInit
# Todellisessa tuotannossa tC$ssC$ tulkitaan Security-tyyppi ja
mahdollinen salasana (16 tavua).
handshake = await client_reader.read(64) # Luetaan kC$ttelyblokki
target_writer.write(handshake)
await target_writer.drain()
print("[*] KC$ttely ohitettu, siirrytC$C$n pakettianalyysiin...")
# 2. VAIHE: Viestien parsinta
while True:
# Luetaan viestin tyyppi (1 tavu)
msg_type_bytes = await client_reader.readexactly(1)
target_writer.write(msg_type_bytes)
msg_type = msg_type_bytes[0]
if msg_type == 5:
# ---- POINTER EVENT (6 tavua) ----
# Rakenne: Tyyppi (1), ButtonMask (1), X (2), Y (2)
payload = await client_reader.readexactly(5)
target_writer.write(payload)
button_mask = payload[0]
x, y = struct.unpack('>HH', payload[1:5]) # >HH =
Big-Endian, kaksi Unsigned Shortia
# Tarkistetaan vasen hiiren painike (Bitti 0)
left_click = bool(button_mask & 1)
if left_click:
print(f"[KLIKKAUS SIEPATTU] X: {x}, Y: {y}")
# TCSTC LAUKAISTAAN CONTEXT AGENT!
# asyncio.create_task(self.trigger_agent(x, y))
elif msg_type == 0:
# SetPixelFormat (20 tavua yhteensC$)
payload = await client_reader.readexactly(19)
target_writer.write(payload)
elif msg_type == 2:
# SetEncodings (4 tavua header + 4 * encodings_mC$C$rC$)
payload = await client_reader.readexactly(3)
target_writer.write(payload)
num_encodings = struct.unpack('>H', payload[1:3])[0]
encodings = await client_reader.readexactly(num_encodings
* 4)
target_writer.write(encodings)
elif msg_type == 3:
# FramebufferUpdateRequest (10 tavua yhteensC$)
payload = await client_reader.readexactly(9)
target_writer.write(payload)
elif msg_type == 4:
# KeyEvent (8 tavua yhteensC$)
payload = await client_reader.readexactly(7)
target_writer.write(payload)
elif msg_type == 6:
# ClientCutText (8 tavua header + pituus-muuttuja)
payload = await client_reader.readexactly(7)
target_writer.write(payload)
length = struct.unpack('>I', payload[3:7])[0]
text = await client_reader.readexactly(length)
target_writer.write(text)
else:
# Tuntematon viesti, ei voida taata stream-synkkaa
print(f"[!] Tuntematon viestityyppi: {msg_type}")
await target_writer.drain()
except asyncio.IncompleteReadError:
print("[-] VNC-asiakas katkaisi yhteyden.")
if __name__ == "__main__":
proxy = VNCProxy()
asyncio.run(proxy.start())