• fuzz——AFL基础使用方法


    最近打 ctf 的时候感觉有点遇到瓶颈,就来 fuzz 这块看看。

    AFL 全称为 American huzzy loop,是 Fuzzing 最高级的测试工具之一。这个工具对有源码和无源码的二进制程序均可以进行 fuzz 测试。

    alf 各位自行安装即可,值得注意的是,在我本机 glibc2.31 的环境下,编译 alf 前要对 AFL/llvm_mode/afl-clang-fast.c修改一下,否则会出现报错,只需把部分内容注释掉即可

    输入 afl-fuzz 出现下图即安装成功

     

    我们先看对有源码的二进制程序是怎样进行测试:

    在 AFL 文件夹里会有很多目录,我们进入 test。首先先把自己要测试的源码放进去,再建两个文件夹分别放测试输入的内容和测试输出的内容,我这里就建了 fuzz_in , fuzz_out。在fuzz_in 里面还要建一个文件,里面随便放一些字母就行(这里笔者也不是很清楚为什么)。在有源码的情况下我们用 afl 自带的编译器,对其进行编译这会使测试更加高效。原因是 afl 自带的编译器在编译时会对目标程序插桩,故此过程叫插桩编译。我从其他师傅的博客里找了一个简单的二进制程序来进行测试。

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <string.h> 
    #include <signal.h> 
    
    int vuln(char *str)
    {
        int len = strlen(str);
        if(str[0] == 'A' && len == 66)
        {
            raise(SIGSEGV);
            //如果输入的字符串的首字符为A并且长度为66,则异常退出
        }
        else if(str[0] == 'F' && len == 6)
        {
            raise(SIGSEGV);
            //如果输入的字符串的首字符为F并且长度为6,则异常退出
        }
        else
        {
            printf("it is good!\n");
        }
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        char buf[100]={0};
        gets(buf);//存在栈溢出漏洞
        printf(buf);//存在格式化字符串漏洞
        vuln(buf);
    
        return 0;
    }

    对其插桩编译

    afl-gcc -g -o afl_test afl_test.c

     我们接下来就可以对其进行测试了,此外在 fuzz 前要关闭系统的核心转储,确保在 fuzz 的过程中即使出现 crash 也不会停止,不然就会出现如下报错

     我们关闭系统核心转储开始测试

    sudo su
    echo core >/proc/sys/kernel/core_pattern
    exit
    afl-fuzz -i fuzz_in -o fuzz_out ./afl_test

     这上面的数字是彩色的,注意 overall results 里的 cycles results 的颜色会随着 fuzz 次数的增加从红色到黄色到蓝色到绿色,当他到绿色的时候也就说明基本上该有的 crash 都出来了,继续跑下去,发现的东西也很少了,此时我们就可以 crtl+c 结束测试。

     

     

     此时我们就可以从我们刚刚建立的 fuzz_out 文件夹里看到测试的结果了。

     我们再进行查看

     

     

     之前一次测试的时候格式化字符串也测试出来了,不知道为什么这次没出来。好吧,那插桩测试就写到这里。

     

     下面我们来看无源码的测试过程。

     进行无源码测试之前我们要进入到 AFL/qemu_mode 在终端中执行一下 ./build_qemu_support.sh

    遇见如下报错:

    make[1]: *** [/xxxxxxxx/AFL/qemu_mode/qemu-2.10.0/rules.mak:66: linux-user/syscall.o] Error 1
    make: *** [Makefile:326: subdir-x86_64-linux-user] Error 2

    查阅资料后得知:给 /AFL/qemu_mode/patches/syscall.diff 打个补丁即可

    --- qemu-2.10.0-clean/linux-user/syscall.c    2020-03-12 18:47:47.898592169 +0100
    +++ qemu-2.10.0/linux-user/syscall.c    2020-03-12 19:16:41.563074307 +0100
    @@ -34,6 +34,7 @@
     #include <sys/resource.h>
     #include <sys/swap.h>
     #include <linux/capability.h>
    +#include <linux/sockios.h> // https://lkml.org/lkml/2019/6/3/988
     #include <sched.h>
     #include <sys/timex.h>
     #ifdef __ia64__
    @@ -116,6 +117,8 @@ int __clone2(int (*fn)(void *), void *ch
     #include "qemu.h"
    
    +extern unsigned int afl_forksrv_pid;
    +
     #ifndef CLONE_IO
     #define CLONE_IO                0x80000000      /* Clone io context */
     #endif
     
    @@ -256,7 +259,9 @@ static type name (type1 arg1,type2 arg2,
     #endif
    
     #ifdef __NR_gettid
    -_syscall0(int, gettid)
    +// taken from https://patchwork.kernel.org/patch/10862231/
    +#define __NR_sys_gettid __NR_gettid
    +_syscall0(int, sys_gettid)
     #else
     /* This is a replacement for the host gettid() and must return a host
        errno. */
    @@ -6219,7 +6224,8 @@ static void *clone_func(void *arg)
         cpu = ENV_GET_CPU(env);
         thread_cpu = cpu;
         ts = (TaskState *)cpu->opaque;
    -    info->tid = gettid();
    +    // taken from https://patchwork.kernel.org/patch/10862231/
    +    info->tid = sys_gettid();
         task_settid(ts);
         if (info->child_tidptr)
             put_user_u32(info->tid, info->child_tidptr);
    @@ -6363,9 +6369,11 @@ static int do_fork(CPUArchState *env, un
                    mapping.  We can't repeat the spinlock hack used above because
                    the child process gets its own copy of the lock.  */
                 if (flags & CLONE_CHILD_SETTID)
    -                put_user_u32(gettid(), child_tidptr);
    +                // taken from https://patchwork.kernel.org/patch/10862231/
    +                put_user_u32(sys_gettid(), child_tidptr);
                 if (flags & CLONE_PARENT_SETTID)
    -                put_user_u32(gettid(), parent_tidptr);
    +                // taken from https://patchwork.kernel.org/patch/10862231/
    +                put_user_u32(sys_gettid(), parent_tidptr);
                 ts = (TaskState *)cpu->opaque;
                 if (flags & CLONE_SETTLS)
                     cpu_set_tls (env, newtls);
    @@ -11402,7 +11410,8 @@ abi_long do_syscall(void *cpu_env, int n
             break;
     #endif
         case TARGET_NR_gettid:
    -        ret = get_errno(gettid());
    +        // taken from https://patchwork.kernel.org/patch/10862231/
    +        ret = get_errno(sys_gettid());
             break;
     #ifdef TARGET_NR_readahead
         case TARGET_NR_readahead:

    成功!

    又出现如下报错:

    这时我们返回 AFL 目录重新 make install 即可

    此后和插桩测试的过程就大体一致了,只是在 test 里直接放进二进制程序即可,并且加上参数 -Q

    afl-fuzz -i fuzz_in -o fuzz_out -Q ./afl_test2

     好了 afl 的一些基础用法掌握了,以后就在 ctf 打不动的时候,跟着其他师傅的博客去复现CVE漏洞看看。

     

    参考文章:

    https://blog.csdn.net/weixin_50919879/article/details/108916954

     https://xz.aliyun.com/t/4314

    https://blog.csdn.net/geniusle201/article/details/111028697

    https://www.codeleading.com/article/61745363753/

    https://blog.csdn.net/qq_38239282/article/details/120975670

    https://bbs.csdn.net/topics/392361391

    https://blog.csdn.net/ChuMeng1999/article/details/121880731


    __EOF__

  • 本文作者: 狒猩橙
  • 本文链接: https://www.cnblogs.com/pwnfeifei/p/15884832.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    挑战10个最难回答的Java面试题(附答案)
    【ONE·Linux || 网络基础(一)】
    数据结构——排序
    NSS [SWPUCTF 2022 新生赛]numgame
    无公网IP通过旁路由openwrt的Zerotier实现和在家一样访问家里每个设备
    如何防止IP和账户关联?
    【深度学习】解析Vision Transformer (ViT): 从基础到实现与训练
    面试灵活拷问:对于数据库的索引,你是怎么理解的?
    基于C#的GRPC
    Windows提权
  • 原文地址:https://www.cnblogs.com/pwnfeifei/p/15884832.html