ARM exploit编写四

31 篇文章 9 订阅

我们先了解内存布局有关知识。
每次我们启动一个程序,都会为该程序保留一个内存区域。然后这个区域被分成多个区域。然后这些区域被分成更多的区域(segment),但是我们将坚持总体概述。所以,我们感兴趣的部分是:程序镜像,堆,栈。
在下图中,我们可以看到这些部分在进程内存中是如何布局的一般表示。用于指定存储区域的地址只是为了举例,因为它们会因环境而异,尤其是在使用ASLR时。
在这里插入图片描述
程序镜像区域基本上保存程序的可执行文件,该文件被加载到内存中。 此内存区域可以拆分为各种段:.plt,.text,.got,.data,.bss等。 这些是最相关的。 例如,.text包含程序的可执行部分,包含所有程序集指令,.data和.bss包含变量或应用程序中使用的指向变量的指针,.plt和.got存储指向各种导入函数的特定指针,用于共享库等。 从安全角度来看,如果攻击者可能影响.text部分的完整性(重写),他可以执行任意代码。类似地,过程链接表(.plt)和全局偏移表(.got)的损坏可能在特定情况下导致执行任意代码。
应用程序使用栈和堆区域来存储和操作在程序执行期间使用的临时数据(变量)。 这些区域通常被攻击者利用,因为堆栈和堆区域中的数据通常可以通过用户的输入进行修改,如果处理不当,可能会导致内存损坏。
除了内存映射之外,我们还需要了解与不同内存区域相关的属性。 内存区域可以具有以下属性中的一个或组合:Read,Write,execute。 Read属性允许程序从特定区域读取数据。 类似地,Write允许程序将数据写入特定的存储区域,并execute - 执行该存储区域中的指令。

接下来了解下内存损坏有关知识。
内存损坏是一种软件错误类型,允许以程序员不想要的方式修改内存。 在大多数情况下,可以利用这种情况来执行任意代码,禁用安全机制等。这可以通过制作和注入payload来完成,该payload会改变正在运行的程序的某些内存部分。 最常见的内存损坏类型/漏洞包括: 缓冲区溢出:栈溢出,堆溢出;悬空指针(释放后重利用);格式化字符串
在本实验中,我们将尝试熟悉缓冲区溢出内存损坏漏洞的基础知识。 在我们即将讨论的示例中,我们将看到内存损坏漏洞的主要原因是用户输入验证不正确,有时会与逻辑缺陷相结合。 对于程序,输入(或payload)可以以用户名,要打开的文件,网络包等形式出现,并且通常可以受到用户的影响。 如果程序员没有为可能有害的用户输入设置安全措施,那么目标程序通常会遇到某种与内存相关的问题。

先来看看缓冲区溢出。
缓冲区溢出是最常见的内存损坏类之一,通常是由编程错误引起的,该错误允许用户提供的数据多于目标变量(缓冲区)可用的数据。 例如,当易受攻击的函数(如gets,strcpy,memcpy或其他函数)与用户提供的数据一起使用时,就会发生这种情况。 这些函数不检查用户数据的长度,这可能导致写入过去(溢出)分配的缓冲区。 为了更好地理解,我们将研究基于堆栈和堆的缓冲区溢出的基础知识。
这次我们要学习的是栈溢出。
顾名思义,栈溢出是影响栈的内存损坏。虽然在大多数情况下,栈的任意损坏很可能导致程序崩溃,但精心设计的栈缓冲区溢出可能导致任意代码执行。 下图显示了栈如何被破坏的。
在这里插入图片描述
可以看到:栈帧(整个栈的一小部分专用于特定函数)可以具有各种组件:用户数据,先前的帧指针,先前的链接寄存器等。如果用户也提供了对于受控变量的大部分数据,FP和LR字段可能会被覆盖。 这会中断程序的执行,因为用户会破坏当前函数完成后应用程序返回/跳转的地址。
实验用到的代码如下:
在这里插入图片描述
在stack.c
我们的示例程序使用变量“buffer”,长度为8个字符,以及一个函数“gets”用于用户的输入,它只是将变量“buffer”的值设置为用户提供的任何输入。
生成可执行文件后使用gdb调试
在这里插入图片描述
查看反汇编代码
在这里插入图片描述
在这里,我们怀疑在“gets”函数完成后可能会发生内存损坏。为了研究这个问题,我们在调用“gets”函数的分支指令之后下一个断点 。 在我们的例子中,地址为0x0001043c。
在这里插入图片描述
为了降低其他无关信息的干扰,我们配置GEF的布局,只向我们展示代码和堆栈。
在这里插入图片描述
一旦设置了断点,我们继续执行程序并提供7 个A作为用户的输入
在这里插入图片描述
当我们研究我们的示例的栈时,我们看到(上图)栈帧没有被破坏。 这是因为用户提供的输入符合预期的8字节缓冲区,并且栈帧中的先前FP和LR值不会被破坏。 现在让我们输入16个A,看看会发生什么。
在这里插入图片描述
在第二个例子中,我们看到(上图)当我们为函数“gets”传入太多数据时,它不会停留在目标缓冲区的边界并继续写下去。 这会导致我们之前的FP和LR值被破坏。 当我们继续运行程序时,程序崩溃(导致“segment fault”),因为在当前函数的结尾期间,FP和LR的先前值从堆栈“加载”到R11和PC寄存器,强制程序到跳转到地址0x41414140(由于切换到Thumb模式,最后一个字节自动转换为0x40),在这种情况下是非法地址。 下图显示了崩溃时寄存器的值(注意到 pc此时为0x41414140)
在这里插入图片描述

接下来我们看看堆溢出
首先,Heap是一个更复杂的内存位置,主要是因为它的管理方式。 为了简单起见,我们要知道:放置在堆内存部分中的每个对象都“打包”成一个“块”,它包含两部分:header头部和user data用户数据(有时由用户完全控制)。 在堆的情况下,当用户能够写入比预期更多的数据时,会发生内存损坏。 在这种情况下,损坏可能发生在块的边界内(intra-chunk overflow),或跨越两个(或更多)块的边界(inter-chunk overflow)。我们来看看下图。
在这里插入图片描述
如上图所示,当用户能够向u_data_1提供更多数据并跨越u_data_1和u_data_2之间的边界时,会发生intra-chunk overflow。 这样,当前对象的字段/属性就会被破坏。 如果用户提供的数据多于当前堆块可容纳的数据,则溢出变为inter-chunk overflow并导致相邻块的损坏。
先来看看intra-chunk 堆溢出
我们可以使用下面的示例。
在这里插入图片描述
代码在intra-chunk.c
程序主要做了:

  1. 定义一个具有两个字段的数据结构(u_data)
  2. 在堆内存区域创建一个u_data类型的对象
  3. 为对象的number字段指定一个静态值
  4. 提示用户为对象的name字段输入值
  5. 根据number字段的值打印字符串
    在这种情况下,我们还怀疑在函数“gets”之后可能发生损坏。
    我们先编译
    在这里插入图片描述
    我们反汇编目标程序的主函数来获取断点的地址。
    在这里插入图片描述
    我们在地址0x10498处设置断点—在gets函数完成之后,我们配置gef只显示代码,然后运行程序并输入7个A
    在这里插入图片描述在这里插入图片描述

一旦命中断点,我们就查找程序的内存布局,找到堆的位置。我们使用vmmap命令,看到堆从地址0x00021000开始。鉴于我们的对象(objA)是程序创建的第一个也是唯一一个对象,我们从一开始就开始分析堆。
在这里插入图片描述
下图可以看到与我们的对象相关的Heap块的详细分解。第一个框是块的header,第二个框是对象(u_data)
在这里插入图片描述
块有一个header(8个字节)和user data(12个字节)存储我们的对象。 我们看到name字段正确存储了提供的7个字符串,以空字节结尾。Number字段存储0x4d2(十进制1234)。让我们重复这些步骤,但在这种情况下输入8 A.
在这里插入图片描述
然后检查堆
在这里插入图片描述
在检查堆时,我们看到number的字段已损坏(现在它等于0x400而不是0x4d2)。空字节终结符覆盖了数字字段的一部分(最后一个字节)。 这会导致块内堆内存损坏。从逻辑上讲,代码中的else语句永远不会到达,因为数字的字段是固定的。但是,我们刚刚观察到的内存损坏使得可以到达代码的else那一部分。如下所示
在这里插入图片描述

接下来我们看看inter-chunk 堆溢出
我们使用下面的程序,在编译时不用优化标志
在这里插入图片描述
代码在inier-chunk.c
在这里插入图片描述
还是同样的流程
在这里插入图片描述
在gets函数后下断点,run输入7个A

在这里插入图片描述在这里插入图片描述
命中断点后,来观察下堆
注意,在这个例子中我们有两个块。我们看到(下图)它们的结构是完整的:some_string(输入的7个A)在其边界内,some_number(程序写好的1234)为0x4d2
在这里插入图片描述
现在我们输入16个A看看
在这里插入图片描述
在上图可以看到,提供过多的输入会导致溢出,从而导致相邻块的损坏。 在这种情况下,我们看到我们输入的过长的A损坏了header和some_number字段的第一个字节。 在这里,通过破坏some_number,我们设法到达逻辑上永远不应该到达的代码部分,即:在这种情况下转向了else部分,输出了memory corrupted。我们试试就知道了

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值