Why should I know this?

Control Flow Integrity for COTS Binaries 본문

Study

Control Flow Integrity for COTS Binaries

die4taoam 2023. 2. 4. 15:28

Control Flow Integrity for COTS Binaries

august 2013 USENIX  best paper awarded. (https://www.usenix.org/node/174767)

“Security thesis review는 보안 관련된 논문의 개인 review로 다수의견과 일치되지 않을 수도 있습니다.”

 

소개글.

Control Flow Integrity(이하 CFI)는 많이 연구되는 분야로 Return Oriented Program(ROP), Jump Oriented Program(JOP)와 같은 Code reuse 공격 기법에 대한 방어 기법이다. 2013년 발표된 이 논문에서는 CFI를 real-world에 적용하기 위한 방안에 대한 연구 내용을 다루고 있다.

 

배경.

기존의 CFI를 적용하기 위한 방법들은 COTS(상용) 바이너리에 적용하기 어려웠다. 그 이유는, CFI를 적용하기 위해 CF가 변경되는 모든 곳의 코드를 변경해야 하는 제약사항이 있는데 기존에 연구된 기법은 COTS 바이너리에는 일반적으로 포함되지 않는 정보들을 기반으로 하기 때문이다. 예를 들어, 해당 논문에서 많이 언급되는 Abadi는 relocation 테이블에 기반하였으나 해당 정보는 stripped된 바이너리에는 존재하지 않는 정보이고, 거의 모든 COTS 바이너리는 stripped된다. 때문에 어떤 외부 정보에도 의존하지 않고 바이너리 자체를 기반으로 CFI를 적용할 수 있는 방법이 필요했다.

 

목표.

논문에서는 연구 목표를 Modularity, Trasparency, Compiler independence and support for hand-coded assembly 세 가지로 설정했다.

Modularity : 바이너리의 실행 간 의존성이 있는 라이브러리 모듈 등에 대해 CFI가 독립적으로 그리고 전역적으로 적용될 것을 보장한다.

Transparency : 바이너리를 변경하는 작업이 대상 바이너리의 실행에 미치는 영향을 없도록 한다.

Compiler independence and support for hand-coded assembly : 컴파일러에 의해 생성된 정보 등에 의존하지 않고 어셈블리로 수작업 된 low-level 코드에도 적용할 수 있도록 한다. (eg, libc)

 

방법.

Disassembler

Disassemble 방식에는 linear, recursive 두 방법이 있고 각각의 장단점이 존재한다. recursive 방식은 Control Flow를 분석하지만 Indirect Control Flow를 해석하지 못하는 문제가 있고, linear 방식은 전체 코드를 분석할 수는 있지만 Data와 혼합된 코드를 해석할 수 없는 문제 등이 있다. Disassembly의 정확성은 실행 흐름 간 코드 주입을 통해 무결성을 확보하는 CFI의 핵심 중에 핵심이므로 매우 중요한 요소이기에 이를 개선하는 방안을 연구했다.

먼저, linear 방식을 적용했을 시에 발생하는 문제를 세 가지로 정의했다

  • Invalid Code
    • x86 instruction의 해석의 문제.
  • Direct control transfers outside the current module
    • Program linkage table(PLT), Global offset table(GOT)나 ICF를 사용해야 할 필요가 있는 경우. 그리고 현재 모듈 범위를 벗어나는 Direct control transfer의 경우.
  • Direct control transfers to the middle of an instructions
    • Disassembly 혹은 control-flow transfer를 잘 못 해석한 경우.

위와 같은 문제가 발생하는 이유를 몇 가지로 정리했다.

  • Code Pointer constants(CK)
    • 컴파일 시에 계산된 코드 주소
  • Computed code addresses(CC)
    • 실행 시에 계산되는 코드 주소
  • Exception handling addresses(EH)
    • 예외 처리 시에 사용되는 코드 주소
  • Exported symbol addresses(ES)
    • export되는 코드 주소
  • Return addresses(RA)
    • call 다음의 코드 주소

 

위와 같은 방법으로 향상된 방법의 디스어셈블러를 구축했다고 소개하며 이에 대한 내용은 (An In-Depth Analysis of Disassembly on Full-Scale x86/x64 Binaries : https://www.usenix.org/system/files/conference/usenixsecurity16/sec16_paper_andriesse.pdf ) 여기서 교차 확인할 수 있다.  또한 이 논문의 저자들이 작성한 다른 논문 및 프로젝트 (A Principled Approach for ROP Defense : http://seclab.cs.sunysb.edu/seclab/pubs/shadow15.pdf)에서 본인들이 사용했다고 소개한 A Platform for Secure Static Binary Instrumentation(http://seclab.cs.sunysb.edu/seclab/pubs/vee14.pdf)를 여기(http://www.seclab.cs.sunysb.edu/seclab/psi/)에서 공개하고 있다.

Implement of CFI

CFI의 구현은 Statically Instrumentation을 통해 Binary rewriting으로 이뤄진다. 주입되는 코드는 주로 ICF의 전/후에 Integrity의 검증을 하는 목적이다. 또한 해당 논문에서는 Dynamic Binary Translation(DBT)기법을 응용하여 동적 함수 포인터 호출 시에 이를 처리할 수 있는 방법도 함께 소개하고 있다. 동적 함수 포인터 호출 시에 해당 주소를 검증하며 호출/반환을 처리할 trampolin 함수를 호출 함으로서 무결성 검증을 해냈다.

 

특장점.

해당 논문은 또한 CFI가 가진 약점인 오버헤드를 최적화 하기 위해서 “분기 예측”, “주소 변환”, “투명성 희생”의 3가지 방안을 제시한다.

Comments