Google의 Project Zero에서 삼성의 Knox 하이퍼바이저를 우회하는 방법을 발견했습니다(1월 패치에서 수정됨)

최신 Project Zero 블로그 게시물에서 팀은 Knox Hypervisor라고 불리는 삼성의 실시간 커널 보호를 우회하는 방법을 발견했습니다.

Google의 Project Zero 팀은 안전한 것으로 알려진 Samsung Knox 보안 제품군을 실행하는 Samsung 휴대폰이 공격을 받을 수 있도록 하는 여러 가지 악용 사례를 확인했습니다. 블로그에서는 모든 취약점이 삼성에 전달되었으며 삼성은 실제로 1월 소프트웨어 업데이트를 통해 해당 취약점에 대한 수정 사항을 발표했다고 밝혔습니다.


배경

Samsung이 도입한 Samsung Knox 보안 소프트웨어 제품군의 일부로 Android 애플리케이션과 커널 사이에 위치하는 소프트웨어가 있습니다. 하이퍼바이저. 이는 Android 기기를 더욱 안전하게 보호하기 위한 추가 계층으로 사용될 수 있습니다. Samsung Knox 하이퍼바이저의 이름은 "실시간 커널 보호" 또는 줄여서 RKP라고 합니다. 이 기사의 나머지 부분에서 이를 참조하겠습니다.

커널은 Android 소프트웨어 스택에서 RKP 아래에 위치하며 기기에서 실행되는 애플리케이션은 맨 위에 위치합니다. RKP의 기본 개념은 장치에 대한 모든 요청(메모리 및 기타 리소스)에 대해 추가 보안 계층을 제공하는 것입니다. 커널에 대한 애플리케이션은 먼저 Knox를 거쳐야 하며, Knox는 애플리케이션이 자신이 수행하는 작업을 수행하는지 감지하려고 시도합니다. 해서는 안됩니다. RKP는 또한 애플리케이션이 장치를 손상시키는 데 사용할 수 있는 민감한 정보를 숨기는 추가 계층을 통해 모호함을 통한 보안을 제공합니다.

블로그 게시물은 Android 메모리, RKP 및 운영 체제가 일반적으로 작동하는 방식에 대해 매우 자세히 설명하므로 발견된 내용에 대한 빠른 개요를 제공하기 위해 이를 요약하고 단순화했습니다. 하지만 시간이 있다면 전체 기사를 읽어 보시기를 권합니다. 이 기사는 매우 깨달음을 주는 내용이기 때문입니다.


익스플로잇 #1:

KASLR 또는 커널 주소 공간 레이아웃 무작위화는 부팅 시 메모리 내 커널 코드 위치를 무작위로 변경하는 프로세스입니다. 장치가 부팅될 때마다 커널은 다른 주소 공간(메모리 영역)에 로드됩니다. 아이디어는 각 부팅 후 커널 코드가 메모리에서 임의의 양만큼 "이동"하기 때문에 공격하기 위해 커널 코드가 있는 위치를 찾는 것을 더 어렵게 만드는 것입니다. 이는 잠재적인 공격자를 방지하기 위한 훌륭한 단계처럼 들리지만 최근에는

연구 KASLR은 실제로 로컬 공격자에 대해 강력한 방식으로 구현하기가 매우 어렵기 때문에 소프트웨어 버그나 취약점 없이 이를 실제로 물리칠 수 있음을 보여주었습니다.

RKP 소프트웨어의 경우 KASLR을 우회하는 능력은 위에서 언급한 연구보다 실제로 더 간단합니다. 모든 안드로이드 장치의 메모리는 포인터에 의해 참조되며, 안드로이드 장치가 인쇄하거나 출력할 때마다(화면이든 출력이든) 공격으로부터 장치를 보호하기 위해 참조됩니다. 로그 또는 디버깅을 위해 파일에 저장) 포인터 참조는 익명으로 처리되므로 포인터를 읽을 때 포인터가 실제로 가리키는 위치를 알아내는 것이 불가능합니다. 산출.

메모리 포인터는 위치를 가리키는 거리 표지판과 같다고 생각하고 익명화는 이를 흐리게 하는 것으로 생각하십시오. TV와 마찬가지로 익명화는 촬영 후에 이루어지며, Android도 출력 시 익명화가 올바르게 구성된 경우에만 이 익명화를 적용하며 작성자는 다음과 같이 말합니다. [그가] 만난 모든 장치에는 포인터 익명화가 올바르게 구성되어 있었습니다.. 이것은 해독하기가 매우 어려운 것처럼 들릴 수 있지만, 여러분이 해야 할 일은 익명화되지 않은(흐릿하게 처리된) 단일 포인터(거리 표지판을 생각해 보세요)를 찾는 것입니다. 포인터가 로그나 기타 위치에 기록될 때 커널 개발자(일반적인 Android 앱 개발자가 아님)에 의해 수행됩니다. 화면이나 파일.

따라서 익명화되지 않은 포인터를 찾을 수 있으면 커널의 무작위 주소 이동을 둘 사이의 차이로 계산할 수 있습니다. 흥미롭게도 작성자는 커널에서 악용 가능한 포인터를 찾을 수 없었지만 RPK 내부에서는 찾았습니다. 개발자들은 디버그(로깅) 출력에서 ​​포인터를 익명화하는 것을 잊어버렸습니다. 오식. Android에서 포인터를 익명화하려면 특수 코드를 사용해야 하며 RPK 개발자가 실수로 소문자 'k' 대신에 대문자 'K'. 그러므로 커널 코드의 무작위 이동량을 파악하고 공격하는 것은 비교적 간단했다.


익스플로잇 #2:

다음 공격은 좀 더 복잡합니다. Samsung Knox는 악성 코드를 차단하기 위해 장치 메모리에 일련의 규칙을 적용하여 장치를 보호합니다. 규칙은 다음과 같습니다.

  1. 커널 코드를 제외한 모든 페이지(메모리의 코드)는 "Privileged Execute Never"로 표시됩니다(여기의 코드는 절대 실행될 수 없음을 의미).
  2. 커널 데이터 페이지(프로그램이 메모리에서 사용하는 데이터)는 실행 가능으로 표시되지 않습니다. 따라서 여기의 코드는 실행될 수 없습니다.
  3. 커널 코드 페이지(메모리의 코드)는 쓰기 가능으로 표시되지 않습니다(따라서 악성 코드가 이를 변경할 수 없음).
  4. 모든 커널 페이지는 2단계 변환 테이블(애플리케이션이 실제 메모리 위치를 알지 못하도록 애플리케이션과 커널 사이에 있는 테이블)에서 읽기 전용으로 표시됩니다.
  5. 모든 메모리 변환 항목은 애플리케이션에 대해 읽기 전용으로 표시됩니다.

저자가 위의 규칙 구현에서 문제를 발견한 규칙 3에 중점을 둘 것입니다. RPK는 실제로 커널의 메모리를 읽기 전용으로 표시하지만 KASL에 대한 감독으로 구멍이 발견되어 다음과 같은 문제가 발생했습니다. "읽기 전용" 섹션에 코드 작성. 부팅 시 커널 위치를 난독화하기 위해 메모리가 커널에 할당되지만 이 메모리 양은 커널의 텍스트 세그먼트보다 훨씬 큽니다. 더 많은 양의 메모리를 할당하면 어디에나 있을 수 있는 실제 커널 코드를 찾기가 훨씬 더 어려워지고 위에서 본 것처럼 장치가 부팅될 때마다 무작위로 이동됩니다.

_text 및 _etext는 보호된 범위를 표시합니다.

저자는 커널이 사용하는 메모리가 실제로 "읽기 전용"으로 표시되어 있음을 확인할 수 있었지만, 커널을 숨기는 데 사용된 대용량 메모리의 나머지 부분은 읽기 전용이었습니다. ~ 아니다 "읽기 전용"으로 표시됩니다. 이는 RKP가 KASLR 슬라이드를 적용한 후 커널 텍스트가 포함된 영역만 보호하기 때문입니다.


익스플로잇 #3

세 번째 공격에서 작성자는 읽기 전용으로 제한되어야 하는 다른 메모리 영역에도 액세스할 수 있었습니다. RKP는 메모리를 보호하고 하이퍼바이저 구성 레지스터 (HCR)을 사용하여 주요 커널 작업을 제어합니다. HCR의 핵심은 유효한 실제 커널 작업이 레지스터에 액세스할 수 있도록 허용하고 악의적인 공격을 차단하는 것입니다. 가상화 기능을 관리하는 레지스터에 대한 호출을 확인하여 이를 수행합니다. HCR은 RKP가 요청을 허용할지 여부를 선택할 수 있도록 정상적으로 처리되는 특정 작업을 차단하도록 구성됩니다.

이 악용에서 HCR 제어는 다음과 같습니다. 두 개의 레지스터를 포함하지 않음 그것은 매우 중요한 것으로 밝혀졌습니다. 저자는 ARM 참조 매뉴얼을 깊이 파고들어 첫 번째 레지스터를 통해 애플리케이션에 대해 기본적으로 RKP를 끌 수 있다는 사실을 발견했습니다. "EL1용 시스템 제어 레지스터(SCTLR_EL1)는 메모리 시스템을 포함하여 시스템에 대한 최상위 제어를 제공합니다.." 완벽한 세상에서 애플리케이션은 RKP를 통해 매핑된 메모리를 사용하므로 RKP는 애플리케이션이 액세스할 수 있는 항목을 제어할 수 있습니다. 그러나 이 레지스터를 끄면 다음이 허용됩니다. RKP 비활성화 RKP를 설치하기 전의 실행 상태로 장치를 효과적으로 되돌립니다. 즉, RKP에서 제공하는 추가 보안 없이 장치가 실제 메모리에 매핑됩니다. 이는 결국 작성자가 RKP 소프트웨어에 의해 원래 정확하게 차단된 메모리를 읽고 쓸 수 있다는 것을 의미했습니다.

놓친 두 번째 레지스터는 더 미묘한 영향을 미쳤지만 궁극적으로는 보안에 치명적인 영향을 미쳤습니다. 그만큼 EL1용 번역 제어 레지스터 (TCR_EL1) 레지스터는 페이지라고 불리는 애플리케이션이 작동하는 메모리 양과 직접적으로 관련됩니다. AARCH64 Linux 커널(예: Android)은 4KB의 변환 크기를 사용하므로 RKP는 4kb의 페이지 크기로 하드코딩됩니다. 문제의 레지스터(TCR_EL1)는 ARM 칩셋을 반환될 메모리 크기로 설정합니다. 그것은 밝혀졌다 이 등록부는 HCR에 의해 보호되지 않습니다 따라서 작성자가 페이지 크기를 64kb로 변경한 것처럼 공격자가 이를 변경할 수 있습니다.

이것이 의미하는 바는 요청이 RKP에 의해 이행될 때 액세스 가능한 실제 메모리 양이 이제 4kb가 아닌 64kb라는 것입니다. 그 이유는 ARM 칩셋이 여전히 페이지 크기를 제어하고 익스플로잇으로 인해 64kb로 설정되었기 때문입니다. RKP는 익스플로잇 #2에 나열된 규칙의 일부로 메모리가 기록되지 않도록 보호하므로 메모리는 여전히 실제로 보호됩니다. 그러나 여기에 문제가 있습니다. RKP는 4kb로 하드코딩되어 있으므로 레지스터가 업데이트될 때 64kb 페이지 크기로 변경되지 않습니다. 메모리의 처음 4kb만 보호됩니다. 공격자가 할 수 있도록 허용 남은 60kb로 원하는 건 뭐든지.


익스플로잇 #4

저자가 보여주는 마지막 익스플로잇은 RKP 소프트웨어가 있는 메모리를 참조하여 공격자가 RKP 소프트웨어 자체를 공격할 수 있다는 것입니다. Linux 커널이 사용하는 이러한 유형의 공격을 중지하는 한 가지 방법은 가상 메모리 주소 공간에서 프로그램의 매핑을 해제하여 응용 프로그램이 참조할 수 없기 때문에 공격할 수 없도록 하는 것입니다.

메모리는 물리적 메모리를 가상 메모리에 매핑하는 포인터와 테이블에 관한 것임을 기억하세요. 이러한 유형의 공격에 대한 일반적인 방어에 따라 RKP는 공격을 받을 수 없도록 자체 매핑을 해제합니다. 그러나 커널이 이러한 기능을 제공하지 않는 경우 RKP는 메모리 조각을 매핑하고 읽기/쓰기로 표시할 수 있도록 허용합니다. 유일한 확인은 매핑되도록 요청된 주소가 RKP 자체가 메모리에 상주하는 영역인지 확인하기 위해 RKP가 확인하지 않기 때문에 기본 커널 자체가 아니라는 것입니다. 기본적으로 RKP 자신을 다시 매핑할 수 있습니다. 응용 프로그램이 액세스할 수 있는 주소 공간으로 다시 돌아가고 측면에서 영향을 미칩니다. 메모리는 자동으로 읽기/쓰기로 표시됩니다. 따라서 공격자는 이제 원하는 대로 메모리를 사용할 수 있습니다.


결론

위에 나열된 네 가지 익스플로잇의 가장 큰 문제 중 하나는 저자가 기본 Android 커널의 기능 부족으로 인해 이러한 익스플로잇을 수행하는 것이 얼마나 어려운지 언급했다는 것입니다. 아이러니하게도 보안 RKP 하이퍼바이저는 공격을 수행하는 데 필요한 모든 도구를 제공했습니다. 때로는 선의의 소프트웨어가 해결하는 것보다 더 많은 문제를 야기한다는 사실을 보여주며, 우리에게 사람들이 있다는 것은 행운입니다. Gal Beniamini처럼 기꺼이 손을 더럽히고 문서가 소프트웨어의 실제 내용과 일치하는지 테스트합니다. 하다.

이러한 익스플로잇은 무서운 것처럼 보이고 Knox를 매우 취약하게 만드는 반면, 이러한 문제는 모두 발생했다는 점을 모두에게 확신시켜 드리고 싶습니다. 1월 업데이트에서 수정됨 삼성에서. 게다가 이러한 익스플로잇을 사용하려면 ARM 프로세서와 프로그래밍에 대한 깊은 이해가 필요하므로 이러한 익스플로잇을 사용하는 데 있어 진입 장벽은 천문학적으로 높습니다.


출처: 프로젝트 제로