Self-Improvement
Stack Buffer OverFlow 기초실습(Ubuntu gdb) 본문
출처 : https://d4m0n.tistory.com/14
위 strcpy 실습을 보면 쉘코드를 입력받는 argv[1]에 넣어주며 buffer 주소를 ret에 넣는 이유는 ret는 4바이트임으로 buffer주소를 넣어줌으로써 쉘코드가 포함된 argv[1]을 buffer에 복사해줌으로써 ret가 실행될때 buffer주소에 접근하여 쉘코드를 실행하게끔 해주는 것이다.
출처 : https://bpsecblog.wordpress.com/2016/03/08/gdb_memory_1/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <string.h>
#include <stdio.h>
void func2(){
puts("func2()");
}
void sum(int a, int b){
printf("sum : %d\n", a+b);
func2();
}
int main(int argc, char *argv[]){
int num=0;
char arr[10];
sum(1,2);
strcpy(arr, argv[1]);
printf("arr: %s\n", arr);
if(num==1){
system("/bin/sh");
}
return 0;
}
|
cs |
소스코드는 간단하게 main()에서 입력받은 arrv[1]을 strcpy 함수를 이용하여 arr변수에 복사해주고 printf()해준다. 그리고 num==1이면 쉘을 얻게되는 구조이다.
여기서 strcpy 함수는 Buffer Overflow에 취약한 함수로 권장하고 있지 않다.
gdb로 컴파일한 파일을 실행시켜준다.
gef > set disassembly-flavor intel (intel 형식으로 어셈블언어를 본다는 뜻이다.)
gef > disassamble main
메인을 분석하기전 <main+0>에 BP를 설정하며 aaaaaaa 값으로 실행해준다.
gef > b *main+0 또는 b *0x080484db
gef > r aaaaaaa
이제 메인을 한줄씩(gef > ni) 진행하면 분석하면서 BoF를 어떻게 해야하는지 알아본다.
1. <main+20> mov dword ptr [ebp-0xc], 0x0 --------> ebp-0xc 즉 v1 변수에 0을 대입해주고 있다.
2. <main+27> sub esp, 0x8 -----> 스택 공간 8바이트를 확보해준다.
3. <main+30> push 0x2 -----> 스택에 2를 넣어준다
4. <main+32> push 0x1 -----> 스택에 1을 넣어준다
5. <main+34> call 0x80484b4<sum> -------> 전에 입력받은 1,2를 인자로 sum()함수를 불러준다.
6. <main+39> add esp, 0x10 -----> sum()에서 사용된 스택을 정리해준다.
7. <main+42> mov eax, dword ptr [ebx+0x4] ------> ebx+0x4 의 값을 eax에 할당해준다.
- ebx+0x4의 값을 확인해보니 0xbffff0a0+4 = 0xbffff0a4이다.
- 0xbffff0a4의 값을 eax에 할당해주는 값을 확인해본다.
gef > x/wx 0xbffff0a4
- eax는 0xbffff134로 되어있다.
8. <main+45> add eax, 0x4 -----> 4를 eax에 더해준다. eax는 0xbffff138이 될 것이다.
- eax의 주소의 값은 0xbffff310d으로 "aaaaaaa"인 입력 값이 들어있다.
9. <main+48> mov eax, dword ptr [eax] -----> eax의 값 0xbffff130을 eax에 할당해준다.
10. <main+50> sub esp, 0x8 -----> 8바이트만큼 스택공간을 확보해준다. (여기서 짐작되는건 8바이트 만큼 인자를 준다는 뜻이다.)
11. <main+53> push eax ----> 0xbffff310을 스택에 넣어준다
12. <main+54> lea eax, [ebp-0x16] ------> ebp-0x16의 주소를 eax에 할당해준다.
- ebp의 주소는 0xbffff088로 - 0x16할 시엔 0xbffff072가 되며 이 주소를 eax에 넣어준다.
13. <main+57> push eax -----> eax의 값을 스택에 넣어준다.
현재까지 스택의 구조를 확인해본다.
| v1(num) ~~ "aaaaaaa" 0xbffff072 |
14. <main+58> call 0x8048350 <strcpy> ----> 스택에 넣은 인자 0xbffff310("aaaaaaa"), 0xbffff072를 인자로 주며 0xbffff072에 복사를 해준다.
- strcpy 함수가 끝나고 스택을 확인해보면
스택 0xbffff074에 입력값이 존재한다.
15. <main+63> add esp, 0x10 -----> strcpy 함수가 종료되고 스택을 정리해준다.
16. <main+66> sub esp, 0x8 -----> 스택 공간을 확보해준다.
17. <main+69> lea eax, [ebp-0x16] -----> ebp+0x16의 주소를 eax에 할당
- ebp-0x16의 값은 0x616161616161 이다. 즉 "aaaaaaa"을 뜻한다.
18. <main+72> push eax ----> eax 값 "aaaaaaa"을 스택에 넣고 그뒤에 printf() 함수를 수행한다.
19. <main+86> cmp dword ptr [ebp-0xc], 0x1 -----> ebp-0xc가 1과 동일한지를 비교하며 동일할 시엔 쉘을 얻을 수 가 있다. 스택을 확인하면 ebp-0xc의 주소는 0xbffff07c이며 0으로 되어있다.
우리가 입력한 값은 0xbffff073에 위치해 있다.
strcpy 함수는 Buffer Overflow에 취약한 함수인 것을 알고 있으며 이제 입력값으로 num 변수의 할당량을 1로 줄 것이다.
스택을 확인하면 "aaaaaaa" 입력한 주소와 num의 사이는 3바이트가 차이가 난다.
※ 스택에 0xbffff074 주소의 값이 "aaaaa"로 되어있는 이유는 그 아래의 a를 포함해서 나타낸것이다. 즉 "00"을 만나기 전까지의 값을 나타내고있다.
즉 다시 실행할때 gef > r aaaaaaabbb1로 실행해주고 다시 확인해 본다.
BoF로 인해 Num 변수의 값이 변조 되었지만 의도와 다르게 헥스값으로 31이 들어가져 있다.
이때는 python이나 perl을 이용하여 헥스값으로 전송하면 된다.
gef > r `python -c 'print "A"*10+"\x01"'`
num 변수에는 정확히 1로 변했으며 결국엔 쉘을 얻게 되었다.
'리버싱 기초' 카테고리의 다른 글
Heap 메모리 구조 (chunk 구조, bins, fd, bk, malloc, free) (0) | 2020.05.14 |
---|---|
함수 호출, 복귀(push ebp, mov epb esp, ret) (0) | 2020.05.12 |
x64dbg (x64dbg, x32dbg) 메모리 맵 (.rdata, .data, .text), 메모리 종류 (0) | 2020.05.08 |
x64dbg(x64dbg, x32dbg) IAT (0) | 2020.05.07 |
RVA, VA, RAW (x64dbg, CFF Explorer) (1) | 2020.05.07 |