• AFL-QBDI与AFL-Unicorn实战


    文章一开始发表在微信公众号

    https://mp.weixin.qq.com/s/wNeeuS3XojfZWvtAJ9xGlQ
    

    Fuzz Android Native库

    为了能够Fuzz Android Native库,笔者基于QBDI框架为AFLplusplus新增一种Fuzz模式,代码和文档如下

    https://github.com/vanhauser-thc/AFLplusplus/tree/master/qbdi_mode
    

    qbdi_mode的工作方式是在template.cpp里面把目标库加载到内存,然后设置好被测函数需要的参数,最后调用目标函数。在这个过程里面会使用QBDI的API获取到目标程序的覆盖率信息并启动forkserver和AFL通信,从而实现Fuzz。

    本节以Whatsapp为例,介绍如何Fuzz Android的Native库。在Whatsapp APK中的libwhatsapp.so里面的Java_com_whatsapp_Mp4Ops_mp4check函数是一个JNI函数

    __int64 __fastcall Java_com_whatsapp_Mp4Ops_mp4check(JNIEnv_ *a1, __int64 a2, __int64 a3, char a4)
    {
      // 转换UTF-8字符串到 C 字符串
      fpath = (a1->functions->GetStringUTFChars)(a1, v5, 0LL);
      clock_gettime(1, &tp);
      
      // 目标函数, 处理视频文件
      v8 = sub_79C70(fpath, &tp, 2 * (v4 == 0), 0);
    

    根据JNI函数的调用约定和Java层的参数信息可以发现该函数的参数类型大概为

    a1: JNIEnv
    a2: jobject
    a3: 文件路径
    a4: 一个bool变量,为0或者1
    

    Java_com_whatsapp_Mp4Ops_mp4check函数最终会把文件路径转换成C字符串并传入sub_79C70函数,后面再也没有用过这个文件路径,那么这个函数应该就是实际处理文件的函数,而且函数的参数比较简单,那么我们就可以直接去Fuzz这个函数,修改template.cpp在main函数里面获取到sub_79C70函数的地址

    	void *offset_func = dlsym(handle, "Java_com_whatsapp_Mp4Ops_mp4check");
    
    	if (NULL == offset_func) {
    		printf("getprocaddress error
    ");
    		return 1;
    	}
    
    	p_target_func = (target_func)((unsigned char *)offset_func + 0x45af0);
    	printf("target function addr: %x
    ", p_target_func);
    

    然后修改fuzz_func,构造好sub_79C70函数需要的参数,然后调用它。

    QBDI_NOINLINE int fuzz_func() {
    
      if (afl_setup()) { afl_forkserver(); }
    
      unsigned long len = 0;
      char *        data = read_file(FPATH, &len);
    
      printf("In fuzz_func
    ");
    	struct timespec tp;
    	clock_gettime(1, &tp);
      p_target_func(FPATH, &tp, 1);
      printf("execute p_target_func:%p
    ", p_target_func);
      exit(0);
      return 1;
    }
    

    编译完成后要能够执行被测程序需要先把libQBDI.so放到安卓设备上并设置LD_LIBRARY_PATH为libQBDI.so和libwhatsapp.so所在的路径,因为libwhatsapp.so还依赖一些APK里面的库。

    # find / -name libwhatsapp.so 2>o
    /data/app/com.whatsapp-wMSOMeRwydbzJJmi-G1wEw==/lib/x86_64/libwhatsapp.so
    # ls ./libQBDI.so
    ./libQBDI.so
    # pwd
    /data/lsl
    # export LD_LIBRARY_PATH=/data/lsl:/data/app/com.whatsapp-wMSOMeRwydbzJJmi-G1wEw==/lib/x86_64/
    # ./loader /data/app/com.whatsapp-wMSOMeRwydbzJJmi-G1wEw==/lib/x86_64/libwhatsapp.so xxx.mp4
    target function addr: 7eaf9c70
    In fuzz_func
    execute p_target_func:0x702f7eaf9c70
    

    确保程序能够正常执行后下面用AFL去Fuzz即可

    ./afl-fuzz -i mp4in/ -o mp4out -m 5000 -t 3000 -p exploit  -- ./loader /data/app/com.whatsapp-wMSOMeRwydbzJJmi-G1wEw==/lib/x86_64/libwhatsapp.so @@
    

    image-20191124182515208

    总结

    本章介绍了各种Fuzz技术并介绍了一些优化Fuzz测试的方法,为了能够熟练使用各种Fuzz技术,读者需要多实践并且要多看看Fuzz工具的源代码。Fuzz测试并不是单纯的启动Fuzz工具让Fuzz工具执行就可以的,在Fuzz的过程中测试人员需要不断地查看Fuzz的状态,一般而言Fuzz的流程如下

    1. 确定并分析Fuzz目标。
    2. 初步运行Fuzz工具保证能够正常开始Fuzz。
    3. 收集大量初始用例并对初始用例去重。
    4. 用去重后的初始用例开始Fuzz。
    5. 在Fuzz过程中当代码覆盖率长时间没有增长时,人工介入分析代码覆盖率,想办法提升代码覆盖率。
    6. 对发现的Crash去重。

    最后祝读者能够挖到更多的漏洞。

  • 相关阅读:
    php 学习笔记 数组2
    php 学习笔记 数组1
    jQuery prop 全选和全不全
    jquery获取多个checkbox的值异步提交给php
    php 计算多维数组中所有值的总和
    系统状态码原型
    hadoop win10开发环境
    kafka spring整合版本匹配
    mac 安装brew
    hadoop2.8.5 idea2019.1.3插件安装
  • 原文地址:https://www.cnblogs.com/hac425/p/14278988.html
Copyright © 2020-2023  润新知