|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


1576, 1/79 |
![]() |
![]() |
![]() |
![]() |
|
vngkv123 | ||||||
|
ubuntu 16.04 UAF버그.. | ||||||
|
http://www.hackerschool.org/HS_Boards/zboard.php?AllArticle=true&no=1861 [복사]
Hit : 4575 Date : 2017/04/16 08:36
|
|||||||
| ![]() |
| |
| 해쿨러 | uaf_vuln2.c 소스코드를 올려주세요 | 2017/04/16 | |
| vngkv123 | #include <stdio.h> #include <stdlib.h> typedef struct UAF{ int number; } uaf; int main(){ uaf *one; uaf *two; one = malloc(100); printf("one -> number : %d\n",one->number); one->number = 12345; printf("one -> number : %d\n", one->number); printf("Address of one -> number : %p\n", &one->number); free(one); two = malloc(100); printf("two -> number : %d\n",two->number); printf("Address of two -> number : %p\n", &two->number); } root@ubuntu:/home/ssun/system_exploit/pwn# |
2017/04/16 | |
| vngkv123 | 지금 보기엔 free하게되면서 동시에 거기 있던 값들이 0으로 초기화되는거 같아보이는뎀 ㅠ | 2017/04/16 | |
| 해쿨러 | 아 어려웠네요 malloc chunk는 struct malloc_chunk { INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T mchunk_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으로 힙할당을 요청할 때 받는 포인터는 첫 두번째꺼 이후의 주소를 받습니다. 그래서 첫 할당을 받을 때 size_t*2만큼이 페이지의 배수에서 더해진 상태로 리턴되는겁니다(32비트에서는 +8, 64비트에서는 +0x10) 이렇게 선언돼있고, number가 0으로 되는 시점은 말씀하신대로 free하는데서 존재합니다 free(one)을 할 때 one->fd = fwd 를 하는데 힙 청크 리스트에서 앞에 있는 청크가 없기 때문에 fwd는 0이고 따라서 one->fd에 0이 들어가면서, one->number가 0으로 덮어 씌워지게 되는거구요 sizeof(pointer)*2 이후에 있는 값은 덮어씌워지지않습니다(nextsize suffix가 붙은 멤버들은 large bin에서만 사용되므로) |
2017/04/16 | |
| 해쿨러 | root@ ~/tmp # ./test one -> n1 : 12345 one -> n2 : 23456 one -> n2 : 34567 two -> n1 : 0 two -> n2 : 0 two -> n3 : 34567 root@ ~/tmp # cat test.c #include <stdio.h> #include <stdlib.h> typedef struct UAF{ int n1; int n2; int n3; } uaf; int main(){ uaf *one; uaf *two; one = malloc(100); one->n1 = 12345; one->n2 = 23456; one->n3 = 34567; printf("one -> n1 : %d\n", one->n1); printf("one -> n2 : %d\n", one->n2); printf("one -> n2 : %d\n", one->n3); free(one); two = malloc(100); printf("two -> n1 : %d\n",two->n1); printf("two -> n2 : %d\n",two->n2); printf("two -> n3 : %d\n",two->n3); } |
2017/04/16 | |
| 해쿨러 | 아 처음에 분석한내용 틀렸습니다 지금 다시 분석중이에요 | 2017/04/16 | |
| 해쿨러 | 쉽게 이해하려면 힙에서 프리를 할때 힙 청크를 관리하는 구조체를 프리된것에 맞게 변경하면서 수정된것이라고 이해하면 되구요 어렵게 이해하려면 힙에는 메모리 사이즈에 맞는 최적화를 위해 메모리 블록의 범위에 따라 다르게 처리하고 있습니다 32비트 리눅스에서는, 512바이트를 기준으로 작으면 small bin, 크면 large bin으로 처리되고, 이중에서 72바이트 미만인 블록들은 fastbin으로 따로 처리해 malloc/free 시에 오버헤드를 최소화 하도록 합니다 저도 그렇게 알고있어서 왜 100바이트를 할당받았는데 fastbin free 루틴을 타나 했는데 http://daehee87.tistory.com/478 이 글을 보니 64bit에서는 120바이트 이하의 블록을 fastbin으로 처리하더군요 결국 fastbin free루틴을 탔고 거기서는 fd만 초기화 합니다(sizeof(pointer), 즉 8바이트, sizeof(int)*2) glibc-2.25의 malloc.c의 L3941~L3961을 보면 if (__builtin_expect (old == p, 0)) { errstr = "double free or corruption (fasttop)"; goto errout; } /* Check that size of fastbin chunk at the top is the same as size of the chunk that we are adding. We can dereference OLD only if we have the lock, otherwise it might have already been deallocated. See use of OLD_IDX below for the actual check. */ if (have_lock && old != NULL) old_idx = fastbin_index(chunksize(old)); p->fd = old2 = old; } while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2); if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0)) { errstr = "invalid fastbin entry (free)"; goto errout; } } 이렇게 p->fd만 변경하는 부분을 볼 수 있습니다 사이즈를 256바이트로 바꿔서 다시해보면 fastbin이 아니기 때문에 sizeof(pointer)*4가 변경되어 제가 쓴 예제코드에서 n1~n3 -> n1~n5로 했을 때 n1~n4가 변경된걸 볼 수 있습니다 |
2017/04/16 | |
| 해쿨러 | 아 64비트에서 하신줄 알았는데 32비트에서 하셨었군요 32비트에서는 sizeof(pointer) == sizeof(int)인것만 빼면 똑같습니다 | 2017/04/16 | |
| 해쿨러 | 그래서 결국은 memset(chunk, 0, sizeof(chunk)) 가 아니라 chunk->first = something 하면서 첫 4바이트만 변경된겁니다 청크 전체가 초기화된게 아닌거죠 |
2017/04/16 | |
| vngkv123 | 감사합니당 근데 저 64비트환경에서 한거에용 | 2017/04/16 | |
|
|