
CVE-2019-5700
안타깝게도 이 취약점에 대한 트렌디하고 영리한 이름이 없습니다. 이 버그는 상당히 간단하게 익스플로잇할 수 있습니다. 처음 생각했던 것보다 더 많은 장치에 영향을 미칠 수 있다는 것을 깨닫기까지 꽤 오랫동안 보류했습니다.
이 버그는 Android 부트 이미지를 부팅하는 Nvidia Tegra t114-t210 SoC에 영향을 미치지만, 한 가지 중요한 차이점이 있습니다:
t114 기반 장치는 통합 부트로더가 TOS(TLK - Nvidia의 시큐어 모니터)도 로드하기 때문에 훨씬 더 심각한 영향을 받습니다. 즉, 부트로더가 이미 시큐어 컨텍스트에서 실행 중입니다...
t124+ 장치에서 Nvidia는 이제 nvtboot를 초기 단계 부트로더로 사용하여 취약한 부트로더가 실행되기 전에 TOS를 로드한 후, 커널을 로드하고 실행합니다. 즉, 우리는 비시큐어 컨텍스트에서 실행 중입니다.
Android 부트 이미지 헤더(v1 - Android 9 이전)를 살펴보겠습니다:
struct boot_img_hdr
{
uint8_t magic[BOOT_MAGIC_SIZE];
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
uint32_t unused;
uint32_t os_version;
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
uint8_t cmdline[BOOT_ARGS_SIZE];
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
};
익숙한 이미지(kernel, ramdisk)에 대한 필드가 보입니다:
uint32_t kernel_size; /* size in bytes */
uint32_t kernel_addr; /* physical load addr */
uint32_t ramdisk_size; /* size in bytes */
uint32_t ramdisk_addr; /* physical load addr */
때로는 태그(종종 디바이스 트리 또는 ATAGS에 사용됨)도 있습니다:
uint32_t tags_addr; /* physical addr for kernel tags */
uint32_t page_size; /* flash page size we assume */
'second' 필드는 어떨까요?
uint32_t second_size; /* size in bytes */
uint32_t second_addr; /* physical load addr */
개인적으로 프로덕션 장치에서 사용된 적은 본 적이 없지만, 'second' 이미지는 2단계 부트로더 또는 로드해야 하는 추가 이미지에 사용될 수 있다고 알고 있습니다. 연구 경험에 따르면 다른 OEM의 대부분의 부트로더는 이 필드를 무시하거나(사용하지 않으므로), 크기와 주소에 대한 안전성 검사를 적용합니다.
Nvidia의 부트로더는 kernel, ramdisk, dtb에 대해 안전성 검사를 적용합니다. 이들 모두 하드코딩된 로딩 주소를 가지므로 헤더의 로딩 주소는 무시됩니다. 그러나 Nvidia가 이 거의 잊혀진 이미지에 대해 잊어버린 것 같습니다... 주소나 크기에 대한 안전성 검사 없이 임의로 로드합니다. 맞습니다. 접근 가능한 모든 메모리 주소(t114에서는 모든 메모리, t124+에서는 비시큐어 메모리)에 어떤 크기의 이미지든 임의로 로드할 수 있습니다.
이는 메모리에서 부트로더를 자유롭게 패치하여 우리의 필요에 맞출 수 있음을 의미합니다. 서명 확인을 건너뛰거나(모든 이미지를 로드한 직후에 발생), t114에서 TOS 로딩을 하이재킹하여 시큐어 컨텍스트 코드 실행을 얻거나, 민감한 정보를 덤프하기 위해 셸코드를 로드하는 등 원하는 대로 할 수 있습니다.
익스플로잇은 보조 이미지를 페이로드/셸코드로 사용하고 addr/len 필드를 페이로드 크기와 원하는 위치에 적절히 설정하여 부트 이미지를 생성하는 것만큼 간단합니다. 이미지는 4바이트만큼 작을 수 있습니다.
t124+ 장치에서는 nvtboot가 이미 부팅 초기 단계에서 TOS를 로드한 후 실행을 이후 단계 부트로더(EBT)에 넘겨주므로 시큐어 컨텍스트가 없지만, 메모리에서 이 후기 단계 부트로더에 자유롭게 쓸 수 있습니다. 취약한 부트로더는 커널을 로드하는 부트로더이므로, 임의의 서명되지 않은 코드를 실행하려는 경우 여전히 상당히 가치가 있습니다.
로딩 주소뿐만 아니라 크기도 확인되지 않으므로 악의적인 secondary_size 필드를 조작하여 다양한 변수/포인터를 오버플로할 수 있어 CVE-2019-5699로 이어집니다. 하지만 초기 보안 게시판이 발행된 후에야 깨달았기 때문에 이에 대한 공로를 인정받을 수 없습니다. 또한 훨씬 더 많은 작업이 필요한 것 같습니다...
t114:
IROM->BCT->EBT->TOS->KERNEL
t124+(최신 64비트 SoC의 경우 약간 다를 수 있음):
IROM->BCT->NVTBOOT->TOS->EBT->KERNEL
이 문제는 2019년 7월 29일 Nvidia의 PSIRT(제품 보안 사고 대응 팀)에 처음 보고되었습니다. 그들은 관련 고객에게 모두 통보되고 수정 사항이 배포될 때까지 공개를 연기해 줄 것을 정중히 요청했으며, 저는 기꺼이 따랐습니다. 그들은 프로세스 전반에 걸쳐 의사소통을 유지했으며 협력하기 즐거웠습니다. 오늘(2019년 12월 5일) Nvidia는 마침내 영향을 받는 코드에 대한 수정 사항을 출시했으며, 이 문제를 반영한 두 가지 다른 보안 게시판을 게시하고 공개를 허락했습니다.
https://nvidia.custhelp.com/app/answers/detail/a_id/4875
https://nvidia.custhelp.com/app/answers/detail/a_id/4910
balika011
beaups
npjohnson
djrbliss/Dan Rosenberg - 부트로더가 부트 이미지 헤더를 어떻게 파싱하는지 꼼꼼히 확인하게 해주셔서 감사합니다.