보안 취약점

2015. 3. 16. 09:23Security ★ Development/Reversing

반응형

1. 스택 오버플로우

스택 오버플로우를 통한 공격은 대체로 악성 코드가 들어가 있는 함수의 포인터를 프로그램이 실행할 스택의 위치에 덮어씌움으로써 발생할 수 있습니다.

예를 보면 다음과 같습니다.

int counter;

char string[8];

float number; 

와 같은 지역 변수를 정의했을 때 스택의 상태는


counter

string[0]

...

string[7];

number

return address

처럼 되어있습니다.


string 변수에 8이상의 값을 써 넣을 경우 스택은


counter

string[0]

...

string[7]

string[8]?

string[9]?

string[10]?

...

처럼 변경됩니다.


여기서 봐야할 것은 함수가 끝난 후 반환주소를 통해 반환을 해야하는데 그곳에 string[9]?의 값이 들어있습니다.  만약 여기에 다른 악성 코드가 들어있는 함수의 포인터가 덮어씌워진다면 해당 악성코드가 실행되게 됩니다.

이에 대한 하나의 대응책으로 return address이전에 특정 flag를 넣고 이 플래그가 스택 오버플로우 취약점에 의해 다른 값으로 변경되지 않았나 검사합니다.  원래 변경되지 말아야할 이 값이 변경되면 그 다음에 위치해있는 return address도 변경되었을 가능성이 있으므로 악의적인 코드가 실행되는 것을 방지할 수 있습니다.

이 때 flag는 임의의 값이어야지 공격자가 예측하여 올바른 값을 덮어씌우는 것을 막을 수 있습니다. 


2. 힙 오버플로우

힙 영역은 링크드리스트 구조로 되어있어 각 힙 메모리 블록은 Next, Prev 블록에 대한 정보를 가지고 있습니다.  이 값을 악성 코드가 들어있는 포인터로 덮어쓰면 공격이 이루어지게 됩니다.  


3. 문자열 필터

strcpy에 대한 취약점이 하나의 예라고 할 수 있습니다.  strcpy는 문자열에서 NULL을 발견할 때까지 복사를 수행하는데 버퍼가 수용할 수 있는 크기 이상의 문자열을 입력하면 오버플로우가 발생합니다.  인터넷을 보다보면 strcpy_s를 쓰라는 경고를 무시하고 예외처리를 통해 그냥 strcpy를 쓰는 경우가 있는데 가능하면 추천해주는 함수를 쓰도록 합시다.


4. 정수 오버플로우

push esi

push 100

call malloc

mov esi, eax

add esp, 4

test esi, esi

je short 0040104E

mov eax, dword ptr [esp+C]

cmp eax, 100

jg short 0040104E

push eax

mov eax, dword ptr [esp+C]

push eax

push esi

call strncpy

add esp, 0C

00r0104E:

mov eax, esi

pop esi

retn

이 코드는 256(100)만큼의 버퍼를 할당하고 사용자의 입력을 해당 버퍼에 복사하는 작업을 합니다.  [esp+c]로부터 사용자 입력 버퍼의 크기를 구하고 256보다 작으면 작업을 수행하고 있습니다.  

여기서 문제는 부호있는 정수를 사용했다는 것입니다.  이에 대한 근거는 jg명령어로부터 알 수 있는데 만약 부호없는 정수를 사용했다면 컴파일러는 ja명령을 사용했을 것입니다.  사용자 버퍼의 크기 입력으로 음수가 들어와도 위의 코드는 jg명령어를 통해 점프하지 않고 할당작업을 수행한다는 것이 문제가 되고 있습니다.


push esi

push edi

mov edi, [esp+0x10]

lea esi, [edi+0x18]

push esi

call malloc (004010d8)

...

mov [eax], exi

mov esi, [esp+0xC]

shr ecx, 0x2

lea edi, [eax+0x18]

rep movsd

...

이 코드는 전달받은 크기에 0x18을 더한 값 만큼의 버퍼를 생성하고 오프셋+18의 위치에 해당 값을 복사하고 있습니다.

여기서 발생할 수 있는 문제는 전달 받은값, 즉 edi의 값이 0xffffffff에 근접한 값일 경우입니다.  18을 더해주었을 때 오버플로우가 발생하게 되고 32비트 이상부분을 잘라내게 되면 0x00000004와 같은 이상한 값이 남아버리게 됩니다.  이런 값으로 버퍼를 할당하고 여기에 데이터를 쓰려고하면 에러가 발생합니다.  이를 해결하기 위해선 입력받은 크기를 검사해야합니다.


5. 형 변환 에러

아래 코드는 위 코드와 비슷하게 버퍼의 크기를 받고 할당한후 데이터를 복사하는 코드의 일부분입니다.

push esi

movsx esi, word ptr[esp+0xC]

push edi

lea edi, [esi+0x18]

...

여기서 문제는 부호있는 데이터 형이 사용되었다는 것입니다. 그 근거는 movsx로부터 찾을 수 있습니다.  부호없는 형을 사용한다면 컴파일러는 movsz를 사용합니다.  이 값을 movsx를 통해 esi값에 넣을 때 부호 확장이 이루어지는데 movsx는 나머지 공간은 부호값으로 채웁니다.  만약 원래의 값이 0x1400 이라면 32비트 부호확장이 이루어질 때 0xffff1400으로 이루어지게 됩니다.  이 값이 4번과 같이 0xffffffff과 비슷해질 때는 동일한 오버플로우 문제가 발생합니다.  기본적으로 매우 큰 메모리를 할당하게 된다는 문제도 있습니다.  그렇기 때문에 버퍼의 크기를 부호없는 형을 사용하도록 합니다.  부호없는 값을 사용하면 컴파일러는 movsx를 사용하고 이는 나머지 공간은 0으로 채움으로서 0x00001400과 같은 결과를 만들어냅니다.