Egy RDP-munkamenetnek ügyfélcím kell, és a kézenfekvő források nem értenek egyet. A CLIENTNAME számítógépnevet ad, a rendszerleíró adatbázis más munkamenetek értékeit tartalmazza, a socket túloldala pedig lehet átjáró- vagy NAT-cím az ügyfél helyett. A Windows valóban közzétesz munkamenetenként egy jelentett ügyfélcímet, de a megfelelő munkamenetet kell kérdeznie, és helyesen kell dekódolnia a választ.

Rögzítse a keresést egyetlen munkamenethez

A munkamenettel kezdje, ne a személlyel. Egy Windows RDP-gazdagép több munkamenetet is hordozhat egy fiókhoz, és az újracsatlakozás előtt látott cím már nem feltétlenül felel meg az élő kapcsolatnak. Jegyezze fel együtt a munkamenet-azonosítót, a felhasználót és az észlelés idejét. A munkamenet-azonosító az a kulcs, amelyet az API elvár, és ez az az érték, amely megakadályozza két munkamenet összekeverését.

A gazdagépen a telepített munkamenet-eszközök felsorolják, mi létezik; a felügyeleti nézetet csak akkor használja, ha jogosult rá. A kiválasztott azonosítót közvetlenül a lekérdezés előtt erősítse meg, mert az újrahasznosított azonosító más munkamenet adatait adja vissza.

qwinsta

Hívja meg a WTSQuerySessionInformationW-t ehhez az azonosítóhoz

A Terminal Services API a 14-es információosztállyal válaszol a kérdésre, WTSClientAddress. Windows alatt egy kis ctypes-burkoló elegendő, és elkerüli egy másik felhasználó hive-jának olvasását. Az alábbi kód explicit munkamenet-azonosítót vesz át, és a helyi gazdagépet kérdezi.

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)

Adja át az imént ellenőrzött egész munkamenet-azonosítót, és tartsa meg a null szerverfogantyút a helyi géphez. A sikertelen hívást hibaként kezelje, ne hiányzó címként, mert a kettő különböző következtetésekhez vezet. Egy másik felhasználó munkamenetének lekérdezése a megfelelő Query Information engedélyt igényli, ezért futtassa az eszközt olyan fiók alatt, amely megkapta, ne emeljen jogosultságot ad hoc módon. A visszaadott puffer az API-hoz tartozik, és akkor is fel kell szabadítani, ha a dekódolás meghiúsul.

Dekódolja a családot, majd szabadítsa fel a puffert

A struktúra nem IP-karakterlánc. A család mezője dönti el, hogyan kell olvasni a húsz címbytét: az IPv4 a kettes eltolásnál kezdődik, az IPv6 viszont a nulla eltolásnál. A nem meghatározott cím azt jelenti, hogy az ügyfél nem jelentett egyet sem, ami nem ugyanaz, mint az üres karakterlánc. A Remote Desktop Gateway kapcsolatok dokumentáltan olyan eset, amikor a cím nem érhető el, ezért az átjárón keresztüli munkamenet semmi hasznosat nem jelent az ügyfél valódi címéről. Ilyenkor a korrelációnak az átjáró saját nyilvántartásaira kell átkerülnie.

Hibakeresés közben nyomtassa ki a családot a cím mellett, mert a kettő közötti eltérés a szokásos oka egy hihető, de hibás értéknek. Szabadítsa fel a puffert a WTSFreeMemory hívással egy finally blokkban, hogy egy kivétel ne szivárogtathassa el.

Válassza el a jelentett címet a bizonyítéktól

A jelentett ügyfélcím az ügyfél által szolgáltatott állítás, nem megbízható megfigyelés. Nem a TCP túloldala, nem a VPN-átjáró bérleti táblázata, és nem az ügyfél nyilvános címe. Amikor a valódi kérdés az, melyik VPN-bérlet tartozik egy személyhez, akkor ugyanabban az időben korrelálja a VPN-kiszolgáló hitelesített munkamenet-rekordját. Amikor a kérdés az, melyik forrás érte el a figyelőt, olvassa a kapcsolati táblázatot vagy az engedélyezett kiszolgálóoldali naplókat.

Tartsa ezeket az értékeket külön címkézve minden támogatóeszközben. A hiányzó WTS-eredmény maradjon hiányzó, ahelyett hogy egy másik munkamenet tetszőleges rendszerleíró értékére esne vissza. Naplózza a munkamenet-azonosítót a cím mellett, mert ugyanaz a felhasználó újracsatlakozhat és új értéket kaphat. Sem az ügyfélnév, sem a jelentett cím nem elégséges bizonyíték a hozzáférés megadásához.

Kapcsolódó cikkek