In this post, I would like to share a walkthrough of the Bookworm Machine from Hack the Box.


This room will be considered an Insane machine on Hack the Box

What will you gain from the Bookworm machine?


For the user flag, you will need a sophisticated exploit chain by leveraging cross-site scripting, insecure upload, and insecure direct object reference vulnerabilities. This orchestrated approach allows for the identification of an HTTP endpoint with file download capabilities. Within this endpoint, a directory traversal attack is exploited when multiple files are requested, enabling the retrieval of arbitrary files in the resulting Zip archive. This exploitation is then utilized to extract database credentials, which conveniently double as SSH credentials on the system. The subsequent user operates a development web server responsible for managing ebook format conversions. This functionality is manipulated by employing symlinks to achieve arbitrary write access. Subsequently, an SSH public key is written, facilitating unauthorized access


As for the root flag, you need an SQL injection vulnerability within a script responsible for label creation to be exploited. This enables PostScript injection, providing the capability to read and write files at the root level, completing the privilege escalation chain.

For those who want to learan or improve CyberSecurity skills especially Red Teaming and Blue Team, You can use the link https://affiliate.hackthebox.com/gnfp67dzy7p0 to support me

Academy link can be found https://affiliate.hackthebox.com/wanmohdariffwanmohdrosdi6259vv

Information Gathering on Bookworm Machine


Once we have started the VPN connection which requires a download from Hackthebox, we can start the information gathering on the machine by executing the command nmap -sC -sV -p- <IP Address> -PN

┌─[darknite@parrot]─[~/Document/htb/bookworm]
└──╼ nmap -sC -sV 10.10.11.215 -oA intial 
# Nmap 7.92 scan initiated Mon May 29 04:16:35 2023 as: nmap -sC -sV -oA initial 10.10.11.215
Nmap scan report for 10.10.11.215
Host is up (0.17s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT     STATE    SERVICE     VERSION
22/tcp   open     ssh         OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 81:1d:22:35:dd:21:15:64:4a:1f:dc:5c:9c:66:e5:e2 (RSA)
|   256 01:f9:0d:3c:22:1d:94:83:06:a4:96:7a:01:1c:9e:a1 (ECDSA)
|_  256 64:7d:17:17:91:79:f6:d7:c4:87:74:f8:a2:16:f7:cf (ED25519)
80/tcp   open     http        nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://bookworm.htb
|_http-server-header: nginx/1.18.0 (Ubuntu)
2710/tcp filtered sso-service
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon May 29 04:16:58 2023 -- 1 IP address (1 host up) scanned in 23.50 seconds

Let’s access the website interface


However, the website interface looks very normal, and I noticed that there are login functions that we can take advantage of.


We are required to register a new account on the website.


At last, we managed to access the dashboard by using the credentials that we created earlier.


Therefore, let’s try to buy a new book by clicking the “Add to Basket” button.


The payload of adding the book into payment will look something like the above.


It will look something like the above.


As a result, we should upload and update the avatar on my profile picture.


The request and response on the burpsuite will look something like as above.


Let’s upload some random picture


The payload on burpsuite as above


From the cookie token, we managed to retrieve an “id” for the profile. However, the ID will be different when creating a new account


Let’s start our Python server.


Therefore, let’s execute our XSS attack on the edit column


Boom! The XSS attack managed to give us a response on the Python server

const { sequelize, User, Book, BasketEntry, Order, OrderLine } = require("./database");

When trying to analyze the index.js source code, we found a path that might provide us with some useful information.

const sequelize = new Sequelize(
  process.env.NODE_ENV === "production"
    ? {
        dialect: "mariadb",
        dialectOptions: {
          host: "127.0.0.1",
          user: "bookworm",
          database: "bookworm",
          password: "FrankTh3JobGiver",
        },
          logging: false,
      }
    : "sqlite::memory::"
);

Inside the database file, we managed to find a password that can be used to access machine as frank ( i just guess from the password structure)


We can read the user flag by typing the “cat user.txt” command.

Escalate to Root Privileges Access


There are a few localhost ports that we can investigate further.


Therefore, let’s do some port-forwarding with the port 3001


The website interface will look something like the above

SSH to Neil Access on the machine


We need to create a pdf file so that we can upload the malicious file into the application


Aside from that, we also need to create a ssh key on our attacker machine


Therefore, we need to redirect the file to the SSH path


We can change the content on the file which we can insert our SSH public key into the application


Finally, we managed to access the machine as Neil


The only SUID binary that we can find is genlabel as shown in the screenshot above.

neil@bookworm:~$ cat /usr/local/bin/genlabel
#!/usr/bin/env python3

import mysql.connector
import sys
import tempfile
import os
import subprocess

with open("/usr/local/labelgeneration/dbcreds.txt", "r") as cred_file:
    db_password = cred_file.read().strip()

cnx = mysql.connector.connect(user='bookworm', password=db_password,
                              host='127.0.0.1',
                              database='bookworm')

if len(sys.argv) != 2:
    print("Usage: genlabel [orderId]")
    exit()

try:
    cursor = cnx.cursor()
    query = "SELECT name, addressLine1, addressLine2, town, postcode, Orders.id as orderId, Users.id as userId FROM Orders LEFT JOIN Users On Orders.userId = Users.id WHERE Orders.id = %s" % sys.argv[1]

    cursor.execute(query)

    temp_dir = tempfile.mkdtemp("printgen")
    postscript_output = os.path.join(temp_dir, "output.ps")
    # Temporary until our virtual printer gets fixed
    pdf_output = os.path.join(temp_dir, "output.pdf")

    with open("/usr/local/labelgeneration/template.ps", "r") as postscript_file:
        file_content = postscript_file.read()

    generated_ps = ""

    print("Fetching order...")
    for (name, address_line_1, address_line_2, town, postcode, order_id, user_id) in cursor:
        file_content = file_content.replace("NAME", name) \
                        .replace("ADDRESSLINE1", address_line_1) \
                        .replace("ADDRESSLINE2", address_line_2) \
                        .replace("TOWN", town) \
                        .replace("POSTCODE", postcode) \
                        .replace("ORDER_ID", str(order_id)) \
                        .replace("USER_ID", str(user_id))

    print("Generating PostScript file...")
    with open(postscript_output, "w") as postscript_file:
        postscript_file.write(file_content)

    print("Generating PDF (until the printer gets fixed...)")
    output = subprocess.check_output(["ps2pdf", "-dNOSAFER", "-sPAPERSIZE=a4", postscript_output, pdf_output])
    if output != b"":
        print("Failed to convert to PDF")
        print(output.decode())

    print("Documents available in", temp_dir)
    os.chmod(postscript_output, 0o644)
    os.chmod(pdf_output, 0o644)
    os.chmod(temp_dir, 0o755)
    # Currently waiting for third party to enable HTTP requests for our on-prem printer
    # response = requests.post("http://printer.bookworm-internal.htb", files={"file": open(postscript_output)})

except Exception as e:
    print("Something went wrong!")
    print(e)

cnx.close()
neil@bookworm:~$ 

The source code of the script can be seen in the text above.


From my understanding, we can play with the SQL command which we can outfile our SSH public key into the machine


At last, we can access the machine as root

Metasploit method on the bookworm machine


Firstly, we can open the msfconsole as shown below


In this activity, we will be using the exploit on the chrome_debugger to gather the payload


We are required to fill in the information above in order for the payload to work


As a result, we will insert as shown above.


The remote port is always changing all the time so we need to change accordingly.


We managed to get a root flag by using this method too.