Lord of BOF_13_Bugbear

코드에는 커맨드 라인을 이용하여 사용하는 라이브러리 버전을 알아내고, 해당 라이브러리의 주소를 알아내는 명령과 해당 라이브러리에서 원하는 함수의 오프셋을 알아내는 명렁이 포함되어 있다.

ldd로 프로그램이 이용하는 라이브러리를 알아내고, 이를 파싱하여 주소를 알아낸다. nm으로 라이브러리에서 이용하는 심볼을 알아내고, 이 중 원하는 함수에 대한 정보를 뽑아 파싱하여 오프셋을 알아낸다.

함수가 올라가는 주소는 라이브러리의 base 주소 + offset 이다. LOB에서는 ASLR이 걸려있지 않기 때문에 그대로 이용할 수 있다. 다른 방법으로도 주소를 구할 수도 있다. gdb에서 주소를 프린트하는 방법이 있다.

핵심 알고리즘은 다음과 같다.

  • assassin 프로그램에서 사용하는 execve 함수 주소를 얻는다.
  • argv[1][44]~[47]의 주소가 execve 함수 주소인지 체크한다.

즉, RTL을 하되, execve를 이용하라는 의미이다.

gdb를 이용하여 execve 주소를 구하였다. 0x400a9d48이다.

0x0a는 줄 바꿈에 해당하는 아스키 코드이다. 이를 argv로 넣기 위해서는 파이썬 코드를 "로 감싸 주어야 한다.

주소를 이용하여 execve 함수 주소를 체크하는 루틴을 우회한 것을 확인할 수 있다.

참고로 tmp 폴더에 프로그램을 복사할 경우, 권한 문제로 인해 ldd가 작동하지 않는다.

따라서 복사한 프로그램에서 구해지는(ldd가 실패했을 때 구해지는 잘못된) execve 주소 계산 결과를 찾아 이용하였다. 이는 0x080da023이다.

이 값을 인자로 주어 실행하면 core파일을 얻을 수 있다. RTL을 할 것이기 때문에, return address에 execve 함수 주소를 넣고, 더미값 4바이트 후 execve 인자를 순서대로 넣을 것이다.

execve 함수는 int execve(const char *filename, char *const argv[], char *const envp[]); 로 정의된다.

filename에는 실행할 프로그램 경로 문자열의 주소, argv에는 argv로 쓰일 인자 배열의 주소(배열은 null로 끝), envp는 환경변수의 배열 주소가 들어간다.

결론적으로, 실행할 프로그램 경로인 /bin/sh 문자열을 저장할 필요가 있다.

envp 에는 null이 위치한 주소(null을 가리키는 포인터)를 넣으면 된다. argv는 첫 번째 배열은 아무 값, 두번째 배열에는 null이 잇는 주소를 넣으면 된다.

strcpy가 시작되는 주소는 EBP-40이다. EBP backup까지 44바이트의 더미 값 뒤에 execve 함수 주소를 넣는다.

그 후 4바이트 더미 값을 넣고, execve 인자를 차례대로 넣는다.

복사한 프로그램에 적용할 수 있는 잘못 계산된 execve 주소인 0x080da023 를 인자로 하여 core파일을 얻어 스택 주소를 알아내었다.

미리 환경변수에 등록해 둔 /bin/sh 문자열은 0xbfffff39 부터 시작한다. 앞의 MYENV=를 잘라내야 한다는 점에 주의한다.

argv 배열 주소로는 0xbffffbd0을 사용하고, envp 배열 주소로는 0xbffffbd4를 이용하겠다.

giant의 비밀번호는 one step closer 이다.


tags: writeup, pwnable, buffer overflow, stack overflow, memory corruption, elf file, linux, return to library, c lang, x86asm