Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

Persistent Data-only Malware: Function Hooks Without Code

论文下载

NDSS’14 Technische Universit at Munchen

作者实现了在不修改或注入代码只修改一些Function Pointer和数据的前提下,在目标(内核)中注入一个恶意行为(ROP)的过程,并介绍了实现过程中遇到的很多问题和对应的解决方案。(劫持什么指针去控制PC,如何修改SP去启动ROP,如何避免ROP Chain被破坏,如何解决两个劫持同时发生时的一些冲突。),

Introduction

  • 由于各种各样防护措施的存在(SECURE BOOT, NX, etc) 向目标(kernel)中插入代码(修改代码)已经越来越困难。。。
  • 已有的rootkit的攻击,都是one-shot形式的,例如,利用一些漏洞去隐藏某一个进程,然后就结束了。。
  • 在本文中,我们说明在不修改或添加任何代码的情况下,利用修改函数指针的方式进行函数hook是可行的

Background

  • 作者首先介绍
    • Resident Malware: 有能力在重启之后仍然在无需人工干预的前提下再启动的
    • Persistent Malware: 改变行为的方式注入在某个目标中
    • Data-only Malware: 不使用代码完成实现驻留的,也就是PC永远不会指向Malware带来的代码
  • 本文的目标是总结如何编写一个Persistent Data-only Malware的条件(针对Kernel)
  • 作者首先被攻击的对象中需要有:
    • 一些可利用的指令
    • 一个漏洞,导致控制流可以被修改
    • 漏洞可以加载Data的合适的内存位置
    • 漏洞可以控制PC
  • Non-Persistent Data-only Malware:
    • 作者所知的唯一的Data-only Malware,通过不断的进行Data-only exploit来攻击

PERSISTENT DATA-ONLY MALWARE

  • Overview:
    • 一次Persistent Data-only Malware分成两个阶段,一个是initialization stage,是第一次控制目标行为的阶段,也就是exp的过程,这个不再赘述。另一个是persistent stage,也就是完成了一个function的hook,并永久的驻留在目标中。。
  • Challenges:
    • Finding a suitable memory location:找到合适的内存位置,我们需要找到一些不会被正常行为使用,而且不会被正常行为修改的内存,存放攻击使用的一些数据。。
      • Protecting against overwrites:
        • 一个是ROP中某个gadget包含call的话,会将我们的payload修改,可能导致再触发的时候失效。
        • 另一个是,在ROP进行中,当前线程可能被中断打断,然后栈上的一部分数据可能会被修改
      • Resuming the original control flow:
        • 需要能恢复到原本的function流程去,context需要恢复
      • 最后就是我们在修改了函数指针后,需要switch stack,后文会讨论一些ROP时的switch stack方法
  • Hardware Mechanisms:
    • 如果我们去做一个Kernel persistent data-only malware,那么我们还可以去找到一些硬件机制帮助我们
    • The sysenter instruction:
      • IA32_SYSENTER_CS
      • IA32_SYSENTER_EIP
      • IA32_SYSENTER_ESP
      • 显然,这是一个理想的攻击位置,因为可以直接修改进入ring0时EIP和ESP
      • 问题在于,原本的ESP会被直接覆盖掉,所以我们还需要把原本的值放入payload。。。
    • Task State Segment (TSS):i386上存在一种一条指令jmp <tss_desc>:0x0000,攻击者只需要设置好TSS描述符,然后让IP走到一条这样的执行上,然后就做了context切换。。。然后还可以再通过指令切换回来。。。而且这个机制没有在现在的大多数操作系统上被使用。。。所以也不需要担心冲突。。。
    • X64:
      • Interrupt Descriptor Table (IDT)
      • Interrupt Stack Table: X64上的机制,Interrupt触发时,用来设置rsp的table。。。然后直接ROP了。
    • Software Mechanisms:
      • Adapting the location of the control structure:
        • Problem:我们想用类似的方式攻击一个进程。。并可以修改一个function call的地址。。。但是。。怎么转成ROP呢。。。当前上下文的所有寄存器都不是我们控制的,同时esp也是正常的。。。
        • 方法: 找到线程栈底。。。在这个不会有人访问的地方加内存,放一个一个有很多ret sled的payload, 然后,跳到sub esp, , ret指令。。。
      • Adapting the location of the stack:作者说什么kernel里有per_cpu variable变量,存着进入内核是esp应该被设置的值(所以没用IST)。。
      • Using Function pointer chains:
                  mov [esp+8],size;
                  mov [esp+4],&source;     ;move absolute address of 
                                           ;the global buffer
                                           ;to the top of the stack
                  mov [esp+0],&dest;
                  call <strncpy@plt>
        
        • 一个攻击者是可以把payload放在source的位置上,现在payload地址就放在了栈上,找gadget switch过去就可以了

Fig

  • Architecture
    • 到4a开始说,因为为了尽可能避免之前提到的其他中断打断自己的过程时修改栈上内容,copy chain在保存现场之后,会在把实际的payload 重新拷贝到一个预设的地方,然后switch过去,这样每次都会是正确的值。。
    • Dispatcher Chain是因为我们的Hook可能是在read syscall上,或者什么上面,可能在多个核心上被同时调用,因此,因此。。。Dispatcher Chain用来给不同核心分发到不同的payload和state上。。同时Dispatcher 需要给他们做patch。。因为显然每个payload 是会有一些差异的。。。最后。。就恢复现场就可以了。。

PROOF OF CONCEPT

Fig

  • 最后作者在ubuntu13.04上实现了整个攻击框架,因此现在攻击只需要构造好Payload