| 关键词: 代码 shellcode 程序 内存 下图 缓冲区 地址 函数 进制 指令 |
缓冲区溢出属于非常有名的漏洞之一,其大体含义为:缓冲区溢出是超出程序内存设定范围,数据溢出后程序发生异常,黑客可以利用缓冲区溢出执行指定代码,重写栈中的返回地址(ret_Addr)内容来执行任意操作。 本文从栈的介绍、shellcode代码示例、切入思路三个方面进行体系化介绍。 一、栈的介绍栈是一种内存使用方式,采用LIFO(Last In,First Out,先进后出),像手枪的子弹夹一样。 ![]() 示例代码 当调用func函数时,在跳转至函数起始地址的瞬间,栈的形式如下图: 基地址为内存高位,从后向前(向地址递减方向)增长, $1、$2、$3为方法变量地址,ret_addr为main函数返回目标地址。 接下来 esp/rsp逐渐递减,为函数内部的局部变量分配内存空间,a&buff为方法内变量,存储形式如下图: 这时,如果数据溢出,超过了原本分配给buff数组的内存空间,数组后面的ebp、ret_addr以及传递给函数的参数都会被溢出的数据覆盖掉,如下图: 一旦 ebp和ret_addr被覆盖掉,将会引发严重的后果,ret_addr存放的为main函数返回目标地址,也就是说,如果覆盖ret_addr,攻击者就可以让程序跳转至任意地址,如果攻击者事前准备一段shellcode,然后让程序跳转至这段代码,也就相当于成功攻击了”可执行任意代码的漏洞“。 二、shellcode介绍关于shellcode方面,简单的shellcode代码如下: ![]() shellcode示例代码 该代码功能就是启动/bin/sh。通过该代码,我们可以将其转换为汇编语言,通过gdb方式对程序进行调试,gdb指令常用操作如下: r:程序运行; b:设置断点,加星号可传递地址; c:在断点处中断后,继续运行程序; x/[数字]i:对指定数量的指令进行反汇编; x/[数字]x:显示指定长度数据; x/[数字]s:以字符串形式显示指定长度数据; set:向寄存器或内存写入; q:退出; 通过对程序进行gdb调试,我们可清晰了解程序运行方式,如下图: ![]() 反汇编 上图0X0000000000400550至558位置为execve方法的三个参数,倒序形式存放,我们在40055b位置设置断点该位置为execve方法调用,当执行该方法时,我们通过r指令通过断点使用x/8x指令,确认rsp内容是否包含“/bin/sh”。 了解系统执行原理后,可通过汇编语句形成代码,代码如下: ![]() shellcode汇编代码 具体代码解读如下: xor eax,eax //清空寄存器; push eax //入栈 push 0x68732f2f //sh push 0x6e69622f //bin mov al, 0x3b //0x3b表示其系统调用号的十六进制,十进制为59,本系统execve的系统调用编号为59。需要根据自身系统来确定。 将汇编转换成16进制 执行以下语句: nasm -f elf testshell.asm ld -m elf_i386 -o testshell testshell.o 最终形成16进制code码,如下图: ![]() 汇编转16进制 将上图16进制代码整合后,形成执行文件, ![]() 执行文件 当我们执行该文件时,会出现段错误,是因为系统有保护机制,全局数据段shellcode不能被运行,即出现段错误。可安装execstack,随后执行:execstack -s 程序名,“故意”关掉 GCC 的堆栈段不可执行保护机制,便可执行成功,如下图: ![]() 执行shellcode成功 三、切入思路通过第一章介绍,我们了解缓冲区溢出原理及如何利用该原理进行渗透。通过第二章我们实现了shellcode代码编写。如何利用缓冲区进行shellcode切入才是重重之重,一般我们不知道程序的返回地址,因此只能进行推测,我们可尽量在内存空间中填充NOP(0x90)指令(可通过gdb进行查看),然后将shellcode放在最后,这样就可以提高shellcode执行的概率。 本文源自我之前在其它博客所写文章,因之前内容不够详实,所以进行了再次编辑,通过本次再梳理使其内容更为丰富,具有更高的可读性。通过以上内存溢出原理和简单的shellcode,提供了一种代码切入思路,在具体实施过程中难度还是非常大的。 |
| 本文出处: https://www.toutiao.com/a6770817354461872647/ |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|