ARM exploit编写一

31 篇文章 9 订阅

我们先ssh连接上之前已经使用qemu搭建好的arm环境。
在这里插入图片描述
本系列实验用到的工具包括:
gdb-调试器
gef-gdb插件
gcc-gnu编译器套件
as-汇编器
ld-链接器
strace-跟踪系统调用
objdump-检查反汇编中的空字节
objcopy-从ELF二进制文件中提取初始shellcode

在开始写shellcode之前,需要知道一些基础的准则,比如:

  1. shellcode应该紧凑并且没有空字节
    原因:我们正在编写shellcode,我们将使用它来利用缓冲区溢出等内存损坏漏洞。 由于使用了C函数’strcpy’,会发生一些缓冲区溢出。 它的工作是复制数据,直到收到空字节。 我们使用溢出来控制程序流,如果strcpy命中空字节,它将停止复制我们的shellcode,我们的漏洞将不起作用。
  2. 尽量避免库调用和绝对内存地址
    理由:为了使shellcode尽可能通用,我们不能依赖于需要特定依赖关系的库调用和依赖于特定环境的绝对内存地址

写shellcode包括如下几个步骤:

  1. 知道你想要使用的系统调用是什么
  2. 配置系统调用号和所选系统调用函数所需的参数
  3. 消除shellcode中的null-byte
  4. 将shellcode转为16进制字符串

理解系统函数
在深入研究我们的第一个shellcode之前,让我们编写一个输出字符串的简单ARM汇编程序。 第一步是查找我们想要使用的系统调用,在我们的例子中是是“write”。 可以在Linux手册页中查找此系统调用的原型:
在这里插入图片描述
从像C这样的高级编程语言的角度来看,这个系统调用的调用如下所示:
const char string[13] = “ARM exploit development\n”;
write(1, string, sizeof(string)); // 此处 sizeof(string) 是 21

查看这个原型,我们可以知道我们需要下列的参数:
fd-1表示标准输出STDOUT
buf-指向字符串的指针
count-需要写出的字节的数量,这里是21
write的系统调用号-为0x4
对于前三个参数我们可以使用寄存器r0,r1,r2;对于系统调用我们需要使用r7然后将0x4存入其中,部分汇编的片段如下所示:
mov r0, #1 @ fd 1 = STDOUT
ldr r1, string @ 从内存中加载字符串到 R1
mov r2, #21 @ 向 STDOUT写21个字节
mov r7, #4 @ 系统调用号 0x4 = write()
svc #0
完整的代码如下,在write.s中
在这里插入图片描述
在data部分,我们通过从字符串后面的地址减去字符串开头的地址来计算字符串的大小。 当然,如果我们只是手动计算字符串大小并将结果直接放入R2中也是可以的。 要退出我们的程序,我们使用系统调用exit(),它的系统调用号是1。
我们编译并执行它
在这里插入图片描述
可以成功输出了,接下来我们研究下期中的细节。

追踪系统调用
我们以下面一个简单的函数为例。
代码如下,在system.c
在这里插入图片描述
第一步是确定此函数调用的系统调用以及系统调用所需的参数。 使用’strace’,我们可以监视程序对OS内核的系统调用。
将上面的代码保存在文件中,然后在运行strace命令之前编译它。
在这里插入图片描述
先看看strace的用法
在这里插入图片描述
-f可以跟踪fork,-v是详细模式,会打印出未缩写的argv.stat,termio[s]等参数

可以看到在上图中,系统函数execve()被调用了

在这里插入图片描述
系统调用号及参数
下一步是计算execve()的系统调用号和该函数需要的参数。
可以在linux man page中看到
输入man execve即可看到如下
在这里插入图片描述
可以看出execve()需要的参数为:
指向指定二进制路径的字符串的指针
argv[]–命令行参数数组
envp[]—环境变量数组
我们可以将其简单地理解为execve(*filename, *argv[], *envp[]) –> execve(*filename, 0, 0).
这个函数的系统调用号可以使用下图的命令查看
在这里插入图片描述
可以看到execve()的系统调用号为11.
函数的参数可以存入寄存器r0,r2;系统调用号可以存到寄存器r7
在这里插入图片描述
在x86上调用系统调用的工作方式如下:首先,在堆栈上调用PUSH参数。 然后,系统调用号被移入EAX(MOV EAX,syscall_number)。 最后,使用SYSENTER / INT 80调用系统调用。
而在ARM上,系统调用有一些不同:

  1. 将参数移入寄存器中-r0,r1…
  2. 将系统调用号移入寄存器r7
    mov r7, #<syscall_number>
  3. 唤起系统调用
    SVC #0或者SVC #1
    4.返回值在r0结束

在ARM汇编中看起来是这样的:
在这里插入图片描述
我们首先使用PC相对寻址将R0指向我们的“/ bin / sh”字符串,然后我们将0移动到R1和R2并将系统调用号11移动到R7
完整的代码在execve1.s
在这里插入图片描述
我们将其编译然后使用objdump反汇编看看
在这里插入图片描述
可以看到在我们的shellcode中有很多null byte,所以下一步就是将其删除并替换所有的涉及到的相关操作。

在shellcode中去除null byte
常用的一种方法是使用Thumb模式。使用Thumb模式可以减少使用空字节的可能性,因为Thumb指令长度为2个字节而不是4个。我们在arm汇编课程中已经学过如果从ARM模式切换到Thumb模式。
这一次我们使用Thumb模式,通过将寄存器相互相减或异或运算,将包含#0的操作替换为导致0的操作。例如,不使用“mov r1,#0”,而是使用“sub r1,r1,r1”(R1 = R1–R1)或“eor r1,R1,R1”(R1 = R1 xor R1)。请记住,因为我们现在使用Thumb模式(2字节指令),并且我们的代码必须是4字节对齐的,所以我们需要在末尾添加一个NOP(例如mov r5、r5)。
在这里插入图片描述
完整代码在execve2.s
同样,编译后使用objdump查看
在这里插入图片描述
我们还剩一个null byte需要去除
我们的代码中导致这个null byte的部分是以空字符结尾的字符串“/ bin / sh \ 0”。
我们有两种方法来解决这个问题:

  1. 使用”/bin/shX”来代替”/bin/sh\0”
  2. 将指令strb(存储字节)与现有的零填充寄存器结合使用,以空字节替换X
    我们使用第一种办法
    在这里插入图片描述
    完整代码在execve3.s
    在这里插入图片描述
    现在已经没有null byte了

接下来我们只需要将shellcode转换为16进制的字符串就可以了
在此之前,最好检查shellcode是否作为独立工作。 但是有一个问题:如果我们像通常那样编译汇编文件,它将无法工作。 原因是我们使用strb操作修改了我们的代码段(.text)。 这要求代码段是可写的,并且可以通过在链接过程中添加-N标志来实现。
我们可以看到ld的参数说明中提到
在这里插入图片描述
所有我们在链接时要加上-N
在这里插入图片描述
可以看到,此时它是能独立运行的
至于转化成十六机制就很简单了,使用下图的两条命令即可
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Exploit 编写系列教程 译序............................................................................................................................................2 Exploit 编写系列教程第一篇:栈溢出...............................................................................3 Exploit 编写系列教程第二篇:跳至 ShellCode............................................................25 Exploit 编写系列教程第三篇 a:基亍 SEH 的 Exploit.................................................54 Exploit 编写系列教程第三篇 b:基亍 SEH 的 Exploit—又一个实例........................77 Exploit 编写系列教程第四篇:编写 Metasploit Exploit.............................................83 Exploit 编写系列教程第五篇:利用调试器模块及插件加速 exploit 开发.................94 Exploit 编写系列教程第六篇:绕过 Cookie,SafeSeh,HW DEP 和 ASLR..............126 Exploit 编写系列教程第七篇:编写 Unicode Exploit................................................218 Exploit 编写系列教程第八篇:Win32 Egg Hunting..................................................256 Exploit 编写系列教程第九篇:Win32 Shellcode 编写入门......................................316 Exploit 编写系列教程第十篇:利用 ROP 绕过 DEP.....................................................432 附录 A:对《基亍栈的溢出》一文的补充.......................................................................509 附录 B:对《编写 unicode exploit》一文的补充........................................................511
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值