Bir RDP oturumu istemci adresine ihtiyaç duyar ve apaçık görünen kaynaklar aynı fikirde değildir. CLIENTNAME bir bilgisayar adı verir, kayıt defteri başka oturumların değerlerini tutar ve soketin karşı ucu istemci yerine bir ağ geçidi veya NAT adresi olabilir. Windows gerçekten her oturum için bildirilen bir istemci adresi sunar, ancak doğru oturumu sorgulamanız ve yanıtı doğru çözmeniz gerekir.

Aramayı tek bir oturuma sabitleyin

Kişiyle değil, oturumla başlayın. Bir Windows RDP konağı tek bir hesap için birkaç oturum taşıyabilir ve yeniden bağlanmadan önce görülen bir adres artık etkin bağlantıyla eşleşmeyebilir. Oturum kimliğini, kullanıcıyı ve gözlem zamanını birlikte kaydedin. Oturum kimliği API'nin beklediği anahtardır ve iki oturumun karıştırılmasını önleyen değer de odur.

Konakta, kurulu oturum araçları nelerin var olduğunu listeler; yönetim görünümünü yalnızca buna hakkınız olduğunda kullanın. Seçilen kimliği sorgudan hemen önce doğrulayın, çünkü yeniden kullanılan bir kimlik başka bir oturumun verilerini döndürür.

qwinsta

O kimlik için WTSQuerySessionInformationW çağırın

Terminal Services API soruyu 14 numaralı bilgi sınıfıyla yanıtlar, WTSClientAddress. Windows'ta küçük bir ctypes sarmalayıcı yeterlidir ve başka bir kullanıcının hive'ını okumaktan kaçınır. Aşağıdaki kod açık bir oturum kimliği alır ve yerel konağa sorar.

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)

Az önce doğruladığınız tamsayı oturum kimliğini iletin ve yerel makine için boş sunucu tutamacını koruyun. Başarısız bir çağrıyı eksik adres olarak değil hata olarak ele alın, çünkü ikisi farklı sonuçlara götürür. Başka bir kullanıcının oturumunu sorgulamak uygun Query Information iznini gerektirir, bu nedenle aracı ad hoc yetki yükseltmek yerine bu iznin verildiği bir hesap altında çalıştırın. Döndürülen arabellek API'ye aittir ve çözme başarısız olsa bile serbest bırakılmalıdır.

Aileyi çözün, ardından arabelleği serbest bırakın

Yapı bir IP dizesi değildir. Aile alanı yirmi adres baytının nasıl okunacağını belirler: IPv4 iki uzaklığında başlar, IPv6 ise sıfır uzaklığında başlar. Belirtilmemiş adres, istemcinin hiçbirini bildirmediği anlamına gelir ve bu boş bir dizeyle aynı şey değildir. Remote Desktop Gateway bağlantıları adresin kullanılamadığı bir durum olarak belgelenmiştir, bu yüzden ağ geçidinden geçen bir oturum istemcinin gerçek adresi hakkında yararlı hiçbir şey bildirmez. İlişkilendirme o zaman ağ geçidinin kendi kayıtlarına taşınmalıdır.

Hata ayıklarken aileyi adresin yanında yazdırın, çünkü ikisi arasındaki uyuşmazlık makul ama yanlış bir değerin olağan nedenidir. Arabelleği finally bloğunda WTSFreeMemory ile serbest bırakın, böylece bir istisna onu sızdırmaz.

Bildirilen adresi kanıttan ayırın

Bildirilen istemci adresi istemcinin sağladığı bir beyandır, güvenilir bir gözlem değildir. TCP'nin karşı ucu değildir, VPN ağ geçidinin kiralama tablosu değildir ve istemcinin genel adresi değildir. Gerçek soru hangi VPN kiralamasının bir kişiye ait olduğuysa, aynı anda VPN sunucusunun kimliği doğrulanmış oturum kaydını ilişkilendirin. Soru hangi kaynağın dinleyiciye ulaştığıysa, bağlantı tablosunu veya izin verilen sunucu tarafı günlüklerini okuyun.

Bu değerleri herhangi bir destek aracında ayrı ayrı etiketli tutun. Eksik bir WTS sonucu, başka bir oturumdan gelen rastgele bir kayıt defteri değerine düşmek yerine eksik kalmalıdır. Oturum kimliğini adresin yanına kaydedin, çünkü aynı kullanıcı yeniden bağlanıp yeni bir değer alabilir. Ne istemci adı ne de bildirilen adres erişim vermek için yeterli kanıttır.

İlgili makaleler