Linux arm64 Static Linear Map KASLR Bypass

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

अवलोकन

arm64 के लिए बने Android kernels लगभग सार्वभौमिक रूप से CONFIG_ARM64_VA_BITS=39 (3-level paging) और CONFIG_MEMORY_HOTPLUG=y सक्षम करते हैं। केवल 512 GiB kernel virtual space उपलब्ध होने के कारण, Linux developers ने भविष्य में hot-plugged RAM को ऊपर की ओर mapping बढ़ाने की सुविधा के लिए linear map को संभवतः सबसे निचले kernel VA पर anchor करने का निर्णय लिया।

commit 1db780bafa4c के बाद, arm64 उस placement को randomize करने का प्रयास भी नहीं करता, जिसका अर्थ है:

  • PAGE_OFFSET = 0xffffff8000000000 संकलित किया गया है।
  • PHYS_OFFSET exported memstart_addr से आता है, जो stock Android devices पर प्रभावी रूप से constant है (आज 0x80000000)।

परिणामस्वरूप, हर physical page का deterministic linear-map virtual address होता है जो KASLR slide से स्वतंत्र है:

#define phys_to_virt(p) (((unsigned long)(p) - 0x80000000UL) | 0xffffff8000000000UL)

यदि कोई attacker किसी physical address (kernel object, PFN from /proc/pagemap, or even a user-controlled page) को सीख या प्रभावित कर सके, तो वे तुरंत संबंधित kernel virtual address जान लेते हैं बिना randomized primary kernel mapping को leak किए।

memstart_addr को पढ़ना और रूपांतरण की पुष्टि

memstart_addr /proc/kallsyms में export किया गया है और rooted devices पर या किसी भी arbitrary kernel-read primitive के जरिए पढ़ा जा सकता है। Project Zero ने Jann Horn के tracing-BPF helper (bpf_arb_read) का उपयोग करके इसे सीधे dump किया:

grep memstart /proc/kallsyms
# ... obtains memstart_addr virtual address
./bpf_arb_read <addr_of_memstart_addr> 8

The bytes 00 00 00 80 00 00 00 00 पुष्टि करते हैं कि memstart_addr = 0x80000000। एक बार जब PAGE_OFFSET और PHYS_OFFSET पिन हो जाते हैं, तो arm64 linear map किसी भी physical address का एक स्थिर affine रूपांतरण होता है।

Deriving stable .data addresses on devices with a fixed kernel physbase

कई Pixels अभी भी हर बूट पर kernel को phys_kernel_base = 0x80010000 पर decompress करते हैं (देखने योग्य: /proc/iomem)। इसे static transform के साथ मिलाकर किसी भी data symbol के लिए cross-reboot-stable addresses मिलते हैं:

  1. /proc/kallsyms (या exact vmlinux) से _stext और अपने target symbol के randomized kernel virtual address को रिकॉर्ड करें।
  2. ऑफ़सेट निकालें: offset = sym_virt - _stext_virt
  3. static boot-time physbase जोड़ें: phys_sym = 0x80010000 + offset
  4. इसे linear-map VA में बदलें: virt_sym = phys_to_virt(phys_sym)

उदाहरण (modprobe_path on a Pixel 9): offset = 0x1fe2398, phys = 0x81ff2398, virt = 0xffffff8001ff2398। कई reboots के बाद, bpf_arb_read 0xffffff8001ff2398 वही बाइट्स लौटाता है, इसलिए exploit payloads सभी .data ऑफ़सेट्स के लिए 0xffffff8000010000 को एक synthetic, non-randomized base की तरह मान सकते हैं।

यह mapping RW है, इसलिए कोई भी primitive जो attacker data को kernel virtual space में रख सके (double free, UAF, non-paged heap write, आदि) credentials, LSM hooks, या dispatch tables को patch कर सकता है बिना कभी true KASLR slide को leaking किए। एकमात्र प्रतिबंध यह है कि .text linear map में non-executable मैप्ड है, इसलिए gadget hunting के लिए अभी भी पारंपरिक leak की आवश्यकता रहती है।

PFN spraying when the kernel physbase is randomized

Vendors जैसे Samsung kernel load PFN को randomize करते हैं, लेकिन static linear map अभी भी abusable है क्योंकि PFN allocation पूरी तरह से random नहीं होती:

  1. Spray user pages: mmap() ~5 GiB, हर पेज को touch करके fault करा लें।
  2. Harvest PFNs: हर पेज के लिए /proc/pagemap पढ़ें (या किसी अन्य PFN leak का उपयोग करें) ताकि backing PFN सूची इकट्ठा हो सके।
  3. Repeat and profile: reboot करें, 100× फिर से चलाएँ, और एक histogram बनाएं जो दिखाए कि कौन से PFN कितनी बार attacker-controlled रहे। कुछ PFNs white-hot होते हैं (boot के तुरंत बाद 100/100 बार allocate होते हैं)।
  4. Convert PFN → kernel VA:
  • phys = (pfn << PAGE_SHIFT) + offset_in_page
  • virt = phys_to_virt(phys)
  1. Forge kernel objects उन pages में और victim pointers (UAF, overflow, आदि) को ज्ञात linear-map addresses की ओर मोड़ें।

क्योंकि linear map identity-mapped RW memory है, यह technique आपको deterministic kernel VAs पर पूरी तरह attacker-controlled data रखने देती है भले ही real kernel base हिल रहा हो। Exploits sprayed pages के अंदर fake file_operations, cred, या refcount structures पहले से बना सकते हैं और फिर मौजूद kernel pointers को उनपर pivot कर सकते हैं।

Practical workflow for arm64 Android exploits

  1. Info gathering
  • root हों या kernel read primitive का उपयोग करके memstart_addr, _stext, और target symbol को /proc/kallsyms से dump करें।
  • Pixels पर, /proc/iomem से static physbase पर भरोसा करें; अन्य डिवाइसों पर PFN profiler तैयार रखें।
  1. Address calculation
  • ऊपर दिए ऑफ़सेट गणित को लागू करें और अपने exploit में resulting linear-map VAs को cache करें।
  • PFN spraying के लिए, उन “reliable” PFNs की सूची रखें जो बार-बार attacker memory में land होते हैं।
  1. Exploit integration
  • जब arbitrary write उपलब्ध हो, तो सीधे precomputed addresses पर modprobe_path, init_cred, या security ops arrays जैसे targets को patch करें।
  • जब केवल heap corruption मौजूद हो, तो known-supervised pages में fake objects बनाएं और victim pointers को उन linear-map VAs की ओर repoint करें।
  1. Verification
  • destructive writes से पहले यह sanity-check करने के लिए bpf_arb_read या किसी सुरक्षित read primitive का उपयोग करें कि computed address Expected bytes ही रखता है।

यह workflow Android पर data-centric kernel exploits के लिए KASLR-leak चरण को समाप्त कर देता है, जिससे exploit complexity काफी घटती है और reliability बढ़ती है।

References

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें