Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

What Cannot Be Read, Cannot Be Leveraged? Revisiting Assumptions of JIT-ROP Defenses

Giorgi Maisuradze, Michael Backes, and Christian Rossow, Saarland University

USENIX Security’16

论文下载

概述

JIT-ROP在代码段中即时搜索可用的gadgets来绕过ASLR达成攻击。过去认为这种攻击方式依赖两点条件,代码段可读,可执行。攻击步骤分为两步,利用内存泄漏漏洞和脚本执行环境来寻找可以的使用的gadgets,利用控制流漏洞执行gadgets。而XNR被认为是对JIT-ROP攻击的一种完备的防御手段.

作者发现通过在可以在可预测的位置利用即时编译产生的代码的位置偏移构造特殊的连续字节。从而产生可以使用的gadgets.

先前的研究表明,通过在代码段中插入一些赋值代码,可以在编译产生的汇编代码中构造出任意的gadgets,现代浏览器因此对所有常量进行了混淆。但我们发现,通过对跳转指令的构造,我们也可以在代码段中编码特定的值,因而对代码段的读并不是攻击的必要条件。现行细粒度的代码随机化和XNR机制并不能防御新的攻击。

新的攻击方法

预设条件

开启了DEP,ASLR,None-readable codes,所有非JIT生成的代码指针都是匿名的, randomized JIT pages, constant blinding,和 guard pages。同时攻击者拥有一个内存泄漏漏洞,改变控制流漏洞,和Javascript环境。

利用条件跳转指令构造gadgets

我们可以利用JS中的if/else for/while构造特殊的连续字节,下面的图是一个很好的例子。

Fig

解释器生成的汇编代码中包含一个偏移地址0XC380CD,在小端模式下下正好是int 0x80;ret;的16进制值。利用这种方式,我们可以在程序中构造合适的gadgets。在这里我们需要知道我们构造的JIT函数的位置,这可以通过将这个函数指针传给另一个JIT函数,然后在另一个JIT函数中读取栈上的值来获取。(此处假设栈地址已知)

作者在Chrome 33 (32-bit)/Chrome 51(64-bit), Firefox 42 (64-bit) and IE 11 (64-bit with 32-bit JavaScript engine)进行了实践。生成0XC380CD,在Chrome上利用了

S1: v=v1+v2,     0x10 bytes
S2: v=0x01010101  0xd bytes

通过使用S1,0xc380c次,S2,1次构造除了期望的gadget。这里有一点值得注意的是对齐,可以在跳转指令前面加入一个奇数长的指令来构造任意的字节。

在Chrome 64和Firefox上,同样可以使用一些其他指令达成功能。IE浏览器有一些特殊,他限制JIT生成代码段长度,并且会随机插入一些NOP指令。但我们依旧可以控制起码两个高位的字节。

利用直接调用构造gadgets

在直接调用中的常数编码了一个指令到函数的相对偏移,我们可以利用这个常数构造一个3字节长度的gadget。

Fig

可以构造类似上面这样的函数,asm_call是一个占位符,同样作为例子,我们希望生成一个0xc3结尾的gadget,此时希望知道被调用函数(一个JIT内部函数,例如V8的helper函数)的位置。虽然他们的位置被随机化了,但是对应的JS结构体中却保存了指针,可以利用内存泄漏漏洞获得他们的值。

在这里,我们需要申请一个16MB申请了的内存存放我们的函数,在其中填满我们的占位符。 可以发现常数偏移会有这样的形式0xY ***,Y由于对齐是一个非任意值。同样,我们可以在call指令前面加入奇数长的指令来改变Y。 同样,作者在Chrome 33 (32-bit)/Chrome 51(64-bit), Firefox 42 (64-bit) and IE 11 (64-bit with 32-bit JavaScript engine)进行了实践.

在Chrome上没有任何特殊的地方,而在firefox上,因为没有直接调用,这种构造方法无法实现。在IE 上,每个函数最长1MB,攻击时需要一些技巧,作者在IE上申请了0x80个这样的函数,每个函数内最高位置1个字节都只有两种取值。在找到一个合适的函数后,将位置的占位函数释放,留给JIT编译生成的函数。最后,我们可以在栈上用下图的函数读取cookie,验证偏移是否正确。

Fig

Fig

最后作者结合两种方法生成了类似下面的gadgets

Fig

生成过程在Chrome 上用了1.3s, in a VirtualBox Virtual Machine running Windows 10 (Intel Core i5-4690 CPU 3.50GHz).

防御

作者总结了这三个浏览器上的防御措施和安全缺陷,如下面两张图。

Fig

Fig

并对应的提出两个防御措施。将所有直接调用转化为间接调用,并且对使用的偏移进行混淆。

Fig

将所有的间接跳转转化为直接跳转。

Fig

性能评价

作者在V8上进行了修改,用V8 Benchmark Suite7作为标准测试,平均时间额外开销在2%,原来生成代码大小为1123KB,修改后为1411KB,额外空间占用为26%。

作为附加,还测试了两个带有超过100万个跳转的函数“ifs true”,“ifs false”,每个函数调用10次 14,25% overhead in “ifs false” and,9,81% for “ifs true”.

结论

作者提出了针对现有JIT-ROP defenses 的两种攻击方法,利用间接跳转和直接调用构造特殊的连续字节作为gadget,并对应给出了自己的解决办法,在V8上进行了实现。获得了很低的overhead

No Pardon for the Interruption: New Inference Attacks on Android Through Interrupt Timing Analysis

论文下载

这篇文章提出了一种Android上的旁路攻击。类似于传感器攻击,该攻击利用的是Android设备的中断机制。文章利用读取系统中断信息,在不申请任何权限的情况下实现两种攻击:推测屏幕图案解锁密码及推测当前运行的APP。

在Android手机上,有很多额外的硬件设备:例如蓝牙,触屏,NFC等等。。这些设备接受响应事件后会向CPU发起中断请求,要求CPU优先处理这些响应事件。而系统会把这些中断请求记录在/proc/interrupts路径下,记录格式如下:

Fig

IRQ:Interrupt Request PIC:programmable interrupt controller.

推测屏幕图案解锁密码攻击:用户手指在触屏上滑动的距离会影响中断次数,根据这些差别可以猜测出解锁图案,结果可以排除90 %的可能性。(共389,112种可能)

Fig

推测当前运行的APP攻击:APP在启动时,屏幕界面会一直变化(foreground UI is continuously refreshed),Display Sub-System (DSS)会产生中断。APP启动一般会有3种基本情况:1)Splash 2)异步加载 3)动画效果。 当然也可能是这几种的组合。但不同的APP会使中断有差别,依次来区分APP。结果可以87 %的准确率(共100个APP)。

Fig

详细的攻击步骤及复杂的数据处理见论文。

Call Me Back! Attacks on System Server and System Apps in Android Through Synchronous Callback

论文下载

Abstract

文章通过静态分析的方法,找到了6个系统服务中一些与callback相关的漏洞,并利用这6个漏洞实现了攻击。

Hazard Situations

Inside the SS(System Server):

  • The callback is invoked in a synchronized code block of any service thread;

某些服务可能会处理一些全局变量,这时需要一些并发控制。例如synchronized{lock}{code}。在一个线程访问这部分代码时,通过锁来阻止其他线程来访问。这部分代码叫做synchronized code block。如果这部分代码中,会调用回调函数,就很危险。如下图(Vul#1):

Fig

ActivityManagerService提供的接口startInstrumentation()需要一个callback handle参数android.app.IInstrumentationWatcher watcher。这段代码在synchronized code block调用了watcher.instrumentationStatus()。而该方法是回调方法,由APP实现。如果在其中加入Thread.sleep(10601000);则会造成System Service Freeze。

  • The callback is invoked in an assistant thread without involving any synchronized block.

SS中的线程分两种primary和assistant。primary thread会将没有被代码捕捉的exception放在reply data中返回。但assistant thread遇到没有被代码捕捉的exception则会崩溃。如果在assistant thread中调用回调函数,就很危险。(Vul#4)

Fig

pi.sendIntent()调用时会调用pi.mTarget.send() 其中send()是回调函数。而这里只能处理SendIntentException,如果是其他Excepion会导致系统重启。

Inside a cooperator system app:

  • The callback is invoked in an activity component;(Vul#5)

Fig

Fig

  • The callback is invoked in a service component or a broadcast receiver component.(Vul#6)

Fig

这两种情况和之前类似,只不过是引起system app的崩溃。例如(Vul#5),让通过在回调函数加入无限等待,可以使系统弹窗没任何反应(卡死)。

分析工具

工具基于flowdroid,但是由于需要分析系统代码,因此会有所改动。只要需要解决四个问题:

  1. 系统类太多,都分析比较麻烦,这时需要定义哪些类有用,哪些类无用。这里用的很技巧,认为规定分析深度,超过一定深度就不再分析。因为他的目的是找到漏洞,不是找全漏洞。
  2. 生成图的时候,多线程转单线程。
  3. 生成图的时候,处理ICC/IPC。二三点解决方法就是细粒度,比如遇到什么函数,就怎么合并。没有统一方法
  4. 某些污点可能是长时间污染的。(全局变量,可能在上一次执行时就被污染了)这里认为作规定。

流程图如下:

Fig

结果分析

共找到6个漏洞,文章给出了细节及利用方法。前面已经举例说明,这里不再一一列举。结果分析算文章主体,前面的工具写的并不详细。

除了每个漏洞的单独利用,文章还设计了高级一点的利用:

  1. 进程防杀。多个进程互相监督,有一个被杀了,就利用漏洞使系统重启。
  2. 防杀毒软件。利用白名单,当杀毒软件扫描进程开始时,就利用漏洞使系统不再相应,看起来好像杀毒软件使系统变卡。最后还是会重启。
  3. 防APP更新。时刻监控有漏洞的APP。如果没了,马上重启。这样会导致新的还没来得及安装。这时更新进程会回滚。
  4. 放系统更新。原理同上。

最后文章还提出了防护手段。唯一的方法就是修复源码:1)尽量异步处理 2)多用try catch结构来捕捉异常。

Measurement and Analysis of Private Key Sharing in the HTTPS Ecosystem

论文下载

本文建议和When HTTPS Meets CDN一起看。

Abstract & Introduction

  • 问题点:网站会将自己的内容托管在第三方的服务器上,如CDN,web hosting providers等,从而需要和第三方托管商共享自己的证书私钥。
  • 研究点:大规模调查网站和和第三方托管商共享自己的证书私钥的情况。

  • 如果一个IP上的私钥除了属于它本来的拥有者A,还属于另外一个不同的组织B,那么作者认为A共享了它的私钥。

  • 发现:

    • 超过76%的组织和第三方托管商共享了至少一个私钥;
    • 如果黑掉最流行的托管商,可以获得Alexa top-1K中60%的域名的私钥;
    • 部分托管商不仅获得了它们客户的私钥,还代替客户管理证书。从证书吊销和重新签发行为上考量,托管商管理证书比客户自己管理证书表现要好。
  • 贡献:

    • 提出了一些新技术,能够分析多个数据集以了解“who owns, who serves, and who manages which certificates”;
    • 针对key-sharing的第一个全网范围的分析;
    • 提出证据表明自管理的证书没有外包管理的证书安全;
    • 所有代码和数据集开源在:https://securepki.org

DataSet

  • SSL certificates:Rapid7拿的数据;2013.10.30-2015.3.30;共收集38,514,130个不同的证书
    • 基于OSX 10.9.2的root store,用openssl找出了1,946个中间证书;
    • 基于以上根证书和中间证书区分出5,067,476个合法叶子证书,覆盖2,552,936个不同的域名;本文不考虑不合法证书;
  • Reverse DNS:同样用的Rapid7收集的数据;(DNS标准不要求IP地址拥有者提供reverse DNS entry)
  • AS Number and Organization:IP地址是按AS分的,每个AS由一个实体控制,判断IP属于哪个AS能够了解IP属于哪个实体。用的CAIDA的数据集。
  • WHOIS:现在知道了哪些IP地址上用了SSL证书,但不知道证书里的域名。利用WHOIS(查域名的IP及所有者)记录来分析。

Methodology

  • Determining who owns a domain:
    • 一个组织可能有多个域名,一个域名可能有多个证书。
    • 根据WHOIS记录里的email address来判断不同域名是否属于一个组织,但记录里有些邮箱需要过滤掉;
    • 四个步骤如图1:

Fig

Fig

  • Determining a site’s hosting providers:根据数据集二、三分析;将101,306,358个IP(77.7%)映射到托管商。

Fig

  • First- vs. third-party hosting:根据前面的结果判断一个证书由website本身还是第三方管理。

Trust

  • How many organizations share keys:8.8%的证书由多个组织管理。76.5的组织至少共享一个私钥。

Fig

  • How many keys do providers have:

Fig

  • How are SAN lists used:SAN list允许一个组织的证书对它的多个名字有效。但有些托管商在SNA list里包含了多个组织的名字。
    • 4%的证书不包含SAN list;
    • 92.8%的包含一个SAN list,里面的名字属于一个组织;
    • 3.2%(共161,810个)的证书SAN list里有一个以上的组织不同于Common Name域里的组织。

Certificate Management

Fig

Fig

Fig

HeapSentry: Kernel-assisted Protection Against Heap Overows

论文下载

这篇文章是2013年发表在DIMVA(Conference on Detection of Intrusions and Malware & Vulnerability Assessment)上的。作者是Leuven大学的Nick Nikiforakis et.al.

过去防止heap overflow的工作都是用canary保护,在free的时候检查canary的值是不是被破坏了。作者认为这个检测的粒度不够细,要在每次调用syscall的时候检测canary的值是不是被破坏。

系统设计

HeapSentry分成用户态和内核态两个模块。

用户态模块用LD_PRELOAD做hook,劫持了malloc和free函数。在malloc的时候增加了一个canary,并通知内核模块增加一个 “地址-canary“ pair。在free的时候,通知内核模块检查canary。

内核模块用kprobes劫持syscall。一是用来处理HeapSentry用户模块发来的请求;二是在每次目标程序发起syscall的时候都检查canary的值。如果不能通过检查就直接调用exit。

Fig

优化

Syscall 分类 作者给syscall按危险程度分类三类:

Fig

  • 如果是High-Risk就把全部的canary都检查一遍。
  • 如果是Medium-Risk就检查一部分的canary。
  • 如果是No-Risk就不检查。

组操作

HeapSentry用户模块会缓存一部分的canary。每次有malloc的时候新分配的canary会先缓存在用户态的一个buffer里,等buffer满了之后再一起更新到内核里。

Fig

Evaluation

Attack Coverage

测试用的是 Ripe: Runtime intrusion prevention evaluator. In Proceedings of the 27th Annual Computer Security Applications Conference (ACSAC), 2011

Fig

Security Evaluation of Risk groups

从shell-storm上找了100个shellcode,用strace跑,发现95个shellcode都用到了High-Risk的syscall。

Performance

Fig

Fig

(1/32,1/16,1/8是Medium-Risk的时候检查的比例)

Inference of Peak Density of Indirect Branches to Detect ROP Attacks

论文下载

发表于CGO’16

Introduction

本文介绍一种通过计算indirect branches的密度来检测ROP攻击的方法

  • 展示了使用 a window of 32 instructions 足以检测在 Exploit Database 选取的15个exp的ROP攻击
  • 这种检测机制可以借助改变编译选项的方法来避免绕过
  • 一种静态分析程序indirect branches的密度的方法

Universal ROP-Detection Thresholds

Fig

In search of a universal threshold

  • 使用pin生产trace
  • 选取了15exp,10 windows, 5 Linux

Fig

实验环境

  • 10 exp on windows
  • programs available in the SPEC CPU2006 benchmark suite
  • compiled with Visual Studio 7 in 32-bit mode to a x86 machine running Windows 7 Ultimate
  • 3天

结论:

  • ROP-based exp 有较高的indirect branches的密度
  • 大的window比较容易模糊辨别界限
  • 至少对我们测试的bencmarks来说,可以确认一个 universal threshold(13 per window of 32 ins)

同时进行64 windows和 Linux的实验,和上面的结果相似

Fig

Evading universal thresholds

使用no-op gadget来绕过检测:

  • no-op gadget:不会影响exp中要用的寄存器或栈或内存的指令
  • 使用Mona进行no-op gadget 搜索

选取no-op gadget标准:

  • > 5 条指令
  • 没有指令会改变栈(push, pop, add esp, etc)
  • 没有只能在privileged mode的指令(cli, ltr, smsw, and 21 more)
  • 不会写在exp中使用的寄存器

对选取出的no-op gadget排序:

  • 间接内存引用升序(避免访问到非法地址)
  • 指令数降序

验证no-op gadget是否可用:

  • Audio Extractor
  • CD to MP3 Converter

因为他们含有最少合法的no-op gadget(21+52)

测试花费时间:>70 man-hours of work

测试结果:3+6

所有可以用的no-op gadget可以分为两类:

  • static initialization sequences
  • alignment blocks

gcc: -falign-labels -falign-jumps 调整alignment

可以通过改变编译器来去除这些no-op gadget

  • 在static initialization sequences中插入写寄存器的指令
  • replace the padding code by no-ops of up to nine bytes (减少指令数)

Using specific thresholds to improve protections

为每个程序建立不同的thresholds

  • the use of specific thresholds reduces by 75% the availability of no-op gadgets

Static Inference of Specific Thresholds

  • IPD:Inference of Peak Density of Indirect Branches

  • (IPD) Given a program P , and two integers: K and R, is there an execution trace of P with no more than K instructions that contains R indirect branches?

δ-CFG: the supporting data-structure

The δ-CFG has three kinds of nodes:

  • BBL:以direct branch指令结尾
  • RET:以return指令结尾
  • FUN:以function call指令结尾

Fig

Algorithm to estimate the peak density of returns

Fig

  • function deduce performs an ex- haustive search bounded by the window size K starting from any node in the program.
  • Function explore receives a trip budget T , a return stack and a node of the δ-CFG.

Fig

  • weight of a path is the sum of all the weights on the edges that constitute this path
  • The IPD problem asks for a path weight K containing R indirect branches

算法实现

  • x86 back-end available in the LLVM compiler
  • our actual implementation of deduce works at the intermediate repre- sentation of the LLVM compilation infra-structure(only analyze code that we can compile)

算法复杂度

  • O(NK+1), N:ins num, K: window size
  • O(N × (2K)), 当所有指令都是2-target branches

Experiments

Specific thresholds lead to less available gadgets

Fig

Fig

On the Accuracy of our Estimates

Fig

Performance of the inference algorithm

Fig

ByteWeight: Learning to Recognize Functions in Binary Code

论文下载

作者是来自CMU的Tiffany Bao, Jonathan Burket, Maverick Woo, 以及David Brumley还有University of Chicago的Rafael Turner等人。

发表于USENIX’14

Abs & Intro

  • 主要是介绍了函数识别对静态分析的重要性。
  • 其中Rosenblum 等人提出了一个开创性工作,他们将二进制程序中的函数识别问题当做supervised machine learning classification problem来进行解决。

Running Example

  • 给出了一个由于不存在直接的调用关系而导致IDA无法识别的例子

Fig

而本作给出的方法,相较于IDA具有更高的识别率,更低的错误率

Problem Definition and Challenges

  • 本文在此说明了,二进制程序中,函数是一系列指令的集合,并且这些指令不需要在一个连续的内存地址上。
  • 本文主要解决的问题就是:
    • Function Start Identification
    • Function Boundary Identification
    • Function Identification
  • 在解决这三个问题时,这其中存在着诸如以下的难点:

Challenges

  • Not every byte belongs to a function
  • Functions may be non-contiguous
  • Functions may not be reachable。由于间接调用导致的问题
  • Functions may have multiple entries:这里例子举得很奇怪,没有特别之处
  • Functions may be removed
  • Each compilation is different

BYTEWEIGHT

  • 利用机器学习的方法,BYTEWEIGHT在分析新的编译器以及新的编译条件产生的Binary,不需要依靠人工添加相关模式或者启发式策略,而是自动化地去生成可用于匹配的literal patterns
  • 这个系统的Overview如下图所示

Fig

  • 和解决传统的分类问题一样,首先需要一个training phase。在训练期间,BYTEWEIGHT利用由源码编译出大量的带有完全调试信息的二进制程序用于学习,在学习时,系统算法根据已知的函数起始时的字节或者指令序列,生成一个weighted prefix tree。作者通过计算从根节点到目标节点的指令序列在training set中出现这个指令序列时并作为函数入口指令的概率,作为这个点的权值。
  • 在实现的过程中,BYTEWEIGHT开发了两种模式:一种直接处理raw bytes;另一个种处理规范化后的指令。

Learning Phase

  • 可分为三步:
    • Extract first l elements for each function (Extraction):l是指定的一个长度值
    • Generate a prefix tree (Tree Generation):
    • Calculate tree weights (Weight Calculation):

Classification Phase

  • 利用在学习阶段建立Weighted Prefix Tree进行匹配。 对于一段指令序列,它的权重,是由它在这个prefix tree中匹配到的最后一个节点上的权值决定的。如果这段指令序列的权值大于一个预先定义的阈值,那么就可以认定这段指令序列是某个函数的入口。

The Function Identification Problem

  • 一旦获得了函数的入口点,就可以从入口点出发,根据指令中的跳转解决,包括直接跳转以及间接跳转(利用VSA来判定它的跳转目标),恢复出整个函数的CFG。

Recursive Function Call Resolution

  • 模式匹配的方式也可能出现遗漏,所以利用RFCR的方法,根据已知的一些函数调用,来判定没有被模式匹配方式所检测到的函数入口点。

Evaluation

  • 作者通过将BYTEWEIGHT与一些已知的二进制程序分析工具进行比较,并给出了一个比较好的结果:

Fig

ORBS: Language-Independent Program Slicing

论文下载

FSE’14

  • 问题: 有许多工程混杂了各种语言的代码甚至脚本。。怎么做切片
  • idea: 删除一些语句,观察程序(行为),判断该语句是否相关,并不断重复该过程。

SLICING DEFINITIONS

  • traditional Slicing:
    • 静态:在任意输入条件下,切出来的代码中指定变量的在特定位置的行为与源程序一致,值一致
    • 动态:只保证代码在给定的输入下与源程序行为一致
    • Critical Slicing:1996年,尝试删除程序中每一条语句,判定是否与目标有关,最后生成不含这些语句的源代码。。

ORBS

  • 首先,给定输入,并在代码中增加一些语句,让他在程序的特定位置输出目标变量的值
  • ORBS不断尝试删除整个工程中的一些连续的行(window),并尝试编译,成功的话,运行,比对输出的结果,如果与原始程序一致,就保留。。
  • 这个过程是尝试从代码末端向前尝试删除的,因为。。。从前删很容易删掉变量定义,导致编译失败。。
  • 其他的一些方法。。
    • F-ORBS:从前找一段一段的删。。
    • DD-ORBS:分成小chunk,然后删掉一个chunk; 完成之后减小chunk的size再重复
    • MDW-DD-ORBS:DD-ORBS结束之后,再用一个逐渐减小的移动窗口去删。。
  • 试验结果:ORBS一般能删掉最多的代码

实验

RQ1: ORBS和其他类似的切分方法比较 RQ2: 能不能切大程序 RQ3: 能不能并行化 RQ4: 讨论外因的影响

与其他方法的比较

Fig

ORBS最好,MDW-DD-ORBS可以进一步讨论

大程序切分

  • 目标:bash
  • 切分bash中的2~4个文件,用时6小时左右。。

Fig

PARALLEL ORBS

  • 不同大小的window的检测同时进行
  • 4个并行,消耗时间下降70%~82%

Fig

EXTERNAL FACTORS

  • 文件顺序,影响结果
  • 编译环境影响结果(c的未定义行为)
  • 源代码布局影响结果(多条语句并入一行,大括号的位置。。)

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

Code Relatives: Detecting Similarly Behaving Software

论文下载

  • 作者:Fang-Hsiang Su, Jonathan Bell, Kenneth Harvey, Simha Sethumadhavan, Gail Kaiser and Tony Jebara
  • 单位:Columbia University
  • 出处:FSE’16

Abs & Intro

在先前的一些相似性检测工作中,主要是检测执行输出是否相同,或者是否有相同的特征identifier或者结构

simions:codes with dynamically similar functional input/output

  • 然而检测simions的方法也是有限制的,由于面对对象语言可以定义新的数据类型,输出数据可以被定义包装成完全不同的数据类型。
  • simion detector在处理不同结构类型的输出时存在着一定的困难。

希望能够通过学习结果的计算过程,通过比较计算过程来判定代码相似性

Code relatives: continuous or discontinuous code fragments that exhibit similar behavior, but may be expressed in structurally or even conceptually different ways.

System Design

DyCLINK由两部分组成:online graph construction以及offline (sub)graph matching

Fig

本文选择了Java作为目标语言,所以DyCLINK会记录执行过程中的JAVA字节码。如果要检测其他语言,只需要实现相应的online graph construction,而后续的子图匹配过程是语言无关

Constructing Graphs

根据动态执行记录的trace。构建相应的graph。其中每个节点代表一条指令,每条边代表指令间的依赖关系。这个图中包含目标方法的所有指令,以及所有目标方法所调用的方法的指令

定义了三种类型的依赖边

  • depinst: A data dependency between an instruction and one of its operands.
  • depwrite: A read-after-write dependency on a variable.
  • depcontrol: A weighted edge indicating that some instructions are controlled by another (e.g., through a jump),corresponding to the frequency that control will follow that edge based on the observed executions.

LinkSub: Link-analysis-based Subgraph Isomorphism Algorithm

接下来的相似性检测过程可以当做一个子图同构问题。

为了提高效率,首先利用粗粒度的筛选缩小目标集合。这里由于依赖关系图类似于一个网络,所以引入PageRank的算法,对源代码段构成的图中的节点进行排位。

PageRank: https://en.wikipedia.org/wiki/PageRank

并根据排位选出其中排位最高的节点,作为source graph的centroid。如果target graph中含有centroid instruction,则它就有可能是source graph的code relative。

接着有根据两个图的distributions of instructions(?),计算他们的Euclidean distance,根据设定的阈值,进一步缩小目标代码集合。

两轮筛选过后利用link analysis来分析目标代码段和源代码段之间的相似度:

  • DyCLINK calculates a PageRank dynamic vector, DV , for the candidate subgraph (LinkAnalysis), where the result is a sorted vector of all of the instructions (vertices from the subgraph), ordered by PageRank.
  • Finally, use the Jaro-Winkler Distance to measure the similarity of two DV s, which represents the similarity between two Gdigs.

Jaro–Winkler distance:https://en.wikipedia.org/wiki/Jaro-Winkler_distanc

Evaluation

文章的测试用例选取了多年Google Code Jam Competition中accepted的答案作为相似性分析的对象。 并将其与SourcererCC以及HitoshiIO作比较

第一个实验说明了Code Relatives的filtering的所带来的效率,以及它的分析时间:

Fig

第二个实验是关于Code Relatives作为Code search的能力,通过和SourcererCC以及HitoshiIO的比较,说明Code Relatives一般能检测出更多功能相似的代码:

Fig

最后一个实验是关于Code Relatives用于KNN算法的准确性:

Fig