remote bufferoverflow.txt


remote_exploit.pdf


출처 : 해커스쿨

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License


dtor_fs.txt


Overwriting ELF .dtors section to modify program execution이란 제목의 문서 번역본 입니다.


출처 : 해커스쿨

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

최근에 SBS에서 방영되고 있는 '유령' 이라는 드라마에서 자동차가 해킹을 당하면 어떤 위험이 생기는지에 대해서 직설적이고 흥미롭게 그려낸 적이 있었다. 실제로 충분히 가능한 일이다. 자동차는 요즘 그냥 자동차가 아닌 하나의 컴퓨터가 탑재 된 첨단기기라고 불릴 만큼 그 기능의 수준이 정말 높으며 그 기능들은 모두 PC의 CPU가 컴퓨터를 제어하는 것처럼 ECU라는 프로세서에 의해 관리 된다. 사실 자동차 해킹은 하드웨어 해킹에 일부분으로 하드웨어 해킹은 해커들에 의해 이전부터 꾸준히 연구되어 왔고 근래에 들어 연구되어왔던 연구결과들이 각종 컨퍼런스에서 발표되고 문서로 배포 되고 있는 상황이다. 하지만 자동차 해킹만큼은 그 결과를 보기 힘든데 그 이유는 아직 관심부족인 이유도 있지만 ECU라는 프로세서에 대해 정확히 이해를 하지 않았기 때문이라 보고 있다. ECU 라는 것은 자동차의 모든 기능들을 관장하는 프로세서로 그 구조가 어떻게 보면 간단할 수도 있지만 그리 간단하지 많은 않기 때문에 쉽사리 연구를 진행하지 못하는 것 같다. 이번 글에서 ECU의 구조와 펌웨어의 구조를 간단히 살펴보고 급발진 원리가 어떻게 되는지, 해킹은 어떻게 이루어질 것인지에 대해 언급하고자 한다.


[ECU]

ECU(Electronic Control Unit)이란, 자동차의 엔진, 변속기(자동), ABS(Anti-lock Braking System) 등을 제어하는 장치로 기존의 목적은 엔진 실린더에 연료분사량 조절, 공회전등의 엔진 핵심 기능을 제어하려 설계되었지만 자동차가 점점 발전하고 그 기능이 많아져 ECU가 제어하는 기능들도 점차 많아져 오늘날에 이르고 있다.


[ECU 구조]

ECU는 단일 마더보드로 구성되어 있고 그 안에는 이전만 하더라도 롬이 장착되어 있었다. 하지만 요즘은 Flash ROM이 장착되어 있어 간단히 펌웨어 Writting이 가능하다. 이러한 이유로 ECU에 특정 비정상 시그널이 전해지게 되면 Flash ROM 내부의 펌웨어 데이터가 깨져 ECU가 제대로 동작하지 않는다. 이건 마치 MySQL이 버전 4에서 5로 올라가면서 DB와 Table을 효율적으로 관리하기 위해 InformationSchema를 추가한 것과 마찬가지인 경우다. 언제든 지우고 쓸 수 있는 FlashROM을 장착함으로써 자동차의 기능을 좀 더 효율적으로 관리할 수 있지만 그에 따른 위험도 같이 동반되기 때문이다.(MySQL의 InformationSchema 때문에 SQL Injection이 쉬워진것과 같은 이치) 

대표적으로 Flash ROM의 Writting 기능이 사용 된 사례는 에쿠스 리콜 사태를 들수 있다. 펌웨어 문제로 인해 많은 에쿠스가 리콜조치 된 사례이다. ECU의 하드웨어적인 구조는 그 복잡도가 역사가 긴만큼 복잡하여 모두 설명하지는 않고 뒷부분에서 언급할 급발진 부분에서 이 글 성격에 맞는 부분만 잠시 언급할 생각이다. 지금 이 부분에서는 소프트웨어 구조를 설명하도록 하겠다.

ECU의 펌웨어 구조는 제조회사마다 조금씩 상이하였는데 최근에 들어 이러한 구조들을 표준화하여 개발을 효율적으로 할 수 있도록 하였다. OSEK/VXD와 ISO에서 정의하여 표준으로 제시하였는데 이 표준의 구조는 다음과 같다.


* 참고 : OSEK는 독일에서 진행한 차량용 분산 제어장치 프로젝트를 말하며 VXD는 프랑스 자동산 산업계 공동 프로젝트이다. 이 둘은 1997년 통합되어 OSEK/VXD로 불린다.


[그림 1 - OSEK/VXD 표준]


[그림 1]에서 Interaction Layer, Network Management, Transport Protocol 는 OSEK에서 정의하였으며, Diagnostic Layer와 Transport Protocol는 ISO에서 정의하였다. 각 레이어에 대해서 간단히 설명을 하자면 다음과 같다.


 * 참고 : CAN 이라는 것은 해당 소프트웨어에서의 표준 프로토콜이라 생각하면 된다.


 - Application Layer : 우리하 흔히 알고 있는 OSI 7 Layer에서 Application Layer와 거의 동일하다고 보면 된다.


 - Interaction Layer : 소프트웨어 구조 설계시 정의 된 메시지 전송 형태의 핸들링을 처리하는 기능의 Layer이다. 또 데이터 교환에 관한 API를 제공하고 각종 기본 값들을 설정 할 수 있다.


 - Diganostic Layer : 자동차에 내장 된 각종 진단 기능에 대해 인터페이스를 제공하는 Layer 이다. 또 예외처리(Busy 등)를 담당하고 있으며 CAN과 관련한 진단사항 요구를 처리한다.


 - Transport Protocol : 대용량(기본 전송 데이터는 8byte인데 이보다 더 큰) 데이터를 보내기 위한 고안된 Protocol이다. 네트워크의 7Layer 중 Transport Layer처럼 데이터 분할 기능도 있다. 또 동기화 기능과 에러감지 기능도 가지고 있다.


 - Network Management : 주된 목적은 자동차의 전원 사용 효율성이다. 각 상태(Network Wakeup, Network Active, Network Slepp)에 따라 전원 사용량을 달리 하는 기능을 가지고 있다.


 - CAN Calibratoin Protocol : ECU의 Flash ROM에 다양한 데이터 접근 방식으로 읽기와 쓰기를 담당하는 프로토콜이다.


정말 간단히 알아보았다. 세부적으로 알아본다면 이보다 더 어렵고 복잡하다. 하지만 이글 특성상 그 부분까지는 가지 않을 것이다. 


[자동차 해킹]

자동차 해킹에는 여러가지가 있을 수 있다. 자동차를 원격 조종한다던가 자동차의 네트워크(근래 들어 자동차에 페이스북이나 트위터 등의 SNS 서비스를 제공하는 자동차들이 많아졌다.)를 해킹한다던가 하는 것들이 있을 수 있다. 하지만 가장 중요한 것은 자동차의 원격 조종, 특히 요즘 논란이 되고 있는 급발진에 대한 부분일 것이다. 사용자가 의도치 않게 엔진이 과회전해 사용자의 제어범위를 넘어서 자동차가 폭주하다 사고가 나는게 급발진인데 바로 생명과 직결될 수 있는 문제이므로 위험한 문제라고 할 수 있겠다. 현재 급발진의 이유로는 ECU의 비정상 신호가 TPS(스로틀밸브를 조절하는 센서)에 이상신호를 보내 TPS가 스로틀밸브를 100% 개방하여 엔진 실린더내에 비정상적으로 많은 공기가 유입되어 정상보다 많은 폭발이 일어나 엔진이 폭주한다는 것이다. 사용자의 제어범위를 넘어서게 되면 자동차는 그야말로 폭주기관차가 되어 운전자나 동승자 뿐만이 아니라 주위에 피해를 줄 수도 있다. 더군다나 자동변속기는 변속이 쉽게 되기 때문에 급발진으로 인해 어딘가에 부딪힐 시 변속기가 변속되어 후진으로 다른 곳에 돌진 할 수도 있어 그 추가 피해가 발생한다. 드라마 '유령'에서는 자동차에 내장된 USB 포트로 펌웨어 변조 악성코드를 주입 해 ECU를 해킹 해 자동차를 급발진 시키는 시나리오를 보여주었는데 이는 어느정도 가능한 이야기이다. 위에서 설명한 소프트웨어 구조 중 CAN Calibration Protocol을 조작하여 Flash ROM을 조작하고 TPS와 관련된 접지단자의 시그널을 비정상 시그널로 바꾸어 TPS에 보내면 되는 것이다.


[그림 2 - ECU 회로도(자세히 보려면 크게 해서 보시기 바랍니다)]


ECU의 회로도를 잠깐 보자. ECU의 접지 단자들 중 TPS와 관련되어 있는 접지 단자가 3개(C-19, C-23, C-24) 있는데 이 중 2개(C-19, C-23)를 통해 신호가 전달된다. 이 부분을 연구하여 조작한다면 쉽게 자동차의 급발진을 제어 할 수 있다. 의외로 자동차에 대해서 지식만 있다면 쉽게 해킹 할 수 있는 부분이다.


[포렌식 전문가로서의 대응방법]

아직까지 자동차를 목적으로 만들어진 악성코드는 일반화 되어 있지 않다.(필자는 아직 존재조차 파악하지 못하였다.) 그러나 이전부터 우려한 산업시설 공격용 악성코드가 지금은 현실화 되어 있다. 그만큼 자동차 해킹에 특화 된 악성코드 개발도 멀지 않았을 것으로 본다. 포렌식에는 자동차 포렌식이라는 분야는 없다. 아마 앞으로도 없을 것으로 예상이 된다. 그런데 과연 악성코드로 인한 급발진이 의심되는 사고가 발생했다면 포렌식 전문가로서 어떻게 대응 할 수 있을까? 현재로서는 단 두가지 방법으로 대응할 수 밖에는 없다.

첫 번째 방법으로는 ECU 펌웨어 덤프를 하여 분석해 악성코드가 어떠한 방식으로 급발진을 일으켰는지 증명해 내는 것이다.

두 번째 방법으로는 EDR 장치 분석이다. EDR(Event Data Record)란, 비행기에 장착되는 블랙박스처럼 자동차에 내장되어 있는 블랙박스를 말한다. 해당 장치는 아직까지 제조회사들의 영업비밀로 간주되어 그 구조나 내용등이 일체 비밀로 되어 있다.(미국은은 공개되어 있고 우리나라만 공개되어 있지 않다.) 하지만 현재 EDR 장치의 모든 공개를 법으로 제정하는 움직임이 있어 멀지 않은 미래에는 EDR을 언제든지 분석 할 수 있는 날이 올 것이다. 만약 EDR 장치를 분석 할 수 만 있다면 선행으로 EDR 장치를 분석하고 그 후 ECU 펌웨어를 분석해 정확히 어떤 부분을 어떻게 조작하였는지 판별 할 수 있을 것이다.



[결론]

현재로서 급발진은 하드웨어적인 조작으로는 충분히 가능한 부분이다. 소프트웨어적으로만 가능하게 된다면 그 위험은 상당히 높아질 것으로 예상이 된다. 아직까지는 모르겠으나 만약 현재 자동차에 추가 되려 하는 네트워크가 ECU와 연결되게끔 추가 된다면 이 또한 상당히 높은 위험으로 간주 될 것이다. 많으 언론매체에서는 국가기반의 산업시설들이 악성코드등으로 피해를 입거나 위험에 놓이게 되며 다이하드4의 신호체계 마비 장면을 예로 든다. 하지만 이는 꼭 국가기반의 산업시설이 공격 당했을 때만 일어나는 것은 아니다. 가까운 미래에 자동차의 네트워크 기능이 추가 되고 만약 ECU와 연결된다면, 해당 네트워크를 통해 ECU 조작 악성코드를 유포 할수도 있는 일이다. 만약 감염된 자동차 ECU가 있다면 운전 중 급발진을 유발 시킬수 있고 바로 사고와 직결되어 수많은 추돌사고를 일으킬 수도 있다.

우리나라의 보안시스템은 아직까지 예방보다는 사후대처가 많은 시스템이다. 지금부터라도 자동차 보안에 조금 더 힘을 써 사후대처가 아닌 예방을 해보는 것은 어떨까 하는 생각이 든다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

이전 글에서 프로세스에 대해 언급하고 간략하게나마 어떻게 구성되어 있는지 알아보았다. 이번에는 쓰레드라는 것에 대해서 알아 볼텐데 일단 쓰레드가 무엇인지 한번 알아보자.


쓰레드란, 실제 CPU에 의해서 명령어가 실행되는 주체를 말한다. 프로세스와 쓰레드의 관계는 지주와 소작농이라고 보면 된다. 프로세스는 자신 밑에 쓰레드를 두어 일을 시키고 쓰레드는 프로세스의 관리를 받으며 일을 한다. 프로세스는 EPROCESS 구조체를 이용해 메모리에서 구성된다고 하였는데 쓰레드는 ETHREAD 구조체를 이용해 그 구조가 형성 된다. 프로세스는 무조건 쓰레드 1개 이상을 가지고 있다. ETHREAD의 주요 멤버들은 다음과 같다.


 - struct _DISPATCHER_HEADER Header : 쓰레드의 종료와 관련된 동기화 객체이다.


 - unit32 ContextSwitches : Thread Switching 횟수


 - struct _LIST_ENTRY WaitBlock[4] : 쓰레드의 상태 중 대기 상태시 동기화 객체를 지시하는데 사용 되는 멤버이다.


 - byte KernelStackResident : 쓰레드의 Kernel Stack이 쓰레드 종료 후에도 Memory에 잔여하는지를 나타내는 멤버이다.


 - byte NextProcessor : 스케줄러에 의해 결정 된 다음 실행 CPU를 나타낸다.


 - struct _KTRAP_FRAME *TrapFrame : 예외 발생 시 사용 되는 Trap Frame 포인터이다.


 * 참고 : Trap Frame이란 에러가 발생하면 CPU는 Interrupt Routine을 수행하게 되는데 이때 수행 바로 직전에 사용 되던 레지스터 값들을 Strack 공간에 저장한다. 이를 Trap Frame이라 한다.


 - unit32 KernelTime : Kernel Mode에서 쓰레드가 수행 된 시간을 나타낸다.


 - unit32 UserTime : User Mode에서 쓰레드가 수행 된 시간을 나타낸다.


 - struct _LIST_ENTRY ThreadListEntry : 프로세스가 소유하고 있는 하위 쓰레드의 목록을 나타낸다.


 - struct _LIST_ENTRY PostBlockList : 쓰레드가 참조하는 모든 객체들의 목록을 나타낸다.


 - struct _LIST_ENTRY ActiveTimerListHead : 쓰레드에 활성화 된 Timer 목록을 나타낸다.


 - void *UniqueThread : 쓰레드의 고유 번호이다.


 - void *Win32StartAddress : User Level에서 생성 된 쓰레드의 시작 코드가 위치한 부분을 나타낸다.


프로그램에서 쓰레드의 정보(ETHREAD)를 얻으려면 어떻게 해야 할까? 프로세스와 마찬가지로 Windows Device Development Kit의 PsGetCurrentThread() 함수를 사용하면 된다. PsGetCurrentProcess() 함수와 별다를 바가 없다. 다른 프로세스의 쓰레드 정보를 얻고 싶다면 PsLookupThreadByThreadId() 함수를 사용하면 된다.


Windows에서 쓰레드는 프로세스와 다르게 목적이 있는 실행 코드 별로 쓰레드를 구분 할 수 있다. 쓰레드는 독립적인 요소로 Error Handling을 가지는데 Windows에서 이를 지원해주고 있다. 이러한 기능을 Structed Exception Handling 이라 한다.


쓰레드에 자세히 알고자 한다면 여기를 참고하기 바란다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Windows 에서는 실행중인 프로그램을 프로세스라고 부른다. 프로세스는 두가지의 의미 또는 단위로 사용 된다.


 - 자원 소유의 단위(의미) : 프로세스는 Memory에 독자적인 영역을 가지고 있으며 실행 이미지 로더와 I/O 장치도 독자적으로 할당 받아야 한다.


 - Dispatching 단위(의미) : 프로세스는 CPU의 자원을 일정기간 동안 할당 받아 명령어를 실행해야 하며 OS는 병렬 명령처리를 위해 CPU의 사용시간을 각 프로세스들에게 골고루 나누어 주어야 한다.



Windows 에서 프로세스는 여러가지 구조체들로 관리되고 이루어진다. 그 중 중요한 구조체와 멤버들에 대해서 알아보도록 하겠다. Windows Kernel에서는 EPROCESS 구조체를 사용 해 kernel Memory의 프로세스를 구조화 한다. EPROCESS 중에서 중요한 멤버들은 다음과 같다.


 - unit32 DirectoryTableBase[2] : 프로세스 별로 가지고 있는 가상 Memory의 CR3 레지스터 값을 저장하고 있다.


 - struct _LIST_ENTRY ThreadListHead : 프로세스가 가지고 있는 쓰레드 목록을 가지고 있는 멤버이다.


 - void *UniqueProcessId : 프로세스의 고유 번호를 가지고 있는 멤버이다.


 - struct _LIST_ENTRY ActiveProcessLinks, *Flink, *Blink : 프로세스 목록을 관리하는 멤버들이다.


 - unit32 WorkingSetSize : 프로세스의 워킹셋 크기를 가지고 있는 멤버이다.


 - struct _HANDLE_TABLE *ObjectTable : 프로세스의 핸들 주소를 가지고 있는 테이블이다.


 - void *VadRoot : 프로세스에 할당되어 있는 모든 User Memory 영역을 설명하는 VAD 포인터이다.


 - byte ImageFileName[16] : 프로세스의 이름을 가지고 있는 멤버이다.


 * 참고 : VAD란 자체 밸런싱 바이너리 트리를 말하는데 이는 특정 노드의 왼쪽은 특정 노드 보다 낮은 값의 노드, 오른쪽은 특정 노드보다 높은 값의 노드로 이루어져 있는 트리를 말한다. 좀 더 자세히 VAD를 알고 싶다면 'A porcess-eye view of Physical Memory(Brendan Dolan-Gavitt)' 문서를 참고하기 바란다.


프로그램에서 실행 중인 프로세스의 목록을 얻어오려면 NTDLL.dll 파일에 존재하는 ZwQuerySystemInformation() API를 사용하면 된다. 자세한 사용법과 설명은 여기를 참조하기 바란다.

또 프로그램에서 현재 프로세스의 EPROCESS 정보를 얻고 싶다면 Windows Device Development Kit의 PsGetCurrentProcess() 함수를 사용하면 된다. 사용법은 여기를 참고하기 바란다.

마지막으로 다른 프로세스의 EPROCESS 정보를 얻고 싶다면 PsLookupProcessByProcessId() 함수를 사용하면 된다. 사용법은 여기를 참고하기 바란다.


프로세스의 구성요소를 한번 살펴보자. 프로세스는 독립적인 Memory 공간을 가지고 있는데 이 메모리 공간은 paging 기법을 사용해 프로세스마다 별도의 고유한 Memory 공간을 갖는 공간을 말한다. 또 VAD를 이용해 프로세스 별로 메모리와 파일을 VAD에 맵핑해 User Memory를 관리하며 Handle Table, Handle, Windows Kernel 객체, PEB가 프로세스의 구성요소로 자리잡고 있다.

Handle Table은 프로세스가 사용하는 핸들의 주소를 가지고 있는 배열 공간을 의미하며 Handle은 프로세스가 사용하는 핸들 주소를 가지고 있다. 이 값을 인덱스 값으로 HandleTable을 검색한다. Windows Kernel 객체는 Windows에서 커널 리소스들을 객체화 해 프로세스들이 공통적인 요소를 독립적으로 사용 할 수 있게끔 해 놓은 것으로 프로세스 구성의 한 부분이다. PEB(Process Environment Block)은 Kernel Level의 프로세스 관리 구조체인 EPROCESS와는 달리 User Level에서의 프로세스 추가적인 정보를 저장하고 있는 구조체이다. 자주 참조하는 정보를 PEB에 저장해 둠으로 불필요하게 Kernel Level 진입을 최소화 하는데 그 목적이 있다. PEB 구조체의 주요 내용은 다음과 같다.


 - Ldr : Ptr32 _PEB_LDR_DATA -> 프로세스에 로드 된 모듈들의 리스트를 가지고 있다.


 - ReadOnlySharedMemoryBase : Ptr32 Void -> 읽기 전용 메모리 공유 멤버이다.


 - AnsiCodePageData : Ptr32 Void -> 읽기 전용 메모리 공유 멤버의 ANSI Code Page Table이다.


 - LoaderLock : Ptre32 Void -> PE Loader가 프로세스 로딩 중 사용하는 잠금 변수이다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

+ Recent posts

티스토리 툴바