Ghost

Recon

nmap_scan.log
└─$ grep ghost /etc/hosts
10.10.11.24     ghost.htb       core.ghost.htb  DC01.ghost.htb  federation.ghost.htb

DNS (53)

SMB (Enumeration)

Looks like we will need credentials to get something out of SMB.

HTTP (8008)

Port 80 enumeration was unsuccessful, so moved on to next http server.

Ghost CMS

Ghost CMS version 5.78 is running on nginx 1.18.0:

Writeup.png
Writeup-1.png

On unsuccessful login or Forgot Password action request is made to API:

Writeup-2.png

Ghost Content API

Going back to Homepage, I thought Search was useless, but inspecting the request we see it's making a request to backend. request looks like raw SQL:

Writeup-4.png

Endpoint list can be found in docs itself: https://ghost.org/docs/content-api/?ref=docslab.electronthemes-ghost.com#endpointsarrow-up-right

This key doesn't have any permissions on admin API, endpoints: https://ghost.org/docs/admin-api/#endpointsarrow-up-right

Gitea (Enumeration)

CMS seemed secure enough to fight off any plain attacks as mentioned on their page: https://ghost.org/docs/security/arrow-up-right and nothing really was working. Port 8443 was serving Ghost Core at core.ghost.htb which later redirects to federation.ghost.htb. Application is quite vast, so there could be more subdomains. Testing subdomains on 8008 port:

Application only allows internal logins, no registration. 2 users and no repositories (or no permissions to view as anonymous). Gitea version doesn't seem vulnerable to any CVEs.

Writeup-3.png

Hmm... nothing was making sense about the application..

Intranet

app on intranet subdomain uses LDAP

Writeup-5.png

Try payloads from swisskyrepo/PayloadsAllTheThings/LDAP Injection > payloadsarrow-up-right

Using payload *:* we are able to get in!

Writeup-6.png

Users:

Username
Full Name
Member of

kathryn.holland

Kathryn Holland

sysadmin

cassandra.shelton

Cassandra Shelton

sysadmin

robert.steeves

Robert Steeves

sysadmin

florence.ramirez

Florence Ramirez

IT

justin.bradley

Justin Bradley

IT, Remote Management Users

arthur.boyd

Arthur Boyd

IT

beth.clark

Beth Clark

HR

charles.gray

Charles Gray

HR

jason.taylor

Jason Taylor

HR

intranet_principal

Intranet Principal

principal

gitea_temp_principal

Gitea_Temp Principal

principal

Another subdomain in Forum:

Writeup-7.png

Brute Passwords via LDAP

Brute the passwords via LDAP injection:

Creds: kathryn.holland:fgevlfymxrksvu9b Creds: gitea_temp_principal:szrr8kpc3z6onlqf

Note: Not sure why, but sometimes script didn't brute the whole passwords. test if password works, if it doesn't try password* to verify.

Gitea (gitea_temp_principal)

Login with gitea_temp_principal account and we get few repositories:

Writeup-8.png

Intranet

api-dev seems to be open on intranet subdomain.

Writeup-9.png

http://gitea.ghost.htb:8008/ghost-dev/intranet/src/branch/main/backend/src/main.rsarrow-up-right

http://gitea.ghost.htb:8008/ghost-dev/intranet/src/branch/main/backend/src/api/dev/scan.rsarrow-up-right

http://gitea.ghost.htb:8008/ghost-dev/intranet/src/branch/main/frontend/src/helpers/fetch.tsarrow-up-right

Something tricky is going on with frontend, the API paths are all hardcoded and there's no way to interact with function.

Blog

Public API Key: a5af628828958c976a3b6cc81a

Writeup-10.png

http://gitea.ghost.htb:8008/ghost-dev/blog/src/branch/main/docker-compose.ymlarrow-up-right

http://gitea.ghost.htb:8008/ghost-dev/blog/src/branch/main/Dockerfilearrow-up-right

Private API Key: 659cdeec9cd6330001baefbf (?)

There's interesting request made via extra parameter in posts-public.js

http://gitea.ghost.htb:8008/ghost-dev/blog/src/branch/main/posts-public.js#L113arrow-up-right

First I tried making request to get the important file, but was unlucky.

Testing for LFI with /etc/hosts is a success!

Leak the environment variables:

Find the usage of key:

Writeup-11.png

RCE

The application lives on intranet.ghost.htb, not ghost.htb :/

Looks like we are root in the container.

Reverse Shell (intranet container)

Get a reverse shell:

database.sqlite is just migration tables from gitea.

Run linpeas:

First I focused on env variable usage:

Docker is started with entrypoint script:

SSH file in /root/.ssh/controlmaster is a socket file... (?)

Looks like we are able to ssh into the other box without password?... Interesting

Run linpeas. curl/wget was not available, but python3 is and with built-in one-liner we can download the files.

Nothing eye catching, but we are part of the domain controller and since this is a Windows box we can get the loot for Bloodhound.

Bash doesn't like exe files and bloodhound-python needs user credentials to work, so no enumeration :/

Kerberos Cache

What are the "/tmp/kerb5cc_<user-id>" files exactly?arrow-up-right

If you want to use a pre-existing credentials cache on the host from inside a container, you can mount it into the container, and set the KRB5CCNAMEarrow-up-right environment variable

Using Kerberos authentication with NetExecarrow-up-right

I wasn't able to go far with kerberos cache, HackerRecipies > Pass the ticketarrow-up-right was not working as user didn't have any privileges.

ADIDNS poisoning

If we go back to forum there's a user who ran some script, but dns was not configured. We can take advantage of that with HackerRecipies > ADIDNS poisoningarrow-up-right method.

Writeup-12.png

Crack the hash:

evil-winrm (justin.bradley)

Creds: justin.bradley:Qwertyuiop1234$$

User.txt

Privilege Escalation (adfs_gmsa$)

Defender is active 💀

Note: sh.exe is SharpHound.exe

Luckily we can use python version and get "loot" remotely.

Note: Make sure to use CE branch version collector, master branch doesn't work with Community Edition Bloodhound.

Writeup-13.png

HackerRecipies > ReadGMSAPasswordarrow-up-rightNetexec > Dump gMSAarrow-up-right

Privilege Escalation (mssqlserver)

Welp... that was useless.

Writeup-14.png

HTTPs (8443)

I decided to take a step back for now. When we go to core.ghost.htb we are asked to login into AD Federation

Writeup-15.png
Writeup-16.png

For now I just logged in as justin:

Creds: GHOST\justin.bradley:Qwertyuiop1234$$

Writeup-17.png

How SAML Authentication Worksarrow-up-right

SAML is a protocol for Single Sign-On (SSO). It lets users log in once and then access multiple services without needing to log in again. SAML passes authentication information between an Identity Provider (IdP) and a Service Provider (SP), so your credentials are verified by the IdP and the service just checks the token. It’s a way to securely manage user authentication across different platforms.

SAML Basicsarrow-up-right

_The SAMLRequest parameter is a compressed and encoded version of the raw XML snippet, utilizing Deflate compression and base64 encoding.

Decode request Onelogin > Base64 Decode + Inflatearrow-up-right

Golden SAML Attack

While searching around for SAML and ADFS I came to blog: Exploring the Golden SAML Attack Against ADFSarrow-up-right

Attack Tutorial: How the Golden SAML Attack Worksarrow-up-right

The blog demonstrates authentication into Office365, but we need SAML

Writeup-18.png

GitHub also includes an example: Generate a SAML 2.0 token for some app:

Note: Later I found useful repo: InternalAllTheThings > Active Directory - Federation Servicesarrow-up-right

Data needed:

  • DKM Key: dkm.key

  • TKS Key: tks.key

  • Domain: core.ghost.htb

  • endpoint: https://core.ghost.htb:8443/adfs/saml/postResponse

  • nameidformat: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress

  • nameid: Administrator@ghost.htb

  • rpidentifier: https://core.ghost.htb:8443

  • assertions: <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"><AttributeValue>Administrator@ghost.htb</AttributeValue></Attribute>

Get Keys:

Get dkm.key from Private Key: (I took second as first)

Get tks.key from Encrypted Token Signing Key:

Get endpoint for SAML:Writeup-19.png

Now after gathering the requirements we are ready to spoof the account and login.

Using the given "Response" was not working as it Internal Server Error

Going back to the ADFSDump.exe we also got some rules, which indicates that we need upn and CommonName assertions in the spoof command:

Microsoft > The Role of Claimsarrow-up-right

Name
Description
URI

UPN

The user principal name (UPN) of the user

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn

Common Name

The common name of the user

http://schemas.xmlsoap.org/claims/CommonName

Make the request to endpoint:

Writeup-20.png

Request to view the request in browser:

Writeup-21.png

MSSQL

PayloadsAllTheThings/SQL Injection/MSSQL Injectionarrow-up-right

The database doesn't allow us to run xp_cmdshell and when we try to enable it we get RequestError: You do not have permission to run the RECONFIGURE statement.

Get permissions:

entity_name
subentity_name
permission_name

server

CONNECT SQL

server

VIEW ANY DATABASE

Get tables from available databases:

The tables were mostly empty and not useful. The words The databases are correctly linked. is oddly suspicious. In PayloadsAllTheThings there's a section for MSSQL Trusted Links

srvid
srvstatus
srvname
srvproduct
providername
datasource
location
providerstring
schemadate
topologyx
topologyy
catalog
srvcollation
connecttimeout
querytimeout
srvnetname
isremote
rpc
pub
sub
dist
dpub
rpcout
dataaccess
collationcompatible
system
useremotecollation
lazyschemavalidation
collation
nonsqlsub

0

1089

DC01

SQL Server

SQLOLEDB

DC01

2024-02-02T20:18:34.940Z

0

0

0

0

DC01

True

True

False

False

False

False

True

False

False

False

True

False

False

1

1249

PRIMARY

SQL Server

SQLOLEDB

PRIMARY

2024-07-27T05:33:22.490Z

0

0

0

0

PRIMARY

False

True

False

False

False

False

True

True

False

False

True

False

False

Hmmmm... weird

Anyway, PayloadsAllTheThings also has EXECUTE in EXECUTE AT SERVER query to exploit trusted database links.

Reverse Shell

Due to Defender I wasn't able to use Powershell #3 (Base64) payload from revshells, so I did curl over shell

Privilege Escalation (CORP system)

SeImpersonatePrivilege is interesting token 👀 HackTricks > Abusing Tokens > SeImpersonatePrivilegearrow-up-right

I first tried Juicy Potatoarrow-up-right, already compiled versions can be found herearrow-up-right. But Defender still didn't like that and didn't allow the program to execute, also nc.exe was also flagged as malicious and removed...

Then I tried Generic Potatoarrow-up-right as suggested by Potatoes - Windows Privilege Escalationarrow-up-right post, but couldn't make it work as in needed trigger on localhost and stuff...

While searching about how to use Generic Potato I stumbled upon new notebook: Pentester's Promiscuous Notebookarrow-up-right. After GenericPotato EfsPotatoarrow-up-right was listed, which is a single C# potato exploit that supports SeImpersonatePrivilege.

C# is available on system, so we can compile it and run it:

https://github.com/gwillgues/Reverse-Shellsarrow-up-right is usually not detected by Defender so we can play with it on different session.

Writeup-22.png

Looks like we are on PRIMARY and we want to be on DC01.

Disable Defender so we can enumerate AD with SharpHound, srcarrow-up-right

...wot...

Writeup-23.png

Trusted Domains

If we look into the domains, we can observe that both domains have TrustedBy relationship.

Writeup-24.png

Gather some info about domain:

ADReconarrow-up-right made few things easier to enumerate.

Trusts.csv:

Source Domain
Target Domain
Trust Direction
Trust Type
Attributes
whenCreated
whenChanged

corp.ghost.htb

ghost.htb

BiDirectional

Uplevel

Within Forest

1/31/2024 6:33:33 PM

7/22/2024 9:21:26 AM

Forest.csv:

Category
Value

Name

ghost.htb

Functional Level

Windows2016Forest

Domain Naming Master

DC01.ghost.htb

Schema Master

DC01.ghost.htb

RootDomain

ghost.htb

Domain Count

2

Site Count

1

Global Catalog Count

2

Domain

ghost.htb

Domain

corp.ghost.htb

Site

Default-First-Site-Name

GlobalCatalog

DC01.ghost.htb

GlobalCatalog

PRIMARY.corp.ghost.htb

Tombstone Lifetime

180

Recycle Bin (2008 R2 onwards)

Disabled

Privileged Access Management (2016 onwards)

Disabled

LAPS

Disabled

Compters.csv:

UserName
Name
DNSHostName
Enabled
IPv4Address
Operating System
Logon Age (days)
Password Age (days)
Dormant (> 90 days)
Password Age (> 30 days)
Delegation Type
Delegation Protocol
Delegation Services
Primary Group ID
SID
SIDHistory
Description
ms-ds-CreatorSid
Last Logon Date
Password LastSet
UserAccountControl
whenCreated
whenChanged
Distinguished Name

PRIMARY$

PRIMARY

PRIMARY.corp.ghost.htb

True

10.0.0.10

Windows Server 2022 Datacenter 10.0 (20348)

0

57

False

True

516

S-1-5-21-2034262909-2733679486-179904498-1000

8/13/2024 9:03:25 PM

6/17/2024 9:51:07 AM

532480

1/31/2024 6:34:00 PM

8/13/2024 9:03:25 PM

CN=PRIMARY,OU=Domain Controllers,DC=corp,DC=ghost,DC=htb

Resources:

Golden Ticket

Steps are replicated from Nairuz Abulhul: Breaking Domain Trusts with Forged Trust Ticketsarrow-up-right blog. We should have access to \\dc01.ghost.htb\c$, but seems like something went wrong ://

One of the steps used child domain sid for sids, which was wrong. What we need is privileged user or group SID!

After some enumeration Enterprise Admins was the one that worked.

Note: The SID has been applied to above commands.

Privilege Escalation (DC01 system)

Use the generated hash:

Oddly enough the secretsdump worked?!...

The secretsdump dumped both domains, corp and then DC01 so we need to use the DC01 hash :/

Root.txt


Writeups referenced:

Last updated