RDP сесији је потребна адреса клијента, а очигледни извори се не слажу. CLIENTNAME даје име рачунара, регистар чува вредности из других сесија, а супротна страна сокета може бити адреса мрежног пролаза или NAT-а, а не клијента. Windows заиста излаже пријављену адресу клијента по сесији, али морате питати праву сесију и исправно декодирати одговор.

Вежите претрагу за једну сесију

Почните са сесијом, не са особом. Windows RDP домаћин може носити неколико сесија за један налог, а адреса виђена пре поновног повезивања можда више не одговара активној вези. Забележите ID сесије, корисника и време посматрања заједно. ID сесије је кључ који API очекује и то је вредност која чува две сесије од забуне.

На домаћину инсталирани алати за сесије излиставају шта постоји; административни приказ користите само када на њега имате право. Потврдите изабрани ID непосредно пре упита, јер рециклирани ID враћа податке друге сесије.

qwinsta

Позовите WTSQuerySessionInformationW за тај ID

API услуга терминала одговара на питање информационом класом 14, WTSClientAddress. Мали ctypes омотач је довољан на Windows-у и избегава читање hive-а другог корисника. Код испод узима експлицитни ID сесије и пита локални домаћин.

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)

Проследите целобројни ID сесије који сте управо проверили и задржите нулту ручку сервера за локалну машину. Неуспешан позив третирајте као грешку, а не као одсутну адресу, јер то двоје води ка различитим закључцима. Упит о сесији другог корисника захтева одговарајућу дозволу Query Information, зато алат покрените под налогом који ју је добио, уместо да ad hoc подижете привилегије. Враћени бафер припада API-ју и мора се ослободити чак и када декодирање не успе.

Декодирајте фамилију, па ослободите бафер

Структура није IP ниска. Њено поље фамилије одлучује како се чита двадесет бајтова адресе: IPv4 почиње на померају два, а IPv6 на померају нула. Неодређена адреса значи да је клијент није пријавио, што није исто као празна ниска. Веза преко Remote Desktop Gateway документована је као случај у којем адреса није доступна, па сесија посредована кроз пролаз не пријављује ништа корисно о стварној адреси клијента. Корелација тада мора прећи на сопствене записе пролаза.

Исписујте фамилију уз адресу док отклањате грешке, јер је неслагање између њих уобичајен узрок уверљиве али погрешне вредности. Ослободите бафер помоћу WTSFreeMemory у finally блоку да га изузетак не би процурио.

Одвојите пријављену адресу од доказа

Пријављена адреса клијента је изјава коју даје клијент, а не поуздано посматрање. То није TCP саговорник, није табела закупа VPN пролаза и није јавна адреса клијента. Када је право питање који VPN закуп припада некој особи, повежите аутентификовани запис сесије VPN сервера у исто време. Када је питање који је извор стигао до слушаоца, читајте табелу веза или дозвољене серверске дневнике.

Држите ове вредности одвојено означене у сваком алату за подршку. Недостајући WTS резултат треба да остане недостајући, уместо да се враћа на произвољну вредност регистра из друге сесије. Бележите ID сесије уз адресу, јер се исти корисник може поново повезати и добити нову вредност. Ни назив клијента ни пријављена адреса нису довољан доказ за давање приступа.

Повезани чланци