Pwn 二进制漏洞审计

简介: Pwn 二进制漏洞审计

 PWN的另一个名字是二进制漏洞审计

image.gif 编辑

Pwn和逆向工程一样,是操作底层二进制的,web则是在php层面进行渗透测试

我是从re开始接触CTF的,有一点二进制基础,本文可能会忽略一些基础知识的补充

”Pwn”是一个黑客语法的俚语词 ,是指攻破设备或者系统。发音类似“砰”,对黑客而言,这就是成功实施黑客攻击的声音——砰的一声,被“黑”的电脑或手机就被你操纵了。

Pwn在CTF竞赛是体现技术实力的关键部分,也是最难的部分。

下面讲解一下Pwn有关的知识

                      ——Your computer,my access!

Pwn的目的

最终目的:获得一个shell

Shell是系统的用户界面,提供了用户与内核进行交互操作的                                                                                                                                                                                                                                                                   一种接口。

它接收用户输入的命令并把它送入内核去执行。

实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。

image.gif编辑

获得一个shell意味着获取了一个服务器的控制台,我们就可以随心所欲地操作服务器中的数据。

基础知识

需要有一点Linux的基础

    • linux基础命令
    • vim文件
    • gcc使用
    • gdb的使用

    课程推荐MIT的CS计算机操作环境导论

    也可以跟着acwing的yxc学习Linux基础课

    程序的编译和链接

    这里涉及到Linux的一些命令和工具

    编译过程

    编译->汇编->链接

    file命令

    可以查看文件类型

    gcc使用的vim查看底层二进制

    在vim中查看底二进制,在命令行中输入:%!xxd

    还原为字符文件 %!xxd -r

    gcc直接编译

    gcc 要编译的文件

    逐步使用gcc编译

    gcc -S 源代码文件 得到汇编文件

    gcc 汇编语言文件 得到可执行文件

    ./可执行文件 可以执行可执行文件

    可执行文件

    Windows:PE

    可执行程序

    exe

    动态链接库

    dll

    静态链接库

    lib

    Linux:ELF

    可执行程序

    out

    动态链接库

    so

    静态链接库

    a

    需要对PE文件和ELF文件有一定的了解,这类资源可以自行搜索解决

    堆栈

    这里讲解一下汇编语言的堆栈机制,读完不能很好理解的读者可以自行学习汇编语言,但是读完本博客的内容做一个抽象性的理解其实也足够了

    下面是我的两篇关于汇编语言基础的blog:

    汇编语言学习 上

    汇编语言学习 下

    堆栈数据结构

    堆栈数据结构就是我们数据结构课中学到的栈

    image.gif编辑

    栈顶添加新元素,删除元素在栈顶删除

    后进去先出FILO

    本文要讲的是运行时堆栈

    运行时堆栈

    运行时堆栈是内存数组,程序的数据存放在内存上,运行时用抽象数据结构中栈的形式来处理数据

    ESP寄存器

    ESP寄存器(extended stack pointer,扩展堆栈指针)

    可以理解为抽象数据结构栈中指向栈顶的指针

    存放某个位置的32位偏移量

    基本上不会被程序员修改

    用CALL,RET,PUSH,POP指令间接修改

    入栈操作

    32位入栈操作是把栈顶指针减4,再将数值复制到栈顶指针指向的位置

    image.gif编辑

    运行时堆栈在内存中是向下生长的,从高地址向低地址扩展

    出栈操作

    从堆栈删除元素,站定指针减小

    下面介绍一些汇编指令

    PUSH指令

    首先减少ESP的值,将操作数复制到堆栈

    POP指令

    将ESP指向的堆栈元素复制到一个操作数当中,增加ESP的值

    PUSHFD指令

    将32位EFLAGS寄存器的内容压入堆栈

    POPFD指令

    将栈顶元素弹出到32位EFLAGS寄存器

    PUSHAD指令

    按照EAX,ECX,EDX,EBX,ESP,EBP,ESI,EBI的顺序

    将所有32位通用寄存器压入堆栈

    POPAD指令

    按照与PUSHAD相反的顺序将其弹出堆栈

    堆栈帧

    堆栈参数

    堆栈帧是一块堆栈保留区域

    存放

      • 被传递的实际参数
      • 子程序的返回值
      • 局部变量
      • 被保存的寄存器

      创建步骤

        1. 将被传递的实际参数压入堆栈
        2. 当子程序被调用时,该子程序的返回值压入堆栈
        3. 子程序开始执行的时候,EBP被压入堆栈
        4. 设置EBP等于ESP,EBP成为子程序所有参数的引用基址
        5. 如果有局部变量,修改ESP在堆栈中为其预留空间
        6. 需要保留的寄存器,将它们压入堆栈

        Fastcall调用方式

        顾名思义,是一种希望快速的调用方式

        我们来分析一下这个调用方式:

        调用自过程的时候,需要首先将参数传入EAX,EBX,ECX,EDX,少数情况还会传入ESI,EDI

        我们知道寄存器是CPU内部的原件,堆栈在内存上,寄存器调用明显更快

        但是我们知道通用寄存器很少,很多都有特定的功能,乘法需要用到EAX,还有许多寄存器用来循环数值和参与计算的操作数

        因此寄存器不可能一直存放传递给过程的参数

        在过程调用之前, 存放参数的寄存器需要首先入栈,然后向其分配过程参数

        但是这些额外的入栈操作会让代码变得混乱,还有可能消除性能优势

        值传递

        一个参数通过数值传递时,该值的副本会被压入堆栈

        .data
        val1 DWORD 3
        val2 DWORD 6
        .code
        push val2
        push val1
        call AddTwo

        image.gif

        引用传递

        通过引用来传递的参数包含的是对象的地址

        push OFFSET val2
        push OFFSET val1

        image.gif

        传递数组

        将数组的地址压入堆栈

        不愿意采用将每个数组元素压入堆栈的原因是这样很慢而且浪费堆栈空间

        访问堆栈的参数

        1.将传递的参数压入堆栈,调用子过程

        2.EBP寄存器存放的是原来栈帧的基址,我们需要现将EBP压入栈保存

        3.然后将当前的ESP作为新的栈帧的基址

        示例

        int AddTwo(int x,int y)
        {
            return x+y;
        }

        image.gif

        将EBP入栈,设置ebp位esp的值

        AddTwo PROC
            push ebp
            mov ebp,esp

        image.gif

        ADD(5,6)

        6

        [EBP+12]
        5 [EBP+8]
        返回地址 [EBP+4]
        EBP mov ebp,esp

        这样通过当前EBP和偏移量就能访问传入的参数和原来的ebp(返回地址)

        显式的堆栈参数

        堆栈参数的引用表达式形如[esp+8],称它们为显式的堆栈参数

        清除堆栈

        子程序返回时,必须将参数从堆栈中删除

        否则会导致内存泄露,堆栈会被破坏

        C调用方式-cdecl

        用于C和C++语言

        子程序的参数按逆序入栈

        解决了运行时堆栈的问题

        在调用子过程后,紧跟一条语句让堆栈指针ESP加上一个数,该数的值即为子程序参数所占的堆栈空间

        main PROC
            push 6
            push 5
            call AddTwo
            add esp,8
            ret
        main ENDP

        image.gif

        能将参数从堆栈中删除

        STDCALL调用规范

        给RET指令添加了一个参数,使程序在返回调用过程的时候,ESP会加上这个参数

        这个添加的整数和过程参数占用的堆栈空间字节数相等

        AddTwo PROC
            push ebp
            mov ebp,esp
            mov eax,[ebp+12]
            add eax,[ebp+8]
            pop ebp
            ret 8
        AddTwo ENDP

        image.gif

        局部变量

        在子过程中创建的变量

        局部变量在ebp下

        void Mysub()
        {
            int X=10;
            int Y=20;
        }

        image.gif

        每个变量的存储大小都要向上取整保存为4的倍数

        两个局部变量一共保留8个字节

        MySub PROC
            push ebp
            mov ebp,esp
            sub esp,8
            mov DWORD PTR [ebp-4],10
            mov DWORD PTR [ebp-8],20
            mov esp,ebp
            pop ebp
            ret
        MySub ENDP

        image.gif

        从堆栈中删除局部变量,只需要执行:

        mov esp,ebp

        image.gif

        esp向上移动=内存释放

        可以给局部变量的偏移量定义一个符号,在代码中使用这些符号

        X_local EQU DWORD PTR [ebp-4]
        Y_local EQU DWORD PTR [ebp-8]
        MySub PROC
            push ebp
            mov ebp,esp
            sub esp,8
            mov X_local,10
            mov Y_local ,20
            mov esp,ebp
            pop ebp
            ret
        MySub ENDP

        image.gif

        保存和恢复寄存器

        子程序在修改寄存器之前将它们的当前值保存到堆栈

        通常在ebp入栈,设置ebp等于esp之后,相关寄存器入栈

        栈帧

        解释说明
        传递的参数 [EBP+8]

        返回地址

        [EBP+4](原来栈帧的EBP)
        EBP

        当前栈帧的EBP

        ECX
        EDX 当前ESP指向的位置

        EBP被初始化之后,整个过程中它的值将保持不变

        ECX,EDX入栈并不影响EBP按照原来的偏移量访问传递的参数

        引用参数

        引用参数通常是基址-偏移量寻址方式进行访问

        每个引用参数都是一个指针

        .data
        count=100
        array WORD count DUP(?)
        .code
        push OFFSET array
        push count
        call ArrayFill

        image.gif

        ArrayFill PROC
            push ebp
            mov ebp,esp

        image.gif

        数组偏移量
        数组长度

        返回地址

        EBP

        下面我们来进入与Pwn的正文

        image.gif编辑

        StackOverflow

        StackOverflow是一种常见的Pwn的手段

        同时与有与之同名的网站StackOverflow是全球最大的编程问答社区

        image.gif编辑

        C语言函数调用栈

        复习和补充一下函数调用栈的内容

          • 函数调用栈是值程序运行时内存一段连续的区域
          • 用来保存函数运行时的状态信息
          • 称之为“栈”是因为发生函数调用的时候,调用函数的状态被保存在栈内
          • 在函数调用结束之后,栈顶的函数状态被弹出,栈顶恢复到调用函数的状态
          • 函数调用栈在内存中从高地址向低地址扩展

          栈帧结构

          previous stack frame pointer
          arguments
          return address
          stack frame pointer
          callee saved registers
          local variable

          arguments会倒序压入栈

          StackOverflow原理

          我们要控制程序执行流

          就要控制EIP,RIP这种PC寄存器

          只要EIP寄存器能写入我们想要的值,整个程序执行流就会被我们劫持

          能传给EIP值的位置只有return address这里

          缓存区溢出

          本质是向定长的缓存区中写入了超长的数据,造成超出的数据覆写了合法内存区域

          栈溢出

            • 最常见,漏洞比例最高,危害最大的二进制漏洞
            • 在CTF PWN中往往是漏洞利用的基础

            堆溢出

              • 现实中的漏洞占比不高
              • 堆管理器复杂,利用花样繁多
              • CTF PWN中的常见题型

              BSS溢出

                • 现实中与CTF比赛中占比都不高
                • 攻击效果依赖于BSS上存放了何种控制数据

                什么样的代码会发生缓存区溢出

                #include<stdio.h>
                int main(){
                    char str[8];
                    read(0,str,24);
                    return 0;
                }

                image.gif

                上述代码企图在8个元素的数组中输入24个数据

                image.gif编辑

                编译执行结果如上图,我们在运行的时候输入了超过8个字符

                在一些Linux中这种缓存区溢出会导致程序崩溃

                如果要是输入一些精心构造的数据,就能实现劫持

                我们输入的数据位置和存储原函数EBP的位置是相邻的

                我们可以利用StackOverflow修改存储原函数的EBP的值

                这样函数返回的时候,原函数的EBP被我们修改了,我们就修改了PC,劫持了这个程序执行流程

                一个合格的程序员是要有一定的安全意识,注意程序存在的安全问题

                PWN必备的工具

                  • IDA pro
                  • pwntools
                  • pwndbg
                  • checksec
                  • ROPgadget
                  • one_gadget

                  IDA pro

                  这是一款逆向工程的强大工具,由于hexray公司生产,官网版本是需要付费的,hexray公司需要用这款工具来开工资

                  IDA pro可以反汇编一个可执行文件,也可以进一步反编译成C语言,可以逆向分析一个可执行文件的运行机制

                  具体使用请参考我的另一篇专门介绍IDA的博客,这里不做赘述,点击下方链接进入

                  IDA基本使用

                  pwngdb

                  是gdb的一个插件

                  gdb是用来调试C语言文件来设计的

                  但是我们在pwn的时候会调试二进制文件,或者说是汇编语言代码

                  这时就需要pwngdb

                  checksec

                  用来查看文件的保护措施

                  一般是做pwn题的第一步

                  检查一下安全保护措施

                  了解之后再进行Attack

                  使用方法

                  旧版本 checksec 文件名

                  新版本 checksec --file=文件名

                  image.gif编辑

                  以新版本为例,上图列出来文件的一些保护机制

                  安装过程

                  依次在终端输入三个命令

                  git clone https://github.com/slimm609/checksec.sh.git
                  cd checksec.sh
                  sudo ln -s checksec /usr/local/bin/checksec

                  image.gif

                  ROPgadget

                  查找程序中用来ROP的代码片段

                  one_gadget

                  很强大的一个工具,找到一些获取shell的代码片段,然后整合在一起

                  未完待续

                  image.gif编辑

                  相关文章
                  |
                  安全 网络安全 PHP
                  网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
                  网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
                  1218 0
                  网络安全-RCE(远程命令执行)漏洞原理、攻击与防御
                  |
                  安全 网络协议 Java
                  网络安全——命令执行漏洞(RCE)详解
                  我也想好好捋一下其他类型的漏洞,同时也分享出来,希望也能帮到大家,今天的内容是命令执行
                  1188 0
                  网络安全——命令执行漏洞(RCE)详解
                  |
                  Linux 网络安全 数据安全/隐私保护
                  渗透测试-CTF文件类型操作
                  渗透测试-CTF文件类型操作
                  渗透测试-CTF文件类型操作
                  |
                  机器学习/深度学习 存储 监控
                  【网络安全】文件包含漏洞--通过日志投毒getshell
                  文件包含漏洞--通过日志投毒getshell
                  357 0
                  【网络安全】文件包含漏洞--通过日志投毒getshell
                  |
                  机器学习/深度学习 存储 安全
                  |
                  云安全 存储 监控
                  Gitlab远程代码执行漏洞(CVE-2021-22205)在野利用,8220挖矿团伙最新变种分析
                  阿里云安全监测到Gitlab远程代码执行(CVE-2021-22205)在野利用,其团伙不仅利用4层协议服务进行入侵,还集成了使用比较广的Web RCE漏洞。
                  970 0
                  Gitlab远程代码执行漏洞(CVE-2021-22205)在野利用,8220挖矿团伙最新变种分析
                  |
                  安全 PHP 数据安全/隐私保护
                  PHP代码审计笔记--代码执行漏洞
                  漏洞形成原因:客户端提交的参数,未经任何过滤,传入可以执行代码的函数,造成代码执行漏洞。 常见代码注射函数:   如:eval、preg_replace+/e、assert、call_user_func、call_user_func_array、create_function等函数     详见http://www.
                  1545 0

                  热门文章

                  最新文章

                  下一篇
                  开通oss服务