본문 바로가기

정보보안

코드보안의 이해

1. 코드보안

프로그래머는 프로그래밍 언어를 사용하여 응용 프로그램이나 운영체제 등을 위한 소스코드(source code)를 작성한다.

  • 소스코드(source code) : 컴퓨터가 이해할 수 있게 프로그래머가 작성하는 명령의 집합.

소스코드는 보안 취약점이 하드웨어나 어셈블리어
에 비해 가장 쉽게 발생하기 때문에 해커들에 의해 종종 분석되고는 한다.

  • 어셈블리어(assembly language) : 기계어와 일대일 대응이 되는 컴퓨터 프로그래밍의 저급 언어.

소스코드에서 문제가 발생하는 요인은 ‘데이터의 형태와 길이에 대한 불명확한 정의’ 로 요약할 수 있다. 따라서 보안 전문가라면 이와 관련하여 대책을 강구하고 코드에 대한 보안을 탐구해야 한다. 코드를 이용한 대표적인 공격은 버퍼 오버플로와 포맷 스트링이 있다. 이에 대해 한 번 알아보자.

2. 버퍼 오버플로 공격

  • 버퍼 오버플로(buffer overflow) : 버퍼에 데이터를 쓰는 소프트웨어가 버퍼의 용량을 초과하여 인접한 메모리 위치를 덮어쓸 때 발생하는 비정상적인 현상.

버퍼 오버플로 공격 중에서도 가장 기본적인 형태는 서론에서 언급한 ‘데이터의 길이에 대한 불명확한 정의’ 를 이용한 공격이다. 더 구체적으로 설명하자면 정상적인 경우라면 사용되지 않았을 주소 공간에 해커가 임의의 코드를 덮어쓰는 것이다. 이는 곧 프로세스가 데이터를 버퍼(buffer) 에 저장할 때 프로그래머가 지정한 곳 바깥에 저장한다는 것을 의미한다.

  • 버퍼(buffer) : 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리의 영역.

그렇게 되면 바깥으로 벗어난 데이터는 인접 메모리를 덮어 쓰게 되고 이로 인해 손상된 값이 프로그램 전체에 영향을 미칠 수도 있다. 따라서 잘못된 프로그램 작동을 비롯한 메모리 접근 오류, 올바르지 않은 결과, 프로그램 종료 및 시스템의 보안 누설 등이 발생할 수 있다.

버퍼 오버플로는 여러 소프트웨어 취약점의 근간이 되어 악의적으로 이용될 수 있는데 이를 방지하기 위한 방법 중 하나는 경계 검사이다. 사용해야 할 공간과 사용하지 말아야 할 공간의 불명확한 경계에 대한 문제는 여러 상황에서 여러 형태로 나타난다. 이는 코드보안에 있어서도 마찬가지이기 때문에 경계 검사는 중요하다. 물론 버퍼 오버플로 공격을 가능하게 해주는 데이터 길이에 대한 불명확한 정의가 모든 코드에 존재하지는 않는다. 이는 취약한 특정 함수에 대해서만 공격이 가능한데, 프로그래머가 취약한 함수를 이용하지 않는다면 버퍼 오버플로 공격이 훨씬 어려워진다는 점을 사용해서 보안을 강화할 수 있다.
따라서 버퍼 오버플로 공격의 대응책은 다음과 같다.

●첫째, 버퍼 오버플로에 취약한 함수를 사용하지 않는다.

(cf>버퍼오버플로에 취약한 함수들)
- strcpy(char*dest,const char*src);
- strcat(char*dest,const char*src);
- gets(char*s);
- getwd(char*buf);
- fscanf(FILE*stream,const char*format,…);
- scanf(const char *format,…);
- realpath(char*path, char resolved_path[]);
- sprinf(char*str, const char*format);

●둘째, 해커의 코드 공격이 실행되지 않도록 방지해주는 최신 운영체제를 사용한다.

non-executable stack, 스택 가드(stack guard), 스택 실드(stack shield)와 같은 해커의 공격 코드가 실행되지 못하게 하는 여러 장치가 최신 운영체제 안에 있다.

3. 포맷 스트링 공격

버퍼 오버플로 공격이 데이터 길이에 대한 불명확한 정의를 이용한 공격이라면 포맷 스트링 공격은 ‘데이터의 형태에 대한 불명확한 정의’를 이용한 공격이다. 따라서 데이터의 포맷 스트링이 명확하게 정의된다면 포맷 스트링 공격이 적용되지 않는다. 포맷 스트링 공격을 알기 위해서는 먼저 포맷 스트링이 무엇인지 알아야 한다.

  • 포맷 스트링(format string) : 일반적으로 사용자로부터 입력을 받아들이거나 결과를 출력하기 위하여 사용하는 형식으로 포맷스트링을 사용하는 함수에 대해 형식이나 형태를 지정해주는 문자열을 의미.
    ex) C언어에서 사용하는 %s가 이에 해당한다. 만약 %s의 값을 바꾼다면 이 또한 포맷 스트링 공격에 해당한다.

다음은 포맷 스트링 문자의 종류이다.

  • 파라미터
  • 특징
- %d
정수형 10진수 상수(integer)
- %f
실수형 상수(float)
- %lf
실수형 상수(double)
- %s
문자 스트링((const)(unsigned)char*)
- %u
양의 정수(10진수)
- %o
양의 정수(8진수)
- %x
양의 정수(16진수)
- %s
문자열
- %n
*int(쓰인 총 바이트 수)
- %hn
%n의 절반인 2바이트 단위

4. 메모리 해킹

메모리 해킹이란 컴퓨터의 주기억장치에 있는 데이터를 불법으로 읽어 가는 행위로 주로 백도어(Back Door) 프로그램을 사용한다.

  • 백도어 : 말 그대로 '뒷문'이라는 뜻으로, 시스템 접근에 대한 사용자 인증 등 정상적인 절차를 거치지 않고 응용 프로그램 또는 시스템에 접근할 수 있도록 하는 프로그램.

프로그램 동작에는 관여하지 않지만 프로그램이 실행되는 데 필요한 데이터들을 저장하는 메모리를 조작한다. 앞서 말했듯이 프로그램 동작에는 관여하지 않으므로 메모리 해킹이 발생했을 시 사용자가 이를 인지하지 못하는 상황이 많다. 대부분의 현대 컴퓨터들은 폰 노이만 구조에 의해 운영되므로 컴퓨터의 메모리 조작 가능성 여부는 운영체제의 종류와 상관없이 모든 종류의 운영체제에서 동일하게 적용이 가능하다.

  • 폰 노이만 구조 : 주기억 장치, 중앙 처리 장치, 입출력 장치의 전형적인 3단계 구조로 이루어진 프로그램 내장형 컴퓨터 구조로, 오늘날 사용하고 있는 대부분의 컴퓨터의 기본 구조.

그렇기 때문에 더욱더 메모리 해킹에 대해서 유의할 필요성이 있다. 기밀성과 무결성, 가용성이 최대로 보장되어야 하는 인터넷 뱅킹 자체의 신뢰성과 안정성에도 큰 위협이 된다는 점에서 최근 금융권과 정보보호업계에서 화제가 되고 있다. 파밍(Pharming) 사기와의 차이점이 있다면 파밍 사기는 보안카드번호 전부를 입력하도록 하지만, 메모리 해킹은 보안카드번호 전부가 아닌 2개만을 입력하게 하거나 보안 강화를 명목으로 한 가짜 팝업창을 띄워 보안카드를번호를 추가로 입력하게 하는 등 수법이 계속해서 진화하고 있다.

  • 파밍(Pharming) : 합법적으로 소유하고 있던 사용자의 도메인을 탈취하거나 도메인 네임 시스템(DNS) 또는 프락시 서버의 주소를 변조함으로써 사용자들로 하여금 진짜 사이트로 오인하여 접속하도록 유도한 뒤에 개인정보를 훔치는 새로운 컴퓨터 범죄 수법.

5. 결론

앞에서는 버퍼 오버플로 공격, 포맷 스트링 공격, 메모리 해킹에 대해 살펴보았다. 이를 통해 코드 보안의 중요성을 다시 상기할 수 있다. 하지만 여전히 버퍼 오버플로 취약점은 매년 발생하는 바이러스, 해킹 등과 같은 보안위협의 50% 이상을 차지하는 취약점이고 C언어로 작성된 프로그램에서 발생하는 포맷스트링 취약점은 버퍼 오버플로 보안 취약점 보다 더 위험하고 그 사례가 해마다 공개적으로 보고된다. 메모리 해킹의 경우 향후 전자금융의 안전성을 위협할 공격 방법으로서 인터넷뱅킹 사고에서 사용된 악성코드를 기반으로 더욱 진화할 것이 분명하다. 따라서 기존의 공격에 대한 코드보안 대책도 강구함과 동시에 신종 공격 방법에도 근본적인 대책마련을 위한 지속적인 연구가 필요하다.

'정보보안' 카테고리의 다른 글

암호화(Encryption)  (0) 2024.10.30
안전한 시스템 설계 8원칙  (2) 2024.10.30
SSRF(Server-Side Request Forgery)  (0) 2024.10.30
SQL Injection  (0) 2024.10.30
패킷분석(Packet Analysis)  (0) 2024.10.30