Bypass Path in system by memory segment
이번 세션을 통해 레지스터와 메모리의 런타임 상태일 때의 쓰임새를 정리해서 공격을 위한 우회 경로를 추론할 수 있는지 가늠해보자. 엊그제 민방위 훈련을 받으러 근처 온천장에 갔다. 민간인 지진 대피 훈련에 민방위 대원들이 합류해서 화재가 난 온천장에서 탈출하는 시나리오대로 훈련하였다. 한 때의 곧 통일될 거라는 사회적 분위기가 지나가긴 했지만 민방위 교육이 이전처럼 안보가 아니라 재해재난의 모의훈련으로 바뀐 모양이다.
화재진압 119 구조대의 모의훈련을 구경하는 동안 "컴퓨터 시스템의 우회 경로란 무엇일까?"가 멍 때리고 있는 사이에 번뜩였다. 모든 재해에서 '우회경로'란 사고 발생 시에 비상으로 가동하는 대피 경로와 동일하다고 생각했다. 그러니 온천장에서 지진 피해로 화재 발생 시에는 건물의 비상 출입망이며, 구조대원들이 구조활동으로 옥상에서 뛰어내릴 수 있게끔 놓은 고무풍선(일종의 버퍼) 매트리스도 안전 탈출망으로 평상시에 지나다니는 출입구에 반해 우회하는 경로에 해당한다.
시스템도 해킹사고 발생 시 필요한 스탠바이(Standby) 경로가 필요하다. 네트워크에서는 기업 서비스망의 주요한 서버(Primary Server)가 DDoS(Distributed Denial of Service: 서비스 거부 공격)으로 말미암아 은행이나 방송사의 홈페이지 작동이 마비되었을 경우, 비상의 서버(Secondary Server)가 작동하는 인프라 대책을 미리 구축해 놓는다. 그렇다면 좀 더 범위를 좁혀서, 시스템에서는 여러 개의 프로그램이 동시에 실행하면서 기존의 정상적인 작동을 위해 CPU 프로세서가 우선순위에 따른 스케쥴러에 맞춰 다중 프로세스를 수행하지 못한다면 우회경로 확보가 필요하다고 생각이 들었다.
프로세스 경합 시(Race Conditioning), 프로세스는 데드락(Deadlock) 상태에 빠지는 데 이때 필요한 메커니즘이 중단과 대기(Hold and Wait), 상호 배제(Mutual Exclution), 환형 대기(Circular wait) 그리고 비선점(No Preeption)으로 정보보안기사뿐만 아니라 정보처리기사의 파편 이론을 장식하는 내용이 나온다. 말 그대로 프로세스들이 서로 자기부터 실행시켜달라고 마이크로 프로세서에게 애원하더라도 아키텍처는 성능에 따라 그 부하량을 감소시키는 행태가 달라질 것이다. 사용자의 입장에서는 한꺼번에 실행시킨 모든 프로그램이 정상적으로 한 번에 작동하는 것이 편리하므로, 컴퓨터는 데드락에 빠지지 않고 프로세스를 마치 다중으로 실행시켜 주는 것처럼 보여야 한다.
그래서 구버전의 운영체제나 패치가 안된 최신 버전의 운영체제(Operating system)는 이러한 메커니즘을 조율하기 위해서 이전의 버그를 일으킨 해킹 기법들과 계속 두뇌싸움을 해야 하는데(공격이 앞서 나간다), 대표적인 현재의 운영체제인 Windows를 가장 많이 터는 집단이 북한의 해커들이다. 본론으로 들어가기 전에 북한의 해커들에 대해 소개하자면, 그들은 김정은 정부 체제 이후 더욱 체계적으로 양성되었다. 마이크로소프트사에서 매번 자사의 해킹 주범으로 북한의 해커집단을 지목하는 까닭은 그들이 말하는 이른바, '우리는 윈도의 숨결과 함께 하고 있다.'라는 캐치 프레이즈와도 맥락을 같이한다.
한국의 해커들도 쉽사리 도전 못하는 최신 윈도의 발표 이후 쉽게 자행하는 윈도 해킹은 윈도가 애초에 C 언어를 기반으로 만들어졌기 때문이다. 요즘 C를 배우는 한국의 코딩 세대는 거의 드물다. 있더라도 나처럼 보안 쪽에 관심이 있거나, 이미 빌 게이츠와 같은 시대를 태어나신 세대의 개발자들이 필수적으로 배운 언어이기 때문에 지금은 대체로 C++부터 배우기 시작한다. 하물면 삼성이나 MS 자사의 직원 교육에서도 이제 C의 구태의연한 기능을 처음부터 배우지 말고 C++에서 C의 구식 명령을 대체한 기능으로 시작하라고 C++의 유명 강사가 피력한다. 그래서 C는 기존의 강좌에서 제외된 지 오래다.
그럼에도 불구하고 북한에서는 C를 해커 양성 대학교에서 기본 언어로 가르치고 있다. 북한의 세 군데의 해커 양성 대학은 어릴 때 이미 수학에서 두각을 낸 인재들을 착출 해서 모은 학교라서 이들은 수학적 사고를 바닥에 깔고 해킹 교육에 들어간다. 김정은이 해커를 양성해서 미국뿐만 아니라 한국의 국방부 안보 문서까지 터는 등 사이버 전쟁으로 외교적 전략으로 삼은지가 오래되었다. 그런데 이들은 한국처럼 새로운 프로그래밍 언어를 접할 수 없는 저변이 오히려 C 언어에 몰두하게 만든 계기가 되었다고 한다.
C 언어는 곧 Windows OS의 저변, 가장 밑바닥의 구성 체계이다. 북한 해커들은 사람이 만든 거라면 자기네들도 알 수 있다는 소위 해킹의 신념 이래, 윈도의 밑바닥을 윈도를 개발한 사람보다 더욱 파헤치고 있다. 실제로 개발자보다 리버스 엔지니어가 분석하는 프로그램의 구동 원리를 더 정확하게 꿰차고 있다는 말이 있다. 만든 사람의 프로그램을 거꾸로 파헤쳐서 그것의 근본을 밝혔으니, 오히려 지식수준의 주객이 전도되는 현상이 이 북한 해커들에게 일어나고 있다고 생각한다.
북한에서 탈북한 북한의 김책 공업 종합 대학의 교수였던 그의 인터뷰에 대한 기사를 보고 통일이 된다면 그들의 해킹 실력은 과연 대한민국의 정보 산업에 어떠한 변수로 작용할지 생각해봤다. 어쨌거나 민방위 훈련을 통해 시스템의 우회경로를 생각했고 그 우회경로에 가장 중요한 부분은 마이크로 프로세서(CPU) 내부의 프로세서 값인 레지스터로 결론 냈다. 저번 섹션에서 '버퍼 오버플로우' 공격에서 주요 레지스터 몇 가지를 언급했었는데, 그중 'EIP'와 'EBP' 그리고 'ESP'이다.
컴퓨터 이론은 한 번에 필요한 개념 모든 것을 쏟아내니 무슨 원리로 동작하는지 깨우치기가 여간 어려운 게 아니다. 보안의 관점에서 필요한 구성 요소만 파헤치면 왜 CPU의 레지스터가 우회경로를 확보하는데 중요한 공간이 되는지 알 수 있다. 메모리가 구동 중일 때(Runtime memory) 총 4가지 부류의 메모리가 논리적(가상)으로 공간을 확보한다. 1) Stack, 2) Heap, 3) Text, 4) BSS and Data이다. 스택과 힙은 종전에 버퍼오버플로우 공격의 취약점이 발생하는 길목이고 '텍스트' 공간이 시스템에서 프로세서가 읽기만 가능하고 쓰기와 실행을 애초에 막어버린 공간이다. 여기에는 위의 도식에서 적힌 것과 같이 컴파일된 기계어가 존재한다.
Function이라는 함수를 실행시키면 컴파일러에 의해 컴퓨터가 해석할 수 있는 코드로 번역해서 저장하는 공간이 Text area이다. 만약 여기에 누군가에 의해 읽기만 가능하지 않고 수정과 실행이 가능하다면 프로그램을 실행시킨 사용자의 의도와 다르게 생뚱맞은 코드가 실행할 수 도 있다. 여기가 해커에게는 '액세스 포인트'가 된다. 생뚱맞은 코드, 악성코드를 실행시키려면 여기를 컴퓨터 시스템 자체(CPU)만이 아닌 인위적인 요소가 개입할 수 있도록 조작해야 한다. 즉 컴퓨터의 실행 주체인 운영체제에서 알맹이에 해당하는 커널(Kernal)이라는 관리자가 기본적으로 운영체제의 역할을 수행한다. 이를 위해 가지고 있는 자체 코딩이 내장되어있는 부분을 '인터럽트 루틴 혹은 시스템 콜'이라고 부르는데 이 부분을 특정 사용자가 인위적으로 개입해서 우회경로로 확보할 수 있다.
버퍼오버플로우 개념도 환기하고 보안 기사 7회 실기에서 출제되었던 위의 윈도 실행 파일 형식인 PE 포맷의 종류와 동일한 명칭의 메모리 세그먼트들도 다시 한번 익혀두자. 읽기만 가능한 텍스트 영역에서 특정 사용자가 자신이 만든 코드를 주입시킬 수 있는 기법이 '버퍼오버플로우', '포맷 스트링', '레이스 컨디셔닝'이라는 버그들이다. 시스템 자체의 주어진 운영자(OS) 권한을 조종하기 위해서는 먼저 그 운영자가 자신이 운영하기 위해 만들어놓은 코드를 실행시키는 작업장이 어딘지 알아야 한다. 그 메모리 부분이 스택, 힙, BSS(Blocked Started by Symbol), Data 세그먼트(메모리 영역 단위)가 아니라 'Text Segment'이다. 그리고 여기에 악성코드를 주입하기 위해 들어갈 수 있는 통로가 레지스터의 EIP(the Instruction Pointer)이다. ESP(스택 포인터)나 EBP(스택 프레임 포인터)는 프로그램의 실행(함수의 호출)을 구현하기 위해 CPU가 값이나 메모리 주소를 가리키는 용도로 쓰인다.
The instruction pointer is an important register that points to compiled executable code(usually in the text segment) for execution by the processor.
논리적인 프로그램 실행 흐름을 탄다면 CPU는 ESP와 EBP 레지스터(변수라고 생각하면 쉽겠다.)를 가지고 어떤 함수 내부의 데이터 사이즈에 맞게 끝과 시작 지점을 가리키고 함수가 종료되면, 기존의 함수(Parent function)로 되돌아가기 위한 주소 값이 저장되어 있는 EIP를 뒤진다. 왜냐하면 EIP는 함수 종료 후 복귀할 주소가 저장되어 있으므로 다음 함수(기존의 함수)를 실행하기 위한 주소를 가리켜 주기 때문이다. 그래서 논리적인 프로그램의 흐름은 계속해서 이어진다. 그런데 만약 실행이 가능한 코드를 '텍스트 세그먼트'를 통해 CPU가 이 코드를 읽는 순서(여기서는 쓰고 실행이 불가능하고 오직 읽기만 가능한 영역이다.)로 넘어가기 전에, 해커는 EIP라는 다음 코드 번지수를 가리키는 푯말에 자신이 주입한 코드로 마치 지금까지 레지스터에서 연산이 이루지는 순서에 해당하는 주소처럼 덧칠할 수 있다.
그리고 기존의 스택 세그먼트의 메모리 영역에서 이루어지는 버퍼오버플로우 공격이 공격자가 의도하는 코드로 실행하기 위해서는 EIP 레지스터 하위의 내부 지역 변수(Local variables)들이 처음 할당되는 공간이 넉넉해야 한다. 왜냐하면 덮어 씌울 수 있는 공간이 얼마 안 되면 EIP에 저장되는 있는 리턴 주소(RET)를 바꿔치기하고도 기입해야 할 악성코드 자리의 임시공간이 부족할 수 도 있기 때문이다. 여하튼 이전에 못다 한 리눅스 시스템에서의 스택 오버플로우 공격 보고를 대신해서 보안 기사 실기 7회 차 기출문제였던 메모리 세그먼트 종류들을 호출해봤다.
1) The executable program(compiled code) in TEXT segment
2) Global variables in the BSS(Uninitialized data) and DATA(Initialized static data) segments
4) Long-term storage, other data in the Heap segment(The data is related algorithms to manage data up to a kind of operating system in the Heap)
그리고 버퍼오버플로우 공격 세션의 맨 처음 섹션 1에 링크 걸었던 UNSW의 '스택 프레임과 함수 호출 관련 동영상 강좌'를 다시 보자. 무슨 말을 하려는 건지 이제 대강 감이 잡힐 거라고 확신한다.