Book just retired today. I had lots of fun solving it and I really enjoyed exploiting the lesser-known vulnerabilities in its web application. The machine’s IP address is ‘10.10.10.176’ and I added it to ‘/etc/hosts’ as ‘book.htb’. Without further ado, let’s jump right in!
Scanning & no vulnerability?!
A basic nmap scan was enough to get me started:
Port 80 was open, so I opened it in a browser and got the following page:
After I registered an account, I signed in and started exploring the website:
There was a lot of functionality to test, and I spent a huge amount of time trying different attacks that didn’t work.
Getting Admin
At some point I ran dirb on the site, and the only interesting URI it found was ‘/admin’:
From the ‘contact’ page, I knew the email of the admin:
However, there was no way of bypassing the password check. After some time, I found something interesting in the normal ‘sign up’ form:
Every time a user signed up, a javascript function called ‘validateForm’ was called. I searched it in the source code of the page and found the following snippet:
I presumed there was only one database that contained the users & the admins of the platform, the only difference between the two probably being a flag that stores whether the user is an admin or not. Knowing there is a length limit, I remembered this task from FacebookCTF 2019.
The basic idea is that MySQL doesn’t make a distinction between ‘admin’ and ‘admin ‘. Combined with the length limit, this is known as an SQL truncation attack. Since I wrote about it here, you can probably guess this is the way forward. I entered the following input on the ‘Sign Up’ form to reset admin’s password:
Password: ‘yakuhito’ (the string you input here will become admin’s password)
I also used Inspect Element to remove the ‘type=”email”’ part from the email field so the form would accept my example data:
I then browsed to ‘/admin’ and logged in using the previously-set password:
XSS in .pdf ?!
Fortunately, there was less functionality to test. The first thing that caught my eye was the option to export Users/Collections as pdf:
Out of curiosity, I exported the Collections as pdf and got the following page:
That table looked oddly familiar. I supposed it was an HTML ‘table’ element, so I tested my hypothesis by signing in as an user and uploading another collection. The new collection’s title was the word ‘text’ surrounded by h1 tags. After uploading it and re-exporting the collections to pdf, I got the following output:
HTML injection inside a pdf? That sounded pretty strange. I went further and tested for an XSS using the following payload:
That payload produced the following output:
This attack was new to me, so I searched ‘pdf xss’ on google and found this article which inspired me to try and read from a local file. I used the following payload to achieve this goal:
The payload above produced the following document:
I also saw that there was a user named ‘reader’ on the machine, so I tried to fetch his id_rsa file. The problem was that, while the file existed, some lines would be longer than the pdf document and all the extra characters would get cut. To solve this problem, I encoded the file in base64 and added a ‘br’ tag every 42 characters. This allowed me to exfiltrate the file without losing any characters on the way. The final payload looked like this (I prettified it so it would be easier to read):
I also need to mention that the ‘chunk’ function was stolen from a StackOverflow thread. After uploading a book with the above payload as a title, the pdf file contained the base64-encoded id_rsa file:
I the used the private key to ssh into reader:
The user proof starts with ‘51’ 😉
Exploiting logrotate
After submitting the user proof, I started enumerating the machine. I found a directory called ‘backups’ in the user’s home directory:
I noticed (by dumb luck) that wenever I output something into access.log, a program clears it and puts the output into access.log.1:
After searching google extensively, I found this StackOverflow thread that mentions an utility called logrotate. The binary was installed on the system (by default), so I searched for an exploit and found this repository on Github. I followed the instructions from the README.md file:
I could have gotten a reverse shell, however, I chose to copy root’s SSH key so I would get a more stable shell (the connect-back shell would time out very shortly after a connection was made):
In order to rotate the logs, I opened another ssh session and echoed data into the file: