[하루한줄] PAC와 PAC Forgery

URL

Target

  • > ARMv8.3

Explain

Fabu1ous님이 말도 없이 제가 하루한줄로 쓰려던 주제를 어제 써버리는 바람에… 오늘은 PACPAC Forgery에 대해서 간단하게 알아보도록 하겠습니다.

PACPointer Authentication Code의 약자로, 말 그대로 포인터들을 인증하는 미티게이션 기법입니다. ARMv8.3-A부터 지원하며 iOS에서 이 미티게이션을 지원하면서 익스플로잇 난이도가 많이 올라갔다고 합니다.

예… 저는 안해봐서 얼마나 어려운지 모르겠네요…?

안드로이드에서도 지원을 하는지 여부는 제대로 확인을 못해봤습니다. ARMv9로 나오는 Cortex CPU에서 PAC를 지원하는 기사를 봤는데, 혹시 아시는 분이 있으면 댓글 달아주세요 ㅜㅜ

PAC가 동작하는 방식은 매우 “간단”합니다.

먼저, pac로 시작하는 명령어(ex. paciasp, pacia)를 통해 context와 key 그리고 해당 포인터를 이용해 sign을 합니다. 이 때, key는 128비트 값이며 시스템 레지스터에 저장되어 있는데, 일단 유저 권한에서는 당연히 접근할 수 없습니다. context는 64비트 값을 사용합니다. paciasp를 사용하여 PAC를 생성할 경우, 스택 포인터를 사용합니다.(paciasp의 맨뒤가 sp인 이유)

그리고 이 세 개의 값은 특정 알고리즘으로 계산되어 PAC를 생성할 수 있는데, 기본적으로 QARMA를 사용하고 CPU 제조사마다 커스텀이 가능합니다. 이렇게 생성된 PAC는 sign하려고 한 포인터의 상위 주소에 저장됩니다.

Sign한 뒤, 해당 포인터를 사용할 때에는 먼저 aut로 시작하는 명령어를 사용하여 해당 포인터가 변조되었는지를 확인합니다. 똑같이 포인터 값과 context 그리고 key 값을 사용해 해당 포인터가 정상인지를 검증합니다. 따라서 userspace에서는 PAC생성 알고리즘에서 사용하는 key와 context뿐만 아니라 PAC를 생성하는 알고리즘을 알고 있어야만 알고리즘에 부합하는 값을 얻어낼 수 있습니다.

PAC Forgery는 key와 알고리즘 없이 이를 우회하는 기법입니다.

첫 번째 블로그의 예시 문제에서는 간단한 버퍼 오버플로우를 통해 LR을 조작할 수 있습니다. 이 문제는 ASLR이 걸려있지 않기 때문에 PAC 생성에 사용되는 스택 주소는 디버깅을 통해 알 수 있습니다.

그리고 sign_contract()함수를 살펴보면 pacia 명령어를 이용해 특정 레지스터에 대한 PAC를 생성합니다. 이처럼 사용자가 활용할 수 있는 pacia 명령어가 존재하고 context를 알고 있다면 원하는 PAC 코드를 생성할 수 있습니다. 그러면 이런 기능을 활용하여 점프하고 싶은 주소에 대한 PAC 코드를 생성하고 LR에 넣으면 원하는 주소로 점프하여 익스플로잇을 할 수 있게 됩니다.

다만, 해당 예시 문제는 pacia를 자유롭게 활용할 수 있는 상황이고 ASLR이 안 걸려 있어 익스플로잇하기 매우 쉬운 상황입니다. 리얼월드에서는 기본적으로 information leak 취약점과 pac 명령어들을 활용하는 취약점이 있어야하기 때문에 기본적으로 두개의 취약점을 가지고 있어야 익스플로잇을 해볼 수 있습니다. 이래서 어려운건지 모르겠네요. 언젠가는 제가 직접 익스플로잇을 해보면서 이에 대해 설명하는 글을 써보도록 하겠습니다.