Која адреса ја пријавува Windows за RDP сесија?
WTS API враќа пријавена адреса на клиентот за една RDP сесија, а регистарот не. Прашајте го точниот ID на сесијата и правилно декодирајте IPv4 или IPv6.
RDP сесијата бара адреса на клиент, а очигледните извори не се согласуваат. CLIENTNAME дава име на компјутер, регистарот чува вредности од други сесии, а спротивната страна на сокетот може да биде адреса на порта или NAT наместо клиентот. Windows навистина изложува пријавена адреса на клиент по сесија, но мора да ја прашате вистинската сесија и правилно да го декодирате одговорот.
Прицврстете го барањето на една сесија
Започнете со сесијата, не со лицето. Windows RDP домаќин може да носи неколку сесии за една сметка, а адреса видена пред повторно поврзување може веќе да не одговара на активната врска. Забележете ги ID на сесијата, корисникот и времето на набљудување заедно. ID на сесијата е клучот што го очекува API и токму таа вредност спречува две сесии да се помешаат.
На домаќинот, инсталираните алатки за сесии наведуваат што постои; административниот приказ користете го само кога имате право на него. Потврдете го избраниот ID веднаш пред барањето, бидејќи рециклиран ID враќа податоци од друга сесија.
qwinsta
Повикајте WTSQuerySessionInformationW за тој ID
API на Terminal Services одговара на прашањето со информациска класа 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 на сесијата покрај адресата, бидејќи истиот корисник може повторно да се поврзе и да добие нова вредност. Ниту името на клиентот ниту пријавената адреса не се доволен доказ за давање пристап.