PG: Jacko
| ターゲット // Jacko | |
|---|---|
| Platform | OffSec Proving Grounds |
| OS | Windows |
| Difficulty | Medium |
| IP | 192.168.89.66 |
Enumeration#
Nmap#
▶ Nmap output
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0 (redirects to H2 Database Engine)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn
445/tcp open microsoft-ds
8082/tcp open http H2 database http console
Windows host. Port 80 redirects to an H2 Database Engine banner, and port 8082 serves the H2 web console directly. SMB (139/445) is present but gives nothing useful as an anonymous user.
One quirk defines this box: the host firewall drops egress on everything except the ports already listening. Any download or reverse-shell callback has to ride an already-open port (80, 135, 139, 445, 8082) — plan payload delivery around that from the start.
Port 8082 - H2 Console#
The console lets you connect to the sample jdbc:h2:~/test database with no authentication — just hit Connect. The left panel then advertises the exact build:
H2 1.4.199 (2019-03-13)
H2 1.4.199 has a well-known code-execution primitive.
Foothold#
H2 1.4.199 Alias RCE#
H2 lets you register a Java method as a SQL alias and then CALL it. Using the JNIScriptEngine.eval gadget (EDB-49384) you get arbitrary command execution straight from the SQL console:
| |
The result comes back inline as a query result — code execution as jacko\tony:

Execution is heavily constrained: powershell.exe is blocked, and most binaries only resolve if you call them out of C:\Windows\system32. cmd, whoami, systeminfo and certutil do work, so cmd /C is the workhorse for enumeration. Fingerprinting the host confirms a modern build — this matters for privesc later:

Looting the Service Config#
Listing the H2 install directory with cmd /C dir "C:\Program Files (x86)\H2\service" surfaces a wrapper.conf — the Java Service Wrapper config. Reading it with cmd /c type leaks the service account’s plaintext password:

wrapper.ntservice.account=.\tony
wrapper.ntservice.password=BeyondLakeBarber399
Creds tony : BeyondLakeBarber399. They validate over SMB (crackmapexec confirms them), but tony is a low-privileged local user with nothing interesting to reach that way — the real payoff is a stable, interactive shell.
Upgrading to a Real Shell#
With egress locked to open ports, stage a reverse-shell binary and pull it over port 80, then execute it — both through the same alias RCE. Build the payload with a callback on an allowed port:
| |
| |
Catch the callback on the listener — interactive shell as tony.
Privilege Escalation#
SeImpersonatePrivilege - PrintSpoofer#
tony runs with SeImpersonatePrivilege, the classic “potato” primitive. JuicyPotato is the reflex here, but it fails — build 18363 is too recent for the DCOM/BITS trick it relies on.
PrintSpoofer exploits the same privilege via the print spooler’s named pipe and works on current Windows 10 builds. Upload it and impersonate SYSTEM:
PrintSpoofer64.exe -i -c cmd
Proof#
C:\Windows\system32> whoami
nt authority\system

Key Takeaways#
- H2 Console with an unauthenticated database and an old build (≤ 1.4.199) is instant RCE via the
JNIScriptEngine.evalSQL-alias gadget — always fingerprint the version off the console’s info panel. - When a box firewalls all outbound except the listening ports, every download and reverse-shell callback has to reuse an already-open port. Design delivery (certutil over 80, callback on 445) around that constraint instead of fighting it.
- Service-wrapper configs (
wrapper.conf) and similar app files routinely store plaintext service-account credentials — grep them before assuming a shell is a dead end. SeImpersonatePrivilegeis game over, but pick the right potato: JuicyPotato dies on modern Windows 10 builds, PrintSpoofer keeps working.