Hvilken adresse rapporterer Windows for en RDP-økt?
WTS-API-et returnerer en rapportert klientadresse for én RDP-økt, og registeret gjør det ikke. Spør etter riktig økt-ID og dekod IPv4 eller IPv6 korrekt.
En RDP-økt trenger en klientadresse, og de åpenbare kildene er uenige. CLIENTNAME gir et datamaskinnavn, registeret inneholder verdier fra andre økter, og socket-motparten kan være en gateway- eller NAT-adresse i stedet for klienten. Windows tilbyr faktisk en rapportert klientadresse per økt, men du må spørre etter riktig økt og dekode svaret korrekt.
Forankre oppslaget i én økt
Begynn med økten, ikke personen. En Windows RDP-vert kan bære flere økter for én konto, og en adresse som ble sett før en gjenoppkobling, passer kanskje ikke lenger til den aktive forbindelsen. Noter økt-ID, bruker og observasjonstidspunkt sammen. Økt-ID-en er nøkkelen API-et forventer, og det er verdien som hindrer to økter i å bli forvekslet.
På verten lister de installerte øktverktøyene opp hva som finnes; bruk den administrative visningen bare når du har rett til den. Bekreft den valgte ID-en rett før spørringen, fordi en gjenbrukt ID returnerer en annen økts data.
qwinsta
Kall WTSQuerySessionInformationW for den ID-en
Terminal Services-API-et besvarer spørsmålet med informasjonsklasse 14, WTSClientAddress. En liten ctypes-innpakning er nok på Windows, og den unngår å lese en annen brukers hive. Koden nedenfor tar en eksplisitt økt-ID og spør den lokale verten.
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 heltalls-økt-ID-en du nettopp bekreftet, og behold null-serverhåndtaket for den lokale maskinen. Behandle et mislykket kall som en feil i stedet for som en manglende adresse, fordi de to fører til ulike konklusjoner. Spørring om en annen brukers økt krever den relevante Query Information-tillatelsen, så kjør verktøyet under en konto som har fått den, i stedet for å eskalere ad hoc. Den returnerte bufferen tilhører API-et og må frigis selv når dekodingen mislykkes.
Dekod familien, og frigjør deretter bufferen
Strukturen er ikke en IP-streng. Familie-feltet avgjør hvordan de tjue adressebyttene leses: IPv4 starter ved forskyvning to, mens IPv6 starter ved forskyvning null. Den uspesifiserte adressen betyr at klienten ikke rapporterte noen, noe som ikke er det samme som en tom streng. Remote Desktop Gateway-forbindelser er dokumentert som et tilfelle der adressen ikke er tilgjengelig, så en gateway-formidlet økt rapporterer ingenting nyttig om klientens virkelige adresse. Korrelasjonen må da flyttes til gatewayens egne registreringer.
Skriv ut familien ved siden av adressen mens du feilsøker, fordi uoverensstemmelse mellom de to er den vanlige årsaken til en troverdig men feil verdi. Frigjør bufferen med WTSFreeMemory i en finally-blokk, slik at et unntak ikke lekker den.
Skill den rapporterte adressen fra bevis
En rapportert klientadresse er en erklæring klienten leverer, ikke en pålitelig observasjon. Den er ikke TCP-motparten, ikke VPN-gatewayens lease-tabell og ikke klientens offentlige adresse. Når det egentlige spørsmålet er hvilken VPN-lease som tilhører en person, korreler VPN-serverens autentiserte øktregistrering samtidig. Når spørsmålet er hvilken kilde som nådde lytteren, les forbindelsestabellen eller de tillatte serverloggene.
Hold disse verdiene atskilt merket i ethvert støtteverktøy. Et manglende WTS-resultat bør forbli manglende i stedet for å falle tilbake på en vilkårlig registerverdi fra en annen økt. Logg økt-ID-en ved siden av adressen, fordi samme bruker kan koble til på nytt og få en ny verdi. Verken klientnavnet eller den rapporterte adressen er tilstrekkelig bevis for å gi tilgang.