RDP sesiji treba adresa klijenta, a očigledni izvori se ne slažu. CLIENTNAME daje naziv računara, registar drži vrijednosti iz drugih sesija, a drugi kraj socketa može biti adresa mrežnog prolaza ili NAT-a, a ne klijenta. Windows ipak izlaže prijavljenu adresu klijenta po sesiji, ali morate pitati za pravu sesiju i ispravno dekodirati odgovor.

Vežite pretragu za jednu sesiju

Počnite sa sesijom, ne sa osobom. Windows RDP host može nositi nekoliko sesija za jedan račun, a adresa viđena prije ponovnog spajanja možda više ne odgovara aktivnoj vezi. Zabilježite ID sesije, korisnika i vrijeme posmatranja zajedno. ID sesije je ključ koji API očekuje, i to je vrijednost koja čuva dvije sesije od zabune.

Na hostu instalirani alati za sesije izlistavaju šta postoji; administrativni prikaz koristite samo kada na njega imate pravo. Potvrdite izabrani ID neposredno prije upita, jer reciklirani ID vraća podatke druge sesije.

qwinsta

Pozovite WTSQuerySessionInformationW za taj ID

Terminal Services API odgovara na pitanje informacijskom klasom 14, WTSClientAddress. Mali ctypes omotač je dovoljan na Windowsu i izbjegava čitanje hive-a drugog korisnika. Kod ispod uzima eksplicitni ID sesije i pita lokalni host.

import ctypes
import ipaddress
import socket
from ctypes import wintypes

class WTS_CLIENT_ADDRESS(ctypes.Structure):
    _fields_ = [("AddressFamily", wintypes.DWORD),
                ("Address", ctypes.c_ubyte * 20)]

wts = ctypes.WinDLL("Wtsapi32", use_last_error=True)
query = wts.WTSQuerySessionInformationW
query.argtypes = [wintypes.HANDLE, wintypes.DWORD, ctypes.c_int,
                  ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(wintypes.DWORD)]
query.restype = wintypes.BOOL
free = wts.WTSFreeMemory
free.argtypes = [ctypes.c_void_p]

def client_address(session_id):
    buf = ctypes.c_void_p()
    size = wintypes.DWORD()
    if not query(None, session_id, 14, ctypes.byref(buf), ctypes.byref(size)):
        raise ctypes.WinError(ctypes.get_last_error())
    try:
        if size.value < ctypes.sizeof(WTS_CLIENT_ADDRESS):
            raise RuntimeError("short WTS buffer")
        value = ctypes.cast(buf, ctypes.POINTER(WTS_CLIENT_ADDRESS)).contents
        raw = bytes(value.Address)
        if value.AddressFamily == socket.AF_INET:
            addr = ipaddress.ip_address(raw[2:6])
        elif value.AddressFamily == socket.AF_INET6:
            addr = ipaddress.ip_address(raw[:16])
        else:
            return None
        return None if addr.is_unspecified else str(addr)
    finally:
        free(buf)

Proslijedite cjelobrojni ID sesije koji ste upravo provjerili i zadržite nulti server handle za lokalnu mašinu. Tretirajte neuspjeli poziv kao grešku, a ne kao odsutnu adresu, jer to dvoje vodi ka različitim zaključcima. Upit o sesiji drugog korisnika zahtijeva odgovarajuću dozvolu Query Information, zato alat pokrenite pod računom koji ju je dobio, umjesto da ad hoc podižete privilegije. Vraćeni bafer pripada API-ju i mora se osloboditi čak i kada dekodiranje ne uspije.

Dekodirajte familiju, pa oslobodite bafer

Struktura nije IP string. Njeno polje familije odlučuje kako se čita dvadeset bajtova adrese: IPv4 počinje na pomaku dva, a IPv6 na pomaku nula. Neodređena adresa znači da je klijent nije prijavio, što nije isto kao prazan string. Veze preko Remote Desktop Gateway dokumentovane su kao slučaj u kojem adresa nije dostupna, pa sesija posredovana kroz prolaz ne prijavljuje ništa korisno o stvarnoj adresi klijenta. Korelacija se tada mora preseliti na vlastite zapise prolaza.

Ispisujte familiju uz adresu dok otklanjate greške, jer je nesklad između njih uobičajen uzrok uvjerljive ali pogrešne vrijednosti. Oslobodite bafer pomoću WTSFreeMemory u finally bloku da ga izuzetak ne bi procurio.

Odvojite prijavljenu adresu od dokaza

Prijavljena adresa klijenta je izjava koju daje klijent, a ne pouzdano posmatranje. To nije TCP sagovornik, nije tabela zakupa VPN prolaza i nije javna adresa klijenta. Kada je pravo pitanje koji VPN zakup pripada nekoj osobi, povežite autentifikovani zapis sesije VPN servera u isto vrijeme. Kada je pitanje koji je izvor stigao do slušaoca, čitajte tabelu veza ili dozvoljene serverske dnevnike.

Držite ove vrijednosti odvojeno označene u svakom alatu za podršku. Nedostajući WTS rezultat treba ostati nedostajući, umjesto da se vraća na proizvoljnu vrijednost registra iz druge sesije. Bilježite ID sesije uz adresu, jer se isti korisnik može ponovo spojiti i dobiti novu vrijednost. Niti naziv klijenta niti prijavljena adresa nisu dovoljan dokaz za davanje pristupa.

Povezani članci