AFL学习记录(二)——一次简单的测试

Posted on Mar 4, 2021

题目做不出来,先来写这篇记录。

昨天把环境搭建好了,今天就拿来简单的进行一次测试。还是使用昨天的代码

#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 能不能找出这些漏洞。

AFL 编译好之后是不会自动加入环境变量的,我把它的路径加入到了环境变量里,这样用起来稍微方便一些。

先插桩编译源代码,我使用 afl-clang-fast 来编译,这个是 llvm 模式的,会快许多(据说这是编译级的插桩)。

afl-clang-fast -g -o /path/of/bin /path/of/souce

编译好之后就可以进行 fuzz 了。我的虚拟机分配了多个核心,不一起用到话比较亏,所以我考虑多线程 fuzz (其实这个程序非常小,fuzz 的很快,不需要多线程,但是先熟悉一下用法也好)。我使用 screen 来实现,免得开很多个终端

screen -S f1 afl-fuzz -i ./testcase -o ./sync_dir -M fuzzer1 afl-test-program
screen -S f2 afl-fuzz -i ./testcase -o ./sync_dir -S fuzzer2 afl-test-program
..

这些输进去就开始 fuzz 了。下面对这些指令进行一些简单的介绍。

这里 screen 后面的 -S 参数是指定这个会话的名字,之后可以用这个名字很方便地访问这个会话。而 afl-fuzz 之后的 -M -S 两个参数是指定该线程模糊器是主模糊器还是从属模糊器,后面的 fuzzer1 指定模糊器的名字。这些模糊器的输出会放在在 sync_dir 中其名字对应的目录中。

大概就是这样一个结构。

这里简单介绍一下 screen 的基本使用

screen -r name

重启叫 name 的会话,使用 Crtl + A + D,可以脱离与会话的连接,但不会结束终端中运行的进程,要删除终端,可以用 exit

同时 screen -ls 可以列出所有的会话。

关于界面

fuzzing 的时候就是这样的界面,简单说一下各个版块(详细的我也说不出来

  • process timing
    • 运行时长,距离最近发现的程序执行路径、崩溃、挂起的时间。
  • overall results
    • 总共产出的结果,后三个分别是找到执行路径、崩溃、挂起的数量。第一个比较特别,数字的颜色会从洋红色逐渐变黄最后到绿色,到绿色的时候已经可以认为没有继续 fuzz 的意义了,此时继续 fuzz 也难以发现新的 payload 了。
  • cycle progress
    • 本轮的进度。
  • map coverage
    • 目标二进制文件中的插桩代码所观察到覆盖范围的细节。
  • stage progress
    • 模糊器正在执行的文件变异策略、执行次数和执行速度。据说这个执行速度若低于 500 就说明效率太低,需要自己优化模糊器了。
  • Findings in depth
    • 找到的执行路径,异常和挂起数量的信息。
  • Fuzzing strategy yields
    • 关于突变策略产生的最新行为和结果的详细信息。
  • path geometry
    • 模糊器找到的执行路径的信息。

结果

我总共获得了 9 组 payload,有六组触发了栈溢出并且造成了 SIGSEVE,那六组都是乱码,我这里就不放了,然后有下面三组

F9A@A@	//id_000001,sig_11,src_000000,op_havoc,rep_4
A%nA	//id_000002,sig_11,src_000000,op_havoc,rep_4
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA A
//id_000003,sig_11,src_000000,op_havoc,rep_4

第一组触发了

else if(str[0] == 'F' && len == 6)
{
raise(SIGSEGV);
//如果输入的字符串的首字符为F并且长度为6,则异常退出
}

第二组中有一个 %n,触发了格式化字符串漏洞

第三组触发了

if(str[0] == 'A' && len == 66)
    {
        raise(SIGSEGV);
        //如果输入的字符串的首字符为A并且长度为66,则异常退出
    }

找出了所有的漏洞。这是一个简单的练手,之后试试 fuzz 开源项目,看看能不能找出来(估计不能)。