Download Game! Currently 84 players. Last logged in:BullwinFloppySentenceStomp

Blitzer's Blog >> 72576

Back to blogs index
Posted: 19 Sep 2026 11:31 [ permalink ]
TC$mC$ on erinomainen lC6ytC6. "Security Type: 19" (VeNCrypt / TLS) selittC$C$
tC$ysin, miksi aVNC jC$C$ pyC6rimC$C$n. Oletuksena moni moderni VNC-palvelin
(kuten TigerVNC tai uudempi x11vnc) pyrkii neuvottelemaan salatun TLS-putken
turvallisuuden takaamiseksi.
Kun yhteys pC$ivitetC$C$n TLS:C$C$n (Security Type 19 = VeNCrypt), kaikki
myC6hempi liikenne on salattua, eikC$ meidC$n proxy-koodimme voi enC$C$ lukea
paketista PointerEvent (viestityyppi 5) tai kC$ttelyn loppuosaa, koska se on
puhdasta TLS-kryptotekstiC$. Proxyn parsinta menee sekaisin, ja VNC-asiakas
jC$C$ odottamaan, ettC$ TLS-kC$ttely viedC$C$n loppuun.
Ratkaisu: EstetC$C$n TLS:n kC$yttC6 (Downgrade-hyC6kkC$ys)
Koska VNC-proxy on luotetussa lokaalissa verkossasi (tai suoraan samalla
koneella, 127.0.0.1), me emme tarvitse salattua yhteyttC$ palvelimen ja proxyn
vC$liin. Haluamme pakottaa palvelimen ja asiakkaan kC$yttC$mC$C$n perinteistC$
VNC-autentikointia (Tyyppi 2) tai salaamatonta yhteyttC$ (Tyyppi 1).
Koska olemme Man-in-the-Middle (MitM), voimme muokata palvelimen
lC$hettC$mC$C$ "Tuetut Security Typet" -listaa ennen kuin asiakas (aVNC)
nC$kee sen. Palvelin saattaa sanoa: "Tuen tyyppejC$ 19, 18, 2". Me muutamme
viestin muotoon: "Tuen vain tyyppiC$ 2 (tai 1)".
TC$mC$ pakottaa aVNC:n valitsemaan selvC$kielisen protokollan.
Korjattu handle_handshake -metodi
TC$ssC$ on koodi, joka muokkaa lennosta palvelimen lC$hettC$mC$C$ kC$ttelyC$
ja poistaa sieltC$ VeNCryptin (19), pakottaen yhteyden selvC$kieliseksi (joko
salasana 2, tai ei salasanaa 1).
Muokkaa vncproxy.py tiedostostasi handle_handshake -funktio tC$smC$lleen
tC$hC$n muotoon:
    async def handle_handshake(self, c_reader, c_writer, s_reader, s_writer):
        # Vaihe 1: Protocol Version (12 tavua)
        s_version = await s_reader.readexactly(12)
        c_writer.write(s_version)
        await c_writer.drain()
        
        c_version = await c_reader.readexactly(12)
        s_writer.write(c_version)
        await s_writer.drain()
        
        # Vaihe 2: Security Types
        # Palvelin kertoo montako tyyppiC$ se tukee
        num_sec_types_bytes = await s_reader.readexactly(1)
        num_sec_types = num_sec_types_bytes[0]
        
        if num_sec_types == 0:
            # Jos 0, palvelin lC$hettC$C$ heti perC$C$n virheviestin syystC$
            c_writer.write(num_sec_types_bytes)
            await c_writer.drain()
            reason_len = struct.unpack('>I', await s_reader.readexactly(4))[0]
            reason = await s_reader.readexactly(reason_len)
            c_writer.write(struct.pack('>I', reason_len) + reason)
            await c_writer.drain()
            raise Exception(f"Palvelin sulki yhteyden: {reason.decode('utf-8',
'ignore')}")
            
        # Luetaan palvelimen tukemat tyypit
        server_sec_types = await s_reader.readexactly(num_sec_types)
        print(f"[*] Palvelimen alkuperC$iset Security Typet: {list(server_sec_t
ypes)}")
        
        # DOWNGRADE: Suodatetaan pois tyypit > 2 (esim 19 VeNCrypt, 18 TLS)
        # Sallitaan vain 1 (None) ja 2 (VNC Auth)
        allowed_types = [t for t in server_sec_types if t in (1, 2)]
        
        if not allowed_types:
            raise Exception("Palvelin tukee vain salattuja yhteyksiC$ (esim.
vain VeNCrypt). Proxyn kC$yttC6 vaatii selvC$kielisen VNC-salasanan tai
No-Auth tuen.")
            
        # LC$hetetC$C$n asiakkaalle (aVNC) meidC$n manipuloitu lista
        print(f"[*] Pakotetaan asiakkaalle Security Typet: {allowed_types}")
        c_writer.write(struct.pack('B', len(allowed_types)))
        c_writer.write(bytes(allowed_types))
        await c_writer.drain()
        
        # Vaihe 3: Client valitsee Security Typen meidC$n manipuloidulta
listalta
        selected_sec_type_bytes = await c_reader.readexactly(1)
        sec_type = selected_sec_type_bytes[0]
        
        # LC$hetetC$C$n asiakkaan valinta palvelimelle.
        # HUOM: Koska poistimme salausvaihtoehdot, palvelin hyvC$ksyy tyypin 1
tai 2,
        # KOSKA se alunperinkin ilmoitti tukevansa niitC$.
        s_writer.write(selected_sec_type_bytes)
        await s_writer.drain()
        
        print(f"[*] Asiakas valitsi Security Typen: {sec_type}")
        
        # Vaihe 4: Autentikaatio
        if sec_type == 2: # VNC Authentication
            challenge = await s_reader.readexactly(16)
            c_writer.write(challenge)
            await c_writer.drain()
            
            response = await c_reader.readexactly(16)
            s_writer.write(response)
            await s_writer.drain()
            
            sec_result = await s_reader.readexactly(4)
            c_writer.write(sec_result)
            await c_writer.drain()
            
            result_code = struct.unpack('>I', sec_result)[0]
            if result_code != 0:
                raise Exception("Salasana vC$C$rin")
                
        elif sec_type == 1: # None
            # RFB 3.8 vaatii SecurityResultin myC6s None-tyypille
            sec_result = await s_reader.readexactly(4)
            c_writer.write(sec_result)
            await c_writer.drain()
        
        # Vaihe 5: ClientInit (1 = Exclusive, 0 = Shared)
        client_init = await c_reader.readexactly(1)
        s_writer.write(client_init)
        await s_writer.drain()
        
        # Vaihe 6: ServerInit
        server_init_header = await s_reader.readexactly(24)
        c_writer.write(server_init_header)
        
        name_length = struct.unpack('>I', server_init_header[20:24])[0]
        name = await s_reader.readexactly(name_length)
        c_writer.write(name)
        await c_writer.drain()
        
        print(f"[*] KC$ttely ohitettu onnistuneesti. TyC6pC6ydC$n nimi:
{name.decode('utf-8', 'ignore')}")

MitC$ nyt pitC$isi tapahtua?
Kun aVNC yhdistC$C$, se nC$kee proxyn manipuloiman vastauksen: "Tuen vain VNC
Authia (2)". aVNC kysyy sinulta VNC-salasanaa (jos sellaista kC$ytetC$C$n),
lC$hettC$C$ salasanavasteen lC$pi proxyn, ja loppuyhteys pysyy perinteisessC$,
selvC$kielisessC$ RFB-muodossa.
Koska liikenne on selvC$kielistC$, silmukka nC$kee taas hiiren klikkaukset ja
koordinaatit.
Kokeile ajaa proxy uudelleen tC$llC$ muutoksella ja yhdistC$ aVNC:llC$.