Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
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
page_table_walk — Gehe manuell x86-64-Seitentabellen in qemu und gdb durch. Zerlege eine virtuelle Adresse, folge cr3 durch alle Ebenen des physischen Speichers und extrahiere eine Flag aus rohen Bytes. | Kitploit
Tools/GitHubGitHub/jazho76/page_table_walk
SpeicherforensikReverse EngineeringDebuggerCTFBinäranalyseLernen & BildungLabs & Praxis
GitHubjazho76/page_table_walk

page_table_walk

Gehe manuell x86-64-Seitentabellen in qemu und gdb durch. Zerlege eine virtuelle Adresse, folge cr3 durch alle Ebenen des physischen Speichers und extrahiere eine Flag aus rohen Bytes.

Repository anzeigen
28112vor 6 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

Capture the Flag im physischen Arbeitsspeicher

Du hast über Paging gelesen. Die Diagramme ergeben Sinn. Vier Ebenen, je 9 Bits, Seitenrahmen, Offset. Klar. Aber dann stößt du auf eine Herausforderung, die verlangt, dass du tatsächlich Seitentabellen durchläufst, und du merkst, dass du es nicht kennst. Du kennst es über. Großer Unterschied.

Was bei mir funktioniert hat: vor QEMU und gdb zu sitzen und den Durchlauf selbst zu machen: jeden Index berechnen, jeden Eintrag aus dem physischen Speicher lesen, jeden Zeiger von Hand verfolgen. Ein Nachmittag davon konnte mehr lehren als Stunden von Vorlesungen.

Dies ist eine Sammlung meiner Notizen aus diesem Prozess. Falls dir noch die konzeptionelle Seite fehlt, schau dir zuerst Zardus' Vortrag über Kernel-Speicherverwaltung an. Das ist die Theorie. Das hier ist das Labor.

Das Ziel: eine virtuelle Adresse nehmen und sie durch den rohen physischen Speicher jagen, bis wir die Daten finden. Keine Kernel-Helfer. Keine Abstraktionen. Nur eine QEMU-VM, gdb und roher physischer Speicher.

Am Ende wird Paging nicht etwas sein, worüber du gelesen hast, sondern etwas, das du kennst, weil du es von Hand gemacht hast.


Einrichtung des Labors

Ein vorgebauter Kernel und initramfs sind enthalten. Ich habe das unter Fedora ausgeführt, aber jedes Betriebssystem, das QEMU und gdb ausführt, sollte funktionieren. Installiere sie mit deinem Paketmanager:```

Ubuntu/Debian

sudo apt install qemu-system-x86 gdb

Fedora/RHEL

sudo dnf install qemu-system-x86 gdb

macOS

brew install qemu gdb

### Die Challenge-Binärdatei

Das Ziel ist ein triviales C-Programm, das eine Flag im Speicher speichert und deren virtuelle Adresse ausgibt:```c
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    char secret[] = "FLAG{p4g3_t4bl3_w4lk3r}";

    printf("secret @ %p\n", (void *)secret);
    printf("pid = %d\n", getpid());
    printf("Spinning. Walk the page tables to find the flag.\n");

    while (1)
    {
    }
}

Die aktive Schleife ist beabsichtigt. Ursprünglich habe ich pause() verwendet, aber das versetzt den Prozess in einem Syscall in den Schlafzustand: Wenn gdb die VM anhält, führt die CPU wahrscheinlich die Leerlaufaufgabe mit einer anderen CR3 aus. Eine Drehschleife hält den Prozess auf der CPU, sodass das Anhalten garantiert, dass Sie sich in seinem Kontext mit den richtigen Seitentabellen befinden.

Ein vorgebautes Initramfs mit dieser Binärdatei ist bereits in initramfs.cpio.gz enthalten. Wenn Sie es neu erstellen müssen (nur Linux, erfordert busybox und glibc-static), führen Sie make in diesem Verzeichnis aus.

QEMU starten```

./start.sh

Das Skript bootet den gebündelten Kernel und das Initramfs unter QEMU mit `-s` (GDB-Server auf `localhost:1234`) und `nokaslr`, sodass die Kernel-Adressen zwischen den Läufen fest bleiben.

Die VM bootet sofort und die Challenge-Binärdatei wird ausgeführt. Sie sehen die virtuelle Adresse der Flagge auf der Konsole ausgegeben.```
secret @ 0x7ffe08985c90
pid = 1
Spinning. Walk the page tables to find the flag.

Notieren Sie diese virtuelle Adresse. Das ist Ihr Ziel.

QEMU terminal after boot, showing the challenge binary's output with the flag address and PID

Die standardmäßige QEMU-Escape-Taste ist Ctrl-a, aber das kollidiert mit meinem tmux-Präfix, daher verwendet das Skript -echr 0x11, um sie auf Ctrl-q umzubelegen. Wenn Sie Ctrl-q für etwas anderes verwenden, ändern Sie den Hexadezimalwert in start.sh entsprechend Ihrer Einrichtung.

gdb anhängen```

gdb -ex "target remote :1234"

![gdb terminal after attaching, halted and ready](https://assets.kitploit.com/production/public/readmes/12435/9fb13e082596378677ea0d42cf7da3a86706df44127860fc724b2bad0a9f138c.png)

---

## Dekomposition der virtuellen Adresse

Sie haben eine virtuelle Adresse. Aber wo sind die Daten, _wirklich_?

Virtuelle Adressen sind die höfliche Fiktion des Betriebssystems. Jeder Prozess
glaubt, er habe seinen eigenen privaten Speicher, der bei Null beginnt. In Wirklichkeit
befinden sich die Daten an einer völlig anderen, nicht zusammenhängenden Stelle im physischen RAM. Die Seitentabelle ist
die Karte zwischen beiden: eine Baumstruktur, die die CPU bei jedem
Speicherzugriff durchläuft (oder aus ihrem TLB-Cache abruft).

Machen wir also das Gleiche wie die CPU. Manuell. Um diese Adresse zu übersetzen, müssen wir
sie in die Indizes zerlegen, die die CPU auf jeder Ebene verwendet.

Eine x86-64 virtuelle Adresse ist 48 Bit breit. Diese 48 Bit sind in fünf
Felder aufgeteilt:```
 63    48 47    39 38    30 29    21 20    12 11       0
┌────────┬────────┬────────┬────────┬────────┬──────────┐
│ sign   │  PGD   │  PUD   │  PMD   │   PT   │  Offset  │
│ extend │ index  │ index  │ index  │ index  │          │
│ (16b)  │ (9b)   │ (9b)   │ (9b)   │ (9b)   │  (12b)   │
└────────┴────────┴────────┴────────┴────────┴──────────┘

Jeder 9-Bit-Index wählt einen von 512 Einträgen in einer Seitentabelle auf dieser Ebene aus. Der 12-Bit-Offset wählt ein Byte innerhalb der finalen 4 KB (0x1000) Seite aus.

Um die Indizes zu extrahieren, verschieben und maskieren:``` PGD index = (VA >> 39) & 0x1FF PUD index = (VA >> 30) & 0x1FF PMD index = (VA >> 21) & 0x1FF PT index = (VA >> 12) & 0x1FF Offset = VA & 0xFFF

In gdb können Sie diese direkt berechnen:```
(gdb) p/x (0x7ffe08985c90 >> 39) & 0x1ff
$1 = 0xff
(gdb) p/x (0x7ffe08985c90 >> 30) & 0x1ff
$2 = 0x1f8
(gdb) p/x (0x7ffe08985c90 >> 21) & 0x1ff
$3 = 0x44
(gdb) p/x (0x7ffe08985c90 >> 12) & 0x1ff
$4 = 0x185
(gdb) p/x 0x7ffe08985c90 & 0xfff
$5 = 0xc90

Notieren Sie diese. Sie werden jede auf der entsprechenden Ebene verwenden.

Ihre Werte werden abweichen. Die Adresse 0x7ffe08985c90 ist nur ein Beispiel. Verwenden Sie die Adresse, die Ihre Challenge-Binary ausgegeben hat.

Eine Anmerkung zum 5-Level-Paging. Aktuelle CPUs und Kernel unterstützen LA57, was eine fünfte Ebene (PML5) oberhalb des PGD hinzufügt und virtuelle Adressen auf 57 Bit erweitert. Der Durchlauf folgt dem gleichen Muster: ein weiterer 9-Bit-Index, eine weitere Tabellensuche. Die meisten Systeme verwenden noch 4-Level-Paging. Sie können dies überprüfen: cat /proc/cpuinfo | grep la57. Alles in diesem Artikel geht von 4-Level-Paging aus.


Finden von CR3: die Wurzel des Baums

Jeder Baum hat eine Wurzel. Für Seitentabellen befindet sich diese Wurzel im CR3-Register: Es enthält die physische Adresse der obersten Tabelle, des PGD. Jeder Prozess erhält seinen eigenen CR3-Wert, den der Kernel bei einem Kontextwechsel austauscht.

Dies ist unser Einstiegspunkt in den Durchlauf. Lesen Sie ihn aus gdb aus:``` (gdb) info registers cr3 cr3 0x66c7000 [ PDBR=26311 PCID=0 ]

Die Seiten-Tabellen-Basis ist `0x66c7000`. Die unteren 12 Bits sind PCID/Flags (hier Null),
die Basisadresse ist also der Wert wie er ist.

Hier beginnt der Walk.

---

## Der Walk

Hier ist der Trick: Jede Ebene
folgt demselben Muster. Die Flags variieren geringfügig zwischen den Ebenen, aber der
Prozess nicht. Das Muster:

1. **Berechne die Eintragsadresse:** `base + index * 8` (jeder Eintrag ist 8 Bytes)
2. **Lese den Eintrag aus dem physischen Speicher** mit dem QEMU-Monitor-Befehl `xp`
3. **Dekodiere die Flags** (siehe Referenz unten). Wenn Present (Bit 0) 0 ist, ist die Seite nicht gemappt und der Walk stoppt
4. **Extrahiere die Basis der nächsten Tabelle:** maskiere den Eintrag mit `& 0x000FFFFFFFFFF000`
5. **Gehe zur nächsten Ebene**
Tool herunterladen