Home > 졸업프로젝트 > UEFI DXE 바이너리 취약점 분석기 프로젝트_12

UEFI DXE 바이너리 취약점 분석기 프로젝트_12
UEFI Ghidra

논문 끝!

다들 고생많으셨습니다!

그래서 한 주 동안 무엇을 했냐

 논문의 레퍼런스를 위해 SMM Callout 관련 자료를 열심히 뒤져본 결과, gBS뿐 아니라 gRT의 침범 역시 SMM Callout의 문제 대상인 것 같았다. gBS만 잡고 gRT를 탐지 대상에서 배제했던 이유로 먼저 gBS는 매우 직관적으로, OS 부팅 이후에는 실행 권한이 OS에 넘어가므로 언제 덮어썼을지 모르는 영역이다. 그러므로 당연히 gBS는 탐지 대상이다. 하지만 gBS는 부팅 이후에도 펌웨어가 사용하는 영역이다. 그래서 이 부분을 탐지하지 않았는데, 알고 보니까 이 부분이 펌웨어”만” 사용하는 영역이 아니라 펌웨어와 OS “모두” 사용되는 영역이라 SMRAM 내부가 아닌 DATA 영역 등에 위치한다고 한다.
즉, gRT를 무심코 사용하는 패턴(흔히 보던 getVariable, setVariable 등) 역시 SMM Callout으로 볼 수 있는 것이다!
출처

그래서 추가를 해보자

 추가 자체는 간단하다. 기존에는 gBS를 담을 전역변수를 하나 만들고 trackSystemTableGBS 함수 하나를 main에서 호출한 뒤, 이 함수가 checkIfStoredToGlobal(포인터가 어디서 메모리로 가는가), trackValueToMemory(메모리 정확히 어떤 지점으로 가는가) 등의 함수를 통해 전역변수, 메모리 등으로 진입하는지를 종합하여 gBS의 주소를 찾았다. 그리고 노드를 인자로 받아서 추적해서 노드를 역추적한 뒤 gBS의 주소와 같은지 확인하는 isTaintByGBS 함수를 가지고 scanForSmmCallouts 함수 내에서 분석을 진행했다.
 여기서 gRT 역시 잡을 수 있도록 전역변수와 trackSystemTableGRT 함수를 하나 더 만들어서 얘 역시 checkIfStoredToGlobal, trackValueToMemory 등의 함수를 가지고 gRT의 주소를 추적하도록 하였다. 여기서 gBS는 SystemTable에서 0x60만큼 떨어져있었지만 gRT는 0x58만큼 떨어져 있으므로 함수 구조는 동일하지만 0x60을 더하는 지점을 찾는 것이 아닌 0x58을 더하는 지점을 찾도록 했다. 이후 이 두 함수가 gRT인지 gBS인지 판단할 수 있도록 두 함수의 인자로 boolean isGBS를 추가하였다. 그리고 isTaintByGBS를 좀 더 범용적으로 쓸 수 있도록 인자에 노드를 추가한 isTaintBy 함수로 교체한 뒤, scanForSmmCallouts 내에서 각 노드에 대해 gBS와 gRT를 한번씩 검색하도록 해서 gRT까지 잡을 수 있도록 했다.
제목
 위 코드와 같이 gRT를 사용하는 코드를 추가하였고, 빌드 이후 해당 efi 파일을 기드라에 넣어 잘 작동하는지 확인했다.
제목
잘 작동했다!

이걸 어떻게 정제하지

 일단 결론적으로, gRT를 쓰는 영역은 전부 취약점으로 보기로 했다. 이 과정에서 json 등을 마구마구 바꿔서 결과 리포트를 바꿔야할 것으로 생각되지만… 이 부분은 당장은 졸업프로젝트를 위해 근시일에 해결 가능한 Future work 정도로 남겨두고, gRT를 호출하는 영역을 성공적으로 잘 잡아내어 취약점 리포트에 담은 것까지 나름 괜찮은 성과로 생각하려 한다..