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로 제한되어 있기 때문에, Linux 개발자들은 향후 핫플러그된 RAM이 매핑을 위로 확장할 수 있도록 linear map을 가능한 가장 낮은 커널 VA에 고정(anchor)하도록 결정했습니다. 커밋 1db780bafa4c 이후, arm64는 해당 위치를 무작위화하려는 시도조차 하지 않으며, 이는 다음을 의미합니다:

  • PAGE_OFFSET = 0xffffff8000000000가 컴파일되어 포함됩니다.
  • PHYS_OFFSET는 export된 memstart_addr에서 가져오며, stock Android 디바이스에서는 사실상 불변(오늘날 0x80000000)입니다.

결과적으로, 모든 물리 페이지는 KASLR slide와 무관한 결정론적 linear-map 가상 주소를 갖습니다:

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

If an attacker can learn or influence a physical address (kernel object, PFN from /proc/pagemap, or even a user-controlled page), they instantly know the corresponding kernel virtual address without leaking the randomized primary kernel mapping.

memstart_addr 읽기 및 변환 확인

memstart_addr/proc/kallsyms에 export되어 있으며 루팅된 기기나 임의의 kernel-read primitive를 통해 읽을 수 있다. Project Zero는 Jann Horn의 tracing-BPF helper (bpf_arb_read)를 사용해 이를 직접 덤프했다:

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

바이트 00 00 00 80 00 00 00 00memstart_addr = 0x80000000을(를) 확인한다. PAGE_OFFSETPHYS_OFFSET가 고정되면, arm64 linear map은 모든 물리 주소에 대해 정적인 affine 변환이 된다.

고정된 kernel physbase를 가진 장치에서 안정적인 .data 주소 유도

많은 Pixel 기기들은 여전히 매 부팅마다 커널을 phys_kernel_base = 0x80010000 에 압축 해제한다(/proc/iomem에서 확인 가능). 이를 정적 변환과 결합하면 어떤 데이터 심볼에 대해서도 재부팅 간에 안정적인 주소를 얻을 수 있다:

  1. /proc/kallsyms(또는 정확한 vmlinux에서) _stext와 대상 심볼의 랜덤화된 kernel 가상 주소를 기록한다.
  2. 오프셋을 계산한다: offset = sym_virt - _stext_virt.
  3. 부팅 시 고정 physbase를 더한다: phys_sym = 0x80010000 + offset.
  4. linear-map VA로 변환한다: virt_sym = phys_to_virt(phys_sym).

예시(Pixel 9의 modprobe_path): offset = 0x1fe2398, phys = 0x81ff2398, virt = 0xffffff8001ff2398. 여러 번 재부팅한 후 bpf_arb_read 0xffffff8001ff2398는 동일한 바이트를 반환하므로, 익스플로잇 페이로드는 모든 .data 오프셋에 대해 0xffffff8000010000을 합성된, 비난수화된(base) 베이스로 취급할 수 있다.

이 매핑은 RW이므로, 공격자 데이터를 kernel 가상 공간에 놓을 수 있는 어떤 primitive(예: double free, UAF, non-paged heap write 등)도 실제 KASLR slide를 leak하지 않고 credentials, LSM hooks, 또는 dispatch tables를 패치할 수 있다. 유일한 제약은 .text가 linear map에서 비실행(non-executable)으로 매핑되어 있어 gadget 수집에는 여전히 전통적인 leak이 필요하다는 점이다.

kernel physbase가 랜덤화된 경우 PFN spraying

Samsung과 같은 벤더들은 kernel 로드 PFN을 랜덤화하지만, PFN 할당이 완전히 랜덤하지 않기 때문에 static linear map은 여전히 악용 가능하다:

  1. Spray user pages: mmap()로 약 5 GiB를 확보하고, 모든 페이지를 접근하여 fault를 발생시킨다.
  2. Harvest PFNs: 각 페이지에 대해 /proc/pagemap을 읽거나(또는 다른 PFN leak을 사용하여) backing PFN 목록을 수집한다.
  3. Repeat and profile: 재부팅하고 100× 재실행하여 각 PFN이 공격자 제어로 할당되는 빈도를 보여주는 히스토그램을 만든다. 일부 PFN은 white-hot하다(부팅 직후 100/100 번 할당됨).
  4. Convert PFN → kernel VA:
  • phys = (pfn << PAGE_SHIFT) + offset_in_page
  • virt = phys_to_virt(phys)
  1. Forge kernel objects in those pages and victim 포인터(UAF, overflow 등)를 알려진 linear-map 주소로 유도한다.

linear map이 identity-mapped RW 메모리이기 때문에, 이 기법은 실제 kernel base가 이동해도 결정론적인 kernel VA에 완전한 공격자 제어 데이터를 배치할 수 있게 해준다. 익스플로잇은 스프레이된 페이지 내부에 가짜 file_operations, cred, 또는 refcount 구조체를 미리 만들어 두고 기존 kernel 포인터를 그쪽으로 피벗할 수 있다.

arm64 Android 익스플로잇을 위한 실전 워크플로

  1. Info gathering
  • Root 권한을 얻거나 kernel read primitive를 사용해 /proc/kallsyms에서 memstart_addr, _stext, 대상 심볼을 덤프한다.
  • Pixel에서는 /proc/iomem의 static physbase를 신뢰하고, 다른 기기에서는 PFN profiler를 준비한다.
  1. Address calculation
  • 위의 offset 연산을 적용하고 결과 linear-map VA를 익스플로잇에 캐시한다.
  • PFN spraying의 경우, 공격자 메모리에 반복적으로 들어오는 “reliable” PFN 목록을 유지한다.
  1. Exploit integration
  • arbitrary write가 가능하면 미리 계산한 주소에서 modprobe_path, init_cred, 또는 security ops 배열과 같은 타겟을 직접 패치한다.
  • heap corruption만 존재할 경우, 알려진 감시 페이지들에 가짜 객체를 만들고 피해자 포인터를 그 linear-map VA로 재지정한다.
  1. Verification
  • 파괴적 쓰기 전에 bpf_arb_read 또는 임의의 안전한 read primitive로 계산한 주소가 예상 바이트를 포함하고 있는지 확인한다.

이 워크플로는 Android에서 데이터 중심 kernel 익스플로잇에 대해 KASLR-leak 단계를 제거하여 익스플로잇 복잡도를 크게 낮추고 신뢰성을 향상시킨다.

참고자료

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 지원하기