Unicode — Hackthebox Walkthrough

Kavishka Gihan
7 min readMay 7, 2022


This was a box that was a perfect fit for a medium. Every step wasn’t too hard or easy. Every step had a little bit of thinking to do. I really liked this box for sure.


My nmap found 2 ports.

nmap -p- -sC -sV -A — min-rate=400 — min-parallelism=512 -vv

22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 fd:a0:f7:93:9e:d3:cc:bd:c2:3c:7f:92:35:70:d7:77 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2tldCNzbxK22LE6gPT7x5wliLZL0gLpI9BHO8qz1I7EIL7ygZ0vLk7tZ5JtDFvkdJiMfsbluCGZTpnHuFUY620uPgYEdfYu+RcTH97ldEyio6GKNkhGN+MRi8swttVWFr24sGGU4FEjhQTBG8/aivffqn+w0yksEIQCmXbh/y4xo5MBLeh/n0tMm67e/wrjUg3Y8zDCXXNVpNWzZMtyR8cThY/adlk1F8TatvcHOzG/MC4Xg16B9qjJ1CzJmztbIHpRRe64ow9vdiO6ofyVroiazMkMaE6ltWEl5XC4rKurbD2DySFDUdRr8QT3aAQpNYNPNU2Q9hJYUN1gKZAUCg0mMUmBIbQXyiKiq/b5JGGLPhUkoD6Pl2WjE60D+3ZnNqW8jabBMzUotwi6KdJ5v4HvJiNxNrzjQRpNCJ6rBhIFOUqZQHBsDsFiyOSLXEPpYnNhG502TGELiHOFuK15QMh9CqCZn9PvwIiACTyeet9NdUyHtxHT8gklpnHdNSXY8=
| 256 8b:b6:98:2d:fa:00:e5:e2:9c:8f:af:0f:44:99:03:b1 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNpOPaB/e8Wk54u5TO7EABpkTxMt6Mz10v02RBzyUPJyzpXi1eC8X2VvIpCngtg4Uvbv07ZEm72Tb9S6IoJ/8MI=
| 256 c9:89:27:3e:91:cb:51:27:6f:39:89:36:10:41:df:7c (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID/Us0SuyKOvqEgu/XGps4fVOmhy+iczFKeIrtjRWxUN
80/tcp open http syn-ack nginx 1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: E06EE2ACCCCCD12A0FD09983B44FE9D9
|_http-generator: Hugo 0.83.1
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Hackmedia
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Visiting port 80, was a typical webpage.

I registered as a new user nad logged in. I saw that this web application is using JWT for authentication. Looking at the JWT token, I saw an URI endpoint.

I added this hostname to my /etc/hosts configuration and cURled it.

By looking at this I knew that these n and e (these are values used in the RSA encryption) were extracted values of the public key that the Web application is using to sign the JWT tokens. And since the path to this JSON file was specified in the JWT token itself, I knew I could abuse this and elevate my privileges to be the admin user.

The basic principal here is to trick the server to use your ownkeys” instead of the real one. By this way, we will be able to make your own JWT tokens and authenticate as whoever we want.

So first I created two RSA key pairs with openssl.

openssl genrsa -out keypair.pem 2048
openssl rsa -in keypair.pem -pubout -out publickey.crt
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key

Then I extracted the n and e values out of them with a little bit of python magic.

I got the values of n and e with this. Then I saved the contents of the http://hackmedia.htb/static/jwks.json as jwks.json and changed the values of the n to be what I got.

After I hosted this file on Python HTTP server with python3 -m http.server 80 Then I changed the JWT according ly to get to the admin user. Also I changed the value of the “jku” parameter to point to the server I was hosting the edited jwks.json file.

Finally, I used the public key (publickey.crt) and the private key(pkcs8.key) I generated to verify the token.

It was verified.Then I copied the JWT token, and replaced with the old one. But I refreshed the page, I got an error saying “jku validation failed”. I didn’t see any requests on my webserver as well.

At this point I thought maybe there is some kind of a check to check the validity of “jku” parameter. So I took a step back and tried to find another way to specify the URL.

That’s when I noticed that there was a redirect functionality in this application. In the source of the /, I saw this.

This was perfect for me. With this I was able to verify the “jku” parameter since the URL points to iteself and still make the server get my jwks.json .

So with this I again changed the JWT token.

Then I replaced the JWT and refreshed.

And I was able to get into the Admin dashboard. Clicking around in the page, I found out which seemed like a way to do LFI. But When I tried some basic LFI techniques, it responded me with a 404.

So I confirmed that there is some kind of a WAF it between. With a little frustration, I googled about “Directory traversal bypass techniques”. That’s when I came across this post.

This was talking about using different encodings to bypass filters. Since the name of the box itself was “Unicode”, I found this interesting. So this time I googled about “Directory traversal bypass techniques Unicode”. And I found this hacktricks article which gave exactly what I needed.

Following this, I built a little payload as follows:

..%ef%bc%8f..%ef%bc%8f..%ef%bc%8f..%ef%bc%8f --> ../../../../

With this I was able to include the /etc/passwd file.

I build a simple python script to do this since it’s easier.

import requests
URL = ''
cookie = {"Cookie": "auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImprdSI6Imh0dHA6Ly9oYWNrbWVkaWEuaHRiL3N0YXRpYy8uLi9yZWRpcmVjdC8_dXJsPTEwLjEwLjE1LjIxL2p3a3MuanNvbiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.QwlWV_U-skdJQUdGUP_8-XUoL8MAb388G-DMW2pjsxkeYvSMDebXDI0yAx1_rKNrL0ucDlXOLKAPJe0sOAt4IaeGICvLSkiqF_HuHQdO-nsdOJKVMqwQWQyvQJG-E5Cb2ThDFlrW8gssfXnFP3qPILcwJ5xWBwq-qth08ZbP36n0LS06I8ANvrFx9BOW8WA7nf85pTnd7Be3CVEi_rjogvdVE9Lrhf2agjrpC8xm6kic4FU3g4L2ZLoFin91XsXMSwSmefZ3r2EHqf22CgTTgeuT8DQCPBc0EYV9r8dim5m20nhy2mxjcdukwTsNGwTQAF_NAY6NYHliv5__zb9vJA"}
while True:
f = input("> ")
if f[0] == '/':
f = f[1:]

r = requests.get(URL + f.strip(),headers=cookie)
if "Hmmm..." not in r.text:

With this I enumerated some common config files and I saw something interesting in the /etc/nginx/sites-available/default file.

I included the db.yaml file that this comment said. And I was able to get some credentials.

user: code
password: B3stC0d3r2021@@!

I was able to SSH in with these credentials.


Looking at the sudo permissions of the code user, I saw he can run /usr/bin/treport as root.

Running this was I saw this allowed me to create,read and download reports. The download option seemed interesting actually. When I used the download option, the output I got was kind of familiar.

I realized that this the output of the cURL. So I thought, maybe this program is using cURL to download files. And it was correct.

Actually, there were a lot of ways to exploit this. The way I did is not the intended way though. The intended way was to analyze this binary and find out that we can use { and } and , characters in the IP specification and abuse this with that.

# Method 1

For this you can just use the -K option which let’s you to specify a config file to use in cURL and read the flag that way. This the /root/root.txt is not in the correct format of a config file, it will just spit out the contents.


This is method you can use the -O option in the same way and put a SSH key which is hosted in a server , login as root.


# Method 2

The way I got the flag was by using the File:/// schema. I just specified File:///root/root.txt as the IP to download the file and it downloaded the file. Then I used the program itself to look at it’s contents.

“If you have any questions, make sure to leave them down in the comments, or contact me through social media.”

Email — iamkavigihan@gmail.com
Instagram —

Happy Hacking !!! 😄



Kavishka Gihan

Cyber Security Student | Machine author in @hackthebox | find me on instagram @_kavi.gihan