관리 메뉴

개발자비행일지

모의해킹_시스템 해킹 기초 본문

▶ 모의해킹 공부

모의해킹_시스템 해킹 기초

Cyber0946 2020. 2. 18. 10:37

#https://dreamhack.io라는 플랫폼을 통해 모의해킹 공부를 시작하고자 한다. 

#시스템 해킹 기초 Lecture 1

 

로그인 | DreamHack

 

dreamhack.io

먼저 관심 분야인 시스템 해킹을 위한 기초 강의를 들으면서 학습한 내용을 정리한다. 

1.해킹의 기초

해킹이란, 이 단어가 가지는 부정적인 이미지 때문에 해킹을 위험하거나 파괴적인 행위라고 생각하는데, 실제로 컴퓨터 보안에서 해킹은 컴퓨터의 하드웨어나 소프트웨어 네트워크 웹사이트 등 각종 정보 체계에서 주어진 권한 이상의 권한을 얻거나 의도하지 않은 동작을 일으키는 행위를 말한다. 

사실 이는 폰 노아민 구조라는 컴퓨터 자체의 특성에서 기반된다. 

해킹은 크게 공격대상을 무엇으로 삼느냐에 따라 해킹 기술을 나눌 수 있다. 대표적으로 웹 사이트를 공격하는 웹 해킹이나, 컴퓨터와 컴퓨터가 연결되는 네트워크를 공격하는 네트워크 해킹, 프로그램의 보안 약점을 공격하는 시스템 해킹이 있다. 

여기서 보안약점이란 보안취약점 중에서 공격이 가능한 보안 취약점을 말한다. 

공격자는 웹 사이트를 해킹해 타인의 계정 정보를 도용하거나 네트워크를 공격해 트래픽을 과부하 시켜 서비스를 다운시킬 수도 있고, 프로그램을 공격해 권한을 탈취할 수 도 있다. 

자 지금부터 우리는 시스템 해킹, 특히 소프트웨어 해킹에 대해서 자세히 학습하도록 한다. 

2. 해킹의 원리

전문적인 프로그래머들이 수년간 개발한 소프트웨어를 공격하는 해커를 보고 해킹이란 시스템을 기상천외하게 공격하는 마법 같은 것이라 생각 할 수 도 있지만, 해킹은 엄연히 논리와 규칙을 따르며, 그 원리를 자세히 살펴본다면 누구나 이해할 수 있을 정도로 단순하다.

해킹은 논리를 활용해 원하는 메모리에 원하는 명령을 컴퓨터에 전달하여 내가 원하는 결과를 얻어내는 일련의 과정일 뿐이다. 

해커는 무에서 유를 창조하는 것이 아니라, 기존의 개발자가 남겨 놓은 프로그램 내에서 결과를 창조한다. 보통 소프트웨어 버그를 활용하는데, 이는 프로그램이 잘못된 결과를 내거나, 오류를 발생하는 등의 의도치 않은 동작을 수행하게 되는 문제를 말한다.

우리는 프로그램을 사용하거나 개발할 때 거의 항상 이런 버그들에 시달립니다. 버그 중에는 소프트웨어의 동작에 거의 영향을 미치지 않는 무해한 버그들도 있지만, 보안을 심각하게 위협하는 위험한 버그들도 있습니다.

소프트웨어 취약점은 공격자가 주어진 권한 이상의 권한을 획득하거나 프로그래머가 의도하지 않은 동작을 수행할 수 있도록 할 수 있는 버그들을 말하고, 소프트웨어 보안약점은 이러한 취약점 중에서 실제로 공격(Exploit)가능한 것을 의미한다.  공격자는 소프트웨어 취약점을 찾아 원하는 것을 달성하려 하고, 보안 전문가들은 취약점을 패치해 프로그램을 보호합니다. 그러나 큰 프로그램이나 복잡한 시스템에서는 미처 발견하지 못한 취약점들이 존재할 수 있고, 공격자가 단 하나의 취약점만으로도 소프트웨어를 공격 가능하다. 

소프트웨어 취약점은 여러 가지 요인으로 인해 발생한다. 그 중 가장 많은 원인은 프로그래머의 실수입니다. 프로그래밍할 때에는 얼핏 생각했을 때에는 직관적으로 보이지만 실제로는 그렇지 않은 코드들이 많이 있다. 이러한 코드들은 지나치기 쉬운 실수를 유발하고 이런 실수는 때때로 심각한 보안 취약점에 연결되는 불행한 결과로 이어진다.

예를들어 만약 프로그래머가 4부터 12까지의 숫자를 저장하기 위해 배열을 선언한다고 하면 배열의 크기를 얼마로 해야 할까?

얼핏 생각했을 때에는 길이 8의 배열을 할당하면 될 것 같지만, 실제로는 양 끝의 숫자를 모두 포함해야 하므로 길이가 9인 배열을 할당해야 합니다. 이는 간단하지만, 그 만큼 많은 개발자들이 하는 실수이다. 공격자는 때때로 이런 조그마한 차이를 이용해 시스템을 완전히 장악한다.

또한, 취약점은 개발자의 잘못된 가정으로 인해 일어나기도 한다. 이는 개발자는 항상 올바른 입력만이 들어 올것이라고 생각하기 때문이다. 하지만 해커는 입력에 제한을 두지 않는다. 간단히 생년월일과 현재 날짜를 입력받고 태어난 후 며칠이 지났는지 계산하는 프로그램을 만든다고 생각해보자. 여기서 숫자를 입력받을 때 사용자의 입력값에 대한 어떠한 검증도 존재하지 않는다면 사용자가 문자열을 입력했을 때 소프트웨어 버그가 발생한다.

하트블리드 취약점은 2014년에 OpenSSL에서 발생했던 취약점으로, 개발자의 잘못된 가정이 얼마나 위험한 결과를 불러올 수 있는지 나타내는 예시이다. 이는 OpenSSL의 확장 규격 중 하나인 HeartBeat에서 발생한 취약점으로, 클라이언트에게 전송받은 데이터의 유효성을 검증하지 않아 발생한 정보 탈취 취약점이다.

안정적인 통신 유지를 위해 클라이언트는 HeartBeat 프로토콜을 이용해 임의의 정보를 그 정보의 길이와 함께 서버에 전송하고 서버는 클라이언트에게 전달받은 정보를 그대로 반환해 연결을 확인한다. 그러나 이때 실제 데이터의 길이와 클라이언트가 명시한 데이터의 길이가 서로 다른 경우 문제가 되는데, 가령 클라이언트가 "theori"라는 데이터와 "6"이라는 데이터 길이를 전송한다면 서버는 정상적으로 "theori"라는 데이터를 반환할 것입니다. 만약 클라이언트가 "theori"라는 데이터와 "3000"이라는 데이터 길이를 전송한다면 서버는 문제점을 감지하고 이를 처리해야한다. 그러나 이 경우 데이터의 길이를 전혀 검증하지 않아 "theori"라는 데이터가 저장된 메모리부터 3,000 바이트를 읽어 클라이언트에게 보내준다.

공격자는 이를 이용해 시스템 메모리에 저장된 민감한 데이터를 탈취했으며, 해당 취약점은 큰 이슈가 되었다.

 

a. 취약점의 분류

익스플로잇이란 사전적으로는 악용이라는 뜻을 가지고 있는 단어로, 취약점을 이용해 공격자가 의도한 동작을 수행하게 하는 코드 혹은 이를 이용한 공격 행위를 의미한다.

소프트웨어 버그는 보안에 영향을 미치는 정도에 따라 크게 4가지로 분류 가능하다. 아래의 그림은 이렇게 나뉜 버그의 종류가 어떤 포함관계를 갖는지 간략히 나타낸 다이어그램이다.  해당 분류는 이 취약점이 공격자의 의도를 달성하는 데 어느 정도 도움을 주는지를 기준으로 하였다. 

먼저 프로그래머가 의도하지 않은 동작을 수행하는 소프트웨어 버그(Bug)가 가장 상위에 있다. 그러한 소프트웨어 버그 중 보안에 영향을 미칠 수 있는 버그를 소프트웨어 취약점(Vulnerability)이라 하고, 소프트웨어 취약점 중 이를 이용해 공격자가 의도한 동작을 수행할 수 있는 버그를 익스플로잇 가능한 취약점(Exploitable Vulnerability)이라 한다. 그러나 익스플로잇이 가능하다고 해서 익스플로잇을 항상 안정적으로 성공할 수 있는 것은 아닙니다. 보안 취약점에서 익스플로잇 확률은 위험성을 평가하는 중요한 요소 중 하나인데, 이는 익스플로잇 확률이 높을수록 무기화되어 사용하기 유용하고, 공격이 탐지될 확률이 줄어들기 때문이다. 이렇게 익스플로잇이 가능한 취약점 중 매우 높은 확률로 공격에 성공할 수 있는 버그를 안정적으로 익스플로잇 가능한 취약점(Reliably Exploitable Vulnerability)이라고 한다.

b. 공격 벡터

모든 소프트웨어 취약점은 소프트웨어와 공격자가 상호 작용하는 곳, 즉 사용자의 입력에서부터 발생하는데, 이렇게 공격자가 소프트웨어와 상호 작용할 수 있는 곳을 Attack Vector(공격 벡터)라고 하며, 이러한 Attack Vector들의 집합을 Attack Surface라고 한다. 

다음의 그림을 살펴보면, 공격자는 입력창을 통해 프로그램과 커뮤니케이션 하며, 제목, 내용에 공격자의 입력을 넣을 수 있고 업로드 기능을 통해 이를 프로그램에 전달 할 수 있다. 이렇게 입력 가능한 부분 모두 공격 벡터라고 할 수 있다. 이 프로그램에서 제목을 처리하는 코드는 안전하고, 내용을 처리하는 코드에서 보안 취약점이 발생하며, 업로드하는 과정에서도 별다른 문제가 없다고 가정해보면,  이때 내용을 처리하는 코드는 공격자가 접근해 악용할 수 있기 때문에 보안 취약점이 된다.

그렇다면 이번에는 프로그램의 unreachable code 영역에 심각한 보안 취약점이 있다고 가정해 보겠습니다. 만약 해당 코드가 어디에서도 사용되지 않고 공격자가 이를 실행할 방법이 없다면 이는 보안 취약점이라고 할 수는 없다. 그러나 이러한 코드도 잠재적으로 악용될 수 있는 코드이기 때문에 존재해서는 안 된다. .

따라서 프로그래머는 사용자에게서 입력받는 부분을 철저히 검증해야 한다. 프로그래머가 사용자의 입력을 받는 부분에서 실수한다면 예상치 못한 버그가 발생할 수 있고, 이 버그 중 일부가 보안 취약점이 되어 공격이 된다.

c. 취약점의 종류 - 메모리 커럽션 취약점

취약점은 공격 방법에 따라 크게 두 가지로 나눌 수 있습니다. C/C++과 같은 저수준 언어에서 메모리를 직접 조작해 공격하는 메모리 커럽션 취약점과 메모리를 조작할 필요 없이 공격할 수 있는 로지컬 취약점입이다.

먼저 메모리 커럽션 취약점의 대표적 예시들에 대해 간략히 알아보자.

  • 메모리 커럽션 취약점

    • Buffer Overflow

    • Out-Of-Boundary

    • Off-by-one

    • Format String Bug

    • Double Free / Use-After-Free

    • etc

Buffer Overflow

Buffer Overflow(BOF)는 메모리 커럽션 취약점 중 가장 대표적인 취약점입니다. 이는 프로그래머가 할당한 크기의 버퍼보다 더 큰 데이터를 입력받아 메모리의 다른 영역을 오염시킬 수 있는 취약점dl다. 버퍼 오버플로우는 발표된 지 30년에 가까운 시간이 흘렀지만, 아직도 공격에 자주 사용되는 취약점입니다.

Out-Of-Boundary

Out-Of-Boundary(OOB) 취약점은 버퍼의 길이 범위를 벗어나는 곳의 데이터에 접근할 수 있는 취약점이다. 이 또한 버퍼 오버플로우와 마찬가지로 매우 강력한 취약점으로, 브라우저와 같은 대규모 최신 소프트웨어에서도 자주 발견되는 취약점이다.

Off-by-one

Off-by-one은 경계 검사에서 하나 더 많은 값을 쓸 수 있을 때 발생하는 취약점입니다. 가령 32바이트 크기의 버퍼에 인덱스 32로 접근하는 것 같은 경우입니다. 이는 반복문을 순회할 때 잘못된 비교 연산자를 사용하거나 인덱스가 0부터 시작하는 것을 고려하지 못했을 때 자주 발생하는 취약점이다.

Format String Bug

Format String Bug(FSB) printf sprintf와 같은 함수에서 포맷 스트링 문자열을 올바르게 사용하지 못해 발생하는 취약점이다. 포맷 스트링 역시 매우 강력한 취약점이지만, 최신 컴파일러에서는 여러 가지 방법으로 이를 방어하고 있어 최근에는 잘 발생하지 않고 있다.

Double Free / Use-After-Free

Double Free Use-After-Free(UAF) 취약점은 동적 할당된 메모리를 정확히 관리하지 못했을 때 발생하는 취약점이다. 이미 해제된 메모리를 다시 한번 해제하려고 시도하는 것을 Double Free, 해제된 메모리에 접근해 이를 사용하려고 하는 것을 Use-After-Free라고 한다.

d.취약점의 종류 - 로지컬 버그

이번에는 로지컬 버그 중 대표적인 몇 가지들을 살펴보도록 하겠습니다. 로지컬 버그는 메모리 커럽션 취약점과는 달리 프로그램의 메모리 구조를 이용해 공격할 필요가 없습니다. 따라서 익스플로잇 작성이 메모리 커럽션 취약점보다는 상대적으로 간단합니다.

  • 로지컬 버그

    • Command Injection

    • Race Condition

    • Path Traversal

    • etc

Command Injection

Command Injection은 사용자의 입력을 셸에 전달해 실행할 때 정확한 검사를 실행하지 않아 발생하는 취약점이며, 공격자가 원하는 명령을 실행할 수 있는 데 비해 익스플로잇이 어렵지 않아 매우 강력하다.

Race Condition

보안 취약점으로서의 Race Condition은 여러 스레드나 프로세스의 자원 관리를 정확히 수행하지 못해 데이터가 오염되는 취약점입니다. 레이스 컨디션은 발생 원인과 공격 방법에 따라 메모리 커럽션 취약점으로도, 로지컬 취약점으로도 분류할 수 있는 취약점이다.

Path Traversal

Path Traversal은 프로그래머가 가정한 디렉토리를 벗어나 외부에 존재하는 파일에 접근할 수 있는 취약점이다. 이는 주로 소스 코드에서 "../"와 같은 경로 문자를 검사하지 않아 발생한다.

3.미티게이션

초기의 소프트웨어는 소프트웨어 보안이라는 개념이 전무하였고 이로 인해 , 공격에 대한 대책이 전혀 준비되어있지 않아 취약점만 존재한다면 무조건 권한을 탈취 당했다. 물론 이런 공격을 원천 차단하는 일은 취약점을 만들지 않는 것입니다. 그러나 프로그래머가 취약하지 않게 프로그램을 작성하기를 바라는 것은 근본적인 해결책이 되지 않습니다. 따라서 자연스럽게 취약점의 존재 여부와는 무관하게 프로그램을 보호하는 방법에 대한 고민이 이루어졌고, 그렇게 등장한 게 미티게이션이다.

미티게이션은 취약점의 공격을 어렵게 만드는 일을 합니다. 대표적인 스택 버퍼 오버플로우의 미티게이션 중 하나인 Stack Smashing Protector(SSP)는 버퍼 오버플로우를 방지하기 위해 버퍼의 뒤에 랜덤한 값을 넣어두고 이를 특정 시점에 검사해 버퍼가 오염되었는지 확인하는 것과 같은 방법을 쓴다.

그러나 해커들 역시 미티게이션을 우회하기 위해 여러 새로운 공격 기법들을 고안하였다. 이렇게 새로 등장한 공격 기법을 막기 위해 또 새로운 미티게이션이 생기고, 이를 우회하기 위한 또 다른 공격 기법들이 만들어지게 된다. 공격 기법과 미티게이션의 공방은 처음 스택 버퍼 오버플로우를 공격하는 문서가 발표된 이후 지금까지 꾸준히 계속되고 있다.

그러나 미티게이션이 프로그램을 어떤 상황에서도 보호하는 것은 아니기 때문에 결국 취약점이 없는 프로그램을 만들기 위한 노력이 가장 중요하다. 소프트웨어는 사람이 시키는 일을 생각 없이 수행하기 때문이다.