რომელ მისამართს აცხადებს Windows RDP სესიისთვის?
WTS API აბრუნებს გამოცხადებულ კლიენტის მისამართს ერთი RDP სესიისთვის, რეესტრი კი არა. იკითხეთ სწორი სესიის ID და სწორად დეკოდირეთ IPv4 ან IPv6.
RDP სესიას კლიენტის მისამართი სჭირდება და აშკარა წყაროები არ თანხმდებიან. CLIENTNAME კომპიუტერის სახელს იძლევა, რეესტრი სხვა სესიების მნიშვნელობებს ინახავს, ხოლო სოკეტის მოპირდაპირე მხარე შეიძლება იყოს კარიბჭის ან NAT-ის მისამართი და არა კლიენტი. Windows ნამდვილად აქვეყნებს გამოცხადებულ კლიენტის მისამართს თითოეული სესიისთვის, მაგრამ უნდა იკითხოთ სწორი სესია და სწორად დეკოდიროთ პასუხი.
მიამაგრეთ ძიება ერთ სესიას
დაიწყეთ სესიით და არა ადამიანით. Windows RDP ჰოსტს ერთი ანგარიშისთვის რამდენიმე სესია შეიძლება ჰქონდეს, და ხელახლა დაკავშირებამდე ნანახი მისამართი შეიძლება აღარ შეესაბამებოდეს აქტიურ კავშირს. ერთად ჩაწერეთ სესიის ID, მომხმარებელი და დაკვირვების დრო. სესიის ID არის გასაღები, რომელსაც API ელოდება, და სწორედ ეს მნიშვნელობა უშლის ხელს ორი სესიის არევას.
ჰოსტზე დაყენებული სესიის ხელსაწყოები ჩამოთვლის რა არსებობს; ადმინისტრაციული ხედი გამოიყენეთ მხოლოდ მაშინ, როცა მისი უფლება გაქვთ. დადასტურეთ არჩეული ID შეკითხვის უშუალო წინ, რადგან გადამუშავებული ID სხვა სესიის მონაცემებს აბრუნებს.
qwinsta
გამოიძახეთ WTSQuerySessionInformationW ამ ID-ისთვის
Terminal Services API პასუხობს კითხვას ინფორმაციის კლასით 14, WTSClientAddress. Windows-ზე პატარა ctypes გარსი საკმარისია და ის თავს არიდებს სხვა მომხმარებლის 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 მისამართის გვერდით, რადგან იგივე მომხმარებელს შეუძლია ხელახლა დაკავშირება და ახალი მნიშვნელობის მიღება. არც კლიენტის სახელი და არც გამოცხადებული მისამართი არ არის საკმარისი მტკიცებულება წვდომის მისაცემად.