Written by reset + s0ngsari

최근 많은 연구들이 Windows 운영체제에 초점이 맞추어져 있지만, 보안적인 측면에서 아이폰과 맥북에 탑재되는 iOS와 macOS를 빼놓을 수 없다. 이번 블로그 시리즈를 통해서 OS X 커널에서의 버그 분석 및 익스플로잇 기법 등을 알아본다.

(1) 커널 버그 찾기

  • BSD, Mach와 IOKit 등 과 같은 커널 레벨에서 실행 가능한 버그를 퍼징, 소스코드 오디팅과 같은 방법을 통해 발견함.
  • BSD : 커널의 BSD 부분은 대부분의 시스템 호출, 네트워킹 및 파일 시스템 기능을 제공함. FreeBSD 5에서 가져온 소스.
  • Mach : Carnegie Mellon University에서 개발 된 Mach 3.0 마이크로 커널에서 파생되어짐. 메모리 맵 및 IPC 와 같은 기본 서비스를 구현함. 사용자 공간 프로그램은 마하 트랩을 통해 마하 서비스에 액세스 가능.
  • IOKit : IOKit은 XNU용 드라이버를 작성하는 C++로 작성된 프레임워크이며, Apple은 libkern이라는 자체 런타임 시스템을 제공함.

(2) Exploit Primitive(s)

  • Arbitrary Read / Write를 이용해 취약점을 공략하는데에 있어서 필요한 데이터를 획득 하거나, 커널 영역에 임의의 데이터를 작성함.
  • 이는 버그 별로 상이한 데이터이기 때문에, Read / Write 로 공격시 이용할 수 있는 데이터를 사용해야함.

(3) 커널 권한 획득 & AAR / AAW in Kernel

  • kernel_task(pid=0)의 권한을 위해 필요한 값 ipc object와 kernel task를 획득하기 위해 커널에 존재하는 모든 프로세스를 트레버싱 한 후 유저 영역에 데이터를 덤프 한다.
  • 이를 이용해, 커널 레벨에서 Read / Write를 할 수 있다.

(4) 루트 권한 획득

  • 각각의 프로세스가 커널 메모리에 적재되어 있기 때문에, 타겟 프로세스를 잡아서 아래의 프로세스 권한 구조체의 CR_RUID(Credential Real UID)를 0으로 변경 [bsd/sys/ucred.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
 * In-kernel credential structure.
 *
 * Note that this structure should not be used outside the kernel, nor should
 * it or copies of it be exported outside.
 */
struct ucred {
    TAILQ_ENTRY(ucred)  cr_link; /* never modify this without KAUTH_CRED_HASH_LOCK */
    u_long  cr_ref;         /* reference count */

struct posix_cred {
    /*
     * The credential hash depends on everything from this point on
     * (see kauth_cred_get_hashkey)
     */
    uid_t   cr_uid;         /* effective user id */
    uid_t   cr_ruid;        /* real user id */
    uid_t   cr_svuid;       /* saved user id */
    short   cr_ngroups;     /* number of groups in advisory list */
    gid_t   cr_groups[NGROUPS]; /* advisory group list */
    gid_t   cr_rgid;        /* real group id */
    gid_t   cr_svgid;       /* saved group id */
    uid_t   cr_gmuid;       /* UID for group membership purposes */
    int cr_flags;       /* flags on credential */
} cr_posix;
    struct label    *cr_label;  /* MAC label */
    /*
     * NOTE: If anything else (besides the flags)
     * added after the label, you must change
     * kauth_cred_find().
     */
    struct au_session cr_audit;     /* user auditing data */
};
  • 변경이 완료되면, 해당 프로세스는 root 권한으로 돌아가는 상태가 되어짐.
  • 따라서, system(“/bin/bash”); 를 실행해 준다면 루트 권한의 쉘을 획득할 수 있음. (Local Privilege Escalation)


배경 지식

Kernel Zone

  • OS X 의 커널에서는 힙이 할당되는 Zone이라는 구조를 사용하고 있음.
  • Zone은 zalloc(zone), kalloc(size)를 이용해 할당되어지며, zfree(zone, ptr), kfree(ptr,size)를 이용해 해제 되어짐.
  • kalloc 호출시, zalloc이 내부 호출 됨. 또한 kalloc zone은 sudo zprint kalloc 를 통해 확인 가능함.
  • zone metadata : 페이지 첫번째에 들어가있는 zone의 정보로 size, page_count, alloc_element, free_element 등을 가지고 있다.

OOL(Out-Of-Line) Port

  • IPC 통신에서 발생하는 인라인이 아닌 패킷을 적재
  • OOL 데이터를 수신하기 전까지 커널에서 보존되어짐.
  • 주로 OS X Kernel Exploit을 할 때, fakeport를 만들기 위해 OOL을 Leak 시킴으로써 공격을 함
  • 따라서, OOL Leak을 완화시키기 위한 보안 패치가 자주 이루어짐.


OS X Kernel Mitigation

kASLR

  • 부팅에 따른 커널 메모리 주소 랜덤화
  • Kext(Kernel Extension)와 커널은 같은 슬라이드를 공유함
  • 우회 : kslide 주소 계산 (kslide = kernel_base - kernel text base)
  • kslide : 바이너리 상의 주소와 실제 주소의 차이

DEP

  • 커널에서의 RWX 권한 방지
  • 우회 : ROP

SMEP / SMAP

  • 인텔 CPU에서 제공하는 커널 메모리 보호 기법
  • SMEP(Supervisor Mode Execution Protection) : 유저 영역 주소 공간에서 커널 코드 실행 불가
  • SMAP(Supervisor Mode Access Protection) : 유저 영역 주소 공간에서 메모리 액세스를 허용하지 않음. 단, 지원되는 CPU 아키텍처에서만 사용 가능
  • 우회 : 커널에서 우회 가능한 ROP 시행

vm_map_copy() 변화

  • OS X 10.11 El Capitan 이전의 커널 익스플로잇은, 오버플로우 취약점을 이용해 vm_map_copy의 kdata 포인터 및 size를 공략하여 임의 데이터 읽기를 시도했으나, 이는 구조가 변경됨으로써 보완 되었음. (osfmk/vm/vm_map.h)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 변경 전
struct vm_map_copy{
    int type;
    #define VM_MAP_COPY_ENTRY_LIST      1
    #define VM_MAP_COPY_OBJECT          2
    #define VMMAP_COPY_KERNEL_BUFFER    3
    vm_object_offset_t offset;
    vm_map_size_t size;
    union {
        struct vm_map_header    hdr;
        vm_object_t             object;
        struct { // <<= Before Change
            void *kdata;
            vm_size_t kalloc_size;
        }c_k;
    }c_u;
};

// 변경 후
struct vm_map_copy{
    int type;
    #define VM_MAP_COPY_ENTRY_LIST 1
    #define VM_MAP_COPY_OBJECT 2
    #define VM_MAP_COPY_KERNEL_BUFFER 3
    vm_object_offset_t offset;
    vm_map_size_t size;
    union{
        struct vm_map_header hdr;
        vm_object_t object;
        uint8_t kdata[0]; // <<= Changed
    }
}
  • 단, OS X 10.11 El capitan의 ipc_kmsg_copyout_ool_descriptor()에서 레이스 컨디션 기법을 이용해 우회한 사례가 있음. (현재 구조 패치 되었음.)


기타

  • iOS와 macOS의 구조 및 보안에 대한 패치가 상당히 비슷하므로, 보통 함께 공략 가능.
  • 완벽한 오버플로우 버그가 아니라면 공격하기 까다로움.
  • 많은 버그들이 리모트 공격으로부터 도달하기 어려워짐. (e.g., 사파리 취약점을 넘어서 커널 권한 획득 까지 가는데 있어서 도달 과정)
  • 이전 버전의 OS X에서는 널 포인터에 데이터를 작성함으로써, 상대적으로 간단하게 LPE가 가능하였으나 (아래 소스 참조), 현재는 불가한 상태임.
1
2
3
4
5
6
7
8
9
10
11
12
void null_page(){
  sync();
  vm_address_t addr=0;
  vm_deallocate(mach_task_self(),0x0,0x1000);
  vm_allocate(mach_task_self(),&addr,0x1000,0);

  uint64_t * np=0;
  for(int i=1;i<0x100;i++)
  {
    np[i] = 0x4141414141414141;
  }
}
  • iOS 9.2, macOS 10.11 이후부터 재 할당되는 메모리 위치를 쉽게 예측할 수 없음. (freelist randomization)
  • iOS 10, macOS 10.12 의 버전에서 애플이 vm_map_size(vm_map_copy)를 변경하여 힙 공격하는 것도 보안 패치 됨.


KERNEL DEBUGGING

Introduction

커널 크래쉬가 나면, OS가 멈추기때문에 하나의 로컬에서는 디버깅을 하지 못하고 VM으로 kdp를 사용하여 디버깅을 해야한다.때문에 하나이상의 VM은 무조건 설치해야 한다. OS X에서 ‘Parallels Desktop’을 사용 한다면 복구파티션을 이용해 OSX VM을 설치 할 수 있다. 원하는 OSX 버전이 있다면 이미지파일 혹은 VM을 검색을 통해 설치하는 방식으로 하면 된다.

Host에서 디버깅을 하기위해 여러가지 환경 구성을 해야하는데, 우선 Kernel Debug Kit 을 다운로드 해야한다. Kernel Debug Kit은 LLDB 혹은 GDB로 어떠한 커널을 디버깅할때 기본적으로 없는 심볼을 로드해 디버깅 할 수 있게 해준다. 커널 바이너리를 직접 분석해 1day를 구경하고싶다면, OSX 버전 업데이트없이 Kernel Debug Kit을 이용하여 바이너리를 분석하면 된다.


Host Setting

https://developer.apple.com/download/more/?=Kernel%20Debug%20Kit

각 버전별로 공유되고있어, 분석하고있는 1-day의 버전에 맞춰 다운로드 받으면 된다. 다운로드한 dmg파일을 실행하여 설치하면 /Library/Developer/KDKs/ 경로에 디버그 킷이 존재한다.

OSX에서 실행되는 커널 바이너리는 /System/Library/Kernels/kernel 에 존재한다. 해당 바이너리를 디버거에 붙혀도 되지만 위 처럼 킷을 설치하는 환경구성은 Host와 Guest의 OSX버전이 달라도 커널디버깅을 할 수 있게 한다.

이제 Host에서 LLDB만 조금 손봐주면 Host의 환경구성은 끝난다.

LLDB에 바이너리를 붙혀 로드하게되면 위와 같은 에러메세지를 볼 수 있다. 해당 에러는 아래와 같이 쉽게 해결 가능하다.

(lldb) command script import "/Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py"

songsangjun-ui-MacBook-Pro:~ s0ngsari$ echo "settings set target.load-script-from-symbol-file true" > ~/.lldbinit

Host와 Guest 모두 System Integrity Protection(SIP)를 disable 해야한다.

Host에서의 환경 구성은 모두 끝났고, 이제 Guest의 환경만 구성하면 커널을 디버깅 할 수 있게된다.


Guest Setting

OSX는 boot-args라는것을 nvram을 통해 건드릴 수 있다.

$ nvram boot-args

boot-args는 부팅될 때 설정한 값대로 OS에 적용된다. 하지만 우리가 해당 인자를 사용하는이유는 디버깅에 필요한 Interrupt와 Logging을 위한것이다. boot-args에도 인자가 많지만 우리는 debug라는것을 먼저 설정 할 것이다. 아래 차트를 보고 설정해주면 된다.

커널 디버깅을 할때에는 debug옵션의 인자를 0x144를 준다. DB_NMI플래그를 주게되면 NMI를 사용하여 디버거가 디버기에 붙을수 있게끔 해준다. 옵션을 줄때는 아래와 같이 설정해 주면 된다.

$ sudo nvram boot-args="debug=0x144 -v"
  • DB_LOG_PI_SCRN
  • DB_ARP
  • DB_NMI
  • Boot Verbose mode
$ sudo reboot

이후 boot-args가 설정되고, NMI 인터럽트를 발생시켜 debugger가 debuggee의 커널을 디버깅 할 수 있게 된다.

가끔 debuggee에서 NMI를 줘도 debugger에서 디버깅이 안될때가 있는데, 그때는 debugger에서 arp 테이블을 추가해줘야 한다.

$ arp -s <DebuggeeIP> <DebuggeeMac>

Host와 Guest모두 설정이 끝났으니 디버깅을 하면 된다.


Attach to debugger

해당 버전에 맞는 1day의 PoC를 예제 삼아 디버깅을 할것이다. 글에서 예제로 쓰이는 1day는 CVE-2017-2370 이다.

$ vi test.c
$ clang -o test test.c

Guest에서 PoC를 컴파일 해주고 NMI를 발생시키면 된다 NMI는 Command + Alt + Control + Shift + Esc로 발생 시킬수 있다. NMI를 발생시키면 OS가 멈추는게 정상이니 안심해도 된다.

디버거에서는 kdp-remote라는것을 사용하여 원격디버깅을 하면 되는데, 처음에 다운로드 받은 KDK의 kernel바이너리를 열어 주면된다.

songsangjun-ui-MacBook-Pro:~ s0ngsari$ lldb /Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel
(lldb) target create "/Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel"
Loading kernel debugging from /Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/kernel.py
LLDB version lldb-350.0.21.9
settings set target.process.python-os-plugin-path "/Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/core/operating_system.py"
settings set target.trap-handler-names hndl_allintrs hndl_alltraps trap_from_kernel hndl_double_fault hndl_machine_check _fleh_prefabt _ExceptionVectorsBase _ExceptionVectorsTable _fleh_undef _fleh_dataabt _fleh_irq _fleh_decirq _fleh_fiq_generic _fleh_dec
command script import "/Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel.dSYM/Contents/Resources/DWARF/../Python/lldbmacros/xnu.py"
xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries.


Current executable set to '/Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel' (x86_64).
(lldb) 

에러 없이 잘 열렸으면 kdp-remote 커맨드를 사용해서 디버기에 연결하면 된다.

(lldb) kdp-remote <debuggeeIP>
Version: Darwin Kernel Version 16.1.0: Wed Oct 19 20:31:56 PDT 2016; root:xnu-3789.21.4~4/RELEASE_X86_64; UUID=75CA1C4D-7BF4-321B-B544-D8F1B6D60EF8; stext=0xffffff8014200000
Kernel UUID: 75CA1C4D-7BF4-321B-B544-D8F1B6D60EF8
Load Address: 0xffffff8014200000
Kernel slid 0x14000000 in memory.
Loaded kernel file /Library/Developer/KDKs/KDK_10.12.1_16B2657.kdk/System/Library/Kernels/kernel
Loading 94 kext modules warning: Can't find binary/dSYM for com.apple.kec.corecrypto (809FEC94-017C-307A-B099-A01EFF5485FB)
.warning: Can't find binary/dSYM for com.apple.kec.pthread (36567317-B854-3157-ABF3-CEAD0A3770BB)
.warning: Can't find binary/dSYM for com.apple.kec.Libm (51D82C5F-0248-334D-ADC6-5861BBB83C97)
.warning: Can't find binary/dSYM for com.apple.iokit.IOACPIFamily (4F7FB6AD-2498-3F71-827C-ED7AA4BF2511)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.AppleACPIPlatform (249D7BA8-3FD5-3207-A482-0605CB898037)
.warning: Can't find binary/dSYM for com.apple.driver.AppleFDEKeyStore (EA5D0966-E8EA-337A-98EB-195806E8F723)
.warning: Can't find binary/dSYM for com.apple.iokit.IOReportFamily (B14DC3D3-7250-3DA3-BF50-C666EBEDAF4C)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.DiskImages (05A729EF-20B8-3254-8F13-42DF42E0544B)
.warning: Can't find binary/dSYM for com.apple.driver.AppleBusPowerController (DB526B45-1A45-3A81-A0C1-57F826CADEDF)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.KernelRelayHost (3B58E6F0-DE92-3289-9D3B-3BF12208585F)
.warning: Can't find binary/dSYM for com.apple.driver.AppleCredentialManager (54677B39-44B3-3AAA-BBEC-D78D0B5CC1A7)
.warning: Can't find binary/dSYM for com.apple.driver.AppleMobileFileIntegrity (0EFA4D2C-2271-3C43-B777-17D05716144A)
.warning: Can't find binary/dSYM for com.apple.driver.AppleKeyStore (75515493-6D25-39F7-8F0B-B08B505CAB74)
.warning: Can't find binary/dSYM for com.apple.security.TMSafetyNet (1CB512A3-24BD-344A-BFB4-44A61F27AB03)
.warning: Can't find binary/dSYM for com.apple.kext.AppleMatch (3B280DAB-903F-33DC-8110-525A1154B11E)
.warning: Can't find binary/dSYM for com.apple.security.sandbox (32039FC4-CA9B-3B74-B326-A2BF5CFE45E1)
.warning: Can't find binary/dSYM for com.apple.security.quarantine (EC92F0F9-694E-3E22-8B2C-4A071D20C6BA)
.warning: Can't find binary/dSYM for com.apple.nke.applicationfirewall (2A0DC0EF-655C-3D4B-93FD-3AED72BEBBDC)
.warning: Can't find binary/dSYM for com.apple.driver.AppleAPIC (BC2E6D01-BCBB-3525-BF38-BF99C3F1EC46)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSMBIOS (9BB02681-4B47-3592-AD62-71FB0BF56965)
.warning: Can't find binary/dSYM for com.apple.driver.AppleRTC (3FD1BCF4-8AFC-3CE6-A36E-26410544AD14)
.warning: Can't find binary/dSYM for com.apple.iokit.IOSMBusFamily (185F0EBF-0262-3370-BD47-8FE4C8AA726E)
.warning: Can't find binary/dSYM for com.apple.driver.AppleACPIEC (BC227AE1-3CD5-3938-9C8C-009F1A966FBE)
.warning: Can't find binary/dSYM for com.apple.driver.AppleHPET (2CFB49B8-4CC2-320B-9C6E-99646DFD8571)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.AppleACPIButtons (4D5E51D6-8A6B-3B6A-A8F2-472D56C9D0C3)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSmartBatteryManager (31670664-0EF0-39B5-A13F-15B8F9EC1283)
.warning: Can't find binary/dSYM for com.apple.driver.AppleEFIRuntime (6B7A5B9A-C313-3F7F-B6E2-60EE54593BC8)
.warning: Can't find binary/dSYM for com.apple.driver.AppleEFINVRAM (6F4404D6-8625-35CA-AEB6-6ECD7B64FA52)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBHostPacketFilter (9888F9CD-B7EE-3A9D-8530-6FA4C167B26C)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBEHCI (BF6EF9A2-F090-3094-B3FA-F34351D946CF)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBUHCI (4EF43593-FC11-31E6-8B27-E7A6B5703C15)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBUHCIPCI (4EC90565-DB48-3190-8608-1F6DA30B8691)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBXHCI (E5F9850E-A1A1-305F-854D-48B46C08B2EC)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBXHCIPCI (B4287428-23D9-3547-93B5-2FEB73A02EA6)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBEHCIPCI (4FCE62CA-0477-34A2-9564-86F807CDBD4D)
.warning: Can't find binary/dSYM for com.apple.iokit.IOATAFamily (BC25A382-3DA0-33C7-93C5-E8A823B50F98)
.warning: Can't find binary/dSYM for com.apple.driver.AppleIntelPIIXATA (BDC5E432-B04E-3ACF-A213-672128140381)
.warning: Can't find binary/dSYM for com.apple.iokit.IOAHCIFamily (5C275B66-A173-3D92-853A-44FC35D45FFC)
.warning: Can't find binary/dSYM for com.apple.driver.AppleAHCIPort (BE72151C-73BE-35B7-8C31-74F49E4C5E98)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.driver.AppleIntel8254XEthernet (34B30414-098D-3D22-AAB5-1A754D0647C6)
.warning: Can't find binary/dSYM for com.apple.iokit.IOAHCIBlockStorage (C449634B-8121-3BFB-972D-966847C4321F)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.iokit.IOAHCISerialATAPI (681FA1E2-E3DE-3FEB-ACA7-16FC2B9078A6)
.warning: Can't find binary/dSYM for com.apple.filesystems.hfs.encodings.kext (68A8D6C1-CDCA-371C-970B-325BF2E7ECAB)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.filesystems.hfs.kext (6C6C4A98-1534-3C52-B006-00FBC479233E)
.warning: Can't find binary/dSYM for com.apple.BootCache (C38789F4-9226-303C-99BE-3B8EAF8EC5C2)
.warning: Can't find binary/dSYM for com.apple.AppleFSCompression.AppleFSCompressionTypeZlib (9B32DDE9-151F-31A1-90E9-3CEB2C7BE27C)
.warning: Can't find binary/dSYM for com.apple.AppleFSCompression.AppleFSCompressionTypeDataless (C6F882D7-C35C-3963-A2FA-10033FF40107)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBHostCompositeDevice (30502C8D-F4B2-345F-B8F0-F8C54CAD7F46)
.warning: Can't find binary/dSYM for com.apple.driver.usb.networking (74394A72-1E87-363E-8CFD-182BD8C9362E)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBHub (F7BC6869-E4BA-3291-B7EA-BF28A0ABEF4A)
.warning: Can't find binary/dSYM for com.apple.driver.usb.IOUSBHostHIDDevice (0548123A-013B-3C74-86A8-33DF73E9CBBB)
.warning: Can't find binary/dSYM for com.apple.driver.AppleHIDKeyboard (664B787F-6DE5-3211-9081-E434055A550B)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.parallels.kext.video (5520E5F4-AC7C-9446-6088-5D8CAF25478D)
.warning: Can't find binary/dSYM for com.parallels.driver.AppleIntelAC97Controller (705C3A56-06CE-E995-5A75-618C5EF3D45D)
.warning: Can't find binary/dSYM for com.apple.vecLib.kext (C0ABF85C-CA30-3F02-9E1E-06F3BA5047A8)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.iokit.IOSlowAdaptiveClockingFamily (F026208D-CC0C-3599-B303-9196904A584E)
.warning: Can't find binary/dSYM for com.apple.driver.AppleIntelSlowAdaptiveClocking (6FE984DD-A1FE-309E-83CF-B346989A6F17)
.warning: Can't find binary/dSYM for com.apple.driver.IOPlatformPluginFamily (087648A2-8A44-3095-AEC7-44A872A46205)
.warning: Can't find binary/dSYM for com.apple.driver.IOPlatformPluginLegacy (9156271B-C61E-3B40-B5B6-102369F12A8B)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSMC (969D80B2-E714-3145-95B0-F61627E0EE4D)
.warning: Can't find binary/dSYM for com.apple.driver.ACPI_SMC_PlatformPlugin (7224B682-B40F-3A4A-BCA0-82727D251ECB)
.warning: Can't find binary/dSYM for com.parallels.kext.tg (09C02F97-D104-80F1-2A96-6BEF8A2F6967)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSMBusController (4DAA381E-3690-3E94-8025-DFB34F714094)
.warning: Can't find binary/dSYM for com.apple.driver.AppleMCCSControl (102DD5D9-2DD5-3BCB-B5C0-BE08E1049CD6)
.warning: Can't find binary/dSYM for com.apple.driver.AppleUpstreamUserClient (F39509A4-191C-35DA-B7D9-08F95E5AB8BC)
.warning: Can't find binary/dSYM for com.apple.driver.AppleHV (39AC9B9B-7B20-322F-82F0-044B3CC08D43)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSSE (907BB577-46DF-3C86-9034-758B61AD054D)
.warning: Can't find binary/dSYM for com.apple.Dont_Steal_Mac_OS_X (B97F871A-44FD-3EA4-BC46-8FD682118C79)
.warning: Can't find binary/dSYM for com.apple.iokit.IOBluetoothFamily (794ACDDD-2B46-3BF0-94E9-4FD7C109A427)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
.warning: Can't find binary/dSYM for com.apple.iokit.IOBluetoothSerialManager (6F68B8CF-6543-328E-AF57-DD250412CF02)
.warning: Can't find binary/dSYM for com.apple.iokit.IOSurface (D3B2D208-487C-3166-9F7D-D6159AABC428)
.warning: Can't find binary/dSYM for com.apple.iokit.IOUserEthernet (5EE448BD-95EC-35AD-B7FC-A1237E4BB346)
.warning: Can't find binary/dSYM for com.apple.driver.pmtelemetry (F46D019B-17FF-3CD5-A093-0894B81C1404)
.warning: Can't find binary/dSYM for com.parallels.driver.AppleIntelAC97Audio (F8F3B21C-958B-BB10-E13C-42CA34BF6815)
.warning: Can't find binary/dSYM for com.apple.driver.AppleOSXWatchdog (757A8B72-2A1A-32BA-99EC-6D802DE6E91F)
.warning: Can't find binary/dSYM for com.apple.kext.triggers (4E564246-8804-3673-B440-606AD360A3BB)
.warning: Can't find binary/dSYM for com.apple.filesystems.autofs (AA36D92F-D92B-3102-BAE3-F86A0A298143)
.warning: Can't find binary/dSYM for com.apple.filesystems.smbfs (42EF3BC8-5041-3E94-BC74-9D5906694E3A)
.warning: Can't find binary/dSYM for com.apple.driver.usb.cdc (6CB80B6B-9071-38ED-9A4B-635ABF20A429)
.Target arch: x86_64
Instantiating threads completely from saved state in memory.
 done.
Target arch: x86_64
Instantiating threads completely from saved state in memory.
kernel was compiled with optimization - stepping may behave oddly; variables may not be available.
Process 1 stopped
* thread #2: tid = 0x16cc, 0xffffff801440bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513, name = '0xffffff801c791028', queue = '0x0', stop reason = signal SIGSTOP
    frame #0: 0xffffff801440bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513 [opt]
(lldb) 

제대로 커널이 잡혔다면 디버기의 프로세스를 Resuming해주고 PoC를 실행시켜주면 디버거에서 크래쉬를 확인 할 수 있다.

(lldb) c
Process 1 resuming
(lldb) Unloading 1 kext modules . done.
Process 1 stopped
* thread #4: tid = 0x1af6, 0xffffff8014751a8c kernel`fp_lookup(p=0xffffff801ebec780, fd=1, resultfp=0xffffff806eb6bf20, locked=0) + 92 at kern_descrip.c:3879, name = '0xffffff801c09a9a8', queue = '0x0', stop reason = EXC_BAD_INSTRUCTION (code=13, subcode=0x0)
    frame #0: 0xffffff8014751a8c kernel`fp_lookup(p=0xffffff801ebec780, fd=1, resultfp=0xffffff806eb6bf20, locked=0) + 92 at kern_descrip.c:3879 [opt]
(lldb) register read
General Purpose Registers:
       rax = 0x4141414141414141
       rbx = 0x0000000000000001
       rcx = 0x0000000000000001
       rdx = 0xffffff8020d0e800
       rdi = 0xffffff801ebec848
       rsi = 0x0000000000000001
       rbp = 0xffffff806eb6bef0
       rsp = 0xffffff806eb6bec0
        r8 = 0x0000000000000000
        r9 = 0x00007fffda6afa50
       r10 = 0x000000000000000a
       r11 = 0x0000000000000246
       r12 = 0xffffff801ebec780
       r13 = 0xffffff801ec3e4f8
       r14 = 0x0000000000000000
       r15 = 0xffffff806eb6bf20
       rip = 0xffffff8014751a8c  kernel`fp_lookup + 92 at kern_descrip.c:3879
    rflags = 0x0000000000010246
        cs = 0x0000000000000008
        fs = 0x0000000000000000
        gs = 0x0000000000000000

(lldb)

LLDB는 GDB와 커맨드가 비슷하지도 않아서 따로 배워두는게 좋다. 혹은 kgmacros라는 스크립트를 사용해서 gdb로 디버깅을 하는것도 나쁘지않다.


Logging the Heap

PoC를 실행하고 브레이크포인트를 걸어도 힙을 일일히 트레이싱하는것은 힘들다. 하지만 위에서 다룬 boot-args를 통해 힙을 트레이싱 할 수가 있다. 이는 OSX heap에서 다루는 zone을 트레이싱하는것이다.

$ sudo nvram boot-args="debug=0x144 -v -zc zlog1=kalloc.128 zlog2=kalloc.256"

위 커맨드와같이 -zc zlog1=zone 을 주고 재부팅을하면 끝난다. 중요한것은 해당 PoC가 어떤 zone을 사용하는지를 알아야한다. 모든 kalloc을 트레이싱하는것이 아니라, kalloc에 있는 여러 zone중에 우리가 선택한 zone을 트레이싱해주기때문에 편하게 트레이싱을 하고싶다면 사용하는 zone 하나만 boot-args 인자로 넘겨주면 된다.

  • zlog 적용한 모습
(lldb) bt
* thread #2: tid = 0x0cb5, 0xffffff801200bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513, name = '0xffffff8019752980', queue = '0x0', stop reason = signal SIGSTOP
  * frame #0: 0xffffff801200bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513 [opt]
    frame #1: 0xffffff801200bb4e kernel`Debugger(message=<unavailable>) + 910 at model_dep.c:1025 [opt]
    frame #2: 0xffffff8011ef368c kernel`panic(str="\"a freed zone element has been modified in zone %s: expected %p but found %p, bits changed %p, at offset %d of %d in element %p, cookies %p %p\"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.21.4/osfmk/kern/zalloc.c:651") + 236 at debug.c:458 [opt]
    frame #3: 0xffffff8011f3f5c0 kernel`backup_ptr_mismatch_panic [inlined] zone_element_was_modified_panic(offset=0) + 800 at zalloc.c:642 [opt]
    frame #4: 0xffffff8011f3f559 kernel`backup_ptr_mismatch_panic(zone=<unavailable>, element=<unavailable>, primary=4702111234474983745, backup=<unavailable>) + 697 at zalloc.c:710 [opt]
    frame #5: 0xffffff8011f3e739 kernel`try_alloc_from_zone(zone=<unavailable>, check_poison=<unavailable>) + 521 at zalloc.c:832 [opt]
    frame #6: 0xffffff8011f3d174 kernel`zalloc_internal(zone=<unavailable>, canblock=1, nopagewait=0) + 484 at zalloc.c:2284 [opt]
    frame #7: 0xffffff8011f84580 kernel`vm_map_copyin_internal + 51 at vm_map.c:9428 [opt]
    frame #8: 0xffffff8011f8454d kernel`vm_map_copyin_internal(src_map=<unavailable>, src_addr=140351705630208, len=3240, flags=<unavailable>, copy_result=<unavailable>) + 253 at vm_map.c:10279 [opt]
    frame #9: 0xffffff8011ed7629 kernel`ipc_kmsg_copyin_ool_descriptor [inlined] vm_map_copyin_common(src_map=<unavailable>, src_destroy=<unavailable>, copy_result=0xffffff8071adbe40, use_maxprot=0) + 201 at vm_map.c:10187 [opt]
    frame #10: 0xffffff8011ed7616 kernel`ipc_kmsg_copyin_ool_descriptor(dsc=0xffffff8018874c98, user_dsc=<unavailable>, is_64bit=<unavailable>, paddr=<unavailable>, copy=0xffffff8071adbe40, space_needed=<unavailable>, map=<unavailable>, mr=<unavailable>) + 182 at ipc_kmsg.c:2701 [opt]
    frame #11: 0xffffff8011ed7c25 kernel`ipc_kmsg_copyin_body(kmsg=0xffffff8018874c00, space=0xffffff8018925b40, map=0xffffff801c0e9e08) + 613 at ipc_kmsg.c:3035 [opt]
    frame #12: 0xffffff8011ee992f kernel`mach_msg_overwrite_trap(args=<unavailable>) + 287 at mach_msg.c:548 [opt]
    frame #13: 0xffffff8011ff26ae kernel`mach_call_munger64(state=0xffffff8018dd12c0) + 430 at bsd_i386.c:562 [opt]
    frame #14: 0xffffff8011ea5f66 kernel`hndl_mach_scall64 + 22
  • zlog 적용하지 않은 모습
(lldb) bt
* thread #2: tid = 0x13ab, 0xffffff8015c0bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513, name = '0xffffff80200f4288', queue = '0x0', stop reason = signal SIGSTOP
  * frame #0: 0xffffff8015c0bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513 [opt]
    frame #1: 0xffffff8015c0bb4e kernel`Debugger(message=<unavailable>) + 910 at model_dep.c:1025 [opt]
    frame #2: 0xffffff8015af368c kernel`panic(str="\"Invalid queue element linkage for %p: next %p next->prev %p prev %p prev->next %p\"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.21.4/osfmk/kern/queue.h:245") + 236 at debug.c:458 [opt]
    frame #3: 0xffffff8015bec040 kernel`pmap_enter_options [inlined] __QUEUE_ELT_VALIDATE + 81 at queue.h:244 [opt]
    frame #4: 0xffffff8015bebfef kernel`pmap_enter_options [inlined] insque at queue.h:347 [opt]
    frame #5: 0xffffff8015bebfef kernel`pmap_enter_options [inlined] pv_hash_add + 32 at pmap_internal.h:544 [opt]
    frame #6: 0xffffff8015bebfcf kernel`pmap_enter_options(pmap=<unavailable>, vaddr=<unavailable>, pn=<unavailable>, prot=<unavailable>, fault_type=<unavailable>, flags=<unavailable>, wired=<unavailable>, options=<unavailable>, arg=<unavailable>) + 5103 at pmap_x86_common.c:926 [opt]
    frame #7: 0xffffff8015b6fb41 kernel`vm_fault_enter(m=0xffffff801c1c3c00, pmap=<unavailable>, vaddr=140736734584832, prot=<unavailable>, caller_prot=<unavailable>, wired=0, change_wiring=<unavailable>, no_cache=0, cs_bypass=<unavailable>, user_tag=1962753648, pmap_options=<unavailable>, need_retry=<unavailable>, type_of_fault=<unavailable>) + 4481 at vm_fault.c:3292 [opt]
    frame #8: 0xffffff8015b71405 kernel`vm_fault_internal(map=<unavailable>, vaddr=<unavailable>, caller_prot=<unavailable>, change_wiring=0, interruptible=2, caller_pmap=0x0000000000000000, caller_pmap_addr=0, physpage_p=<unavailable>) + 4421 at vm_fault.c:4086 [opt]
    frame #9: 0xffffff8015c069fc kernel`user_trap [inlined] vm_fault(map=<unavailable>, vaddr=<unavailable>, fault_type=<unavailable>, change_wiring=0, interruptible=2, caller_pmap=<unavailable>, caller_pmap_addr=0) + 652 at vm_fault.c:3397 [opt]
    frame #10: 0xffffff8015c069d8 kernel`user_trap(saved_state=0xffffff801ff11060) + 616 at trap.c:1120 [opt]
    frame #11: 0xffffff8015aa5655 kernel`hndl_alltraps + 229

Call stack을 확인했을때 두개의 차이점이 확실하게 보인다. zlog을 적용한 call stack은 zalloc으로 할당되는것을 볼 수 있지만 적용하지 않은것은 할당되는것들이 보이지않는다. 이렇게 Heap Corruption을 다루는 1day가 있을때 zone 개념을 파악하고 zlog을 사용한다면 더 확실하게 디버깅 할 수 있는 장점이 있어 참고해두면 유용하게 사용 할 수 있다.


ETC

버그에 대한 이해도 중요하지만 디버깅 또한 중요하다. 간단하게 디버깅을 하여 여러가지 커맨드를 사용해볼것이다.

(lldb) bt
* thread #2: tid = 0x1650, 0xffffff801200bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513, name = '0xffffff801a0eee18', queue = '0x0', stop reason = signal SIGSTOP
  * frame #0: 0xffffff801200bb4e kernel`Debugger [inlined] hw_atomic_sub(delt=1) at locks.c:1513 [opt]
    frame #1: 0xffffff801200bb4e kernel`Debugger(message=<unavailable>) + 910 at model_dep.c:1025 [opt]
    frame #2: 0xffffff8011ef368c kernel`panic(str="\"a freed zone element has been modified in zone %s: expected %p but found %p, bits changed %p, at offset %d of %d in element %p, cookies %p %p\"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3789.21.4/osfmk/kern/zalloc.c:651") + 236 at debug.c:458 [opt]
    frame #3: 0xffffff8011f3f5c0 kernel`backup_ptr_mismatch_panic [inlined] zone_element_was_modified_panic(offset=0) + 800 at zalloc.c:642 [opt]
    frame #4: 0xffffff8011f3f559 kernel`backup_ptr_mismatch_panic(zone=<unavailable>, element=<unavailable>, primary=4702111234474983745, backup=<unavailable>) + 697 at zalloc.c:710 [opt]
    frame #5: 0xffffff8011f3e739 kernel`try_alloc_from_zone(zone=<unavailable>, check_poison=<unavailable>) + 521 at zalloc.c:832 [opt]
    frame #6: 0xffffff8011f3d174 kernel`zalloc_internal(zone=<unavailable>, canblock=1, nopagewait=0) + 484 at zalloc.c:2284 [opt]
    frame #7: 0xffffff8011ed5248 kernel`ipc_kmsg_alloc(msg_and_trailer_size=4352) + 248 at ipc_kmsg.c:929 [opt]
    frame #8: 0xffffff8011ef832d kernel`ipc_kobject_server(request=<unavailable>, option=<unavailable>) + 141 at ipc_kobject.c:299 [opt]
    frame #9: 0xffffff8011ed5f61 kernel`ipc_kmsg_send(kmsg=<unavailable>, option=<unavailable>, send_timeout=<unavailable>) + 225 at ipc_kmsg.c:1826 [opt]
    frame #10: 0xffffff8011ee9957 kernel`mach_msg_overwrite_trap(args=<unavailable>) + 327 at mach_msg.c:556 [opt]
    frame #11: 0xffffff8011ff26ae kernel`mach_call_munger64(state=0xffffff8019fed920) + 430 at bsd_i386.c:562 [opt]
    frame #12: 0xffffff8011ea5f66 kernel`hndl_mach_scall64 + 22

bt 명령어는 BackTrace 약자로, 현재 커널이 어느위치에 있는지 프레임단위로 보여준다. 각 프레임들을 선택 할 수 있고, 우리가 원하는 프레임으로 뛰어 로컬 변수들을 확인 할 수도 있다.

(lldb) frame select 5
frame #5: 0xffffff8011f3e739 kernel`try_alloc_from_zone(zone=<unavailable>, check_poison=<unavailable>) + 521 at zalloc.c:832 [opt]

frame select 라는 명령으로 프레임 넘버를 선택해주면 그 frame으로 현재위치가 잡히고, rip또한 아래와 같이 그 프레임대로 잡히게 된다.

(lldb) register read
General Purpose Registers:
       rbx = 0xffffff801f977000
       rbp = 0xffffff8872cabc50
       rsp = 0xffffff8872cabc10
       r12 = 0x7e415085550ee3c7
       r13 = 0x4141414141414141
       r14 = 0xffffff8017cd70a0
       r15 = 0x4141414141414141
       rip = 0xffffff8011f3e739  kernel`try_alloc_from_zone + 521 at zalloc.c:832

rip가 우리가 선택한 frame대로 잡혀있는것을 확인 할 수 있고, 해당 함수에서의 로컬변수값을 볼 수 있다.

(lldb) frame var
(zone_t) zone = <variable not available>

(boolean_t *) check_poison = <variable not available>

(zone_page_metadata *) page_meta = 0xffffff8017cd70a0
(vm_offset_t) element = 18446743524483756032
(vm_offset_t *) primary = 0xffffff801f977000
(vm_offset_t) next_element_primary = 4702111234474983745
(vm_offset_t) next_element = 9097641255853024199
(vm_offset_t) next_element_backup = 4702111234474983745
(vm_offset_t *) backup = <no location, value may have been optimized out>

OSX에서는 Page 맨 처음부분에 Meta data라는것이 존재하는데, 힙청크의 메타데이터와 같이 그 zone의 여러가지 정보들이 들어 있다.

iOS 10의 경우 메타데이터는 아래와 같다:

  • zindex: zone_array안에 있는 존의 index
  • page_count : 페이지의 할당 사이즈
  • free_count : 페이지의 free element갯수
  • freelist_offset : 페이지의 처음 free element의 주소

우리가 여기서 봐야할 것은 Element라는 변수인데, 무엇인지 한번 확인해보겠다.

(lldb) memory read 0xffffff801f977000
0xffffff801f977000: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0xffffff801f977010: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA

PoC가 제대로 트리거되었다면 Element에는 A가 잔뜩 채워져있는것이 정상이다. zone에 할당된 엘리먼트에 memset으로 A를 채워넣었기때문에 위와같은 결과가 나오게된다.

이런식으로 PoC를 트리거 한 후, 원하는 프레임이 있다면 해당 프레임을 선택하고 로컬변수를 확인하는 식으로 디버깅을 진행하면 된다. 프레임에 관련된 커맨드는 종종 유용하게 쓰이니 알아두면 좋다.

맥에서 돌아가는 task들의 베이스주소를 확인이 가능한데, 우리가 볼 것은 커널이다. 커널의 task이름은 kernel_task인데, 커맨드로 해당 주소를 출력해볼것이다.

(lldb) showalltasks 
task                 vm_map               ipc_space            #acts flags    pid       process             io_policy  wq_state  command             
0xffffff80185b3aa0   0xffffff8014d1e6e8   0xffffff80180ab800     134            0   0xffffff80126ba360                -1 -1 -1    kernel_task         
0xffffff80185b3000   0xffffff8018db0838   0xffffff80180ab840       6            1   0xffffff8018d81128                -1 -1 -1    launchd             
0xffffff801961c000   0xffffff8019603268   0xffffff80195c2740       4 D         34   0xffffff8018d80cb0                -1 -1 -1    UserEventAgent      
0xffffff801961caa0   0xffffff8019603838   0xffffff80195c2980       2 D         36   0xffffff8018d80838             TQ -1 -1 -1    uninstalld          
0xffffff8019634aa0   0xffffff8019603458   0xffffff80195c29c0       2 D         37   0xffffff8018d81e90                -1 -1 -1    kextd               
0xffffff8019634550   0xffffff8019602ba0   0xffffff80195c2700      10 D         38   0xffffff8018d82308                -1 -1 -1    fseventsd           
0xffffff8018e67550   0xffffff8019602aa8   0xffffff80195c2680      10 D         44   0xffffff8018d7fad0                -1 -1 -1    configd             
0xffffff801965baa0   0xffffff80196026c8   0xffffff80195c2a00       3 D         45   0xffffff8018d834e8                -1 -1 -1    powerd              
0xffffff8018ee2000   0xffffff80196029b0   0xffffff80195c2a40       4 D         50   0xffffff8018d846c8                -1 -1 -1    logd  
...

이렇게 task, vm_map, ipc_space 각각 할당된 주소를 확인할 수 있고, 해당 task의 객체들 또한 확인이 가능하다. 원하는 task의 process주소를 복사해서 아래와 같이 하면된다.

(lldb) showtaskvme 0xffffff80185b3aa0
vm_map entries for task 0xffffff80185b3aa0
task                 vm_map               ipc_space            #acts flags
0xffffff80185b3aa0   0xffffff8014d1e6e8   0xffffff80180ab800     134      
vm_map             pmap               size                    #ents              rsize              start:end               
0xffffff8014d1e6e8 0xffffff8012688f88 0x00000008f838a000        731              70200 0xffffff7f80000000:0xffffffffffffe000
entry                           start:end                      #pgs tag.kmod prot&flags object             offset            
0xffffff8014d28750 0xffffff7f80000000:0xffffff7f92600000      75264   0      00         0x0000000000000000 0x0               
0xffffff8014d287a0 0xffffff7f92600000:0xffffff8000000000     449024   6      37s        G_KEXT_MAP         0xffffff7f92600000
0xffffff8018d40640 0xffffff8000000000:0xffffff8012751000      75601   0      00         0x0000000000000000 0x80000000        
0xffffff8018d40a50 0xffffff8012751000:0xffffff8012879000        296   0      37         0xffffff8018d93d00 0x0               
0xffffff8018d40960 0xffffff8012879000:0xffffff8016ac4000      16971   0      00         0x0000000000000000 0x92879000 
...
0xffffff8014d28700 0xffffff8016b99000:0xffffff8017c1b000       4226  10      37         KERNEL_OBJECT      0xffffff8016b99000
0xffffff8014d286b0 0xffffff8017c1b000:0xffffff8047c1b000     196608  12      37s        ZONE_MAP           0xffffff8017c1b000
0xffffff8014d28570 0xffffff8047c1b000:0xffffff804bc1b000      16384   0      37s        KALLOC_MAP         0xffffff8047c1b000
0xffffff8014d287f0 0xffffff804bc1b000:0xffffff804bc42000         39  18      37         0xffffff801809b600 0x0               
0xffffff8014d284d0 0xffffff804bc42000:0xffffff804bd5c000        282  18      37         0xffffff801809b700 0x0               
0xffffff8014d28840 0xffffff804bd5c000:0xffffff804bd5d000          1  18      37         0xffffff801809b800 0x0               
0xffffff8014d28890 0xffffff804bd5d000:0xffffff804bd84000         39  18      37         0xffffff801809b500 0x0               
0xffffff8014d28480 0xffffff804bd84000:0xffffff804be9e000        282  18      37         0xffffff801809b400 0x0               
0xffffff8014d28430 0xffffff804be9e000:0xffffff804be9f000          1  18      37         0xffffff801809b900 0x0               
0xffffff8014d28520 0xffffff804be9f000:0xffffff804bedf000         64   0      00         KERNEL_OBJECT      0xffffff804be9f000
0xffffff8014d288e0 0xffffff804bedf000:0xffffff804bef1000         18  19      37         0xffffff801809ba00 0x0               
0xffffff8014d28930 0xffffff804bef1000:0xffffff804bef5000          4  18      37         0xffffff801809bb00 0x0               
0xffffff8014d28980 0xffffff804bef5000:0xffffff804befa000          5   1      37         0xffffff801809b300 0x0               
0xffffff8014d289d0 0xffffff804befa000:0xffffff804bf00000          6  17      37         KERNEL_OBJECT      0xffffff804befa000
0xffffff8014d28a20 0xffffff804bf00000:0xffffff804bf01000          1  27      37         0xffffff801809bc00 0x0               
0xffffff8014d283e0 0xffffff804bf01000:0xffffff804bf02000          1  27      37         0xffffff801809bd00 0x0               
0xffffff8014d28a70 0xffffff804bf02000:0xffffff804c002000        256   7      37s        IPC_KERNEL_MAP     0xffffff804bf02000
0xffffff8014d28b10 0xffffff804c002000:0xffffff804c802000       2048   7      37s        IPC_KERNEL_COPY_MAP 0xffffff804c002000

커널 오브젝트도 존재하고, Zone이 맵핑된 주소등 다양한 정보들을 볼 수 있다. 원하는 개체를 확인하고 싶을때 위 커맨드를 사용해서 확인하면 된다. 그리고 간단하게 짚고 넘어가야하는것이 있는데 OSX를 공부하면 알게되는 zprint 커맨드이다. zprint는 OSX에서 할당되는 모든 Zone을 출력해주는데, 맥 터미널에서는 기본으로 제공해준다. 하지만 맥 커맨드로 zprint를 하면 주소는 나오지 않고 무슨 zone이 존재하는지만 보여준다. 그렇지만 디버거가 커널을 잡았을때는 다르다. LLDB에서도 zprint 커맨드를 제공해주는데 결과는 아래와 같다.

(lldb) zprint
       ZONE            TOT_SZ PAGE_COUNT ALLOC_ELTS  FREE_ELTS    FREE_SZ ALL_FREE_PGS     ELT_SZ      ALLOC(  ELTS    PGS  WASTE)      FLAGS      NAME 
       
...
0xffffff801266a0e0     393216         96      22614       1962      31392          0         16   4096    256      1  CX             kalloc.16 
0xffffff801266a200    1134592        277      20951      14505     464160          1         32   4096    128      1  CX             kalloc.32 
0xffffff801266a320     836400        205      16259       1166      55968          1         48   4096     85      1  CX             kalloc.48 
0xffffff801266a440    1585152        387      24594        174      11136          0         64   4096     64      1  CX             kalloc.64 
0xffffff801266a560     477360        117       5320        647      51760          0         80   4096     51      1  CX             kalloc.80 
0xffffff801266a680     367200         90       3710        115      11040          0         96   8192     85      2  CX             kalloc.96 
0xffffff801266a7a0    2203648        538      17016        200      25600          1        128   4096     32      1  CX             kalloc.128 
0xffffff801266a8c0     236640         58       1264        215      34400          0        160   8192     51      2  CX             kalloc.160 
0xffffff801266a9e0     270336         66       1353         55      10560          0        192  12288     64      3  CX             kalloc.192 
0xffffff801266ab00     512000        125       1960         40      10240          0        256   4096     16      1  CX             kalloc.256 
0xffffff801266ac20     265824         65        902         21       6048          0        288  20480     71      5  CX             kalloc.288 
0xffffff801266ad40    1282048        313       2420         84      43008          1        512   4096      8      1  CX             kalloc.512 
0xffffff801266ae60      28224          7         20         29      16704          2        576   4096      7      1  CX             kalloc.576 
0xffffff801266af80     847872        207        780         48      49152          9       1024   4096      4      1  CX             kalloc.1024 
0xffffff801266b0a0      32256          8         18         10      11520          0       1152   8192      7      2  CX             kalloc.1152 
0xffffff801266b1c0      40960         10         17         15      19200          0       1280  20480     16      5  CX             kalloc.1280 
0xffffff801266b2e0    1568768        383        750         16      32768          3       2048   4096      2      1  CX             kalloc.2048 
0xffffff801266b400    6479872       1582        314       1268    5193728       1268       4096   4096      1      1  CX             kalloc.4096 
0xffffff801266b520    1949696        476         84        154    1261568        306       8192   8192      1      2  CX             kalloc.8192 
...

터미널에서 제공해주는 zprint와는 다르게 LLDB에선 페이지의 메타데이터(주소, 엘리먼트 갯수 등등) 들이 전부 출력된다.

LLDB에는 수많은 커맨드들이 있기 때문에, tab기능을 이용하여 확인하면 원하는 커맨드를 사용할 수 있으니 참고하길 바란다.

다음 시리즈에서는 공개된 버그와 보안 패치를 바탕으로 exploit을 작성해보도록 할 예정이다.