RDP sesijai reikia kliento adreso, o akivaizdūs šaltiniai nesutaria. CLIENTNAME pateikia kompiuterio vardą, registre saugomos kitų sesijų reikšmės, o lizdo priešinė pusė gali būti tinklų sietuvo arba NAT adresas, o ne klientas. „Windows“ tikrai pateikia praneštą kliento adresą kiekvienai sesijai, tačiau reikia užklausti tinkamos sesijos ir teisingai iššifruoti atsakymą.

Pririškite paiešką prie vienos sesijos

Pradėkite nuo sesijos, o ne nuo žmogaus. „Windows“ RDP serveris gali turėti kelias sesijas vienai paskyrai, o adresas, matytas prieš prisijungimą iš naujo, gali nebeatitikti aktyvios jungties. Užrašykite sesijos ID, naudotoją ir stebėjimo laiką kartu. Sesijos ID yra raktas, kurio tikisi API, ir būtent ši reikšmė neleidžia supainioti dviejų sesijų.

Serveryje įdiegtos sesijų priemonės išvardija, kas egzistuoja; administracinį vaizdą naudokite tik tada, kai turite tam teisę. Patvirtinkite pasirinktą ID prieš pat užklausą, nes pernaudotas ID grąžina kitos sesijos duomenis.

qwinsta

Iškvieskite WTSQuerySessionInformationW tam ID

Terminal Services API atsako į klausimą 14 informacijos klase, WTSClientAddress. „Windows“ pakanka nedidelės ctypes apvalkalo, ir ji išvengia kito naudotojo hive skaitymo. Toliau pateiktas kodas priima aiškų sesijos ID ir klausia vietinio serverio.

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)

Perduokite ką tik patikrintą sveikąjį sesijos ID ir palikite nulinį serverio apdorojimo žymeklį vietinei mašinai. Nepavykusį iškvietimą traktuokite kaip klaidą, o ne kaip nesančio adreso atvejį, nes abu veda prie skirtingų išvadų. Kito naudotojo sesijos užklausai reikia atitinkamos Query Information teisės, todėl vykdykite priemonę paskyroje, kuriai ji suteikta, o ne didinkite teises ad hoc. Grąžintas buferis priklauso API ir turi būti atlaisvintas net jei iššifravimas nepavyksta.

Iššifruokite šeimą, tada atlaisvinkite buferį

Struktūra nėra IP eilutė. Jos šeimos laukas lemia, kaip skaitomi dvidešimt adreso baitų: IPv4 prasideda nuo dviejų poslinkio, o IPv6 – nuo nulio poslinkio. Nenurodytas adresas reiškia, kad klientas jo nepranešė, ir tai nėra tas pats kaip tuščia eilutė. „Remote Desktop Gateway“ jungtys dokumentuotos kaip atvejis, kai adresas nepasiekiamas, todėl per sietuvą einanti sesija nieko naudingo nepraneša apie tikrąjį kliento adresą. Tada koreliacija turi persikelti į paties sietuvo įrašus.

Derinimo metu spausdinkite šeimą šalia adreso, nes jų neatitikimas yra įprasta tikėtinos, bet neteisingos reikšmės priežastis. Atlaisvinkite buferį su WTSFreeMemory finally bloke, kad išimtis jo nenutekintų.

Atskirkite praneštą adresą nuo įrodymo

Praneštas kliento adresas yra kliento pateiktas teiginys, o ne patikimas stebėjimas. Tai nėra TCP priešinė pusė, nėra VPN sietuvo nuomos lentelė ir nėra kliento viešasis adresas. Kai tikrasis klausimas yra, kuri VPN nuoma priklauso žmogui, tuo pačiu metu koreliuokite autentifikuotą VPN serverio sesijos įrašą. Kai klausimas yra, kuris šaltinis pasiekė klausytoją, skaitykite jungčių lentelę arba leidžiamus serverio pusės žurnalus.

Laikykite šias reikšmes atskirai pažymėtas bet kurioje palaikymo priemonėje. Trūkstamas WTS rezultatas turi likti trūkstamas, o ne grįžti prie savavališkos kitos sesijos registro reikšmės. Registruokite sesijos ID šalia adreso, nes tas pats naudotojas gali prisijungti iš naujo ir gauti naują reikšmę. Nei kliento vardas, nei praneštas adresas nėra pakankamas įrodymas suteikti prieigą.

Susiję straipsniai