Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
amazon-mustang-hack — Amazon Fire 7 (Fire OS 7.3.3.1) पर Mali kbase JIT use-after-free CVE-2022-38181 के माध्यम से अस्थायी root प्राप्त करने वाला Kernel exploit शोध, जिसमें modprobe_path overwrite chain शामिल है। | Kitploit
उपकरण/GitHubGitHub/artur9010/amazon-mustang-hack
एंड्रॉइड सुरक्षाविशेषाधिकार वृद्धिभेद्यता विश्लेषणशोषणरिवर्स इंजीनियरिंगमोबाइल सुरक्षापेपर और शोधपेलोड डेवलपमेंटबाइनरी शोषण

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें
GitHubartur9010/amazon-mustang-hack

amazon-mustang-hack

Amazon Fire 7 (Fire OS 7.3.3.1) पर Mali kbase JIT use-after-free CVE-2022-38181 के माध्यम से अस्थायी root प्राप्त करने वाला Kernel exploit शोध, जिसमें modprobe_path overwrite chain शामिल है।

रिपॉजिटरी देखेंवेबसाइट
14घं 3मि पहलेअभी तक समीक्षित नहीं

AI-सहायित परियोजना। यह शोध, एक्सप्लॉइट विकास, और दस्तावेज़ीकरण AI सहायता से मॉडल GLM-5.3 और DeepSeek V4.1 Flash का उपयोग करके तैयार किए गए थे।

amazon-mustang-hack

अंतिम फर्मवेयर पर Amazon Fire 7 9th gen (mustang, MT8163, Mali-T720) के लिए रूट एक्सप्लॉइट शोध — Fire OS 7.3.3.1, PS7331.4463N, kernel 4.9.117 (निर्मित 2025-05-03, SPL 2024-08-01)।

लक्ष्य: LineageOS। इस यूनिट पर बूटलोडर पथ समाप्त है (पैच किया गया bootrom — केवल preloader, CMD शॉर्ट के माध्यम से), इसलिए एकमात्र शेष मार्ग सॉफ़्टवेयर कर्नेल एक्सप्लॉइट है।

त्वरित शुरुआत```

one-shot: build, run the exploit (retries across the probabilistic reclaim),

install a setuid-root su and verify it as an unprivileged user

nix-shell -p android-tools --run './run.sh' # add -p zig too if no zig

root@kitploit:~
सफलता पर:```
/data/metrics/su id     # run a command as root
/data/metrics/su        # interactive root shell

The reclaim लगभग 3 में से 1 boot जीतता है और हारने पर tablet panic/reboot हो जाता है; run.sh बस reboot का इंतज़ार करता है और फिर से try करता है। SELinux को exploit के हिस्से के रूप में जबरन Permissive किया जाता है, इसलिए root runtime-only है — reboot करने पर stock वापस आ जाता है और आप run.sh फिर से चलाते हैं।

Prebuilt st3 और su (armv7 static) commit किए गए हैं, इसलिए चलाने के लिए किसी toolchain की ज़रूरत नहीं है। ./run.sh --build उन्हें poc/*.c से rebuild करता है अगर आपके पास zig है।

इसके नीचे जो कुछ भी है वह model द्वारा किए गए काम का log है, नीचे कोई hooman input नहीं है।

PRIMARY TARGET (session 5 से): kbase CVE-2022-38181 — stage 2 PROVEN

GhostLock (नीचे) parked है: MTK का BUG_ON rtmutex variant + shell से zero kernel-address disclosure = इस build पर architectural dead end (sessions 2-4)। kbase JIT UAF का फिर से निदान किया गया (destroy-worker "unconditional panic" वह JIT_FREE deref था, log adbd death mid-panic में खो गया) और stage 2 अब oracle-proven है — SESSION 5 section देखें।

PARKED: GhostLock, CVE-2026-43499

rtmutex remove_waiter() futex-PI stack-UAF (NebuSec disclosure 2026-07, fix 3bfdc63936dd 2026-04 में landed)। Vulnerable range 2.6.39–7.1 → हमारा 4.9.117 (May 2025) affected है।

हमारे exact build पर verified:

  • CONFIG_FUTEX=y, rtmutex compiled in, bug verbatim मौजूद: rtmutex.c:1108-1111 current->pi_lock/current->pi_blocked_on का उपयोग करता है (होना चाहिए waiter->task); buggy call site rtmutex.c:1723 (rt_mutex_start_proxy_lock error path)
  • Trigger surface = pure futex syscalls (WAIT_REQUEUE_PI/CMP_REQUEUE_PI), कोई device node नहीं, कुछ भी SELinux-gated नहीं — kbase path की fatal obstacles यहाँ मौजूद नहीं हैं
  • Consumer: sched_setattr → __sched_setscheduler → rt_mutex_adjust_pi(p) at sched/core.c:4706 — stale को deref करता है ✓

TODO (port plan)

  1. Trigger लिखें (3-thread requeue-PI deadlock, cores 0-3) — exp32/main.c का port
  2. Stamp geometry: rt_waiter frame offset vs do_sys_select fd_set area — हमारे vmlinux को disassemble करें (do_sys_select stack_fds vs futex_wait_requeue_pi frame), STAMP_NFDS/STAMP_WAITER_OFF को tunables के रूप में expose करें
  3. arm32 48-byte waiter के लिए fake-writer encoding → "write V to ADDR" slots
  4. 2 slots → modprobe_path, fire, root script
  5. Fallbacks अगर select-stamp तक नहीं पहुँच सकते: setsockopt(MCAST_JOIN_SOURCE_GROUP) stamp

Status

  • Bootrom (amonet hardware method) — इस unit पर patched, dead end
  • mtk-su (CVE-2020-0069) — patched, Failed critical init step 3
  • Attack surface survey — /dev/mali0 world-RW + SELinux gpu_device, kbase r26p0-01rel0
  • CVE-2022-38181 exact-build source में confirmed; stage-1 trigger काम करता है
  • CVE-2026-43499 (GhostLock) verified लेकिन blocked: MTK BUG_ON rtmutex variant + shell से कोई kernel-address disclosure नहीं (sessions 2-4)
  • CVE-2022-38181 stage 2 PROVEN (session 5): destroy-worker panic एक misdiagnosis था; UAF redirect sprayed region पर, oracle-verified
  • Stage 1: trigger + stamp + consumer (crash = chain live)
  • Stage 2 (kbase path): UAF redirect sprayed region पर — PROVEN session 5
  • Stage 2b: raw-byte slot control (xattr stamp churn) → unlink write
  • Stage 3: arbitrary kernel function call → ROOT (session 10) — nf LOCAL_OUT hook hijack, 2-packet chain: को zero करें, fake entry को में rewrite करें। , SELinux Permissive.

Key findings

Device / firmware

  • Model KFMUWI, device mustang, Fire OS 7.3.3.1 PS7331.4463N/0031575863040
  • Kernel 4.9.117-g08fe75b-dirty, built Sat May 3 01:25:15 UTC 2025 (Linaro GCC 6.3-2017.05)
  • Amazon ने May 2025 में चुपचाप 7.3.3.1 फिर से जारी किया (नया incremental, वही version string)
  • Bootrom post-2020 revision: eMMC CMD पर short-to-GND देता है केवल preloader (patched)
  • /dev/kb, /dev/dkb (Amazon kernel-backup partitions) root:drmrpc 0660 — locked

CVE-2022-38181 क्यों लागू होता है

  • Driver: mali_kbase r26p0-01rel0 (Midgard, Mali-T720), NVD affected range r4p0–r31p0 के अंदर
  • Amazon के May 2025 rebuild ने 2018 का bug verbatim ship किया — कोई backport नहीं
  • Exact vulnerable code, source-verified:
    • mali_kbase_mem.c:2721 kbase_jit_destroy_worker region free करता है, कभी kctx->jit_alloc[id] clear नहीं करता
    • mali_kbase_softjobs.c:1270 kbase_jit_free_finish stale jit_alloc[ids[j]] को deref करता है
    • mali_kbase_mem.c:3138 kbase_jit_backing_lost → destroy path (reclaim के दौरान fire होता है)

Exploitation climate (सभी live config dump + OTA vmlinux से verified)

  • armv7 32-bit, non-LPAE → no KASLR (kernel fixed 0xc0008000 VA / 0x40080000 PA पर)
  • No ARM_SW_DOMAIN_PAN → ret2usr viable; CONFIG_PANIC_ON_OOPS=y (failed attempts = reboot)
  • No SLAB_FREELIST_RANDOM/HARDENED, no CONFIG_USER_NS/USERFAULTFD/NF_TABLES
  • CONFIG_MODULES=y, no STATIC_USERMODEHELPER → modprobe_path overwrite = root
  • 1 GB RAM → direct reclaim (eviction के लिए ज़रूरी) trivially reachable; pressure >~1 GB kernel को अपने आप panic कर देता है (unrelated lowmem/OOM bug) — spray ≤ 900 MB रखें, ~700 MB उपयोग करें

PoC development के दौरान मिली UAPI quirks (r26p0, _IOC_TYPE 0x80)

  • MEM_ALLOC union 32 bytes है (in में 4 × u64 incl. extent)
  • flags में BASE_MEM_PROT_GPU_RD|WR (bits 2|3) शामिल होना चाहिए, legacy R|W नहीं
  • किसी भी alloc से पहले tracking-page mmap ज़रूरी: mmap(fd, offset=3<<12, PROT_NONE)
  • JOB_SUBMIT stride sizeof(base_jd_atom_v2) = 48 के बराबर होना चाहिए (base_jd_prio/base_jd_dep_type u8 typedefs हैं)
  • JIT: MEM_JIT_INIT (nr 14, v2 struct), alloc/free soft jobs हैं JOB_SUBMIT के ज़रिए (BASE_JD_REQ_SOFT_JIT_ALLOC=0x209, ...FREE=0x20a; =user ptr, =count)

Stage-1 differential (proof कि bug fire होता है)

Panic eviction के दौरान ही होता है (evictable_reclaim_scan_objects → backing_lost → destroy worker) — dangling refs (jit_alloc[], evict list) पर चला जाता है इससे पहले कि हम कभी JIT_FREE submit करें। Stage 2 को race जीतनी होगी: freed kbase_va_region को अपने MEM_ALLOC spray से reallocate करें जबकि pressure अभी भी चल रहा हो।

Artifacts

  • poc/stage2.c — stage-2 exploit (modes: step/uaf/spstep/spfree/spray/keys) — spray 700 = पूरा oracle run; survive करता है और pause करता है (clean up के लिए kill करें)
  • poc/mustang_jit_uaf.c — stage-1 PoC (modes: jit N / control N / pressure N)
  • poc/build.sh — zig cross-build (static musl armv7)
  • kernel/vmlinux — exact OTA build से recovered symbols (vmlinux-to-elf)

Build & run```

nix-shell -p zig --run 'zig cc -target arm-linux-musleabihf -static -O2 -o juaf poc/mustang_jit_uaf.c' adb push juaf /data/local/tmp/juaf && adb shell chmod 755 /data/local/tmp/juaf adb shell /data/local/tmp/juaf jit 700 # full trigger (~reboots device) adb shell /data/local/tmp/juaf control 700 # no-JIT control adb shell /data/local/tmp/juaf pressure 700 # raw memory-pressure control

root@kitploit:~
## संदर्भ

- GHSL-2022-054 सलाह: https://securitylab.github.com/advisories/GHSL-2022-054_Arm_Mali/
- Mo का Pixel 6 एक्सप्लॉइट राइटअप: https://github.blog/2023-01-23-pwning-the-all-google-phone-with-a-non-google-bug/
- Fire HD 10 (trona) मिसाल, वही बग परिवार: ericpardee.github.io/fire-hd-ownership
- Amazon OSS पोर्टल: amazon.com gp/help/customer/display.html nodeId=200203720
- XDA अनलॉक थ्रेड (इस hw rev के लिए मृत): xdaforums.com/t/fire-7-2019-mustang-unbrick-downgrade-unlock-root.3944365/


## सत्र 3 परिशिष्ट (गहन syscall-stamp सर्वेक्षण)

मापी गई कॉपी-स्रोत गहराइयाँ (निरपेक्ष बनाम syscall-entry sp0; waiter -0x1d8..-0x1a8 तक फैला):
- sendto sockaddr @ -0xc4 | process_vm iov @ -0x104 | recvmsg iov @ -0x11c
- sendmsg iov @ -0x12c | recvmmsg iov @ -0x154 | select fds @ -0x174
- pselect6 fds @ -0x19c | **sendmmsg iov @ -0x1bc (सर्वोत्तम — waiter+0x00 से 0x1c कम)**
- poll entries @ -0x3e0 (पूरी तरह नीचे; गलत तरफ)

इस सत्र में बाहर किए गए:
- io_submit श्रृंखला बहुत उथली (~-0x130) | semtimedop: CONFIG_SYSVIPC=n (स्टब)
- configfs माउंटेड लेकिन शून्य सबसिस्टम पंजीकृत (कोई mkdir लक्ष्य नहीं)
- /sys/kernel/debug, /config: shell के लिए SELinux-अस्वीकृत
- /proc/sys/kernel: getdents काम करता है (29 प्रविष्टियाँ सूचीबद्ध), केवल pid_max खोलने योग्य;
  kptr_restrict/hotplug/hostname/domainname पढ़ना सभी अस्वीकृत
- लिखने का मान हमेशा waiter+0 होता है (kernel stack addr, executable, shellcode
  +0x1c पर): rb_link_node *link = node, insert_color parent-color लिखता है — बिना
  tree-field stamping के कोई नियंत्रित-मान वेरिएंट संभव नहीं (अंतराल -0x1d8..-0x1bc)
- Double-deref dispatch फ़ील्ड पढ़ते हैं *(waiter+0)=1, *(waiter+4/+8)=0 — BLX 1/0
  (nf_hooks, net_families, inet[6]_protos, seq_file->op सभी मृत)
- timer_list.function@+0xc और work_struct.func@+0xc पढ़ेंगे *(waiter+0xc) =
  pi_tree self-ptr = EXECUTABLE waiter+0xc — लेकिन कोई पथ waiter+0 को
  timer/work के रूप में कतार में नहीं डालता (link corruption / कोई अप्रत्यक्ष कतार स्रोत नहीं)
- Tree-root-nonzero (sysctl handler स्लॉट) = .text के माध्यम से rb-tree के रूप में
  नियतात्मक pointer-chase; एक शून्य शब्द पर समाप्त होता है — offline-simulable, लेकिन
  किसी उपयोगी writable स्लॉट में उतरना असंभाव्य है

सत्र 4 के लिए शेष सुराग:
1. ioctl गहरे पथ: dev_ioctl ifreq कॉपी (40B उपयोगकर्ता डेटा) — SyS_ioctl→sock_ioctl→dev_ioctl
   श्रृंखला की गहराई -0x1d8 की तुलना में मापें
2. sendmmsg से 0x1c अधिक गहरी कोई अन्य कॉपी (अभी तक कुछ नहीं मिला)
3. यदि stamp-surface खोज विफल हो: walk-chained निर्माणों पर पुनर्विचार करें या
   अभी तक गिने न गए writable-zero-called स्लॉट वर्गों की खोज करें


## सत्र 4 — दो सफलताएँ

### 1. MTK का rtmutex_common.h ही पूरा रहस्य है
MTK ने upstream के NULL-safe rt_mutex_top_waiter को इससे बदल दिया:```c
w = rb_entry(lock->waiters_leftmost, struct rt_mutex_waiter, tree_entry);
BUG_ON(w->lock != lock);   // compiled to: ldr sb,[lock+8]; ldr r3,[sb+0x1c]; cmp; bne→udf#0x12

NO NULL CHECK + BUG_ON. हर all-zero anchor *(NULL+0x1c) पर मर जाता है; garbage anchors udf पर मर जाते हैं। THE WALK REQUIRES: lock->waiters_leftmost (lock+8) को एक fake waiter W (writable) की ओर इशारा करना चाहिए जिसमें W->lock (+0x1c) == lock हो।

Walk flow पूरी तरह mapped (rt_mutex_adjust_prio_chain @ 0xc0189a58):

  • 9b44-9b54: retry head; pi_blocked_on==NULL → clean exit ret 0
  • 9abc-9adc: orig_waiter==NULL → skip pi_waiters checks (adjust_pi always passes NULL)
  • 9b10-9b28: prio check (prio==task->prio + MIN → exit 9b58)
  • 9b2c-9b38: trylock(lock+0) — ticket; fails → retry loop w/ counter bail (9a90-9aa8, limit @ *(0xc11189c8))
  • 9ba4-9bc0: deadlock checks
  • 9bcc-9bd8: THE BUG_ON (leftmost→W→W->lock==lock or die)
  • 9bdc-9c04: dequeue (leftover tree RB_CLEAR_NODE'd = EMPTY → safe skip), prio/deadline write
  • 9c04 bl: rt_mutex_enqueue → *link = waiter+0 at lock+4 ← THE WRITE
  • 9c3c+: owner==NULL → clean exit path

2. The kernel-stack-address leak (kills the address-free requirement)

/proc/self/task//stat field 28 (kstkesp) SHELL context से syscall-blocked threads के लिए REAL kernel SP लौटाता है (verified: nonzero values observed)।

  • waiter read(blocking_pipe) में blocks → stat → kstkesp
  • stack base = kstkesp & ~0x1fff (arm32 THREAD_SIZE=8192)
  • rt_waiter abs addr = base + fixed delta (computable: sp0 = base+0x2000-0x48 pt_regs; waiter = sp0-0x1d8)
  • ALL self-referential stamp values computable हो जाते हैं!

Full self-consistent stamp (leak के बाद):

  • L = waiter+0x24 (fake lock IN THE WINDOW — all 4 words controllable)
  • iov[0].base (waiter+0x1c lock) = L
  • iov[0].len (waiter+0x20 prio) = 1 (≠139)
  • W = waiter+0x1c; stamp *(W+0x1c) = *(waiter+0x38) = L (BUG_ON passes)
  • lock+0 (waiter+0x24) = 0; lock+4 (waiter+0x28) = 0 (write lands here); lock+8 (waiter+0x2c) = W; lock+0xc (waiter+0x30) = 0 (owner NULL)

Oracle status

  • crash during walk = walk ran (dead-lock probe: deterministic crash, clean code)
  • clean walk + no write = trylock-fail retry-bailout (kptr anchor: runtime word nonzero)
  • Everything is now deterministic post-pollution-fix.

Next session TODO

  1. Implement leak: waiter blocks on pipe, main reads stat, computes base
  2. Stamp self-consistent window, fire walk → crash-free completion = write proven
  3. Weaponize: write always lands at lock+4 (rb_link_node) — lock must live in the window (only fully-controlled memory), so target selection research: either find called-slot-in-window trick, or two-stage construction.

SESSION 4 FINAL STATE — THE WALL (precisely characterized)

The complete picture

The walk fires deterministically (dead-lock probe: crash every time, clean code). The write cannot land because of a 3-way kernel-hardening coincidence:

  1. MTK rtmutex BUG_ON variant: lock+8 (leftmost) MUST point at W with *(W+0x1c)==lock. All-zero/garbage anchors die. No static self-referential pattern exists (6571 candidates scanned, 0 hits). Runtime pointers unknown.
  2. No kernel-address disclosure from shell:
    • kstkesp on arm32 = USER SP (task_pt_regs->ARM_sp) — not kernel stack. DEAD.
    • dmesg/pstore/pagetypeinfo/kallsyms/stack — all denied.
    • kptr_restrict=1 at runtime (fops anchor words also runtime-nonzero — the kptr anchor run exited via trylock-fail retry-bailout, not trylock success)
  3. fops tables in rodata: trylock strex aborts (session-3 sweep crashes).

The stamp window (waiter+0x1c..0x5b) is the only controlled+known-content memory, but its ADDRESS is the unknown we need. Self-referential constructions all require stamping a kernel address as a constant — circular without a leak.

gitchw comparison (why their ARM32 write worked, ours can't yet)

Their 5.4 kernel has UPSTREAM rtmutex_top_waiter (NULL-safe: if (!leftmost) return NULL) — empty-tree anchors survive, their write landed on null_fops (writable on their kernel). Even THEY are stuck at dispatch ("ioctl reboot"). Mustang's 4.9.117 MTK tree has the BUG_ON variant — Fire OS 8 tablets (GhostLock-5.10) succeeded because their 5.10 kernels are upstream-style.

Session-4 verified facts

  • Walk retry loop has a counter bailout (limit @ *(0xc11189c8)); trylock-fail on runtime-nonzero anchor words → clean retry-bailout exit (kptr anchor runs)
  • No-requeue path (9ce4, FULL walk) also derefs leftmost at 9d64 — no escape
  • RB_CLEAR_NODE self-pointers exist as leftovers in the window (waiter+0 and +0xc contain their own addresses) but no check-comparison uses them in a way that avoids stamping known addresses
  • Real-mutex candidates (chain mutex has live waiter = BUG_ON would pass) — but &chain_mutex is a heap address, unreachable without leak

NEXT SESSION OPTIONS (ranked)

  1. logcat kernel-pointer hunt: Amazon HALs/daemons are chatty; any logged kernel pointer (even stale) unblocks the construction. Cheap to test.
  2. /proc/net %pK behavior on THIS build: some 4.9 trees print unhashed pointers in /proc/net/tcp,udp,unix for unprivileged readers. Test live.
  3. Thread-exit paths on dangling pi_blocked_on (one-shot, different derefs).
  4. Revisit shelved kbase JIT bug with accumulated 4.9 knowledge.

SESSION 4 ADDENDUM — LEAK HUNT: EXHAUSTED (definitive)

Tested and dead from shell domain:

  • /proc/net/{tcp,unix,packet,netlink,ptype}: %pK-hashed to 00000000 (kptr_restrict=1)
  • /proc/timer_list: READABLE but pointers %pK-zeroed (symbols visible, no addrs)
  • logcat: no kernel pointers in Amazon/wpa chatter
  • kstkesp (stat f28): USER SP on arm32 (task_pt_regs->ARM_sp)
  • MTK nodes (/proc/ged, mtk_cmdq_debug, mtktz, ptp, chip, aed, driver/*): all SELinux-denied
  • /proc/{iomem,vmstat,kmsg,keys,crypto,slabs...}: denied
  • /sys/kernel/notes: denied
  • CONFIG_VECTORS_BASE=0xffff0000 (high vectors — NULL+0x1c faults)
  • CONFIG_KUSER_HELPERS=y (kuser at 0xffff0000, not page 0)

CONCLUSION: GhostLock on mustang requires a kernel-address disclosure that this kernel does not expose to the shell domain. The self-referential fake lock cannot be constructed without it.

DECISION POINT

(a) Boot-deterministic grind: reboot → calibrate stack address via crash oracle (~20-30 reboots), verify reproducibility. Long shot — late-boot thread stack allocation unlikely stable. (b) PIVOT back to kbase CVE-2022-38181 with accumulated assets: exact-build vmlinux + full source + toolchain + O_SYNC trace discipline + deep 4.9 knowledge. Original blocker (destroy-worker panic during JIT eviction) is a spray-timing problem, now better understood. (c) Stop at honest ~45%: trigger proven, walk mapped to the instruction, write blocked by MTK BUG_ON + no-leak.

Recommended: (b) — the kbase bug is verified-present in this exact source, had a working trigger, and its blocker is mechanical, not architectural.

SESSION 5 — STAGE 2 PROVEN (option b executed)

Re-diagnosis: the "unconditional destroy panic" never existed

step mode (alloc id=1 → DONT_NEED → 700MB pressure → MEM_QUERY, NO free) survives: query=-1 (region freed by destroy worker, rbtree-clean). The worker path is byte-identical to the legal JIT_FREE-under-pressure flow. Session-1's crash was always the JIT_FREE dangling deref; its log line was lost because the panic kills adbd mid-flush. Verified twice more with uaf mode (bare free → panic, same log cutoff). The GHSL-2022-054 flow is fully live on this build.

Complete primitive inventory (exact-vmlinux disassembly)

kbase_jit_free(kctx, reg) @ 0xc058495c with fully-controlled fake reg:

  • reg->cpu_alloc NULL → backed size 0 → trim block skipped (0xc0584978)
  • bin decrement: kctx+0x147dd (byte) + kctx+0x147de+bin_id (byte)
  • mark_reclaim(reg->gpu_alloc) @ 0xc059b158: chain K=*(gpu_alloc+0x38) → *(K+0x1429c)==0 skips mm-atomics → atomic_sub nents@K+0x141c8, D=*(K+4) → atomic_sub nents@D+0x538. With nents=0 all writes are no-op stores (strex of same value).
  • reg->flags |= 0x100000 (write into fake, benign)
  • shrink_cpu_mapping early-exits when new==old (nents=0 → return)
  • list_add(gpu_alloc->evict_node, &kctx->evict_list): evict_list head @ kctx+0x1427c; writes into gpu_alloc+0x18/0x1c (must be writable)
  • WARN path (0xc0584bd4) is nonfatal (no panic_on_warn) and CONTINUES
  • UNLINK @ 0xc0584b08/b0c: r3=*(reg+0x3c) prev, r2=*(reg+0x38) next → *(next+4)=prev; *(prev+0)=next — two arbitrary write-whats-wheres, then relink of reg+0x38 into jit_pool_head @ kctx+0x148e8

Static fake-gpu_alloc chain (offline vmlinux scan, /tmp/opencode/scan_s.py)

9 candidates; S=0xc118b7ec (xfrm data, dormant on this device): *(S+8)=0 (nents), *(S+0x18)=S+0x18 (empty evict_node → no WARN), K=*(S+0x38)=0xc118b820 → *(K+0x1429c)=0, K/D+0x141c8/+0x538 all in writable data. Oracle targets staged: init_uts_ns.name.nodename=0xc110d561 ("(none)", readable via uname), scratch P=0xc118bd58 (xfrm zeros). Avoid S=0xc111cba4 (tracepoint-adjacent). CONFIG_DEBUG_RODATA=y → all write targets must be in .data/.bss (bss 0xc11d9000-0xc12d9000).

Spray engineering (what worked, what didn't)

  • add_key (CONFIG_KEYS=y): SELinux-denied for shell. Dead.
  • setxattr value buffer: kvmalloc(96)+copy_from_user happens BEFORE the SELinux check → alloc dance is SELinux-proof even when the call fails; transient (freed at syscall end), bytes persist at +4..95 (freelist ptr clobbers +0..3 = rblink, unused by kbase_jit_free)
  • kbase_va_region itself: kzalloc(72) → kmalloc-96! MEM_ALLOC(va=0x40, commit=0x10) puts ONLY the region in kmalloc-96 (phy alloc → 384) → deterministic reclaim type. A real-region victim makes kbase_jit_free complete through fully-legal state (empty jit_node → self-unlink).
  • Sequential post-pressure spray: ALWAYS misses — the worker frees the slot mid-pressure into partial slabs (SLUB: free to non-active slab ≠ cpu freelist); under pressure our allocs fail → zero net volume → no rotation
  • Pinned sprayers + caps: still miss (512-cap exhausted before eviction; worker may run on any cpu)
  • WINNER: commit_pages=0 spray — no phys pages → MEM_ALLOCs succeed through the whole pressure storm → ~6000 net allocations → partial-list rotation guaranteed. 8 threads (2/cpu, cpus 0-3 hardcoded — /proc/cpuinfo is shell-filtered to 1 core, use Cpus_allowed_list) + pressure child pinned to cpu0 + 16-alloc retention batch after join.
  • query(jit_va) trap: post-reclaim, spray regions reuse the freed VA in the custom zone → query=0 is ambiguous (live-original vs spray-covering-VA)

ORACLE HIT — machine-verified redirect

spray 700 run 2026-09-11: 5895 regions sprayed during pressure, JIT_FREE on dangling id=1 completed on a reclaimed region, then JIT_ALLOC(0x40, bin 0) walked jit_pool_head and returned sprayed region #4251's VA (0x142701000) — the exact region the dangling pointer consumed. Process kill after: kctx teardown clean, no crash. Stage 2 complete: deterministic UAF redirect with controlled object type + contents.

Stage 3 plan (raw-byte unlink)

Region-type reclaim gives legal-dance survival but jit_node is INIT'd self → no unlink primitive. Need raw bytes at +0x38/+0x3c:

  1. xattr stamping: alternate region-alloc bursts (net volume → slab rotation) with xattr storms (stamp every head slot, bytes persist post-free) → quiet window → deref
  2. or pinned sendmsg cmsgs (optmem_max=10240 → ~106 × 96B held)
  3. then: W1 *(N+4)=P with P=userland shellcode page (no PAN!) — candidates: const fops are .rodata (DEBUG_RODATA) → target non-const fn ptr in .data, or binfmt formats list head, or sysctl proc_handler (verify table writability). fallback: modprobe_path via byte-chained writes (values must be writable addrs — use pointer-shaped targets)
  4. no-KASLR + exact vmlinux: prepare_kernel_cred 0xc0149e3c, commit_creds 0xc014993c

SESSION 5B — STAGE 3: weapon built, reclaim race not yet won

Done

  • Stage-3 weapon complete & staged (poc/stage3.c):
    • Target: kern_table[pid_max].proc_handler @ 0xc1113f40 (writable .data, verified via string-pointer scan + handler == proc_dointvec_minmax)
    • N = shellcode entry 0x11111112 (mmap 0x11111000; W1 clobbers entry+4, skipped by b +8; W2 writes N at P = handler field)
    • arm32 ring0 shellcode hand-encoded: prepare_kernel_cred(0) + commit_creds + ret 0; trigger = read /proc/sys/kernel/pid_max (readable from shell); runs in own task context → creds apply to us
    • benign oracle mode writes uts nodename (0xc110d561, unaligned ok)
  • Spray primitive selection:
    • NETLINK_USERSOCK sendmsg pins (msg_control kmalloc-96 copy, held while blocked, never parsed): SELinux-denied (socket create EACCES)
    • unix/UDP sendmsg: cmsg parsing poisons payload bytes ✗
    • inotify events: inotify_handle_event kmallocs name_len+0x1d, name bytes (fully controlled, NUL/slash-free constraint) at event+0x1c; name_len=60 → kmalloc-96; queued → held; 4 instances → 4 events per rename; SELinux-OK from shell. Fake redesigned NUL-free: cpu_alloc points at S (nents@S+8 = 0 → same semantics as NULL)
  • Mechanical chain validated end-to-end (drain4, no-eviction run): 20K drained events + 13.5K multi-cpu trailing renames + JIT_FREE + oracle + pause, all clean. O_SYNC log (/data/local/tmp/s3.log) survives panics — exact crash-point forensics.

Reclaim attempts on the freed slot (all missed so far)

variantresult
concurrent rename sprayers during storm

Working hypothesis: storm-junk race — between the destroy worker freeing the slot (mid-storm) and child-kill/quiet, residual reclaim activity takes the sole-free-slot of the victim slab with non-payload bytes. Region spray (stage 2) wins because it allocates continuously DURING the storm; renames can't.

Gotchas hit

  • spray toggle bug: rename source must be the payload name (was temp name → ENOENT after 2 waves → only 512 events ever)
  • device hostname is "localhost"/varies — oracle compares before/after
  • paused st3 + pkill → device WEDGE (teardown with 33K events?!) — kill paused processes only via reboot; second hard-wedge of the session
  • /proc/cpuinfo shows 1 cpu to shell; use Cpus_allowed_list

Next moves (ranked)

  1. drain4 @ 500MB (eviction threshold confirmed there), 1ms poll, instant kill, 4-cpu trailing × 3200 — shrink the storm window
  2. xattr-stamp churn (setxattr alloc-copy happens BEFORE SELinux check — SELinux-proof) concurrent with storm + region rotation, end-with-stamp
  3. accept region-reclaim (proven) + find a second-stage primitive on the region-victim state (double jit_free analysis negative so far)

SESSION 5C — the blocker, precisely characterized

Empirical results this session

  • drain4@500 (1ms poll, instant kill, +4.5K renames): still crash at deref
  • overlap trailing with kill (drain5): crashes EARLIER (renames during kill-recovery storm hit a system-level fault) — overlap abandoned
  • ISOLATING EXPERIMENT (iso mode): identical timing, trailing with commit-0 REGIONS + stage-2 pool-reuse oracle → ORACLE HIT → timing/reachability are FINE; events are the problem
  • mask-cycled events (MOVED_TO/CREATE/DELETE rotation to defeat inotify_merge): still crash at deref
  • CONFIG_MEMCG=n → events and regions share ONE kmalloc-96 (memcg theory dead); inotify_merge compares names too (merge theory dead — our toggling names never merged; events were queued and held all along)
  • /proc/slabinfo absent; /proc/self/pagemap readable but PFN-zeroed (post-4.0 masking, no CAP_SYS_ADMIN)

THE ACTUAL BLOCKER (two parts, both proven)

  1. Soft-job finish runs in kbase job-scheduler WORKER context (jd_run_atom ← js dispatch, mali_kbase_jd.c:81-112/677), not inline in the submit ioctl → current->mm is a kernel thread's → the elegant "point the fake's pointers into our own userspace mmap" design (no PAN!) FAULTS nondeterministically. 5/5 crashes with an otherwise-perfect fake.
  2. Therefore gpu_alloc must point at KERNEL memory with a survivable runtime chain: K=*(S+0x38) readable, *(K+0x1429c)==0 at runtime (skips mm-atomics), K+0x141c8 writable, D=*(K+4) → D+0x538 writable, nents *(S+8) preferably 0. The 9 offline S-candidates were validated against FILE bytes — runtime drift (xfrm/tracepoint init) makes them unverified. A wrong chain = crash = reboot (~3 min cycle).

Session-6 plans (both fully specified)

A. Physmap-spray fake (ret2dir, classic arm32 no-PAN): spray ~450MB of user pages each containing the fake pattern baked for ONE guessed address G (G&0xfff = 0x141 for NUL-free name bytes; S=G; K=G-0x141b4 so K+4 lands in-page; K+0x141c8/+0x1429c → G+0x10/+0xd4 in-page; D=G+0x300; stray sub-0 stores hit random mapped RAM - harmless with nents=0). Spray doubles as the eviction pressure (dirty anon = unevictable → only ~100-200MB extra needed). Odds ≈ 45% (page hit) × ~50% (foreign K+0x1429c word is zero... if K+0x1429c kept in-page per layout above, odds = page-hit only). Miss = crash = reboot, retry. B. Brute-force the 9 static S-candidates (xfrm 0xc118b7ec first, tracepoint-adjacent 0xc111cba4 second...): 1 reboot per candidate, benign-oracle payload first, weapon on hit. C. pagemap-based exact G (dead: PFNs masked) — do not revisit.

SESSION 5D — physmap fake built; G-sweep 0/3; confounds eliminated

Established this session (all binary/device-verified)

  • Cache identity CONFIRMED same: region = kmem_cache_alloc_trace( kmalloc_caches[7], GFP|0x8000, 0x48) [kbase_alloc_free_region disasm]; event = __kmalloc(89, GFP) → kmalloc-96. Events and regions CAN share the victim's cache. (MEMCG off; single cache set.)
  • inotify queue: ≥5000 events held, no overflow, no merge collapse (qmeas 1000 & 5000 runs) — the event spray persists
  • iso2 (physmap spray + region trailing + oracle): HIT — the physmap spray does NOT break region reclaim; machinery sound
  • events vs regions reclaim: regions 3/3 (iso, iso2, stage-2), events 0/10 BUT the 3 pmap runs are explained by G-misses at 0.3-0.45 odds each (P(3 misses|events-work) ≈ 0.2-0.3 — not conclusive)
  • mix mode confounded: 480MB spray suffocates post-kill renames (+0); 350MB OK (+4452); spinning failed-rename threads also disturb region reclaim (mix crashed, iso2 clean)
  • query_commit returns -1 on EINVAL too — instrumented; EINVAL observed = rbtree lookup miss = genuinely freed ✓ (not a false positive)

Current pmap design (in stage3.c, mode pmap/mix/iso2)

  • G baked into every sprayed page (offset 0x2a4): nents@+0x2ac=0, evict self@+0x2bc/0x2c0, K=G+0x100@+0x2dc, D=G+0x200@+0x3a8; K+0x141c8/-0x1429c land ~20 pages up (sub-0 store harmless / read must be 0-or-valid). PM_SPRAY_MB 350, G sweep tried: c2a412a4, c2f4b2a4, c2a7d2a4 — all crash at deref
  • physmap range sanity: RAM 1GB → physmap ~0xc0000000-0xc3fffffff; MTK carveouts (GPU/M4U/secure) may occupy chunks — G landmines

Session-6 TODO (ranked)

  1. Extract the full kernel source (2.2GB tarball at ~/Desktop/amazon-mustang/ — platform.tar): get arch/arm + mm/ + drivers/of + MTK reserve mappings → compute the carveout map → target G into verified-RAM physmap subranges; also verify kmalloc cache geometry (ARCH_KMALLOC_MINALIGN!) and the 0x8000 GFP bit
  2. G sweep with placement-informed guesses (multiple reboots, vary spray size to decorrelate)
  3. If G sweep exhausts: reconsider multi-G payload or S-candidates from runtime-plausible statics (uts-adjacent pointer fields failed: NULL-K)

SESSION 6 — zram discovery, source extraction, event question still open### पूर्ण कर्नेल स्रोत अब निकाला गया

/tmp/opencode/ksrc2/kernel/mediatek/mt8163/4.9/ (arch/arm incl. mustang.dtsi, mm/, fs/eventpoll.c, fs/notify) ksrc/platform.tar से। निष्कर्ष:

  • 0x8000 GFP बिट = ___GFP_ZERO (बस kzalloc; कोई कैश स्प्लिट नहीं)
  • kmalloc-96 एक वास्तविक 96-बाइट कैश है (kmalloc कैश पर कोई HWCACHE_ALIGN नहीं)
  • mustang.dtsi: मेमोरी नोड 0x40000000/512MB — preloader द्वारा विस्तारित (डिवाइस MemTotal 977MB दिखाता है); CONFIG_VMSPLIT_3G, HIGHMEM=y
  • zram0 सक्रिय (SwapCached > 0) → "dirty anon = unevictable" गलत था: physmap स्प्रे दबाव में स्वैप आउट हो जाता है → G alias पुराना हो जाता है → kill के बाद physmap_retouch() जोड़ा गया (trailing/deref से पहले सभी स्प्रे पेज फॉल्ट करके वापस लाए जाते हैं)

इस सत्र के रन (सभी O_SYNC लॉग किए गए, ~6 रीबूट)

events पर निर्णय (Bayesian, ईमानदार)

Regions reclaim: 3/3. Events: 0/~12 प्रयास जिनमें 28K exclusive allocations शामिल हैं, head start और correct-by-construction fake के साथ। यदि events p_hit(G)≈0.35 के साथ reclaim करते हैं, तो पाँच pmap misses ≈ 11.6% — संभव पर अब असंभावित (~10-15%)। या तो events संरचनात्मक रूप से यह स्लॉट नहीं ले सकते (कारण अज्ञात — वही कैश, वही संदर्भ, वही टाइमिंग) या हमारे G अनुमान व्यवस्थित रूप से चूक रहे हैं (highmem-boundary skew, allocator placement)।

Session-7 निर्णय वृक्ष

  1. पहले G तय करें (सस्ता, कोई exploit नहीं): अस्थायी रूप से ISO2 फ़्लो को instrument करें — region trailing + oracle — लेकिन PAYLOAD event को physmap fake बनाएँ और जाँचें कि क्या swept range में कोई भी G बिना regions race के nodename परिवर्तन उत्पन्न करता है (शुद्ध pmap, G sweep ~0xc1500000-0xc2a00000 lowmem center पर, प्रति रीबूट 1 G, 4-5 रीबूट)
  2. यदि G sweep समाप्त हो जाए → events को मृत घोषित करें → shell से पहुँचने योग्य वैकल्पिक raw-byte kmalloc-96 allocators खोजें (audit: seq_file, tty ldisc, fdtable, sk_filter (blocked: code-field at +0x38), netlink nlmsg (skb ✗), keys (denied)) — या two-stage region primitives पर पुनर्विचार करें (विश्लेषण अब तक नकारात्मक)
  3. बाद में root के माध्यम से UART/ramoops unlock पर विचार करें; पीछे न पड़ें

SESSION 7 — cmdline bombshells; event रहस्य अब सटीक रूप से सीमित

mustang_defconfig CONFIG_CMDLINE (placement के लिए ground truth):

vmalloc=496M slub_max_order=0 slub_debug=O loglevel=8 initcall_debug

  1. vmalloc=496M → physmap = 0xc0008000..~0xc2080000 ONLY (RAM के निचले 520MB ) — सभी पूर्व G अनुमान (0xc2a4xxxx+) VMALLOC SPACE में थे। sessions 5D/6 के प्रत्येक "G-miss" निष्कर्ष अमान्य हो जाते हैं; crash-interpretation कायम है लेकिन sweep गलत map पर लक्षित था।
  2. slub_max_order=0: सभी slab pages order-0
  3. KMALLOC_MIN_SIZE = ARCH_KMALLOC_MINALIGN = 64 (L1_CACHE_SHIFT 6) → 96/192 के लिए kmalloc_index() special-cases DISABLED हैं → region kzalloc(0x48=72) → caches[7]; event __kmalloc(89) → caches[7] (disasm + include/linux/slab.h:287 सत्यापित) — दोनों merged 128-बाइट "kmalloc-128/96" कैश में। Cache identity: पुनः पुष्टि समान।
  4. zram सक्रिय → anon physmap spray को kbm_spray से बदला: 160 × 2MB kbase MEM_ALLOC regions (GFP_KERNEL → ZONE_NORMAL → lowmem-only, pinned → zram-immune), pattern CPU mmap के माध्यम से लिखा — सही range, ~65% lowmem coverage

रन (O_SYNC लॉग किए गए)

  • kbm + G=0xc16412a4: deref पर क्रैश (+4831 renames)
  • kbm + G=0xc1c4b2a4 @200MB: कोई eviction नहीं (query=16 — दबाव अंशांकन pinned spray के साथ बदलता है; legal free, बच गया)
  • kbm + G=0xc1c4b2a4 @400MB: eviction ✓, +4053 renames, deref पर क्रैश
  • Valid-range G रिकॉर्ड: 0/2. यदि events ~65% coverage के साथ काम करते हैं: P(2 misses) ≈ 12%. प्रश्न अभी भी खुला है पर पहले से कहीं अधिक संकीर्ण।

प्रश्न, अंतिम रूप

Regions victim slot 3/3 लेते हैं; events 0/13. वही कैश (source + disasm स्तर पर सिद्ध), वही प्रक्रिया संदर्भ, वही pinned cpus, वही post-kill timing, exclusive head start के साथ हज़ारों allocations। तंत्र अज्ञात। शेष संदिग्ध: allocation-rate/frequency का partial-list rotation के साथ सहसंबंध (region ioctls ~1ms अंतराल पर बनाम event renames ~100µs अंतराल पर — विपरीत दिशाएँ?), या SLUB freelist ordering विवरण slub_max_order=0 के अंतर्गत जो... अस्पष्ट।

Session-8 TODO

  1. Instrument-grade प्रयोग: दो event payload variants जिनमें भिन्न N/P मान बारी-बारी (दो name sets) — यदि nodename कभी बदलता है, तो अंतिम विजेता की पहचान होती है; G को [0xc1200000..0xc2000000] में kbm spray के साथ sweep करें, 3-4 रीबूट बजट
  2. यदि अभी भी 0/N: events छोड़ दें। विकल्प रैंक किए गए: a. pipe_buf arrays via F_SETPIPE_SZ(4096 → 1 buf? नहीं — 16 bufs = kcalloc(16, 28)=448→512 ✗) — dead b. अन्य name/data-carrying kmalloc-128 के लिए fs/notify + fs का audit (fanotify events? mq off; fanotify को groups चाहिए...) c. seq_file buffers (kmalloc(PAGE_SIZE) ✗) d. sock filters (code-field collision at +0x38 ✗) e. region-type reclaim स्वीकारें + एक दूसरा bug/technique श्रृंखलाबद्ध करें
  3. पुनः जाँचें कि regions क्यों जीतते हैं — शायद multiple jit ids के माध्यम से instrument करें: N dangling slots, प्रति slot region-vs-event race, oracle पता लगाता है कि कौन सा spray ने कौन सा slot लिया → तंत्र का सांख्यिकीय fingerprint

SESSION 8 — डिवाइस पर ARBITRARY WRITE प्राप्त; dispatch रहस्य शेष

मील का पत्थर```

[+] uname.nodename="X?lhost" (was "localhost") <<< ORACLE HIT

root@kitploit:~
**पूरी raw-byte श्रृंखला लाइव डिवाइस पर काम करती है**: इवेंट मुक्त किए गए
region slot को reclaim करता है → kbase_jit_free हमारे fake को deref करता है (S=physmap page from
the kbm spray, G=0xc154b2a4) → unlink हमारे दो writes को निष्पादित करता है।
benign payload (nodename write) के साथ बार-बार सत्यापित।

### खोजों की सत्र श्रृंखला
1. kbm pages GFP_HIGHUSER थे → HIGHMEM, physmap को अदृश्य
   (mali_kbase_mem_pool.c:164!) — zonelist spill से ठीक किया गया: 260 × 2MB
   spray > highmem-free → अतिरिक्त ZONE_NORMAL (physmap) में गिरता है
2. पहले weapon प्रयास क्रैश हुए: W1 target N+4 एक USER page था —
   unlink kworker ctx (no mm) में चलता है → fault। इसे page+0x600 पर physmap pattern में
   ring-0 shellcode बेक करके ठीक किया गया (arm32 non-LPAE पर direct map RWX)
   — kernel-resident code, ret2usr की आवश्यकता नहीं
3. ctl_table offset bug: proc_handler entry+0x14 पर है, +0x18 पर नहीं (मूल scan
   में यह सही था; मेरा define गलत था) — extra1 लिख रहा था
4. Over-pressure regression मिला और revert किया गया: kid budget 20×100MB +
   trailing 10s ने reclaim तोड़ दिया; काम करने वाला config 2 kids/200MB +
   5s/+3200 trailing है (revert के बाद benign hit 1/1)
5. **diag2: W2 → &pid_max global (0xc1114d7c) → read हमारा मान लौटाता है
   (-1055861411 = 0xc110d55d as int32) — write + readback PROVEN**

### शेष रहस्य (बंद होने से एक प्रयोग दूर)
सही handler address (0xc1113f3c) के साथ diag1: W1 fire होता है (nodename
बदलता है), W2 निष्पादित हुआ होगा (अगला instruction) — फिर भी pid_max reads
साफ़ मान लौटाते हैं → जो handler field हम लिखते हैं वह वह नहीं है जिससे
inode dispatch करता है। diag3 (queued; hit boot चाहिए): W2 →
entry->data FIELD (0xc1113f2c) जो nodename की ओर इंगित करता है — यदि read तब
nodename-bytes-as-int दिखाता है, तो हमारी entry IS live है और केवल handler
offset किसी तरह गलत है; यदि अप्रभावित, तो inode एक shadow table copy का उपयोग करता है और हम live वाले की खोज करते हैं।

### Hit-rate वास्तविकता
प्रति-boot coin flip (~25-40%), clustered; कई safe-miss/crash boots
लगातार सामान्य हैं। लगभग 3-4 boots में 1 hit होता है। काम करने वाला
config EXACTLY रखें (2 kids, 5s trailing, 260-region kbm, G=0xc154b2a4)।

### Session-9 TODO
1. hit boot पर diag3 पूरा करें ("W1 FIRED" तक roll करें)
2. यदि entry live है: handler offset को अनुभवजन्य रूप से पुनः जाँचें (proc_dostring का address
   handler के रूप में लिखें... N का मान उपयोगी होना चाहिए — unlink का उपयोग entry->data लिखने के लिए करें और pivot करें: उदाहरण के लिए,
   data=selinux_enforcing-adjacent...)
3. यदि shadow table है: live वाले का पता लगाएँ — kallsyms में कोई data symbol नहीं है;
   उम्मीदवार: /proc/sys व्यवहार स्कैन करें, या .data में header list pattern के माध्यम से दूसरा ctl_table
   region खोजें (0x20-stride entries
   handler=proc_dointvec_minmax और maxlen=4 के साथ — सभी को enumerate करें और
   प्रत्येक को diag-write करें)
4. वैकल्पिक target class जो dispatch को पूरी तरह बचाती है: .data
   function pointers जो shell-reachable paths से कॉल होते हैं (audit आवश्यक)
5. write primitive स्वयं DONE है — root के लिए अब कोई भी विश्वसनीय kernel-address
   target पर्याप्त है

## SESSION 9 — nf-WEAPON: reclaim+unlink+G-hit PROVEN IN-WEAPON; केवल hook walk शेष है

### नया trigger design (sysctl-handler path को पूरी तरह प्रतिस्थापित करता है)
User का विचार kernel memory में अनूदित: कोई SUID file नहीं (system
dm-verity RO है; primitive kernel RAM लिखता है)। इसके बजाय: **fake netfilter
hook**। इस kernel में NEW
nf_hook_entries API का Android-common backport है, लेकिन LINKED LIST के रूप में कार्यान्वित (nf_hook_slow + helper 0xc09897d4 के disasm से सत्यापित):
- `__ip_local_out(net, sk, skb)` entries CELL को
  **[net+0x58c]** से लोड करता है, state+0x1c में संग्रहीत करता है, nf_hook_slow को कॉल करता है
- walk: `entry = *cell`; while(entry){ if (state->[4] <= entry->[0x20])
  call entry->[0xc](entry->[0x14], skb, state); entry = entry->[0]; }
  — अर्थात **fn@entry+0x0c, priv@entry+0x14, priority@entry+0x20,
  next@entry+0x00**; state+4 = INT_MIN threshold (हमेशा पास होता है)
- init_net = **0xc1104548** (CONFIG_NET_NS=n → sock_net() constant को inline करता है; 6678 movw/movt refs, histogram champion; nf_hook_slow के स्वयं के literal से cross-confirmed)। TARGET: **[init_net+0x58c] = 0xc1104ad4**
- LOCAL_OUT hook SENDER की process context में चलता है → हमारे hookfn का
  commit_creds(prepare_kernel_cred(0)) उस process को root करता है जिसने
  packet भेजा। Trigger = sendto(127.0.0.1:9) UDP।

### nf mode layout (poc/stage3.c, mode `nf 200`)
- kbm pattern pages (page-relative, single source of truth — पुराने
  weapon में THREE bugs थे जो अब ठीक हैं: proc_handler@+0x14 not +0x18; W1
  target KERNEL mem होना चाहिए (kworker ctx, no mm); baked code at
  page+0x600 vs entry G+0x600=page+0x8a4 mismatch):
  - +0x2ac/+0x2bc/+0x2c0/+0x2dc/+0x3a8: fake phy-alloc chain (अपरिवर्तित)
  - +0x600: nf_code hookfn (marker store + prepare_kernel_cred +
    commit_creds + return NF_ACCEPT(1))
  - +0x700: fake entry {next=0, fn=PM_PAGE+0x600, priv=0, prio=0x100}
  - +0x740: cell → PM_PAGE+0x700
- payload: N = PM_PAGE+0x740 (0xc154b740), P = 0xc1104ad4
  → W1: *(cell+4)=P (हमारे page में गिरता है), W2: *(init_net+0x58c)=cell

### SELF-DIAGNOSING instrumentation (kbm_scan_for)
kbm CPU mappings रखे जाते हैं; free के बाद हम हर sprayed
page को एक ज्ञात word के लिए स्कैन करते हैं:
- scan(HOOKS_PTR_ADDR) at page+0x744 → reclaim + unlink सिद्ध करता है + बताता है
  कौन सा phys page G guess को back करता है
- scan(0x600d600d) at page+0x7f0 → सिद्ध करता है कि hookfn EXECUTED
  (nf_code इस marker को अपनी 2nd action के रूप में लिखता है)

### THE RUN THAT MATTERS (2026-09-11, late session 9)```
[+] W1 CONFIRMED: region 135 page+0x185000 <- 0xc1104ad4 (reclaim + G hit!)
[+] nf trigger done, uid=2000 euid=2000

पूरी हथियार श्रृंखला लाइव बूट पर चली: इवेंट ने स्लॉट पुनः प्राप्त किया, नकली चला, unlink निष्पादित हुआ, G-guess पेज (0xc154b000) वास्तव में हमारा था (region 135 page 389)। W2 = *(0xc1104ad4)=cell आसन्न निर्देश है — उसे निष्पादित होना ही था। फिर भी UDP sendto ने हमें रूट नहीं किया → विफलता हुक पथ के अंदर है: walk semantics, [state+0x1c] plumbing, priority compare, या entry fields। (hookfn-ran-vs-not को अलग करने के लिए मार्कर प्रयोग जोड़ा गया; सत्र समाप्ति से पहले केवल crash-boots — अभी तक कोई साफ़ डेटा नहीं।)

Hit-rate / boot-state सीख (कड़ी मेहनत से अर्जित)

  • काम करने वाला कॉन्फ़िग (इसे न छुएँ): 2 kids × 100MB stepped pressure, trailing 100×50ms/+3200 renames, 260×2MB kbm spray, G=0xc154b2a4, pre-drain ~5000 renames
  • Over-pressure (20 kids / 10s trailing) reclaim को तोड़ देता है — वापस लिया गया
  • Boot settle मायने रखता है: boot_completed के तुरंत बाद लॉन्च किए गए रन सिस्टम के स्टार्टअप allocations से रेस करते हैं → cold streaks; चलाने से पहले बूट के 60-90s बाद settle करें
  • "W1 did not fire" (nodename check) nf payload के लिए अर्थहीन है — W1 हमारे पेज में लिखता है; इसके बजाय kbm_scan_for का उपयोग करें
  • Crash-at-free boots ≈ garbage slot या G-miss conversions; benign control (pmap 200) पर्यावरण sanity check है (warm होने पर 4/4 hits; cold होने पर crash-miss)
  • /data/local/tmp/.w* dirs रन शुरू होने पर साफ़ कर दी जाती हैं (जमा हुई dirs reclaim को ख़राब करती हैं)

Session-10 TODO (decision tree, क्रम में)

  1. settle-delayed boots पर nf 200 चलाएँ जब तक W1-CONFIRMED लाइन न आ जाए, फिर MARKER लाइन पढ़ें: a. marker PRESENT, uid!=0 → shellcode के creds विफल (prepare_kernel_cred/commit_creds addrs जाँचें; blx encodings) b. marker ABSENT → walk ने हमें कभी कॉल नहीं किया: दूसरे marker से सत्यापित करें जो... अगली diagnostics: hookfn जो केवल marker लिखता है और 1 लौटाता है (कोई creds नहीं) — यदि फिर भी अनुपस्थित:
    • trigger से ठीक पहले CPU mapping के माध्यम से हमारे वास्तविक entry bytes डंप करें (वे पढ़ने के लिए हमारे हैं!)
    • जाँचें कि क्या [init_net+0x58c] की परामर्श भी ली जाती है: इसके बजाय लेखन का उपयोग किसी अवलोकनीय चीज़ को भ्रष्ट करने के लिए करें (जैसे इसे ऐसे cell पर इंगित करें जिसका *cell = entry हो fn = kfree जैसा kernel function → trigger पर तत्काल crash = field की परामर्श ली जाती है)
    • 0x58c offset पुनः सत्यापित करें: शायद hooks_ipv4[NF_INET_LOCAL_OUT] भिन्न index पर रहता है (NF_INET_POST_ROUTING=4?)
  2. यदि walk हमें कॉल करता है: creds ठीक करें → root → फिर उपयोगकर्ता की योजना: setenforce 0; cp /system/bin/sh /data/local/tmp/su; chown root; chmod 6755; ls -la सत्यापित करें; marker files छोड़ें
  3. Persistence (post-root): /dev/block/by-name/boot के माध्यम से boot-image patch
    • dm-verity अक्षम करें, या Magisk-style; reboot के बाद अकेले /data पर su uid0-in-shell-domain है (SELinux फिर से enforcing) — setenforce 0 केवल runtime-only है
  4. Cleanup notes: paused st3 processes में corrupt kctx state होती है — केवल reboot के माध्यम से kill करें; nf hijack सभी ट्रैफ़िक के लिए LOCAL_OUT hooks तोड़ देता है — root के बाद reboot करके पुनर्स्थापित करें

आज रात की asset additions

  • poc/stage3.c modes: pin/root/drain{,2,3,4,5}/iso — पूर्ण हथियार + oracle + isolation harness, O_SYNC crash-point forensics
  • userland-fake infrastructure (ufake_prep) — रखें लेकिन केवल तभी उपयोग करने योग्य जब कभी context-inline deref path मिल जाए
  • tools/: kdis/scan_s/resolve/dumpb/findsysctl offline vmlinux analysis

SESSION 10 — ROOT ACHIEVED (2026-09-11)

nf-weapon को रोकने वाले तीन बग, सभी ठीक किए गए

  1. गलत init_net: 0xc1104548 __stack_chk_guard है (movw/movt histogram stack-canary loads से दूषित था — 2025 ने पूरी nf योजना उस पर बनाई)। असली init_net = 0xc1185040 (पुष्ट: ip_send_skb(net,...) इस literal के साथ कॉल किया गया; ~994 refs सभी net stack में)। IPv4 LOCAL_OUT cell = init_net+0x58c = 0xc11855cc।
  2. Double-deref बग: nf_iterate [init_net+0x58c] को स्वयं nf_hook_ops pointer मानता है — यह fn@+0xc, priv@+0x14, prio@+0x20 सीधे उस मान से पढ़ता है। session-9 का fake entry PM_PAGE+0x700 पर था जिसमें cell उसकी ओर इंगित करता था (cell पर अप्रयुक्त next/fn fields → → crash)। fake entry को (0xc154b740) पर ही रहना चाहिए। इसे ठीक करने पर, hook call सिद्ध हुआ ( mode = SAFE_FN सभी 200 sendtos को साफ़ तरीके से process करता है)।

SELinux की दीवार और 2-packet bypass

commit_creds(prepare_kernel_cred(0)) / override_creds(&init_cred) uid 0 देता है लेकिन kernel SELinux SID में पहुँचता है, जिसे यह Fire OS policy /data या /sys/fs/selinux/enforce लिखने की अनुमति नहीं देती (सत्यापित: EACCES)। असली init SID (7) भी अस्वीकृत (fake struct cred test)। enforcing_setup __init है (freed → crash)। mark_reclaim के atomic_sub को nents=1 चाहिए जो shrink_cpu_mapping के early-exit को तोड़ देता है।

जीत: exploit process kbm CPU mappings रखता है, इसलिए fake nf entry को packets के बीच in place फिर से लिखा जा सकता है:

  • selroot mode: entry = {fn=0xc01d503c (mov r3,#0;str r3,[r0];bx lr), priv=0xc1213ea8 (selinux_state.enforcing)}।
  • Packet 1: *(enforcing)=0 → SELinux Permissive।
  • entry को kbm_cpu[reg]+off के माध्यम से {fn=commit_creds, priv=&init_cred} पर फिर से लिखें।
  • Packet 2: sender के task में commit_creds(&init_cred) → permissive SELinux के साथ uid 0 → उपयोगी root, सब एक reclaim में, कोई chain आवश्यक नहीं।

डिवाइस पर सत्यापित (2026-09-11)```

[+] W1 CONFIRMED: region 67 page+0xad000 <- 0xc11855cc (reclaim + G hit!) [*] sendto 0 -> -1 errno=1 uid=0 euid=0 [+] nf trigger done, uid=0 euid=0 <<< HOOK RAN - commit_creds OK [+] ROOT: uid=0 euid=0 [+] setenforce write=1 [+] su copied bytes=236220

root@kitploit:~
- `getenforce` → **Permissive**; paused st3 है `Uid: 0 0 0 0`,
  `CapEff: 3fffffffff`.
- `/data` **nosuid** के रूप में माउंट है इसलिए एक setuid `su` काम नहीं कर सकता। एक छोटा
  `rootshell` (UDP भेजें → स्वयं पर `commit_creds` → `execl sh`) एक
  इंटरैक्टिव रूट शेल देता है: `uid=0(root) context=u:r:kernel:s0`.
- रूट `/dev/block/by-name/*` को पढ़/लिख सकता है (`dd if=boot ...` ठीक)।

### Stage-3 कोड स्थिति (`poc/stage3.c`)
- मोड: `nf <mb> [probe|uprobe|oc|chain|fc <sid>|notrig|selroot]`
- `selroot` काम करने वाला हथियार है। मुख्य स्टेटिक्स: `init_net=0xc1185040`,
  `HOOKS_PTR_ADDR=0xc11855cc`, `ENFORCING_ADDR=0xc1213ea8`,
  `ZERO_GADGET=0xc01d503c`, `commit_creds=0xc014993c`,
  `init_cred=0xc1114f54`.
- पोस्ट-एक्सप्लॉइट सीधे सिसकॉल हैं (कोई `system()` नहीं); kctx को जीवित रखें
  (`pause()`) ताकि teardown क्रैश से बचा जा सके।

### शेष (Stage 4/5)
- रीबूट के बाद भी बने रहना (verity / boot image / recovery), क्योंकि सेल
  हाईजैक + permissive SELinux केवल रनटाइम हैं और एक्सप्लॉइट को दोबारा चलाने के लिए
  ~1/3 reclaim सिक्का उछाल चाहिए।
- `su` को एक गैर-nosuid होम (`/system`) या एक लॉन्चर चाहिए जो दोबारा ट्रिगर करे।

## SESSION 11 — PERSISTENCE RECON (Track B + Track A) और RE हैंडऑफ

लक्ष्य स्थायी रूट था। दो ट्रैक तय किए गए:
- **Track B**: verified boot (dm-verity / SELinux) अक्षम करें ताकि `/system` को पैच किया जा सके।
- **Track A**: बूट पर एक्सप्लॉइट दोबारा चलाएँ।

दोनों एक ही अवरोधक पर आते हैं: **LK को डिवाइस को `eng`/`unlocked` मानने पर मजबूर करें।**

### Verified-boot तथ्य (सटीक बिल्ड)
- Bootloader लॉक, AVB `green`, `ro.boot.unlocked_kernel=false`, `ro.boot.secure_cpu=1`,
  `rpmb_state=1`. Bootrom पैच (कोई BROM नहीं); preloader केवल CMD शॉर्ट के माध्यम से।
- `/system` **lk-built kernel cmdline से Android dm-verity द्वारा** माउंट है:
  `root=/dev/dm-0 dm="system none ro,0 1 android-verity PARTUUID=b6404ef3-… "`,
  `veritykeyid=id:f3530e18f64d11fc25eb2dd762979f078de990bf`, `androidboot.veritymode=eio`,
  `skip_initramfs` (system-as-root)। `dm-0` = `system` नाम का verity डिवाइस; `dm-1` = `/vendor`।
- LK: Amazon **UFBL**, `ro.boot.lk_version=0x0006`, बिल्ड `0db73c9-20231025_030009`;
  preloader `pl_version=0x000a`, बिल्ड `80c6fcb-20230523_065640`। `/dev/block/by-name/lk` = mmcblk0p5 (1 MB)।
- पूर्ण GPT (16 पार्टीशन, कोई `persist`/`seccfg`/`nvram`/`protect`/`para` नहीं):
  `proinfo` p0, `PMT` p1, `kb` p2, `dkb` p3, `lk` p4, `tee1` p5, `tee2` p6, `metadata` p7,
  `MISC` p8, `reserved` p9, `boot` p10, `recovery` p11, `system` p12, `vendor` p13,
  `cache` p14, `userdata` p15। eMMC boot0 (1 MB) = preloader (`EMMC_BOOT` magic);
  boot1 (4 MB) = IDME स्टोर।

### LK (UFBL) स्टेटिक निष्कर्ष
`lk.img` हेडर: `88 16 88 58 | 00052974 | "LK"`; 0x200 पर ARM वेक्टर टेबल, बाकी Thumb-2,
position-independent/relocated (literal pools `ldr+add pc` का उपयोग करते हैं, इसलिए naive base-relative disasm विफल होता है)।
प्रासंगिक स्ट्रिंग्स (फ़ाइल ऑफ़सेट): `amzn_image_verify`, `amzn_verify_unlock`, `amzn_verify_code_internal`,
`unlock_code`, `unlock code error`, `unlock failed`, `$Common Kernel Signing Engineering CA0`,
`seccfg`, `para`, `ENV_v1`, `LK_ENV`, `Kfos_flags`/`Kdev_flags`/`Kusr_flags`/`Kunlock_code`/`Kunlock_version`,
`FOS_FLAGS_{NONE,ADB_ON,ADB_ROOT,CONSOLE_ON,RAMDUMP_ON,VERBOSITY_ON,ADB_AUTH_DISABLE,FORCE_DM_VERITY,DM_VERITY_OFF,BOOT_DEXOPT}`,
`[DM-VERITY] verify for system(root) is enabled`, `[DM-VERITY] verify off by fos_flags`,
`[DM-VERITY] disabled by fos_flags on eng devices or unlocked device`,
`[SELINUX] set to permissive mode by dev_flags`, `androidboot.prod=1|0`, `androidboot.unlocked_kernel=%s`.
**निष्कर्ष: LK `fos_flags`/`dev_flags` सुरक्षा प्रभावों को eng/unlocked पर गेट करता है।**

### IDME स्टोर (eMMC **boot1**) — लिखने योग्य, स्थायी, LK और Android द्वारा पढ़ा जाता है
- 0x0 पर Magic `beefdeed` + `"2.1\0"` + count(0x19=25); आइटम 0x10 से।
- आइटम प्रारूप: `char name[16]; u32 size; u32 type(=1); u32 magic(=0x124); u8 data[size] (pad4)`।
- आइटम ऑफ़सेट (प्रिस्टीन): `board_id@0x10 serial@0x3c mac_addr@0x68 mac_sec@0x94 bt_mac_addr@0xd0
  bt_mfg@0xfc product_name@0x198 productid@0x1d4 productid2@0x210 region@0x24c bootmode@0x26c
  postmode@0x28c bootcount@0x2ac manufacturing@0x2d0 unlock_code@0x4ec sensorcal@0x908 alscal@0x9c4
  KB@0xa00 DKB@0x1e1c device_type_id@0x2238 dev_flags@0x2274 fos_flags@0x2298 usr_flags@0x22bc
  wifi_mfg@0x22e0 unlock_version@0x26fc`। मान ASCII हैं (फ्लैग **हेक्स स्ट्रिंग्स** हैं)।
- रनटाइम रीड: `/proc/idme/<name>` (केवल-पढ़ने के लिए)। अंतिम-बूट मान कैश्ड; boot1 पर लिखा गया
  अगले बूट पर प्रभावी होता है। लिखने के पथ के लिए `/sys/block/mmcblk0boot1/force_ro` (रूट) को साफ़ करना आवश्यक है।
- **पुष्टि की गई कि LK boot1 पढ़ता है**: `serial` बदलने से अगले बूट पर `ro.boot.serialno` बदल गया।
  लेकिन LK **serial को 16 बाइट्स तक काट देता है** और `fos_flags=0x80`, `dev_flags=0xff`,
  all-ones, आदि को अनदेखा कर दिया — verity/selinux/`prod` अपरिवर्तित। इसलिए serial के माध्यम से cmdline इंजेक्शन विफल होता है।

### IDME फ्लैग्स के Android-साइड उपभोक्ता
- `/init.fosflags.sh` (सेवा `fosflags`, `u:r:fosflags:s0`): `FOS_FLAGS_ADB_ON=0x1`,
  `CONSOLE_ON=0x4`, `RAMDUMP_ON=0x8`, `VERBOSITY_ON=0x10`, `ADB_AUTH_DISABLE=0x20`,
  `BOOT_DEXOPT=0x100`। सत्यापित: फ्लैग सेट करने से प्रभाव पड़ता है (`sys.usb=adb`, `noadbauth=1`)।
- **adbd** (unstripped ARM ET_EXEC; `.text` VA 0x8160 / फ़ाइल 0x160; fileoff = VA-0x8000):
  - `amzn_is_root_allowed` @0x2d5b8 = `amzn_is_dev_unlocked() && (fos_flags & 0x2)`
  - `amzn_is_adb_auth_disable_allowed` @0x2d5e8 = `fos_flags & 0x20` (ungated)
  - `amzn_is_dev_unlocked` @0x2d5fc = `/proc/cmdline` में `androidboot.prod=0` **या**
    `androidboot.unlocked_kernel=true` है
  - `fos_read_debug_flags` @0x2d724 `/proc/idme/<name>` पढ़ता है और **हेक्स** पार्स करता है
  - `restart_root_service` @0xcb74 / `restart_unroot_service` @0xcc64
  - स्ट्रिंग्स: `amzn_fos: ADB: Auto-root succeeded`, `… eng_device=%d`, `… unlocked_kernel=%d`,
    `adbd cannot run as root in production builds`, `ro.debuggable`
  - `adb root` → "cannot run as root in production builds" (`ro.debuggable=0`) — इसलिए auto-root गेट
    संतुष्ट होने पर भी, AOSP prod चेक कमांड पथ को गेट करता है।

### Session-10 रूट स्थायी क्यों नहीं होता
- SELinux permissive + सेल हाईजैक + रूट केवल रनटाइम हैं।
- `/data/metrics` एक **vpartition** है: `/system/bin/vpartition.sh` हर बूट पर `/data/vp/metrics.img`
  (ext4, non-nosuid/noexec) को `/data/metrics` पर माउंट करता है; वहाँ लिखा गया `su` रीबूट के बाद **नहीं**
  बचता। (यही कारण है कि setuid `su` ने uid 0 दिया लेकिन **शून्य caps**।)

### Track A (बूट-टाइम पुनः-एक्सप्लॉइट) — अवरुद्ध
- कोई init `.rc` ट्रिगर नियंत्रणीय कोड निष्पादित नहीं करता (सभी आयात सत्यापित; `persist.*` ट्रिगर केवल
  `start` निश्चित सेवाएँ; `/system`/`/vendor` में स्क्रिप्ट्स)।
- रूट सेवाएँ `/data` कॉन्फ़िग्स पढ़ती हैं लेकिन उनसे कभी exec नहीं करतीं (`perfmonitord`, `amazonfiled`,
  `vpartition.sh`, `kisd`, …)।
- एकमात्र बूट executor = एक **ऐप**, लेकिन एक्सप्लॉइट का paused फुटप्रिंट **VmRSS 534 MB**
  (`kbm` स्प्रे) है → lmkd इसे मार देता है; साथ ही एक खोया reclaim पैनिक करता है (`PANIC_ON_OOPS`) → bootloop।
- **adbd auto-root** मौजूद है लेकिन LK-built cmdline (`prod=0`/`unlocked_kernel=true`) पर गेटेड है।

### निष्कर्ष / अगला लक्ष्य (चुना गया: Track B RE)
सब कुछ LK को `eng`/`unlocked` रिपोर्ट कराने पर निर्भर है। पहुँच में:
`androidboot.prod=1|0` और `androidboot.unlocked_kernel=false` LK द्वारा सेट किए जाते हैं। LK को रिवर्स करें ताकि पता चले:
1. यह `fos_flags`/`dev_flags`/`usr_flags` (`K*` आइटम) कहाँ पढ़ता है और सटीक गेट क्या है;
2. `prod`/`unlocked` निर्धारण (IDME आइटम? buildvariant? `amzn_verify_unlock` परिणाम?);
3. `amzn_verify_unlock` (libtomcrypt RSA verify) बायपास या कमजोर unlock_code/version पथ के लिए;
4. `seccfg`/`para`/`ENV_v1`(LK_ENV) स्टोरेज (किसी भी डंप किए गए पार्टीशन में नहीं — शायद tee-protected);
5. preloader (`boot0`, `EMMC_BOOT`) में बग के लिए।
यदि इनमें से कोई भी हमें eng/unlocked सेट करने देता है (स्थायी रूप से, boot1 या रॉ पार्टीशन राइट के माध्यम से), तो
`FOS_FLAGS_DM_VERITY_OFF` system(root) verity को अक्षम कर देता है और `/system` को स्थायी रूप से पैच किया जा सकता है।

### आर्टिफैक्ट्स (इस सत्र से)
`/tmp/opencode/mustang-dumps/` (होस्ट रीबूट पर साफ़ हो सकता है): `lk.img`, `boot1.img` (प्रिस्टीन),
`boot.img`, `MISC.img`, `metadata*.img`, `pmt.img`, `mbr.img`, `kb.img`, `dkb.img`, `reserved.img`,
`cache.img`, `boot0.img`, `boot1.img`, `adbd.bin`, `perfmonitord.bin`, `amazonfiled.bin`।
हेल्पर्स: `tools/findinitnet.py`, `findgadget*.py`, `findstores.py`, `adbd_sym.py` (/tmp में);
रेपो में `run.sh`, `poc/stage3.c` (`selroot`), `poc/su.c`, `rootcmd.sh` हैं।

### उपयोगी कमांड```
# IDME read
/data/metrics/su sh -p -c 'for f in fos_flags dev_flags usr_flags serial region device_type_id unlock_version; do echo -n "$f="; cat /proc/idme/$f; echo; done'
# write boot1 (root; su lives only until reboot -> re-run run.sh first)
/data/metrics/su sh -p -c 'echo 0 > /sys/block/mmcblk0boot1/force_ro; dd if=/data/local/tmp/boot1.img of=/dev/block/mmcblk0boot1 bs=4096 count=4; sync; echo 1 > /sys/block/mmcblk0boot1/force_ro'
# dump a partition to host
adb exec-out '/data/metrics/su dd if=/dev/block/by-name/lk bs=4096 2>/dev/null' > lk.img

सत्र 12 — LK RE: eng/unlocked गेट वास्तविक है, और अहस्ताक्षरित फ्लैग स्टोर मौजूद नहीं हैं

लक्ष्य: LK को डिवाइस को eng/unlocked मानने के लिए बाध्य करना, या preloader/LK बग खोजना, ताकि verity/SELinux को स्थायी रूप से अक्षम किया जा सके। परिणाम: प्रासंगिक LK कोड पथ को end-to-end उलट दिया गया; उपलब्ध स्टोर के माध्यम से यह फ्लिप पहुँच से बाहर है। कोई डिवाइस ब्रिक नहीं हुआ; एक boot1 प्रयोग को मूल स्थिति में वापस लाया गया।

LK Thumb-2 PIC है, जो बेस 0xFF400000 पर स्थानांतरित है

lk.img एक छोटे ARM स्टब (फ़ाइल 0x200) से शुरू होता है। 0x224 पर स्थित relocator 0x200 से एक लिटरल गंतव्य तक कॉपी करता है और एक लिटरल एंट्री पर ब्रांच करता है:

इसलिए 0x200 से अधिक या बराबर ऑफ़सेट के लिए रनटाइम एड्रेस = 0xFF400000 + फ़ाइल ऑफ़सेट। स्टब के बाद सब कुछ Thumb-2 है, position-independent। स्ट्रिंग्स ldr rT,[pc,#imm] (T1 ऑफ़सेट = imm8*4; ldr.w ऑफ़सेट = imm12) के बाद add rT, pc से बनाई जाती हैं; लक्ष्य (add+4) + *pool है। एक मजबूत स्कैनर जो ARM स्टब और लिटरल पूल्स को पार कर लेता है, tools/lk_xref.py के रूप में जोड़ा गया (16- और 32-बिट रूपों को संभालता है, हर 2 बाइट्स स्कैन करता है)। नीचे दिए गए सभी ऑफ़सेट फ़ाइल ऑफ़सेट हैं; रनटाइम एड्रेस के लिए 0xFF400000 जोड़ें।

डिकोड किया गया कंट्रोल फ़्लो (ऑफ़सेट -> अर्थ)

अनलॉक कोड Amazon-RSA-हस्ताक्षरित है — जाली नहीं बनाया जा सकता

0x20b4 unlock_code IDME आइटम (0x400 बाइट्स, इस यूनिट पर सभी शून्य) पढ़ता है और amzn_verify_unlock (0x222c -> 0x20f0) चलाता है। वह फ़ंक्शन libtomcrypt को चलाता है (दर्जनों /features/libtomcrypt/src/pk/asn1/der/... पथ और RSA verify), और इमेज में सर्टिफिकेट सामग्री एम्बेडेड है: Sunnyvale / Amazon Lab126 / "$Common Kernel Signing Engineering CA0" 0x317d9+ पर, साथ ही डायग्नोस्टिक्स Image FAILED AUTHENTICATION on PRODUCTION device (0x3166e), Authentication failed on engineering device with production certificate (0x316a0), Image FAILED AUTHENTICATION on ENGINEERING device (0x31703), Image AUTHENTICATED with PRODUCTION certificate (0x31736)। कोई खाली-कोड / लंबाई / संस्करण शॉर्टकट नहीं है: verify(zeros) != 0, इसलिए ( में पुष्टि की गई)। या को फ्लिप करने के लिए या तो एक वैध Amazon-हस्ताक्षरित (निजी कुंजी अनुपलब्ध) या वेरिफायर में एक कोड-एक्ज़ीक्यूशन बग की आवश्यकता होती है। 0x20b4/0x222c/0x20f0 में स्थिर रूप से कुछ भी शोषणीय (bounds/size) नहीं पाया गया। =>

verity/SELinux फ्लैग ऐसे स्टोर से नहीं आते जो मौजूद है

सुरक्षा फ्लैग 0x57c पर गेटर के माध्यम से पढ़े जाते हैं। अनुभवजन्य परीक्षण:```

boot1 IDME item fos_flags data (offset 0x22B4, 8 bytes) set to "00000080"

dd if=/dev/block/mmcblk0boot1 ... ; reboot /proc/idme/fos_flags -> 00000080 (persisted, Android sees it) ro.boot.veritymode -> eio (unchanged!) root=/dev/dm-0 dm="system none ro,0 1 android-verity PARTUUID=..." (unchanged) androidboot.prod=1 / secure_cpu=1 / buildvariant=user (unchanged)

root@kitploit:~
`fos_flags=0x80` `FOS_FLAGS_DM_VERITY_OFF` है; डिकोड किया गया गेट verity को बंद कर देता **अगर** getter ने इसे लौटाया होता। ऐसा नहीं हुआ। गेट जीवित है, डेड कोड नहीं: इसका one-time cache sentinel इमेज में `-1` है
(`*(u32*)0x50c74 == 0xffffffff`), इसलिए फ़ंक्शन ने वास्तव में
`check_flag("fos_flags",0x80)` पथ निष्पादित किया और 0 प्राप्त किया। इसलिए getter (कम से कम
verity-protection समय पर) boot1 IDME आइटम्स को **नहीं** पढ़ रहा है।

अन्य संभावित स्टोर **LK env** है, जो वस्तुतः
`"para"` नामक पार्टीशन से लोड होता है (loader 0x12fd4, magic `ENV_v1`, checksum @0x3ffc)। LK की स्वयं की
पार्टीशन तालिका (0x4fcc0..0x50340) में preloader/proinfo/nvram/protect1/
protect2/persist/seccfg/secro/**para**/logo/custom/expdb/tee1/tee2/metadata/
system/cache/userdata सूचीबद्ध हैं — लेकिन टैबलेट के वास्तविक GPT में **केवल 16 entries** हैं, सभी
प्रकार `af3dc60f838472478e793d69d8477de4` की:

#0 proinfo 0x400 #1 PMT 0x1c00 #2 kb 0x4000 #3 dkb 0x4800 #4 lk 0x5000 #5 tee1 0x5800 #6 tee2 0x8000 #7 metadata 0xa800 #8 MISC 0x1e400 #9 reserved 0x1e800 #10 boot 0x22800 #11 recovery 0x2a800 #12 system 0x34800 #13 vendor 0x644000 #14 cache 0x6b4800 #15 userdata 0x7ae800

root@kitploit:~
इस उत्पाद पर **कोई `para`, `seccfg`, `nvram`, `protect`, या `persist` पार्टीशन नहीं है** (और `PMT`/`pmt.img` डंप सभी शून्य हैं)। इसलिए LK env खाली है, `Kfos_flags`/`Kdev_flags` कुंजियाँ कभी मौजूद नहीं होतीं, और सभी `fos_flags`/`dev_flags` जाँचें 0 पर हल होती हैं — चाहे IDME आइटम में कुछ भी हो। boot1 IDME आइटम Android (`/init.fosflags.sh`, `adbd`, `/proc/idme/*`) द्वारा उपभोग किए जाते हैं, लेकिन LK के सुरक्षा गेट्स द्वारा नहीं।

### निष्कर्ष — स्थायी eng/unlock क्यों अवरुद्ध है
1. `unlocked_kernel` के लिए Amazon-हस्ताक्षरित `unlock_code` (RSA/libtomcrypt, एम्बेडेड CA) आवश्यक है। ऑफ़लाइन जाली नहीं बनाई जा सकती; कोई verifier बग नहीं मिला। **हार्ड ब्लॉक।**
2. `DM_VERITY_OFF` / `selinux=permissive` फ़्लैग LK env (`para`/`ENV_v1`) से उपभोग किए जाते हैं, जो इस GPT पर मौजूद नहीं है। IDME `fos_flags` को LK द्वारा अनुभवजन्य रूप से अनदेखा किया जाता है (0x80 बना रहा, verity `eio` ही रहा)। **हार्ड ब्लॉक** जब तक पार्टीशन टेबल संशोधित न हो।
3. एक सफल `fos_flags=0x80` भी केवल `androidboot.veritymode=disabled` और एक गैर-`dm-0` `root=` सेट करेगा; यह अनलॉक नहीं करेगा, और SELinux को permissive होने के लिए उसी अनुपस्थित env से `dev_flags` की आवश्यकता होगी।
4. इसलिए Track A (बूट-समय पुनः-शोषण) ठीक SESSION 11 की तरह ही अवरुद्ध है: इसका एकमात्र अनलॉक पथ वही LK गेट है।

### शेष मार्ग (भविष्य, उच्च जोखिम; प्रयास नहीं किया गया)
- **एक `para`/`ENV_v1` स्टोर संश्लेषित करें**: `userdata` के बाद खाली स्थान में `para` नाम की GPT प्रविष्टि जोड़ें (प्राइमरी + बैकअप GPT दोनों को अद्यतन करना होगा) (userdata LBA 0x3a3dfde पर समाप्त होता है; डिस्क = 30535680 सेक्टर), फिर `fos_flags=0x80` और `dev_flags=0x40` के साथ एक env बनाएँ (चेकसम +0x3ffc पर = 0x3ffc पर बाइट योग)। verity-off का यह एकमात्र शेष मार्ग है। जोखिम: प्राइमरी/बैकअप GPT को भ्रष्ट करना ब्रिक कर सकता है; और यह **सिद्ध नहीं हुआ** कि verity गेट वास्तव में `para` पढ़ता है (केवल यह कि यह boot1 IDME नहीं है)।
- **Preloader (`boot0`/`EMMC_BOOT`) बग**: इस सत्र में रिवर्स नहीं किया गया। boot0 लिखना तब तक वर्जित है जब तक एक प्राचीन प्रति और एक रिकवरी पथ मौजूद न हो।
- **Verifier शोध**: इंजीनियरिंग-प्रमाणपत्र पथ (0x316a0/0x31703) केवल तभी पहुँच योग्य है जब एक डिवाइस पहचान "इंजीनियरिंग" के रूप में स्वीकृत हो और इंजीनियरिंग कुंजी द्वारा हस्ताक्षरित कोड हो; कोई निजी कुंजी उपलब्ध नहीं है।

### आर्टिफैक्ट्स / पुनरुत्पादकता
- जोड़ा गया टूल: `tools/lk_xref.py` — बेस-स्वतंत्र LK स्ट्रिंग-xref रिज़ॉल्वर।
- उपयोग किए गए डंप: `/tmp/opencode/mustang-dumps/lk.img`, `boot1.img` (प्राचीन), `boot0.img`, `mbr.img` (GPT), `pmt.img` (सभी शून्य)।
- boot1 प्रयोग इमेज (fos_flags=0x80) `/tmp/opencode/s12/boot1_f80.img` पर रखी गई; **डिवाइस प्राचीन boot1 पर पुनर्स्थापित** (सत्यापित `/proc/idme/fos_flags` -> `0`)।

### उपयोगी कमांड (root आवश्यक; `./run.sh` से पुनः-सशस्त्र करें)```
# re-arm runtime root (~1/3 per boot)
./run.sh --no-build

# confirm LK's decisions without a UART
/data/metrics/su /system/bin/sh -p -c 'cat /proc/cmdline'
#   watch: root=/dev/dm-0 dm="system ... android-verity ..."  (verity on)
#          androidboot.veritymode=eio ; androidboot.selinux=enforce ; prod=1

# IDME read (Android copy; NOT what LK's gates use)
for f in fos_flags dev_flags usr_flags unlock_version serial; do cat /proc/idme/$f; echo; done

सत्र 13 — प्रीलोडर अंततः पहुँच योग्य है (1949:20ff = MTK प्रीलोडर, HID ट्रांसपोर्ट)

जब बंद अवस्था में USB में प्लग किया जाता है, तो टैबलेट 1949:20ff (Lab126) के रूप में एन्यूमरेट होता है — न Android और न ही 0e8d:0003 बूटरोम। डिस्क्रिप्टर:``` bInterfaceClass 3 (HID), iConfiguration "HID", iInterface "HID Interface" HID report descriptor = 05 01 09 00 a1 01 c0 (empty collection!) EP 0x81 IN interrupt 4 bytes, bInterval 4 EP 0x01 OUT interrupt 4 bytes, bInterval 4 iSerial = GCC0X90805310009 (the IDME serial)

root@kitploit:~
**पहचान।** `0x20FF` को mtkclient की `config/usb_ids.py` में **"MTK Preloader"** के रूप में सूचीबद्ध किया गया है (MediaTek VID `0x0e8d` के अंतर्गत: `0xe8d:{0x0003 Brom, 0x2000/0x2001/0x20ff/0x3000 Preloader}`)। Amazon ने preloader PID को बनाए रखा और VID को `0x1949` में बदल दिया, तथा इसे एक dummy report descriptor के साथ HID endpoint pair के रूप में प्रस्तुत किया। तो यह **MediaTek preloader / USBDL mode** है, जो LK से *नीचे* का एक चरण है — यहाँ power-off + plug द्वारा पहुँचा जाता है, CMD short द्वारा नहीं।

descriptor strings "HID"/"HID Interface" `lk.img`, `boot0.img`, `boot.img` या अन्य dumps में मौजूद नहीं हैं, अर्थात् यह mode किसी ऐसे component द्वारा उत्पन्न होता है जिसे हमने dump नहीं किया (bootrom/TEE) या runtime पर assembled होता है।

**यह क्यों मायने रखता है।** `aftv2-tools` द्वारा उपयोग किया जाने वाला Amazon preloader इसी exact byte stream पर built-in, **Download-Agent-less** commands को expose करता है:```
handshake : host A0 0A 50 05 -> dev 5F F5 AF FA
0xD1 read32 (addr, n_words)  : echo cmd/addr/n, 00 00, n*u32, 00 00
0xD4 write32(addr, words[])  : echo cmd/addr/n, 00 00, n*u32, 00 00

aftv2-tools/read_mmc.py read32/write32 का उपयोग MSDC कंट्रोलर को पोक करने के लिए करता है (MT8173 पर बेस 0x11230000; MT8163 के लिए सत्यापित करें) और raw eMMC ब्लॉक को पढ़ता/लिखता है, बिना DA के और इस प्रकार बिना AVB/verity के रास्ते में। यदि mustang का preloader 0xD1/0xD4 स्वीकार करता है, तो यह स्थायी अनलॉक (patch boot / lk) का सीधा रास्ता है, जो RSA अनलॉक कोड और अनुपस्थित LK env से स्वतंत्र है।

जोड़े गए टूल्स (root आवश्यक; पहले USB नोड को chmod करें)```

lsusb -d 1949:20ff # note Bus/Dev, e.g. Bus 001 Device 003 sudo chmod 666 /dev/bus/usb/001/003

1) does it answer the MTK handshake? (no DA, no flash access)

nix-shell -p python3Packages.pyusb --run
'python3 tools/mtk_preloader_hid.py handshake'

2) read-only arbitrary memory read

nix-shell -p python3Packages.pyusb --run
'python3 tools/mtk_preloader_hid.py read32 0x00100000 4'

root@kitploit:~
`tools/probe_preloader.py` न्यूनतम handshake-only probe है;
`tools/mtk_preloader_hid.py` पूर्ण transport है (`handshake`/`read32`/
`write32`; `write32` guarded है और eMMC register map की पुष्टि होने तक इसका उपयोग नहीं किया जाना चाहिए)।

### स्थिति / अगले कदम
- **अपुष्ट**: क्या mustang का preloader वास्तव में 0xD1/0xD4 implement करता है
  (handshake probe यह तय करता है)। यदि करता है, तो aftv2 eMMC read/write
  path संभवतः सीधे port किया जा सकता है।
- फिर: MT8163 MSDC base खोजें (kernel DT या preloader), एक partition dump करें
  (`read_mmc`), फिर preloader से `boot.img`/`lk` patch करें और reboot करें।
- यह SESSION 12 में सब कुछ से *निचला* boot stage है, इसलिए यह
  `amzn_verify_unlock` या LK env gate पर निर्भर नहीं करता।
- protocol और eMMC layout की पुष्टि होने से पहले इसके विरुद्ध SP Flash Tool / mtkclient writes न चलाएँ।
टूल डाउनलोड करें
pi_blocked_on
  • Proxy waiter waiter thread के अपने stack पर रहता है (futex.c:1975 this->rt_waiter pass करता है, जो futex_wait_requeue_pi में futex.c:2880 पर declared है) → waiter arm32 select (nr 142) fd_sets के ज़रिए अपना ही freed frame stamp करता है
  • Exploitation climate: no KASLR (fixed base 0xc0008000), no PAN, DEBUG_RT_MUTEXES off → compact 48-byte rt_mutex_waiter (tree_entry@0, pi_tree_entry@0xc, task@0x18, lock@0x1c, prio@0x20, deadline@0x28)
  • Minimal chain: 2 write-slots → modprobe_path @ 0xc111488c (string vmlinux में self-located; KALLSYMS_ALL off इसलिए data symbols को यह trick चाहिए) → unknown-binfmt exec → root script (setenforce 0, disable OTA, su)
  • refs/ में references: NebuSec/CyberMeowfia (original), GhostLock-5.10 (Fire OS 8 port, src/exp32/ में पूरा 32-bit ARM trigger), ghostlock-...-4.19-k40 (Qualcomm 4.19 Android port)
  • selroot
    selinux_state.enforcing
    commit_creds(&init_cred)
    uid=0
  • [_] Stage 4: root script (su, permissive, OTA off) + persistence — root प्राप्त; persistence blocked (SESSION 11 देखें): LK verity-off/SELinux-permissive को eng/unlocked पर gate करता है, boot-time re-exploit के पास कोई viable executor नहीं है। अगला: reverse LK/amzn_verify_unlock.
  • Stage 5: custom OS boot chain
  • jc
    nr_extres
  • JIT alloc result kernel द्वारा info->gpu_alloc_addr के ज़रिए लिखा जाता है (एक GPU VA जिसे आपको pre-allocate करके pass करना होता है)
  • evictable objectpressureresult
    none900 MBsurvived
    none1300 MBpanic (system lowmem bug — unrelated)
    normal region + DONT_NEED700 MBsurvived
    JIT region + DONT_NEED700 MBpanic in reclaim path
  • kernel/config-* — running device से /proc/config.gz dump
  • ksrc/ — Amazon OSS source (platform.tar + extracted midgard-r26p0 tree)
  • OTA: /tmp/opencode/mustang_ota.bin (sha256 6068515a… fireos-archive से match करता है) और 2.2 GB kernel-source tarball ~/Desktop/amazon-mustang/ पर रखा है
  • Source tree path: ksrc/kernel/mediatek/mt8163/4.9/drivers/misc/mediatek/gpu/gpu_mali/mali_midgard/midgard-r26p0/
  • renames stall (journal/GFP_NOFS) → 128 total → garbage deref
    pre-drain 12K events + pressure + small trailingcrash at deref
    + kill-child-at-eviction (10ms poll)crash at deref
    + cpu0-pinned lifecycle (drain3)crash at deref
    stepped pressure (drain4 v1)children freed memory on exit → no eviction (validated legal path)
    runपरिणाम
    pmap G=c2a412a4 400MBderef पर क्रैश
    pmap G=c2f4b2a4 480MBक्रैश; +0 post-kill renames (480MB fs को घुटता है)
    iso2 (spray + regions + oracle)REGION HIT — स्प्रे reclaim नहीं तोड़ता
    mix v1 (समवर्ती events+regions)क्रैश; confounded (घूमते event थ्रेड्स)
    pmap G=c2a7d2a4 350MB + retouchक्रैश; +4452 renames OK
    mix2 (क्रमिक: 2s events फिर regions)क्रैश; +7126 renames (28K event allocs), 2715 regions
    fn=0
    cell address
    PM_PAGE+NF_CELL_OFF
    probe
  • Physmap direct map kernel_x_end के ऊपर XN है: arch/arm/mm/mmu.c map_lowmem() lowram को kernel text MT_MEMORY_RWX के नीचे map करता है, लेकिन kernel_x_end के ऊपर सब कुछ MT_MEMORY_RW → PMD_SECT_XN (line 509)। 0xc154b600 पर baked shellcode prefetch-abort करता है। Payload एक असली kernel function pointer होना चाहिए, physmap में code नहीं।
  • लिटरल (फ़ाइल ऑफ़सेट)मानअर्थ
    0x2700xFF4002F8str r4,[r6] स्क्रैच
    0x2740xFF40027Cगंतव्य (base+0x27C)
    0x2780xFF54A440कॉपी अंत (BSS सहित)
    0x27C0xFF400484एंट्री पॉइंट
    ऑफ़सेटफ़ंक्शन
    0xdf7cis_secure_or_prod() -> byte[ [[g]+0 ] + 0x163 ]; g = global @0x52838। इस यूनिट पर 1।
    0x20b4verify_stored_unlock() = memset(buf,0,0x100); 0x57c के माध्यम से IDME/env unlock_code (0x100) पढ़ता है; bl 0x222c; (verify==0) लौटाता है।
    0x222c / 0x20f0amzn_verify_unlock(code,len) — libtomcrypt RSA/PKCS#1 verify (नीचे देखें)।
    0xda3eis_unlocked() = is_secure_or_prod() && verify_stored_unlock()।
    0x29a28is_verity_disabled() = (fos_flags & 0x80) && !(is_secure_or_prod() && verify_stored_unlock()); global @0x50c74 में कैश किया गया।
    0x29974SELinux cmdline बिल्डर: dev_flags & 0x20 -> androidboot.selinux=enforce, dev_flags & 0x40 -> ...=permissive (प्रत्येक byte[+0x162] द्वारा गेटेड)।
    0x118xx/0x11bxxkernel cmdline बिल्डर (unlocked_kernel, prod=1/0, verifiedbootstate, rpmb_state, secure_cpu, संस्करण, root=)।
    0x27af8UART गेट: fos_flags & 0x4 -> printk.disable_uart=0, अन्यथा =1।
    0x12fd4LK env लोडर: पार्टीशन "para", 0x4000 बाइट्स, मैजिक ENV_v1, चेकसम = 0x3ffc पर वर्ड की तुलना में 0x3ffc पर बाइट्स का योग।
    0x1efd0नाम से पार्टीशन लुकअप ("para", "boot", ... के लिए उपयोग किया जाता है)।
    0x57cकॉलबैक स्लॉट @0x58218 के माध्यम से गेटर डिस्पैचर; स्लॉट @0x58200..0x5821c 0x5a8-0x734 पर एक टेबल से रजिस्टर किए जाते हैं।
    0x2a19cfastboot oem unlock: bl 0x222c(code,len); सफल होने पर 0x408 के माध्यम से unlock_code (0x100) लिखता है।
    unlocked_kernel=false
    /proc/cmdline
    androidboot.unlocked_kernel
    androidboot.prod
    unlock_code
    प्रलेखित पथ के माध्यम से eng/unlocked फ्लिप क्रिप्टोग्राफ़िक रूप से असंभव है।