Watter adres rapporteer Windows vir ’n RDP-sessie?
Die WTS-API gee ’n gerapporteerde kliëntadres vir een RDP-sessie, en die register nie. Vra die regte sessie-ID en dekodeer IPv4 of IPv6 korrek.
’n RDP-sessie het ’n kliëntadres nodig, en die ooglopende bronne stem nie saam nie. CLIENTNAME gee ’n rekenaarnaam, die register hou waardes van ander sessies, en ’n socket-eweknie kan ’n gateway- of NAT-adres wees eerder as die kliënt. Windows stel wel ’n gerapporteerde kliëntadres per sessie beskikbaar, maar jy moet vir die regte sessie vra en die antwoord korrek dekodeer.
Anker die soektog aan een sessie
Begin met die sessie, nie die persoon nie. ’n Windows-RDP-gasheer kan verskeie sessies vir een rekening dra, en ’n adres wat voor ’n herverbinding gesien is, pas dalk nie meer by die lewendige skakel nie. Teken die sessie-ID, die gebruiker en die waarnemingstyd saam aan. Die sessie-ID is die sleutel wat die API verwag, en dit is die waarde wat verhoed dat twee sessies verwar word.
Op die gasheer lys die geïnstalleerde sessiegereedskap wat bestaan; gebruik die administratiewe aansig net wanneer jy daarop geregtig is. Bevestig die gekose ID onmiddellik voor die navraag, want ’n hergebruikte ID lewer ’n ander sessie se data.
qwinsta
Roep WTSQuerySessionInformationW vir daardie ID
Die Terminal Services-API beantwoord die vraag met inligtingsklas 14, WTSClientAddress. ’n Klein ctypes-omhulsel is op Windows genoeg, en dit vermy om ’n ander gebruiker se hive te lees. Die kode hieronder neem ’n eksplisiete sessie-ID en vra die plaaslike gasheer.
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)
Gee die heelgetal-sessie-ID wat jy pas bevestig het deur, en hou die nul-bediener-handvatsel vir die plaaslike masjien. Hanteer ’n mislukte oproep as ’n fout eerder as as ’n afwesige adres, want die twee lei tot verskillende gevolgtrekkings. Om ’n ander gebruiker se sessie na te vra vereis die toepaslike Query Information-toestemming, so laat die gereedskap onder ’n rekening loop wat dit toegestaan is, eerder as om ad hoc te eskaleer. Die teruggekeerde buffer behoort aan die API en moet vrygestel word selfs wanneer dekodering misluk.
Dekodeer die familie en stel dan die buffer vry
Die struktuur is nie ’n IP-string nie. Sy familieveld bepaal hoe die twintig adresgrepe gelees word: IPv4 begin by offset twee, terwyl IPv6 by offset nul begin. Die ongespesifiseerde adres beteken die kliënt het nie een gerapporteer nie, wat nie dieselfde is as ’n leë string nie. Remote Desktop Gateway-verbindings word gedokumenteer as ’n geval waar die adres nie beskikbaar is nie, so ’n gateway-bemiddelde sessie rapporteer niks nuttigs vir die kliënt se werklike adres. Korrelasie moet dan na die gateway se eie rekords skuif.
Druk die familie saam met die adres terwyl jy ontfout, want ’n wanverhouding tussen die twee is die gewone oorsaak van ’n geloofwaardige maar verkeerde waarde. Stel die buffer vry met WTSFreeMemory in ’n finally-blok sodat ’n uitsondering dit nie lek nie.
Skei die gerapporteerde adres van bewys
’n Gerapporteerde kliëntadres is ’n verklaring wat die kliënt verskaf, nie ’n betroubare waarneming nie. Dit is nie die TCP-eweknie nie, nie die VPN-gasheer se huurtabel nie, en nie die kliënt se openbare adres nie. Wanneer die werklike vraag is watter VPN-verhuring aan ’n persoon behoort, korreleer dan die VPN-bediener se geauthentiseerde sessierekord op dieselfde tyd. Wanneer die vraag is watter bron die luisteraar bereik het, lees die verbindingstabel of die toegelate bediener-kant logs.
Hou hierdie waardes afsonderlik gemerk in enige ondersteuningsinstrument. ’n Ontbrekende WTS-resultaat moet ontbrekend bly eerder as om terug te val op ’n willekeurige registerwaarde van ’n ander sessie. Teken die sessie-ID langs die adres aan, want dieselfde gebruiker kan weer verbind en ’n nuwe waarde kry. Nóg die kliëntnaam nóg die gerapporteerde adres is voldoende bewys om toegang te verleen.