Windows báo cáo địa chỉ nào cho một phiên RDP?
API WTS trả về địa chỉ máy khách được báo cáo cho một phiên RDP, còn sổ đăng ký thì không. Hãy truy vấn đúng ID phiên và giải mã IPv4 hoặc IPv6 chính xác.
Một phiên RDP cần địa chỉ máy khách, và các nguồn hiển nhiên không đồng ý với nhau. CLIENTNAME cho biết tên máy tính, sổ đăng ký chứa giá trị từ các phiên khác, và đầu bên kia của socket có thể là địa chỉ cổng hoặc NAT chứ không phải máy khách. Windows thực sự công bố địa chỉ máy khách được báo cáo cho từng phiên, nhưng bạn phải hỏi đúng phiên và giải mã câu trả lời chính xác.
Gắn việc tra cứu vào một phiên duy nhất
Hãy bắt đầu từ phiên, không phải từ người. Một máy chủ RDP của Windows có thể mang nhiều phiên cho một tài khoản, và một địa chỉ đã thấy trước khi kết nối lại có thể không còn khớp với liên kết đang hoạt động. Ghi lại ID phiên, người dùng và thời điểm quan sát cùng nhau. ID phiên là khóa mà API mong đợi, và chính giá trị đó ngăn hai phiên bị nhầm lẫn.
Trên máy chủ, các công cụ phiên đã cài đặt liệt kê những gì tồn tại; chỉ dùng chế độ xem quản trị khi bạn có quyền với nó. Xác nhận ID đã chọn ngay trước khi truy vấn, vì một ID được tái sử dụng sẽ trả về dữ liệu của phiên khác.
qwinsta
Gọi WTSQuerySessionInformationW cho ID đó
API Terminal Services trả lời câu hỏi bằng lớp thông tin 14, WTSClientAddress. Một trình bao ctypes nhỏ là đủ trên Windows, và nó tránh việc đọc hive của người dùng khác. Đoạn mã dưới đây nhận ID phiên rõ ràng và hỏi máy chủ cục bộ.
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)
Truyền ID phiên dạng số nguyên mà bạn vừa xác minh, và giữ xử lý máy chủ rỗng cho máy cục bộ. Hãy coi lệnh gọi thất bại là lỗi chứ không phải địa chỉ vắng mặt, vì hai điều đó dẫn đến kết luận khác nhau. Truy vấn phiên của người dùng khác cần quyền Query Information thích hợp, nên hãy chạy công cụ dưới một tài khoản đã được cấp quyền đó thay vì nâng quyền tạm thời. Bộ đệm trả về thuộc về API và phải được giải phóng kể cả khi việc giải mã thất bại.
Giải mã họ rồi giải phóng bộ đệm
Cấu trúc này không phải một chuỗi IP. Trường họ của nó quyết định cách đọc hai mươi byte địa chỉ: IPv4 bắt đầu ở độ lệch hai, còn IPv6 bắt đầu ở độ lệch không. Địa chỉ không xác định nghĩa là máy khách không báo cáo địa chỉ nào, điều này không giống một chuỗi rỗng. Các kết nối qua Remote Desktop Gateway được ghi nhận là trường hợp địa chỉ không khả dụng, nên một phiên qua cổng không báo cáo gì hữu ích về địa chỉ thật của máy khách. Khi đó việc tương quan phải chuyển sang hồ sơ của chính cổng.
In họ bên cạnh địa chỉ khi gỡ lỗi, vì sự không khớp giữa hai giá trị là nguyên nhân thường gặp của một giá trị có vẻ hợp lý nhưng sai. Giải phóng bộ đệm bằng WTSFreeMemory trong khối finally để một ngoại lệ không làm rò rỉ nó.
Tách địa chỉ được báo cáo khỏi bằng chứng
Địa chỉ máy khách được báo cáo là một tuyên bố do máy khách cung cấp, không phải quan sát đáng tin cậy. Đó không phải đầu bên kia của TCP, không phải bảng thuê của cổng VPN và không phải địa chỉ công cộng của máy khách. Khi câu hỏi thực sự là thuê VPN nào thuộc về một người, hãy tương quan bản ghi phiên đã xác thực của máy chủ VPN cùng lúc. Khi câu hỏi là nguồn nào đã đến được trình lắng nghe, hãy đọc bảng kết nối hoặc nhật ký phía máy chủ được phép.
Giữ các giá trị này được gắn nhãn riêng trong bất kỳ công cụ hỗ trợ nào. Kết quả WTS bị thiếu nên tiếp tục thiếu thay vì quay về một giá trị sổ đăng ký tùy ý từ phiên khác. Ghi ID phiên bên cạnh địa chỉ, vì cùng một người dùng có thể kết nối lại và nhận giá trị mới. Tên máy khách hay địa chỉ được báo cáo đều không phải bằng chứng đủ để cấp quyền truy cập.