ARM Exploitation

ARM32 에서의 return-into-libc attack

통칭 Code Reuse Attack이라고 불리는 기법으로 return-into-libc라는 공격이 있다. 이는 쉘 코드 등을 사용하지 못하도록 스택에 실행 권한을 제거한 NX, DEP 등의 보호 기법이 출시되자 그에 대한 새로운 우회 방법으로 제안된 것이다.


Davi, Lucas Vincenzo. Code-reuse attacks and defenses. Diss. Technische Universität, 2015.

return-into-libc[1]는 standard UNIX C 라이브러리인 libc에서 system() 함수를 표적으로 한다. 주어진 프로그램의 복귀 주소를 해당 라이브러리 내의 주요 함수 부분으로 지정하여 "/bin/sh"과 같은 매개 변수를 함께 전달함으로써 결국 대상 시스템에서 system("/bin/sh")이 수행되어 쉘을 획득하기 위함이다. 이 방법을 사용하면 추가적인 쉘 코드를 사용하지 않고도 이미 시스템 내에 기존 존재하던 함수만을 이용해 제어 흐름을 변경할 수 있다.

하지만 이 공격 기법은 인텔 x86의 호출 규약에 기반하기 때문에, ARM 시스템에서 바로 적용할 수 없다. 위에서 설명한 것처럼 system() 함수에 대한 매개 변수 전달 시 인텔은 스택에 있는 값을 가져온다. 하지만 ARM은 r0~r3 레지스터를 이용해서 함수의 매개 변수를 처리한다. 메모리 상의 스택의 값은 임의로 조작이 가능하나, CPU상의 레지스터는 임의로 변경할 수 없기 때문에 불가능한 것이다. 사실 이러한 문제는 인텔 x86_64에서도 동일하게 발생한다. 이를 해결하기 위해 진보된 return-into-libc 가 제안되었다. Krahmer의 방법은 레지스터의 값을 쓰는 코드 조각을 찾고 이를 빌려와서(borrowed code chunks) 익스플로잇에 악용하는 것을 골자로 한다[2]. 

한편 2010년 Avraham, Itzhak Zuk 이라는 사람이 Defcon 18 대회에서 Ret2ZP (Return To Zero Protection) 이라는 기법을 발표했다. 그는 ARM 환경에서 retur-into-libc가 동작하지 않는 이유를 설명하며 그에 대한 대안으로 Ret2ZP를 제안한 것이다. 그는 다음과 같은 순서로 페이로드를 작성을 진행한다고 했다.

  • Parameter adjustments
  • Variable adjustments
  • Gaining back control to PC
  • Stack lifting

결국 Ret2ZP는 ROP + Ret2Libc + Stack lifting + Parameter/Variable adjustments 의 조합으로 진행된다는 것이다. Defcon 발표의 특성상 엄청 학술적인 기준이라기보다는 실용적으로 어떤 파급 효과를 가져다줄 수 있는가에 주안점이 있을 수 있는데 실제로 ARM 기반의 Android 스마트 폰에서 익스플로잇을 시연하기도 하였을 만큼 좋은 발표였으리라 짐작이 된다. 다만 내가 봤을 때 그의 발표는 2010년이었고 이미 2005년에 인텔 x86_64에서 발생했던 이슈와 그에 대한 해결책에서 아이디어를 얻었던 게 아닐까라는 추측을 해본다. 그가 특별히 참고문헌을 밝히지 않았기에 이 부분은 나의 뇌피셜로 남겨둔다. 어쨌거나 ARM 환경에서 return-into-libc 공격을 하려면 정확하게는 Ret2ZP 기법이라고 부르는 것이 맞겠다.


Non-Executable Stack ARM Exploitation Research Paper (Rev1.0)


실제로 라즈베리 파이에서 ret2zp 기법을 통해 protostar stack6 문제를 풀이하는 과정을 다음 글에서 진행할 예정이다. 


참고로 이 글을 작성하는 2020년 현재에 Ret2ZP 기법이 여전히 효과적인지에 대해서는 다소 회의적이다. 우선 이 기법은 libc 내에 존재하는 system(), exec() 등의 함수에 의존한다. 이 때문에 만약 이런 함수를 제거한다면 공격자는 더 이상 이런 시도를 수행할 수가 없다. 실제로 현대의 많은 시스템들은 공유 라이브러리 영역에 매핑된 부분에 의도적으로 NULL byte를 삽입시켜서 공격자가 쉽사리 호출할 수 없도록 하고 있다. 뿐만 아니라 return-into-libc 공격은 한 번에 함수 하나 혹은 두개 정도만을 호출할 수 있기 때문에, 공격자가 보다 원활한 행동을 수행하는데 제약이 있다. 특히 unconditional branching을 수행할 수 없기 때문에 제어 흐름을 완벽히 통제할 수 없다는 한계가 존재하고, 페이로드 생성에 있어 Turing-Complete 하지 않다.

return-into-libc의 후속이라 할 수 있는 대안이 바로 잘 알려져 있는 ROP(Return Oriented Programming) 공격이다. 이 공격은 앞서 Krahmer[2]의 기법을 일반화한 것으로, 2007년 Hovav Shacham의 논문[4]으로 잘 알려져 있다. 이 기법은 x86 뿐만 아니라 ARM을 포함한 SPARC, PowerPC 등의 아키텍처에도 동작한다는 것이 확인되었다. ROP 및 ROP without returns 등에 대해서는 추후 별도의 글을 통해 설명하도록 하겠다.



[1] Solar Designer. lpr LIBC RETURN exploit, 1997. 

[2] Sebastian Krahmer. x86-64 buffer overflow exploits and the borrowed code chunks exploitation technique, 2005.

[3] Avraham, Itzhak Zuk. "Non-Executable Stack ARM Exploitation Research Paper." Revision 1 (2010): 2010-2011.

[4] Hovav Shacham. The geometry of innocent flesh on the bone: Return-into-libc without function calls (on the x86). In Proceedings of the 14th ACM Conference on Computer and Communications Security, CCS’07, 2007.

Software Security Engineer

CPUU 님의 창작활동을 응원하고 싶으세요?

CPUU의 Daydreamin'
CPUU의 Daydreamin'
구독자 220

0개의 댓글

SNS 계정으로 간편하게 로그인하고 댓글을 남겨주세요.
새로운 알림이 없습니다.