En RDP-session har brug for en klientadresse, og de oplagte kilder er uenige. CLIENTNAME giver et computernavn, registreringsdatabasen indeholder værdier fra andre sessioner, og socket-modparten kan være en gateway- eller NAT-adresse i stedet for klienten. Windows stiller faktisk en rapporteret klientadresse til rådighed for hver session, men du skal spørge efter den rigtige session og afkode svaret korrekt.

Forankr opslaget i én session

Begynd med sessionen, ikke personen. En Windows RDP-vært kan bære flere sessioner for én konto, og en adresse, der blev set før en genopkobling, matcher måske ikke længere den aktive forbindelse. Notér sessions-ID, bruger og observationstidspunkt sammen. Sessions-ID’et er den nøgle, API’et forventer, og det er den værdi, der forhindrer to sessioner i at blive forvekslet.

På værten viser de installerede sessionsværktøjer, hvad der findes; brug kun den administrative visning, når du har ret til den. Bekræft det valgte ID umiddelbart før forespørgslen, fordi et genbrugt ID returnerer en anden sessions data.

qwinsta

Kald WTSQuerySessionInformationW for det ID

Terminal Services-API’et besvarer spørgsmålet med informationsklasse 14, WTSClientAddress. En lille ctypes-indpakning er nok på Windows, og den undgår at læse en anden brugers hive. Koden nedenfor tager et eksplicit sessions-ID og spørger den lokale vært.

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)

Send det heltals-sessions-ID, du netop har bekræftet, og behold det nulstillede server-håndtag til den lokale maskine. Behandl et mislykket kald som en fejl i stedet for som en manglende adresse, fordi de to fører til forskellige konklusioner. Forespørgsel om en anden brugers session kræver den relevante Query Information-tilladelse, så kør værktøjet under en konto, der har fået den, i stedet for at eskalere ad hoc. Den returnerede buffer tilhører API’et og skal frigives, selv når afkodningen fejler.

Afkod familien, og frigiv derefter bufferen

Strukturen er ikke en IP-streng. Dens familiefelt afgør, hvordan de tyve adressebytes læses: IPv4 starter ved offset to, mens IPv6 starter ved offset nul. Den uspecificerede adresse betyder, at klienten ikke rapporterede nogen, hvilket ikke er det samme som en tom streng. Remote Desktop Gateway-forbindelser er dokumenteret som et tilfælde, hvor adressen ikke er tilgængelig, så en gateway-formidlet session rapporterer intet brugbart om klientens rigtige adresse. Korrelationen må derefter flyttes til gatewayens egne registreringer.

Udskriv familien ved siden af adressen, mens du fejlretter, fordi uoverensstemmelse mellem de to er den sædvanlige årsag til en troværdig, men forkert værdi. Frigiv bufferen med WTSFreeMemory i en finally-blok, så en undtagelse ikke lækker den.

Adskil den rapporterede adresse fra bevis

En rapporteret klientadresse er en erklæring, som klienten leverer, ikke en pålidelig observation. Den er ikke TCP-modparten, ikke VPN-gatewayens lease-tabel og ikke klientens offentlige adresse. Når det egentlige spørgsmål er, hvilken VPN-lease der tilhører en person, skal du korrelere VPN-serverens autentificerede sessionsregistrering på samme tid. Når spørgsmålet er, hvilken kilde der nåede lytteren, skal du læse forbindelsestabellen eller de tilladte serverlogs.

Hold disse værdier adskilt mærket i ethvert supportværktøj. Et manglende WTS-resultat bør forblive manglende i stedet for at falde tilbage på en vilkårlig registreringsværdi fra en anden session. Log sessions-ID’et ved siden af adressen, fordi den samme bruger kan genopkoble og få en ny værdi. Hverken klientnavnet eller den rapporterede adresse er tilstrækkeligt bevis for at give adgang.

Relaterede artikler