ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • heap1 풀이
    System hacking training/Protostar 2018. 12. 21. 11:57
    [heap1.c]

    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdio.h>
    #include <sys/types.h>

    struct internet {
        int priority;
        char *name;
    };

    void winner()
    {
        printf("and we have a winner @ %d\n", time(NULL));
    }

    int main(int argc, char **argv)
    {

        struct internet *i1, *i2, *i3;
        
        i1 = malloc(sizeof(struct internet));
        i1->priority = 1;
        i1->name = malloc(8);
        
        i2 = malloc(sizeof(struct internet));
        i2->priority = 2;
        i2->name = malloc(8);

        strcpy(i1->name, argv[1]);
        strcpy(i2->name, argv[2]);

        printf("and that's a wrap folks!\n");
    }

    heap1도 heap0과 마찬가지로 heap overflow 문제다.


    i1 = malloc(sizeof(struct internet));
    i1->priority = 1;
    i1->name = malloc(8);

    i2 = malloc(sizeof(struct internet));
    i2->priority = 2;
    i2->name = malloc(8);

    main()에서 malloc으로 struct internet의 크기 만큼 i1에 할당을 한다.

    이후 값을 넣어주는데,

    i1->name = malloc(8);을 하는 것을 볼 수 있다.

    i2도 똑같이 malloc을 2번해서

    총 4개의 chunk를 할당받는다.


    (gdb) set disassembly-flavor intel
    (gdb) disas main
    Dump of assembler code for function main:
    0x080484b9 <main+0>:    push   ebp
    0x080484ba <main+1>:    mov    ebp,esp
    0x080484bc <main+3>:    and    esp,0xfffffff0
    0x080484bf <main+6>:    sub    esp,0x20
    0x080484c2 <main+9>:    mov    DWORD PTR [esp],0x8
    0x080484c9 <main+16>:    call   0x80483bc <malloc@plt>
    0x080484ce <main+21>:    mov    DWORD PTR [esp+0x14],eax
    0x080484d2 <main+25>:    mov    eax,DWORD PTR [esp+0x14]
    0x080484d6 <main+29>:    mov    DWORD PTR [eax],0x1
    0x080484dc <main+35>:    mov    DWORD PTR [esp],0x8
    0x080484e3 <main+42>:    call   0x80483bc <malloc@plt>
    0x080484e8 <main+47>:    mov    edx,eax
    0x080484ea <main+49>:    mov    eax,DWORD PTR [esp+0x14]
    0x080484ee <main+53>:    mov    DWORD PTR [eax+0x4],edx
    0x080484f1 <main+56>:    mov    DWORD PTR [esp],0x8
    0x080484f8 <main+63>:    call   0x80483bc <malloc@plt>
    0x080484fd <main+68>:    mov    DWORD PTR [esp+0x18],eax
    0x08048501 <main+72>:    mov    eax,DWORD PTR [esp+0x18]
    0x08048505 <main+76>:    mov    DWORD PTR [eax],0x2
    0x0804850b <main+82>:    mov    DWORD PTR [esp],0x8
    0x08048512 <main+89>:    call   0x80483bc <malloc@plt>
    0x08048517 <main+94>:    mov    edx,eax
    0x08048519 <main+96>:    mov    eax,DWORD PTR [esp+0x18]
    0x0804851d <main+100>:    mov    DWORD PTR [eax+0x4],edx
    0x08048520 <main+103>:    mov    eax,DWORD PTR [ebp+0xc]
    0x08048523 <main+106>:    add    eax,0x4
    0x08048526 <main+109>:    mov    eax,DWORD PTR [eax]
    0x08048528 <main+111>:    mov    edx,eax
    0x0804852a <main+113>:    mov    eax,DWORD PTR [esp+0x14]
    0x0804852e <main+117>:    mov    eax,DWORD PTR [eax+0x4]
    0x08048531 <main+120>:    mov    DWORD PTR [esp+0x4],edx
    0x08048535 <main+124>:    mov    DWORD PTR [esp],eax
    0x08048538 <main+127>:    call   0x804838c <strcpy@plt>
    0x0804853d <main+132>:    mov    eax,DWORD PTR [ebp+0xc]
    0x08048540 <main+135>:    add    eax,0x8
    0x08048543 <main+138>:    mov    eax,DWORD PTR [eax]
    0x08048545 <main+140>:    mov    edx,eax
    0x08048547 <main+142>:    mov    eax,DWORD PTR [esp+0x18]
    0x0804854b <main+146>:    mov    eax,DWORD PTR [eax+0x4]
    0x0804854e <main+149>:    mov    DWORD PTR [esp+0x4],edx
    0x08048552 <main+153>:    mov    DWORD PTR [esp],eax
    0x08048555 <main+156>:    call   0x804838c <strcpy@plt>
    0x0804855a <main+161>:    mov    DWORD PTR [esp],0x804864b
    0x08048561 <main+168>:    call   0x80483cc <puts@plt>
    ---Type <return> to continue, or q <return> to quit---
    0x08048566 <main+173>:    leave  
    0x08048567 <main+174>:    ret    
    End of assembler dump.

    각각의 chunk가 어디에 존재하고, 어떤 구조를 갖고 있는지 해당 위치에 bp를 걸고 확인해봤다.
















    다음과 같은 형태를 띈다.

    취약점은 단골 함수인 strcpy()를 호출하여 발생하는데

    strcpy(i1->name, argv[1]);
    strcpy(i2->name, argv[2]);

    딱 봐도 got overwrie를 해야한다.

    좀만 생각하면 답이 나오는데 strcpy()를 사용한다고 해서 stack 처럼 ret를 건드릴 수 있는 것도 아니고,

    heap 은 좀 다르게 chunk라는 애들이 존재하니까...

    그럼 이걸로 어떻게 winner()를 띄우냐...

    소스코드를 보면 답이 나온다.

    strcpy(i1->name, argv[1]);
    strcpy(i2->name, argv[2]);

    printf("and that's a wrap folks!\n");

    strcpy() 호출 이후 printf()가 호출되니까 printf()의 got를 winner()의 주소로 바꾸면 된다.

    (strcpy()도 보기 좋게 2개 있겠다!)
















    argv[1]에 AAAA argv[2]에 BBBB를 넣고 확인해본 결과

    chunk i1에서 마지막 data 부분이 i1->name의 값이 들어가는 주소를 가리킨다.

    chunk 2도 마찬가지다.

    그럼 printf@got를 overwrite하기 위해서는 먼저 첫번째 strcpy()에서 overflow하여

    chunk i2에서 마지막 data 즉 0x0804a038 부분을 printf의 got로 overwrite 하면 된다.

    그리면 두 번째 strcpy()가 호출될 때 인자 정보가 다음과 같게 된다.

    strcpy(i2->name (= printf@got), argv[2]);

    따라서 argv[2]에는 winner()의 주소를 넣어서 다음 printf() 호출 때 winner()를 띄우면 된다.







    끗.


    반응형

    'System hacking training > Protostar' 카테고리의 다른 글

    Stack7 풀이  (1) 2019.04.11
    heap2 풀이  (0) 2018.12.22
    heap0 풀이  (0) 2018.12.21
    Stack6 풀이  (0) 2018.02.16
    Stack4 풀이  (3) 2018.02.04
Designed by Tistory.