CONFIG_RANDSTRUCT Architecture Simulator Category 6: Structure Hardening

Compile-time Structure Member Layout Randomization against Fixed-Offset Attacks

배속:
CONFIG_RANDSTRUCT Active: Structure Layouts Shuffled via 256-bit Seed
ATTACKER PROCESS (Ring 3 / EL0) 공격자 고정 오프셋 가정 (헤더 분석) Standard C struct cred / victim: • Offset 16 -> uid (4B, root=0) • Offset 40 -> callback (8B ptr) 사전 컴파일된 고정 오프셋 악용 임의 쓰기 익스플로잇 페이로드 Write to [Base + 16]: 0x00000000 (uid -> root) Write to [Base + 40]: 0xffff8000... (shellcode) 공격 메커니즘 특성 • 표준 리눅스 ABI 고정 레이아웃 가정 • 임의 쓰기 원시값(Primitive)으로 특정 오프셋의 uid / 함수 포인터 덮어씀 • KASLR과 무관하게 구조체 내부 타깃 KERNEL STRUCTURE LAYOUT (struct victim_struct, 48B) Offset 00..07 [8B] uint64_t magic 0x56494354494d3031 Offset 08..15 [8B] void (*privileged_op)(void) safe_handler() Offset 16..19 [4B] 🎯 Attacker Target char session_token[0..3] "AUTH" (안전) Offset 20..23 [4B] uint32_t gid gid=1000 Offset 24..35 [12B] char session_token[4..15] "ENTIC_USER!" Offset 36..39 [4B] 🛡️ Shuffled UID Slot uint32_t uid uid=1000 (보호됨) Offset 40..47 [8B] 🎯 Attacker Target 2 void (*callback)(void) normal_callback() EXPLOIT OUTCOME 🛡️ DEFENSE ACTIVE 고정 오프셋 공격 실패! Offset 16은 uid가 아님 session_token 덮어씀 g_victim.uid = 1000 권한 상승 차단 성공 CONFIG_RANDSTRUCT=y 256-bit Random Seed Per-build Layout Shuffle 실제 struct cred 오프셋 cred->uid : %zu cred->gid : %zu cred->euid : %zu cred->caps : %zu 빌드마다 오프셋 재배치됨 하드코딩 root 공격 무력화

🎯 고정 오프셋 공격(Fixed-Offset Attacks)의 원리

전통적인 커널 익스플로잇은 타깃 시스템의 구조체 멤버 배치가 C 언어 소스코드 선언 순서와 정확히 일치한다는 점을 악용합니다.

// 공격자의 전형적인 임의 쓰기 페이로드: *(uint32_t*)(cred_addr + 16) = 0; // uid = 0 (root 권한 탈취) *(uint64_t*)(fops_addr + 40) = shellcode; // 함수 포인터 하이재킹

공격자는 공개된 커널 헤더나 vmlinux 바이너리에서 오프셋을 사전에 계산하여 한 번에 권한을 탈취합니다.

🛡️ CONFIG_RANDSTRUCT의 무작위화 방어

컴파일 시점(Build-time)에 256비트 암호학적 난수 시드(randstruct.seed)를 생성하여 __randomize_layout 구조체 멤버를 뒤섞습니다.

  • 무작위화 대상: __randomize_layout이 명시된 구조체(struct cred 등) 및 함수 포인터로만 구성된 구조체(struct file_operations 등).
  • 공격 차단: 공격자가 Offset 16에 0을 덮어쓰더라도 해당 위치는 uid가 아닌 토큰이나 패딩이므로 권한 상승이 완전히 실패함.
  • 빌드 고유성: 배포판 커널 빌드마다 시드가 다르므로 단일 익스플로잇으로 모든 시스템을 공격하는 것이 불가능함.

⚡ GCC 플러그인 vs Clang 16+ 네이티브 구현

과거 PaX/Grsecurity의 GCC 플러그인에서 시작하여 현대 Clang 컴파일러로 표준화되었습니다.

  • Clang 16+ (LLVM=1): -frandomize-layout-seed-file 옵션으로 네이티브 레이아웃 셔플링 지원. 크로스 컴파일(ARM64, x86_64)에 이상적임.
  • GCC 플러그인: scripts/gcc-plugins/randomize_layout_plugin.c를 통해 지원되나 플러그인 헤더 패키지 필요.
  • 성능 영향: 구조체 멤버 배치에 따른 캐시 미스(Cache Miss) 증가로 약 1% 미만의 미세한 오버헤드만 발생함.