POC 2019 에서 SecureROM 의 취약점을 공격한 checkm8 에 대한 발표(Luca Todesco, “The One Weird Trick SecureROM Hates”)가 있었습니다.

SecureROM 이 포함된 부팅 프로세스는 iOS 보안의 핵심입니다.

애플의 강력한 보안 메커니즘들이 부팅 과정에서 설정됩니다. 하지만 이러한 부팅 과정에 문제가 발생한다면, 커널 캐시를 미리 패치하여 커널 패치 보안 메커니즘을 우회하거나 샌드박스를 비활성화 시킬 수 있습니다.

Jailbreak 를 위해서는 애플의 보안 메커니즘을 우회해야 하는데, 디바이스가 부팅된 상태에서 시스템의 취약점을 이용하거나 디바이스의 부팅 과정에서 부트체인(boot chain)을 손상시켜 이를 우회할 수 있습니다.

iOS Boot Chain

  • A10 이전 부트체인

  • A10 이후 부트체인

1) BootROM/SecureROM 은 LLB 를 준비하고 LLB 의 시그니쳐를 검증합니다.

2) LLB 는 펌웨어를 읽고 iBoot 를 검증 후 실행합니다.

3) iBoot 는 HFS 파일 시스템을 마운트하고 커널 캐시를 복호화 후 검증, 제어 흐름을 커널로 전달합니다.

A10 이전에는 이러한 절차를 거치고 A10 부터는 BootROM/SecureROM 에서 iBoot 를 검증합니다.

SecureROM

SecureROM어플리케이션 프로세서(AP)에서 첫 번째로 실행되는 코드이며, 가장 신뢰할 수 있는 코드입니다. SecureROM의 코드는 read-only 메모리에 저장되므로 패치도 불가능합니다. 이 단계는 CPU 초기화, 시스템 초기화, 플랫폼 초기화 등의 초기화가 수행됩니다. PAC의 랜덤 시드도 설정됩니다.

설정이 완료되면 다음 단계 부트 로더 이미지를 로드하는데 이때 로드에 실패하게 되면 DFU (Device Firmware Update) 모드로 빠집니다. DFU 모드는 GPIO 키를 이용해서도 진입 가능합니다.

DFU

DFU 는 USB Control Transfer를 통해 구현된 간단한 프로토콜을 사용해서 호스트에서 디바이스로 데이터를 가져옵니다. 전송이 완료되면 DFU 가 종료되고, 업로드된 이미지를 부팅 시도합니다.

이 과정에서 DFU abort request 와 같은 방법으로 DFU 를 종료시킬 수도 있습니다.

USB Control Transfer

명령을 실행하거나, 호스트에서 디바이스로 혹은 디바이스에서 호스트로 데이터를 요청하는데 사용됩니다.

Control Transfer는 총 3 단계로 구성되어 있습니다.

  • Setup Stage : request 전송
  • Data Stage : 하나 또는 여러개의 IN/OUT transfer
  • Status Stage : request 의 상태 보고

Setup Stage 에서는 request 의 내용에 대한 정보를 담고 있는 setup 패킷이 전송됩니다. 8 바이트 길이의 setup 패킷은 다섯 개의 필드를 가지고 있는데 그 중 마지막 필드가 전송될 바이트 수를 나타냅니다.

전송될 바이트가 존재한다면 Data Stage 의 패킷이 뒤따라옵니다. IN/OUT transfer 에 따라서 내용이 달라지는데, DFU mode 에서는 호스트에서 디바이스로 데이터를 전송하는 OUT transfer 를 사용합니다. 데이터는 USB 속도에 따라 8 바이트에서 최대 64 바이트 크기의 패킷으로 전달됩니다. 디바이스에서는 DFU 초기화 과정 중 IO 를 위한 임시 버퍼가 할당되고, 디바이스가 수신한 데이터 패킷이 해당 버퍼에 memcpy 되어 들어갑니다.

전송이 완료되면 Status Stage 가 이어지며 길이가 0인 packet 을 전송하여 Control Transfer 의 끝을 표시합니다.

Vulnerability

DFU mode 에 진입하면 Data Stage 의 패킷을 임시 저장 할 버퍼가 할당됩니다. 이 버퍼에 대한 포인터는 전역 변수에 저장됩니다. 그 후 DFU mode 가 종료되면 이 버퍼는 free 됩니다. 하지만 이 버퍼의 포인터가 저장된 전역 변수가 NULL 로 초기화 되지 않아 결국 Use-After-Free 버그가 발생하게 됩니다.

DFU abort 로 인해 버퍼가 free 되고 DFU mode 로 재진입했을 때, 이전에 중단된 Data Stage 패킷을 다시 전송하게 되면 free 된 포인터에 데이터가 복사되어 들어가게 됩니다.

다른 객체를 IO 버퍼 자리에 할당시키면 IO 버퍼를 이용하여 대상 객체를 조작할 수 있습니다.

Exploitation

checkm8 에서는 공격 대상으로 usb_device_io_request 구조체를 할당합니다. 이 구조체는 함수 포인터인 callback 과 다음 구조체를 가리키는 next 필드를 가지고 있습니다. USB reset 요청시 각 request 에 대한 callback 이 호출됩니다.

IO 버퍼에 이 구조체를 여러개 위치시킨 후, 각각의 callback 을 ROP gadget 으로 조작합니다. 그 후 USB reset 을 요청하게 되면 callback 이 호출되면서 ROP 체인이 실행되게 됩니다.

checkm8 의 익스플로잇 순서는 다음과 같습니다.

  1. 힙 풍수
  2. IO 버퍼 할당 후 해제
  3. UAF 를 이용하여 usb_device_io_request 조작
  4. payload 삽입
  5. callback-chain 실행
  6. shellcode 실행

Conclusion

이 취약점은 iOS 버전과 관계 없이 iPhone 4S (A5) 부터 iPhone X (A11) 까지 동작합니다.

실제 환경에서 익스플로잇으로 활용되기에는 제약이 많으므로 일반 사용자에게는 큰 위협이 되지 않습니다. 하지만 해당 iOS 취약점을 이용해 누구나 iOS 디바이스를 탈옥할 수 있고, 내부를 들여다보는 것이 가능해졌기 때문에 iOS 취약점 연구에 기여하는 바가 큽니다.

Reference

  1. http://iokit.racing/oneweirdtrick.pdf
  2. http://newosxbook.com/bonus/iboot.pdf
  3. https://www.beyondlogic.org/usbnutshell/usb4.shtml
  4. https://www.beyondlogic.org/usbnutshell/usb6.shtml#SetupPacket
  5. https://habr.com/en/company/dsec/blog/472762/