GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum müssen Systemaufruftabellen in Linux geändert werden?

Sie können überprüfen, ob sie schreibgeschützt sind, indem Sie die Kernelsymbole nachschlagen. Das "R" bedeutet schreibgeschützt.

$ grep sys_call_table /proc/kallsyms
0000000000000000 R sys_call_table
0000000000000000 R ia32_sys_call_table
0000000000000000 R x32_sys_call_table

Also sind sie schreibgeschützt und seit Kernel 2.6.16. Ein Kernel-Rootkit hat jedoch die Fähigkeit, sie wieder beschreibbar zu machen. Alles, was es tun muss, ist, eine Funktion wie diese im Kernel-Modus (direkt oder über ausreichend flexible ROP-Gadgets, von denen es viele gibt) mit jeder Adresse als Argument auszuführen:

static void set_addr_rw(const unsigned long addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);

    if (pte->pte &~ _PAGE_RW)
        pte->pte |= _PAGE_RW;

    local_flush_tlb();
}

Dies ändert die Berechtigungen der Syscall-Tabelle und macht es möglich, sie zu bearbeiten. Falls dies aus welchen Gründen auch immer nicht funktioniert, kann der Schreibschutz im Kernel global mit folgendem ASM deaktiviert werden:

cli
mov %cr0, %eax
and $~0x10000, %eax
mov %eax, %cr0
sti

Dadurch werden Interrupts deaktiviert, das WP-Bit (Write-Protect) in CR0 deaktiviert und Interrupts wieder aktiviert. Durch die Verwendung von Assembler funktioniert dies trotz write_cr0(read_cr0() & ~0x10000) Versagen aufgrund der vordefinierten Funktion zum Schreiben auf CR0, die jetzt sensible Bits fixiert. Stellen Sie jedoch sicher, dass Sie WP danach wieder aktivieren!

Warum ist es also als schreibgeschützt markiert, wenn es so einfach zu deaktivieren ist? Ein Grund dafür sind Sicherheitslücken, die es ermöglichen, Kernel-Speicher zu modifizieren, aber nicht unbedingt Code direkt auszuführen. Indem kritische Bereiche des Kernels als schreibgeschützt markiert werden, wird es schwieriger, sie auszunutzen, ohne einen zusätzlichen zu finden Schwachstelle, um die Seiten als beschreibbar zu markieren (oder den Schreibschutz ganz zu deaktivieren). Nun, das bietet keine sehr starke Sicherheit, also ist der Hauptgrund, dass es als schreibgeschützt markiert ist, es einfacher zu machen, es versehentlich zu stoppen überschreibt, um einen katastrophalen und nicht behebbaren Systemabsturz zu verursachen.

* Das angegebene Beispiel gilt für einen x86_64-Prozessor. Die erste Tabelle gilt für Systemaufrufe im nativen 64-Bit-Modus (x64). Der zweite ist für Systemaufrufe im 32-Bit-Modus (IA32). Der dritte ist für die selten verwendete x32-Systemaufruf-ABI, die es Programmen ermöglicht, alle Funktionen des 64-Bit-Modus (z. B. SSE anstelle von x87 für Gleitkommaoperationen) zu verwenden, während 32-Bit-Zeiger und -Werte verwendet werden.

† ​​Die interne API des Kernels ändert sich ständig, daher funktioniert genau diese Funktion möglicherweise nicht auf älteren oder neueren Kerneln. Globales Deaktivieren von CR0.WP in ASM funktioniert jedoch garantiert auf allen x86-Systemen, unabhängig von der Kernel-Version.


Wie von forest angemerkt, erlaubt modernes Linux dies nicht, aber es ist einfach zu überschreiben.

Historisch gesehen war es jedoch nützlich (und vielleicht immer noch) aus Sicherheitsgründen:Hot-Patching gegen Schwachstellen. Damals in den 1990er und frühen 2000er Jahren, als eine neue Schwachstelle für einen Systemaufruf bekannt gegeben wurde, brauchte ich nicht unbedingt (ptrace war damals sehr verbreitet), würde ich ein Kernelmodul schreiben, um die Funktionsadresse in der Syscall-Tabelle mit der Adresse einer Funktion zu überschreiben, die gerade return -ENOSYS; ausgeführt hat . Dadurch wurde die Angriffsfläche eliminiert, bis ein aktualisierter Kernel verfügbar war. Für einige dubiose Systemaufrufe, die ich nicht brauchte und die wiederholt Schwachstellen aufwiesen, habe ich dies nur präventiv für sie getan und das Modul die ganze Zeit aktiviert gelassen.


Linux
  1. Linux – Warum ist kein Rootfs-Dateisystem auf dem System vorhanden?

  2. Linux – Warum kann der Kernel Init nicht ausführen?

  3. Warum gibt es keine DirectX-API für Linux?

  4. Warum brauchen wir einen Bootloader in einem eingebetteten Gerät?

  5. Warum brauchen wir die .so.1-Datei unter Linux?

Ist Linux ein Betriebssystem oder ein Kernel?

Linux-Systemaufruftabelle oder Cheatsheet für Assembly

Schnellster Linux-Systemaufruf

Wie übergebe ich Parameter an den Linux-Systemaufruf?

Wie entferne ich ein Linux-System?

Warum unterscheiden sich Linux-Systemrufnummern in x86 und x86_64?