Citation
Yaniv David, Nimrod Partush, and Eran Yahav. 2018. FirmUp: Precise Static Detection of Common Vulnerabilities in Firmware. In Proceedings of 2018 Architectural Support for Programming Languages and Operating Systems (ASPLOS’18). ACM, New York, NY, USA, 13 pages. https://doi.org/https://doi.org/10.1145/3173162.3177157
Abstract
- stripped된 firmware image에서 CVE를 찾기 위해서 static, precise, scalable한 기술을 제시한다.
- 실행 가능한 바이너리의 취약한 procedure와 여러 strip된 바이너리가 포함된 Firmware Image가 주어지면, 해당 펌웨어 이미지에서 취약한 preocedure의 발생 가능성을 탐지하는 것이다.
- 벤더사마다 다양한 아키텍처와 고유한 tool chain, 맞춤화된 firmware 특성으로 strip된 firmware를 식별하는 것은 어렵다.
- 취약점 탐지를 위해서는 procedure간의 유사성뿐만 아니라 관련된 실행 파일의 procedure간의 관계에 대한 정보도 필요하다. 이러한 관찰은 두 바이너리에서 procedure 간의 부분적인 대응을 설정하는 새로운 기술의 토대가 된다.
- FirmUp이라는 도구에서 이 기법을 구현하고 공개된 벤더사의 firmware image에서 크롤링한 4000만개의 procedure, 자주 사용되는 4가지 이상의 아키텍처에 대해 evaluation했다.
- 그 결과, 공개적으로 사용 가능한 펌웨어에 영향을 미치는 373개의 취약점을 발견했고, 그 중 147개는 최신 버전에서 취약점이 발생했다.
- FirmUp은 기존에 알려진 최신 연구 방법에 비해 탐지율이 평균 45% 능가한다.
Introduction
해당 논문에서는 3가지의 핵심을 설명한다.
- Firmware is often customized per device
- Problem definition
- Existing Approaches의 한계
Firmware is often customized per device
- Firmware는 실행되는 특정 장치에 맞게 라이브러리의 일부만 포함하도록 Customize 및 최적화되는 경우가 많다.
- Firmware image의 압축을 풀고 디바이스의 파일 시스템을 살펴봐도 실행 파일에서 디버그 정보(Symbol)가 제거되어 있는 경우가 많다.
- 해당 binary를 실행하려면 실행 파일의 아키텍처와 환경에 대한 commandline access가 필요한데, 쉽지않다.
- Firmware 실행 파일에서 취약한 어셈블리 코드를 직접 검색하는 것도 쉽지 않은데, 각 공급업체마다 고유한 빌드 Tool-Chain을 사용할 수 있으며, 이로 인해 어셈블리에서 엄청난 구문 차이가 발생할 수 있다.
Problem definition
- 정의
- 실행 파일 모음 $\mathcal{F} = {T_1,\dots,T_n}$(e.g., a firmware image)
- 분석하고자 하는 실행 파일 : $\mathcal{Q}$
- $\mathcal{Q}$의 취약한 Procedure : $\mathcal{q_v}$
- 목표 : $\mathcal{T_i} \in \mathcal{F}$. 즉, 주어진 쿼리 실행 파일 $\mathcal{Q}$에 있는 취약한 Procedure $\mathcal{q_v}$와 유사한 procedure $\mathcal{F}$에 속한 다른 실행 파일들(${T_1,\dots,T_n}$)에도 있는지를 확인하려고 한다.
- 두 Procedure를 동일한 소스 코드에서 유래된 경우 유사하다고 정의한다. 유사성은 소스 코드의 변경(패치, 버전)에 따라 달라지며, 프로시저가 의미상으로 다를수록 유사성이 감소했다고 본다. $\mathcal{F}$의 각 실행 파일들이 어떤 컴파일러로 컴파일되었는지에 관계없이, 그리고 이름 정보가 제거되었는지 여부와 관계없이 유사성을 평가한다.
Existing Approaches의 한계
- Binary Code Search는 Well-reasearched problem이지만, 이전 접근 방법은 다음과 같다.
- 여러 Basic Block이나 Single Procedure를 사용하여 취약점에 대한 Signature를 생성한다. Signature는 Basic Block의 코드와 CFG(Control Flow Graph)의 구조를 기반으로 만든다.
- 이 방법은 Binary에 포함된 다른 procedure들에 대한 중요한 정보를 무시한다는 단점이 존재한다.
- 전체 바이너리를 비교하여 개별 CFG 또는 call-graphs의 완전한 동형성을 찾아내고, 그로부터 취약한 Procedure를 찾아낸다.
- 이 방법은 소프트웨어가 다양한 환경과 요구 사항에 맞추어 다르게 구축된다는 점을 간과한다. 예를 들어, wget과 curl 같은 binary는 컴파일 옵션에 따라 구조가 크게 달라질 수 있어서 완전한 동형성을 달성하기 어렵다.
- 여러 Basic Block이나 Single Procedure를 사용하여 취약점에 대한 Signature를 생성한다. Signature는 Basic Block의 코드와 CFG(Control Flow Graph)의 구조를 기반으로 만든다.
- 이전 접근 방식은 높은 false positive가 존재한다.
- 이 실험에서는 GitZ, BinDiff와의 비교를 통해 입증했다.
1.1 Our Approach
stripped binaries에서 유사한 procedures를 찾아내는 것이 목표다.
- Procedure를 정형화된 fragments로 표현
- 단일 실행파일이 아닌, 모든 실행파일들에 대한 procedure 정보 활용
- 실행 파일의 context에서 procedure를 효율적으로 매칭
- back-and-forth game에서 영감을 받아, 쿼리 프로시저에 대한 더 정밀한 매칭을 찾기 위해 실행 파일의 주변 프로시저를 사용하는 알고리즘 제안
- MIPS32, ARM32, PPC32, Intel-x86 아키텍처를 사용하는 임베디드 장치에 대해 실행 파일의 유사성을 검색하는 FirmUp 개발
2. Overview
2.1 Pairwise Procedure Similarity
이 예시는 wget(v1.15)과 NETGEAR의 ftp_glob_retrieve()
procedure의 첫 번째 basic block(BB)다. 해당 MIPS Assembly 코드 snippet을 보면, 아래 두 코드는 매우 다르고 코드 라인을 전혀 공유하지 않는다. 이러한 구문적 차이가 발생하는 이유는 다양한 설정과 tool chain을 사용하여 procedure를 컴파일했기 때문이다. 비록 구문적으로 다르지만, 이 코드 조각은 많은 의미를 공유한다.
- 두 코드는 모두 스택에서 값을 가져온다. ((a) 5번째 줄, (b) 1번째 줄)
- 두 코드 모두 0x1f를 load하고, 이를 jump비교 연산에 사용한다. ((a) 4,6번째 줄, (b) 5,6번째 줄)
- 두 코드 모두 procedure를 호출한다. ((a) 1번째 줄, (b) 3번째 줄)
비록 구문적으로 동일하지 않지만, 이 프로시저들은 큰 유사성을 공유한다. 그러나 명령어 선택, 순서 및 레지스터 사용의 차이, 그리고 다른 코드 및 데이터 레이아웃(오프셋) 때문에 이 유사성을 찾기가 어렵다.