Quina adreça informa Windows per a una sessió RDP?
L’API WTS retorna una adreça de client informada per a una sessió RDP, i el registre no. Consulteu l’ID de sessió correcte i descodifiqueu IPv4 o IPv6 correctament.
Una sessió RDP necessita una adreça de client, i les fonts òbvies no coincideixen. CLIENTNAME dóna un nom d’ordinador, el registre conté valors d’altres sessions, i l’extrem del sòcol pot ser una adreça de passarel·la o NAT en lloc del client. Windows sí que exposa una adreça de client informada per sessió, però heu de demanar la sessió correcta i descodificar la resposta correctament.
Ancleu la consulta a una sola sessió
Comenceu per la sessió, no per la persona. Un amfitrió RDP de Windows pot portar diverses sessions per a un compte, i una adreça vista abans d’una reconnexió pot ja no correspondre a l’enllaç actiu. Registreu l’ID de sessió, l’usuari i el moment d’observació junts. L’ID de sessió és la clau que espera l’API, i és el valor que evita confondre dues sessions.
A l’amfitrió, les eines de sessió instal·lades llisten què existeix; feu servir la vista administrativa només quan hi tingueu dret. Confirmeu l’ID triat just abans de la consulta, perquè un ID reciclat retorna les dades d’una altra sessió.
qwinsta
Crideu WTSQuerySessionInformationW per a aquest ID
L’API de Serveis de Terminal respon la pregunta amb la classe d’informació 14, WTSClientAddress. Un petit embolcall de ctypes n’hi ha prou a Windows, i evita llegir el rusc d’un altre usuari. El codi de sota pren un ID de sessió explícit i pregunta a l’amfitrió local.
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)
Passeu l’ID de sessió enter que acabeu de verificar, i mantingueu el manejador de servidor nul per a la màquina local. Tracteu una crida fallida com un error i no com una adreça absent, perquè les dues coses porten a conclusions diferents. Consultar la sessió d’un altre usuari requereix el permís Query Information adequat, així que executeu l’eina amb un compte que el tingui concedit en lloc d’escalar ad hoc. El búfer retornat pertany a l’API i s’ha d’alliberar fins i tot quan la descodificació falla.
Descodifiqueu la família i després allibereu el búfer
L’estructura no és una cadena IP. El seu camp de família decideix com es llegeixen els vint bytes d’adreça: IPv4 comença a l’offset dos, mentre que IPv6 comença a l’offset zero. L’adreça no especificada vol dir que el client no n’ha informat cap, cosa que no és el mateix que una cadena buida. Les connexions a través de Remote Desktop Gateway estan documentades com un cas en què l’adreça no està disponible, així que una sessió mitjançada per passarel·la no informa res d’útil sobre l’adreça real del client. La correlació s’ha de traslladar llavors als registres propis de la passarel·la.
Imprimiu la família al costat de l’adreça mentre depureu, perquè una discrepància entre les dues és la causa habitual d’un valor versemblant però incorrecte. Allibereu el búfer amb WTSFreeMemory en un bloc finally perquè una excepció no el perdi.
Separeu l’adreça informada de la prova
Una adreça de client informada és una afirmació que aporta el client, no una observació fiable. No és l’extrem TCP, ni la taula de concessions de la passarel·la VPN, ni l’adreça pública del client. Quan la pregunta real és quina concessió VPN pertany a una persona, correleu el registre de sessió autenticat del servidor VPN al mateix temps. Quan la pregunta és quina font ha arribat a l’oient, llegiu la taula de connexions o els registres permesos del costat del servidor.
Mantingueu aquests valors etiquetats per separat a qualsevol eina de suport. Un resultat WTS absent hauria de quedar absent en lloc de recórrer a un valor de registre arbitrari d’una altra sessió. Registreu l’ID de sessió al costat de l’adreça, perquè el mateix usuari pot reconnectar-se i rebre un valor nou. Ni el nom del client ni l’adreça informada no són prova suficient per concedir accés.