libFuzzer模糊测试引擎调研与自定义开发
2024-10-18 01:59:0 Author: mp.weixin.qq.com(查看原文) 阅读量:5 收藏


简介

项目地址:llvm-project/compiler-rt/lib/fuzzer at main · llvm/llvm-project (github.com)

libFuzzer 是由 LLVM 项目开发的覆盖率引导模糊测试引擎,广泛用于自动发现软件中的漏洞和错误。它通过不断生成和测试输入数据,提高代码覆盖率,找到潜在的缺陷。libFuzzer 尤其适合测试用 C 和 C++ 编写的代码。


libFuzzer 的模块结构

libFuzzer 是一个面向库的模糊测试引擎,广泛用于发现软件中的漏洞。了解其模块结构有助于深入理解其工作原理和扩展能力。以下是 libFuzzer 的主要模块结构:

FuzzerDriver

功能:这是 libFuzzer 的核心入口点,负责初始化模糊测试环境、读取输入文件、启动模糊测试循环。

关键函数

  • main: 入口函数,负责解析命令行参数并调用FuzzerDriver

  • FuzzerDriver: 核心循环,包含模糊测试的主逻辑。

Mutation

功能:负责生成新的测试用例,通过变异(Mutation)已有的输入数据来发现更多潜在的漏洞。

关键函数

  • Mutate: 对输入数据进行变异。

  • CrossOver: 将两个输入数据交叉生成新的输入。

相关文件FuzzerMutate.cpp,FuzzerMutate.h

Corpus

功能:管理测试用例集合(Corpus),包括收集和存储有效的测试用例。

关键函数

  • AddToCorpus: 将新的测试用例添加到集合中。

  • LoadCorpus: 从磁盘加载测试用例集合。

相关文件FuzzerCorpus.cpp,FuzzerCorpus.h

Coverage

功能:收集代码覆盖率信息,以便评估测试用例的有效性和指导变异策略。

关键函数

  • UpdateCoverage: 更新覆盖率信息。

  • GetCoverage: 获取当前的覆盖率。

相关文件FuzzerTracePC.cpp,FuzzerTracePC.h

Crash Detection

功能:检测程序崩溃,并记录相关的崩溃信息以便后续分析。

关键函数

  • HandleCrash: 处理崩溃事件。

  • ReportCrash: 报告崩溃信息。

相关文件FuzzerFork.cpp,FuzzerFork.h

FuzzerInterface

功能:定义模糊测试引擎的接口,包括用户需要实现的目标函数。

关键函数

  • LLVMFuzzerTestOneInput: 用户提供的函数,libFuzzer 将变异后的输入传递给该函数进行测试。

相关文件FuzzerInterface.h

Options

功能:管理 libFuzzer 的配置选项,允许用户通过命令行参数或配置文件来调整模糊测试行为。

关键函数

  • ParseFlags: 解析命令行参数。

  • PrintHelp: 打印帮助信息。

相关文件FuzzerOptions.cpp,FuzzerOptions.h

Utils

功能:提供各种实用工具函数,用于日志记录、内存管理等。

关键函数

  • Print: 打印日志信息。

  • AllocateMemory: 分配内存。

相关文件FuzzerUtil.cpp,FuzzerUtil.h

MainLoop

功能:控制模糊测试的主循环,协调各模块的工作。

关键函数

  • RunOne: 运行一个测试用例。

  • Loop: 主循环,反复调用RunOne进行模糊测试。

相关文件FuzzerLoop.cpp,FuzzerLoop.h


libFuzzer 功能详解

libFuzzer 的主要功能包括:

覆盖率引导测试:通过覆盖率信息指导输入生成,使测试尽可能覆盖更多代码路径。

最小化崩溃输入:自动最小化导致崩溃的输入,便于调试。

多样化输入生成:支持多种输入生成策略,包括基于变异的输入生成。

词典支持:支持用户提供的词典文件,以增强输入生成的效果。

内存错误检测:结合 AddressSanitizer 使用,可以检测到各种内存错误,如缓冲区溢出和使用未初始化内存等。

并行模糊测试:libFuzzer可以指定行运行加速模糊测试、提高覆盖率。

fork模式:它通过创建多个子进程来同时进行模糊测试,从而提高测试效率。


libFuzzer源码解析

Libfuzzer的主类构成

码位置:llvm-project/compiler-rt/lib/fuzzer at main · llvm/llvm-project (github.com)

这个Fuzzer类的构成可以分为以下几个部分:

1.构造函数与析构函数

Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, FuzzingOptions Options);

~Fuzzer();

2.公有成员函数(Public Member Functions)

主要功能函数:

  • void Loop(Vector<SizedFile> &CorporaFiles); // 主循环,执行模糊测试过程

  • void ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles); // 读取并执行种子语料

  • void MinimizeCrashLoop(const Unit &U); // 最小化崩溃处理

  • void RereadOutputCorpus(size_t MaxSize); // 重新读取输出语料库

时间与状态函数:

  • size_t secondsSinceProcessStartUp(); // 获取从进程启动到现在的秒数

  • bool TimedOut(); // 检查是否超时

  • size_t execPerSec(); // 计算每秒执行的次数

  • size_t getTotalNumberOfRuns(); // 获取总执行次数

静态回调函数(Static Callback Functions):

  • static void StaticAlarmCallback();

  • static void StaticCrashSignalCallback();

  • static void StaticExitCallback();

  • static void StaticInterruptCallback();

  • static void StaticFileSizeExceedCallback();

  • static void StaticGracefulExitCallback();

其他功能函数:

  • void ExecuteCallback(const uint8_t *Data, size_t Size); // 执行用户回调

  • bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, InputInfo *II = nullptr, bool *FoundUniqFeatures = nullptr); // 运行一次模糊测试

  • void Merge(const Vector<std::string> &Corpora); // 合并语料库

  • void CrashResistantMergeInternalStep(const std::string &ControlFilePath); // 崩溃情况下的内部合并步骤

  • MutationDispatcher &GetMD(); // 获取变异调度器

  • void PrintFinalStats(); // 打印最终统计信息

  • void SetMaxInputLen(size_t MaxInputLen); // 设置最大输入长度

  • void SetMaxMutationLen(size_t MaxMutationLen); // 设置最大变异长度

  • void RssLimitCallback(); // 内存使用限制的回调

  • bool InFuzzingThread() const; // 检查是否在模糊测试线程中

  • size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; // 获取模糊测试线程中的当前单元数据

  • void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, bool DuringInitialCorpusExecution); // 尝试检测内存泄漏

  • void HandleMalloc(size_t Size); // 处理内存分配操作

  • static void MaybeExitGracefully(); // 可能会优雅退出程序

  • std::string WriteToOutputCorpus(const Unit &U); // 将单元写入输出语料库

3.私有成员函数(Private Member Functions)

void AlarmCallback();// 闹钟信号的回调

void CrashCallback();// 崩溃信号的回调

void ExitCallback();// 程序退出的回调

void CrashOnOverwrittenData();// 数据被覆盖时崩溃的回调

void InterruptCallback();// 中断信号的回调

void MutateAndTestOne();// 变异并测试一个单元

void PurgeAllocator();// 清理内存分配器

void ReportNewCoverage(InputInfo *II, const Unit &U);// 报告新覆盖率

void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size);// 打印状态并报告慢速输入

void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);// 使用前缀将单元写入文件

void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0, size_t Features = 0);// 打印统计信息

void PrintStatusForNewUnit(const Unit &U, const char *Text);// 打印新单元的状态信息

void CheckExitOnSrcPosOrItem();// 检查是否需要退出

static void StaticDeathCallback();// 处理死亡信号的回调

void DumpCurrentUnit(const char *Prefix);// 转储当前单元数据

void DeathCallback();// 死亡信号的回调

void AllocateCurrentUnitData();// 分配当前单元数据

4.私有成员变量(Private Member Variables)

uint8_t *CurrentUnitData = nullptr;// 当前单元数据指针

std::atomic<size_t> CurrentUnitSize;// 当前单元大小(原子变量)

uint8_t BaseSha1[kSHA1NumBytes];// 基本单元的SHA1校验和

bool GracefulExitRequested = false;// 是否请求优雅退出

size_t TotalNumberOfRuns = 0;// 总执行次数

size_t NumberOfNewUnitsAdded = 0;// 新单元的数量

size_t LastCorpusUpdateRun = 0;// 上次语料库更新的运行次数

bool HasMoreMallocsThanFrees = false;// 是否有比释放更多的内存分配操作

size_t NumberOfLeakDetectionAttempts = 0;// 检测内存泄漏的尝试次数

system_clock::time_point LastAllocatorPurgeAttemptTime = system_clock::now();// 上次内存分配器清理的时间点

UserCallback CB;// 用户回调函数

InputCorpus &Corpus;// 输入语料库的引用

MutationDispatcher &MD;// 变异调度器的引用

FuzzingOptions Options;// 模糊测试选项

DataFlowTrace DFT;// 数据流跟踪对象

system_clock::time_point ProcessStartTime = system_clock::now();// 进程启动时间

system_clock::time_point UnitStartTime;// 当前单元开始时间

system_clock::time_point UnitStopTime;// 当前单元结束时间

long TimeOfLongestUnitInSeconds = 0;// 最长单元执行时间(秒)

long EpochOfLastReadOfOutputCorpus = 0;// 最后读取输出语料库的时间

size_t MaxInputLen = 0;// 最大输入长度

size_t MaxMutationLen = 0;// 最大变异长度

size_t TmpMaxMutationLen = 0;// 临时最大变异长度

Vector<uint32_t> UniqFeatureSetTmp;// 唯一特征集的临时存储

static thread_local bool IsMyThread;// 用于标识当前线程是否是模糊测试线程

这个类主要涉及模糊测试的核心功能,包括种子语料库的处理、崩溃管理、变异调度、统计信息打印等多个方面。

libFuzzer的核心运行流程

Libfuzzer源码学习项目:Dor1s/libfuzzer-workshop: Repository for materials of "Modern fuzzing of C/C++ Projects" workshop. (github.com)

libfuzzer最新源码位置:llvm-project/compiler-rt/lib/fuzzer at main · llvm/llvm-project (github.com)

源码讲解:https://www.bilibili.com/video/BV1RH4y1r74p/?spm_id_from=333.788

libFuzzer 是 LLVM 项目中的一部分,专门用于通过模糊测试来自动化测试 C/C++ 项目中的漏洞。其核心流程大致分为以下几个步骤:

1.主函数入口 (FuzzerMain.cpp)

主函数入口代码如下:

#include "FuzzerDefs.h"

extern "C" {
// 该函数由用户定义,用于测试目标函数
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
} // extern "C"

ATTRIBUTE_INTERFACE int main(int argc, char **argv) {
return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
}

在这个主函数中,调用了fuzzer::FuzzerDriver函数,并传入了用户定义的LLVMFuzzerTestOneInput函数。LLVMFuzzerTestOneInput是由用户编写的,用于定义模糊测试的目标函数,它接收输入数据进行测试并返回测试结果。FuzzerDriver函数则负责模糊测试的核心逻辑。

2.进入核心函数FuzzerDriver(FuzzerDriver.cpp)

FuzzerDriver是 libFuzzer 的核心函数,它的主要作用是设置和启动模糊测试。函数签名如下:

int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
// 进行对象初始化
auto *MD = new MutationDispatcher(Rand, Options);
auto *Corpus = new InputCorpus(Options.OutputCorpus);
auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);

// 解析命令选项
...

// 读取并处理输入的语料库文件,传入模糊测试主循环
auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
F->Loop(CorporaFiles);
}

◆核心步骤包括:

  • 对象初始化:创建并初始化负责输入变异的 MutationDispatcher、输入语料库 InputCorpus 以及核心 Fuzzer 对象。

    • MutationDispatcher:负责生成新的输入变异,目的是探索更多可能的代码路径。

    • InputCorpus:管理模糊测试所使用的输入数据集合(语料库)。

    • Fuzzer:负责执行具体的模糊测试流程,调用用户定义的 LLVMFuzzerTestOneInput

  • 解析命令行选项:处理用户通过命令行传递的选项,包括模糊测试的各种配置参数。

  • 处理语料库:通过 ReadCorpora 函数从输入文件中读取语料库文件,并调用 Fuzzer::Loop 函数启动模糊测试的主循环。

主循环 (Fuzzer::Loop)
Loop是 libFuzzer 中用于执行模糊测试的核心循环。它会不断从语料库中提取输入数据,进行输入变异,并将变异后的输入传递给LLVMFuzzerTestOneInput进行测试。循环的目的是通过广泛探索输入空间,发现导致程序崩溃或行为异常的输入,从而发现潜在的漏洞。

变异引擎
MutationDispatcher是 libFuzzer 的变异引擎,它会生成各种输入数据变种,覆盖尽可能多的代码路径。变异策略包括:

    • 位变异、字节翻转

    • 随机插入或删除数据

    • 拼接不同输入的部分通过不断生成新的变种,libFuzzer 可以更深入地挖掘目标程序中的代码路径,进而发现隐藏的错误或漏洞。

测试结果收集
每次输入变异后,libFuzzer 会将结果反馈给Fuzzer对象,判断程序是否崩溃或异常。出现崩溃时,libFuzzer 会记录触发崩溃的输入,并终止循环进行进一步分析。

源码安装 Clang

更多版本:Release LLVM 18.1.8 · llvm/llvm-project (github.com)
libFuzzer的源码根据需要下载对应版本进行源码编译。

一键配置clang脚本:,该脚本在Ubuntu20上成功测试运行过:

#!/bin/bash

# 安装 Clang 的依赖
sudo apt-get --yes install curl subversion screen gcc g++ cmake ninja-build golang autoconf libtool apache2 python-dev pkg-config zlib1g-dev libgcrypt20-dev libgss-dev libssl-dev libxml2-dev ragel nasm libarchive-dev make automake libdbus-1-dev libboost-dev autoconf-archive libtinfo5

# 定义 Clang 的版本和下载链接
CLANG_VERSION="18.1.8"
CLANG_TAR="clang+llvm-${CLANG_VERSION}-x86_64-linux-gnu-ubuntu-18.04.tar.xz"
CLANG_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_VERSION}/${CLANG_TAR}"
CLANG_INSTALL_DIR="/usr/local/clang-${CLANG_VERSION}"

# 检查 Clang 是否已下载
if [ -f "${CLANG_TAR}" ]; then
echo "Clang 已经下载 (${CLANG_TAR})"
else
echo "正在下载 Clang..."
wget "${CLANG_URL}"
fi

# 检查 Clang 是否已安装
if [ -d "${CLANG_INSTALL_DIR}" ]; then
echo "Clang 已经安装在 ${CLANG_INSTALL_DIR}"
else
echo "正在安装 Clang..."

# 创建目录
sudo mkdir -p "${CLANG_INSTALL_DIR}"

echo "正在安装 解压时间比较久..."
# 解压 Clang
sudo tar -xf "${CLANG_TAR}" -C "${CLANG_INSTALL_DIR}" --strip-components=1
fi

# 检查环境变量是否已经设置
if ! grep -q "${CLANG_INSTALL_DIR}/bin" ~/.bashrc; then
echo "添加环境变量..."
echo "export PATH=${CLANG_INSTALL_DIR}/bin:\$PATH" >> ~/.bashrc
echo "export LD_LIBRARY_PATH=${CLANG_INSTALL_DIR}/lib:\$LD_LIBRARY_PATH" >> ~/.bashrc

# 使环境变量生效
source ~/.bashrc
else
echo "环境变量已经配置"
fi

# 运行 Clang 验证安装
echo "验证 Clang 安装..."
clang --version
echo "如果验证失败再次运行该命令: source ~/.bashrc"

libFuzzer与覆盖率有关的命令行使用

libfuzzer与覆盖率有关的命令行

与覆盖率相关的选项如下:

// 是否打印新覆盖的 PC 地址
Options.PrintNewCovPcs = Flags.print_pcs;

// 是否打印新覆盖的函数
Options.PrintNewCovFuncs = Flags.print_funcs;

// 是否打印覆盖率信息
Options.PrintCoverage = Flags.print_coverage;

// 是否打印完整的覆盖率信息
Options.PrintFullCoverage = Flags.print_full_coverage;

以下是与覆盖率相关的选项的使用方法和案例说明:

1.Options.PrintNewCovPcs = Flags.print_pcs

功能: 打印新的覆盖 PC(程序计数器)地址。

使用方法: 当你希望在测试过程中显示每次新发现的代码路径(对应的 PC 地址)时,可以启用此选项。

命令行示例:

./woff2-2016-05-06-fsanitize_fuzzer -print_pcs=1

案例输出:

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2544448443
INFO: Loaded 1 modules (10708 inline 8-bit counters): 10708 [0x562f5c3345c0, 0x562f5c336f94),
INFO: Loaded 1 PC tables (10708 PCs): 10708 [0x562f5c336f98,0x562f5c360cd8),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 15 ft: 16 corp: 1/1b exec/s: 0 rss: 32Mb
NEW_PC: 0x562f5c220771 in ReadWOFF2Header /home/ub20/FTS/woff/SRC/src/woff2_dec.cc:987:7
#21 NEW cov: 16 ft: 17 corp: 2/5b lim: 4 exec/s: 0 rss: 33Mb L: 4/4 MS: 4 CrossOver-InsertByte-ChangeBit-CopyPart-
NEW_PC: 0x562f5c2161a8 in ReadU32 /home/ub20/FTS/woff/SRC/src/./buffer.h:127:9
#999 NEW cov: 17 ft: 18 corp: 3/9b lim: 11 exec/s: 0 rss: 34Mb L: 4/4 MS: 3 ChangeByte-ShuffleBytes-CMP- DE: "wOF2"-
NEW_PC: 0x562f5c22077c in ReadU32 /home/ub20/FTS/woff/SRC/src/./buffer.h:127:9
#1300 NEW cov: 18 ft: 19 corp: 4/17b lim: 11 exec/s: 0 rss: 34Mb L: 8/8 MS: 1 PersAutoDict- DE: "wOF2"-
NEW_PC: 0x562f5c22103f in ReadWOFF2Header /home/ub20/FTS/woff/SRC/src/woff2_dec.cc:995:7
#1618 NEW cov: 19 ft: 20 corp: 5/29b lim: 14 exec/s: 0 rss: 34Mb L: 12/12 MS: 3 InsertRepeatedBytes-PersAutoDict-InsertRepeatedBytes- DE: "wOF2"-

2.Options.PrintNewCovFuncs = Flags.print_funcs

功能: 打印新覆盖的函数。

使用方法: 当你想知道每次新发现的函数覆盖时,可以启用此选项。

命令行示例:

./woff2-2016-05-06-fsanitize_fuzzer -print_funcs=1

案例输出:

ub20@ub20:~/FTS/woff$ ./woff2-2016-05-06-fsanitize_fuzzer -print_funcs=1
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2688967800
INFO: Loaded 1 modules (10708 inline 8-bit counters): 10708 [0x55b819abf5c0, 0x55b819ac1f94),
INFO: Loaded 1 PC tables (10708 PCs): 10708 [0x55b819ac1f98,0x55b819aebcd8),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 15 ft: 16 corp: 1/1b exec/s: 0 rss: 32Mb
#10 NEW cov: 16 ft: 17 corp: 2/5b lim: 4 exec/s: 0 rss: 32Mb L: 4/4 MS: 3 CrossOver-InsertByte-CrossOver-
...
#144927 NEW cov: 29 ft: 30 corp: 14/437b lim: 1390 exec/s: 48309 rss: 47Mb L: 119/119 MS: 1 PersAutoDict- DE: "\012\000\000\000\000\000\000\000"-
NEW_FUNC[1/1]: 0x55b8199a0050 in woff2::ReadBase128(woff2::Buffer*, unsigned int*) /home/ub20/FTS/woff/SRC/src/variable_length.cc:94
...

3.Options.PrintCoverage = Flags.print_coverage

功能: 打印覆盖率信息。

使用方法: 启用此选项可以在 fuzzing 过程中定期打印当前的覆盖率统计信息。

命令行示例:

./openssl-1.0.1f-fsanitize_fuzzer -print_coverage=1

案例输出:

UNCOVERED_FUNC: hits: 0 edges: 0/5 Init() /home/ub20/FTS/openssl-1.0.1f/target.cc:9
COVERED_FUNC: hits: 42 edges: 2/5 LLVMFuzzerTestOneInput /home/ub20/FTS/openssl-1.0.1f/target.cc:26
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f/target.cc:27
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f/target.cc:27
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f/target.cc:0

COVERED_FUNC: hits: 42 edges: 19/34 ssleay_rand_add /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:194
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:228
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:228
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:249
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:249
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:260
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:263
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:266
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:294
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:294
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:0
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:306
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:0
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:311
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:321
UNCOVERED_PC: /home/ub20/FTS/openssl-1.0.1f_crash/BUILD/crypto/rand/md_rand.c:322

4.Options.PrintFullCoverage = Flags.print_full_coverage

功能: 打印完整的覆盖率信息。

使用方法: 启用此选项时,程序会在结束时输出完整的覆盖率报告,详细列出所有覆盖到的代码。

命令行示例:

./woff2-2016-05-06-fsanitize_fuzzer -print_full_coverage=1

案例输出:

ub20@ub20:~/FTS/woff$ ./woff2-2016-05-06-fsanitize_fuzzer -print_coverage=1
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3116423339
INFO: Loaded 1 modules (10708 inline 8-bit counters): 10708 [0x5652816785c0, 0x56528167af94),
INFO: Loaded 1 PC tables (10708 PCs): 10708 [0x56528167af98,0x5652816a4cd8),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 15 ft: 16 corp: 1/1b exec/s: 0 rss: 32Mb
#27 NEW cov: 16 ft: 17 corp: 2/5b lim: 4 exec/s: 0 rss: 33Mb L: 4/4 MS: 5 ChangeBit-ChangeBit-ChangeBinInt-CopyPart-CopyPart-
#433 NEW cov: 17 ft: 18 corp: 3/10b lim: 6 exec/s: 0 rss: 33Mb L: 5/5 MS: 1 CMP- DE: "wOF2"-
#636 REDUCE cov: 17 ft: 18 corp: 3/9b lim: 6 exec/s: 0 rss: 33Mb L: 4/4 MS: 3 ShuffleBytes-ChangeBit-EraseBytes-
#884 REDUCE cov: 18 ft: 19 corp: 4/17b lim: 8 exec/s: 0 rss: 34Mb L: 8/8 MS: 3 InsertRepeatedBytes-ChangeByte-PersAutoDict- DE: "wOF2"-
#1635 NEW cov: 19 ft: 20 corp: 5/29b lim: 14 exec/s: 0 rss: 34Mb L: 12/12 MS: 1 CrossOver-
#3505 NEW cov: 20 ft: 21 corp: 6/58b lim: 29 exec/s: 0 rss: 35Mb L: 29/29 MS: 5 PersAutoDict-CrossOver-InsertRepeatedBytes-ChangeByte-ChangeBinInt- DE: "wOF2"-
#4629 NEW cov: 21 ft: 22 corp: 7/87b lim: 38 exec/s: 0 rss: 35Mb L: 29/29 MS: 4 ChangeBit-CopyPart-ShuffleBytes-ChangeBit-
#9279 REDUCE cov: 21 ft: 22 corp: 7/72b lim: 80 exec/s: 0 rss: 35Mb L: 14/29 MS: 5 EraseBytes-EraseBytes-ChangeBit-EraseBytes-ChangeBinInt-
#9535 REDUCE cov: 22 ft: 23 corp: 8/86b lim: 80 exec/s: 0 rss: 35Mb L: 14/29 MS: 1 ChangeByte-
#27928 REDUCE cov: 23 ft: 24 corp: 9/99b lim: 261 exec/s: 0 rss: 37Mb L: 13/29 MS: 3 ChangeBit-EraseBytes-ChangeBinInt-
#31817 NEW cov: 24 ft: 25 corp: 10/120b lim: 293 exec/s: 0 rss: 37Mb L: 21/29 MS: 4 ChangeBit-EraseBytes-ChangeBit-ChangeBinInt-
#40024 REDUCE cov: 24 ft: 25 corp: 10/119b lim: 373 exec/s: 0 rss: 38Mb L: 12/29 MS: 2 EraseBytes-CMP- DE: "\001\000\000\000\000\000\000\014"-
#42588 NEW cov: 25 ft: 26 corp: 11/155b lim: 397 exec/s: 0 rss: 38Mb L: 36/36 MS: 4 CrossOver-CopyPart-InsertByte-ChangeBinInt-
^C==12029== libFuzzer: run interrupted; exiting
COVERAGE:
UNCOVERED_FUNC: hits: 0 edges: 0/19 brotli::ZopfliCreateCommands(unsigned long, unsigned long, unsigned long, std::vector<unsigned int, std::allocator<unsigned int>> const&, brotli::ZopfliNode const*, int*, unsigned long*, brotli::Command*, unsigned long*) /home/ub20/FTS/woff/BROTLI/enc/backward_references.cc:437
UNCOVERED_FUNC: hits: 0 edges: 0/18 brotli::Command::Command(unsigned long, unsigned long, unsigned long, unsigned long) /home/ub20/FTS/woff/BROTLI/enc/././command.h:102
UNCOVERED_FUNC: hits: 0 edges: 0/31 brotli::ZopfliComputeShortestPath(unsigned long, unsigned long, unsigned char const*, unsigned long, unsigned long, int const*, brotli::HashToBinaryTree*, brotli::ZopfliNode*, std::vector<unsigned int, std::allocator<unsigned int>>*) /home/ub20/FTS/woff/BROTLI/enc/backward_references.cc:510
UNCOVERED_FUNC: hits: 0 edges: 0/27 brotli::ZopfliCostModel::SetFromLiteralCosts(unsigned long, unsigned long, unsigned char const*, unsigned long) /home/ub20/FTS/woff/BROTLI/enc/backward_references.cc:77
UNCOVERED_FUNC: hits: 0 edges: 0/44 brotli::HashToBinaryTree::FindAllMatches(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned long, brotli::BackwardMatch*) /home/ub20/FTS/woff/BROTLI/enc/././hash.h:681
...

总结

-print_pcs=1: 适用于监控每次 fuzzing 发现的新代码路径。

-print_funcs=1: 适用于了解每次 fuzzing 发现的新函数覆盖。

-print_coverage=1: 适用于定期检查当前覆盖率的进展情况。

-print_full_coverage=1: 适用于获取 fuzzing 结束后的完整覆盖率报告。
这些选项可以帮助你更好地理解 fuzzing 的进展和覆盖的代码区域。

libFuzzer所有可用的命令行参数:

在libfuzzer中有很多命令并未实现可以自行寻找,这是在vscode匹配命令选项的正则表达式:Options\.\w+\s*=\s*Flags\.\w+;

// 设置详细程度的级别
Options.Verbosity = Flags.verbosity;

// 设置最大输入长度
Options.MaxLen = Flags.max_len;
...
// 是否处理 SIGINT 信号
Options.HandleInt = Flags.handle_int;

// 是否处理 SIGSEGV 信号
Options.HandleSegv = Flags.handle_segv;

// 是否处理 SIGTERM 信号
Options.HandleTerm = Flags.handle_term;

// 是否处理 SIGXFSZ 信号
Options.HandleXfsz = Flags.handle_xfsz;

// 是否处理 SIGUSR1 信号
Options.HandleUsr1 = Flags.handle_usr1;

// 是否处理 SIGUSR2 信号
Options.HandleUsr2 = Flags.handle_usr2;

// 是否处理 Windows 异常
Options.HandleWinExcept = Flags.handle_winexcept;

// 是否启用分叉的种子组
Options.ForkCorpusGroups = Flags.fork_corpus_groups;

为了满足以下二次开发需求:

1.将模糊测试的数据导出并编写接口传递到前端页面。

2.解决 libFuzzer 无法持续性 fuzz 的问题,如遇到 crash 就停止模糊测试。
可以通过以下方式进行源码修改与编译。

1. 模糊测试的覆盖率接口编写

首先,修改libFuzzer/FuzzerLoop.cpp,增加用于导出模糊测试过程中数据的接口。我们可以通过直接修改 libFuzzer 的覆盖率部分,创建接口来收集并输出信息。下面是覆盖率和其他统计信息的部分代码片段:

// 返回总的程序计数器覆盖率(PC Coverage)
size_t GetTotalPCCoverage() const {
return TPC.GetTotalPCCoverage();
}

// 返回发现的特征数量
size_t GetNumFeatures() const {
return Corpus.NumFeatures();
}

// 返回活跃输入的数量
size_t GetNumActiveUnits() const {
return Corpus.NumActiveUnits();
}

// 返回语料库大小(以字节为单位)
size_t GetSizeInBytes() const {
return Corpus.SizeInBytes();
}

// 返回触发重点功能(Focus Function)的输入数量
size_t GetNumInputsThatTouchFocusFunction() const {
return Corpus.NumInputsThatTouchFocusFunction();
}

// 返回每秒执行次数
size_t GetExecPerSec() const {
return execPerSec();
}

// 返回临时最大变异长度
size_t GetTmpMaxMutationLen() const {
return TmpMaxMutationLen;
}

// 返回峰值内存使用量(以MB为单位)
size_t GetPeakRSSMb() const {
return GetPeakRSSMb();
}

// 打印模糊测试的统计信息并导出数据
void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
size_t Features)
{
size_t ExecPerSec = GetExecPerSec();

if (!Options.Verbosity)
return;

Printf("#%zd\t%s", TotalNumberOfRuns, Where);

if (size_t N = GetTotalPCCoverage())
Printf(" cov: %zd", N);

if (size_t N = Features ? Features : GetNumFeatures())
Printf(" ft: %zd", N);

if (!Corpus.empty()) {
Printf(" corp: %zd", GetNumActiveUnits());

if (size_t N = GetSizeInBytes()) {
if (N < (1 << 14))
Printf("/%zdb", N);
else if (N < (1 << 24))
Printf("/%zdKb", N >> 10);
else
Printf("/%zdMb", N >> 20);
}

if (size_t FF = GetNumInputsThatTouchFocusFunction())
Printf(" focus: %zd", FF);
}

if (size_t Lim = GetTmpMaxMutationLen())
Printf(" lim: %zd", Lim);

if (Units)
Printf(" units: %zd", Units);

Printf(" exec/s: %zd", ExecPerSec);
Printf(" rss: %zdMb", GetPeakRSSMb());

// 添加魔改标识
Printf(" [MODIFIED] Custom version of Fuzzer::PrintStats is running!\n");

// 输出结束符
Printf("%s", End);

// 可以在这里添加接口将数据传递到前端
ExportDataToFrontend({
{"TotalNumberOfRuns", TotalNumberOfRuns},
{"PCCoverage", GetTotalPCCoverage()},
{"NumFeatures", GetNumFeatures()},
{"NumActiveUnits", GetNumActiveUnits()},
{"SizeInBytes", GetSizeInBytes()},
{"ExecPerSec", GetExecPerSec()},
{"PeakRSSMb", GetPeakRSSMb()}
});
}

// 示例数据导出函数,可将数据通过接口传递给前端
void ExportDataToFrontend(const std::map<std::string, size_t>& data) {
// 通过网络接口、文件、或者其他方式将数据传递到前端页面
// 这里可以通过 JSON 格式将数据发送到 HTTP 服务器或 WebSocket
}

Fuzzer::PrintStats函数中,我们已经将覆盖率、执行次数、内存使用情况等统计信息打印,并通过ExportDataToFrontend函数导出到外部系统,可以进一步传递到前端页面。

2. 解决 libFuzzer 无法持续性 fuzz 的问题

要实现 libFuzzer 的持久模糊测试,并且避免在发现 crash 后终止,可以通过修改 libFuzzer 源码来调整其行为。libFuzzer 默认行为是当检测到崩溃(如非法内存访问、堆溢出等)时终止模糊测试。为了避免这种情况,目标是允许 fuzzing 继续进行而不退出。

修改思路

1.定位崩溃处理逻辑
libFuzzer 在检测到 crash 后会调用LLVMFuzzerTestOneInput,这段代码可能会引发未处理异常,导致 fuzzing 过程终止。我们可以通过修改 libFuzzer 的 crash 处理逻辑,使其在崩溃时记录问题但继续模糊测试。

2.关键代码修改点
需要查找 libFuzzer 源码中的崩溃处理位置,一般在FuzzerLoop.cppFuzzerDriver.cpp文件中。

3.持久化模糊测试的入口
如果你想让模糊测试保持“持久化”,即反复利用同一测试环境进行测试,可以在FuzzerLoop.cpp中引入一个持久化模式(Persistent Mode)。这种模式会允许测试继续,而不是每次退出。

示例修改步骤

实现持久化模式
FuzzerLoop.cpp中找到模糊测试的主要循环。将其改成持久化循环模式,像这样:

捕获崩溃并继续测试
修改 libFuzzer 中的FuzzerDriver.cpp文件,让崩溃不会终止程序。可以在捕获崩溃的地方加入try-catch或平台相关的异常处理机制,确保在崩溃时记录并恢复。

处理信号(Signal Handling)
在某些情况下,libFuzzer 可能通过信号(如 SIGSEGV, SIGABRT)来处理崩溃。你可以修改信号处理函数,确保信号不会导致进程终止。

具体修改位置:

1.libFuzzer/FuzzerLoop.cpp: 主模糊测试循环部分。

2.libFuzzer/FuzzerDriver.cpp: 驱动整个模糊测试的入口。

3.信号处理部分:如果有需要,检查是否需要在libFuzzer中添加或修改信号处理机制。
通过以上修改,可以避免在检测到崩溃时 libFuzzer 终止程序,并且实现持久模糊测试模式。如果你有特定的需求或问题,还可以进一步定制相关代码。

3. 编译自定义的 libFuzzer

编译脚本文件路径:llvm-project/compiler-rt/lib/fuzzer/build.sh at main · llvm/llvm-project (github.com)

在完成代码修改后,需要重新编译 libFuzzer 生成libFuzzer.a静态库。可以使用如下编译脚本:

#!/bin/sh
LIBFUZZER_SRC_DIR=$(dirname $0)
CXX="${CXX:-clang}"
for f in $LIBFUZZER_SRC_DIR/*.cpp; do
$CXX -g -O2 -fno-omit-frame-pointer -std=c++17 $f -c &
done
wait
rm -f libFuzzer.a
ar r libFuzzer.a Fuzzer*.o
rm -f Fuzzer*.o

将修改后的源码放置到 libFuzzer 源码目录,运行该脚本编译,生成一个libFuzzer.a静态库,用于后续的模糊测试项目链接使用。

自定义的libFuzzer的使用方式:

clang++ -g -O1 fuzz_target.cc libFuzzer.a -o mytarget_fuzzer

这里的libFuzzer.a是自己使用项目提供的build.sh编译出来的版本,还可以添加其他编译选项自行添加!

教程地址:fuzzing/tutorial/libFuzzerTutorial.md 在 master ·谷歌/模糊测试 (github.com)

案例一:长时间无crash的案例

步骤 1:下载测试目标
#使用官方案例进行测试
ub20@ub20:~$git clone https://github.com/google/fuzzer-test-suite.git FTS
ub20@ub20:~$cd FTS; mkdir -p woff; cd woff;
ub20@ub20:~$~/FTS/woff2-2016-05-06/build.sh
步骤 2:创建模糊测试目标

文件位置:FTS/woff2-2016-05-06/target.cc

// Copyright 2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
#include <stddef.h>
#include <stdint.h>

#include "woff2_dec.h"

// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::string buf;
woff2::WOFF2StringOut out(&buf);
out.SetMaxSize(30 * 1024 * 1024);
woff2::ConvertWOFF2ToTTF(data, size, &out);
return 0;
}

步骤 3:编译模糊测试目标
ub20@ub20:~/woff$ ~/Fuzz/FTS/woff2-2016-05-06/build.sh
ub20@ub20:~/woff$ ~/Fuzz/FTS/woff2-2016-05-06/build.sh
正克隆到 'SRC'...
remote: Enumerating objects: 1150, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 1150 (delta 2), reused 20 (delta 0), pack-reused 1126 (from 1)
接收对象中: 100% (1150/1150), 3.48 MiB | 6.03 MiB/s, 完成.
处理 delta 中: 100% (680/680), 完成.
...
#编译成功后
ub20@ub20:~/woff$ ls
backward_references.o compress_fragment_two_pass.o font.o normalize.o table_tags.o woff2_dec.o
bit_reader.o decode.o glyph.o seeds transform.o woff2_enc.o
block_splitter.o dictionary.o histogram.o SRC utf8_util.o woff2_out.o
BROTLI encode.o huffman.o state.o variable_length.o
brotli_bit_stream.o encode_parallel.o literal_cost.o static_dict.o woff2-2016-05-06-fsanitize_fuzzer
compress_fragment.o entropy_encode.o metablock.o streams.o woff2_common.o
步骤 4:运行模糊测试
ub20@ub20:~/woff$ ./woff2-2016-05-06-fsanitize_fuzzer
INFO: Seed: 707405402
INFO: Loaded 1 modules (11231 inline 8-bit counters): 11231 [0x799080, 0x79bc5f),
INFO: Loaded 1 PC tables (11231 PCs): 11231 [0x726be0,0x7529d0),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 15 ft: 16 corp: 1/1b exec/s: 0 rss: 28Mb
#9 NEW cov: 16 ft: 17 corp: 2/5b lim: 4 exec/s: 0 rss: 28Mb L: 4/4 MS: 2 CopyPart-CrossOver-
#3134 NEW cov: 17 ft: 18 corp: 3/10b lim: 33 exec/s: 0 rss: 28Mb L: 5/5 MS: 5 InsertByte-ShuffleBytes-ChangeBinInt-ChangeByte-CMP- DE: "wOF2"-
....

案例二:快速有crash的案例

步骤 1:下载测试目标

漏洞原理:OpenSSL 心脏滴血漏洞(CVE-2014-0160)漏洞讲解(小白可懂,简单详细)-CSDN博客

使用github项目已经准备好的编译脚本:

#下载对应目标漏洞的fuzzer项目
[AFL++ 570d9dc7fa7e] /downloads # git clone https://github.com/google/fuzzer-test-suite.git
Cloning into 'fuzzer-test-suite'...
remote: Enumerating objects: 3521, done.
remote: Counting objects: 100% (26/26), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 3521 (delta 10), reused 19 (delta 8), pack-reused 3495
Receiving objects: 100% (3521/3521), 2.78 MiB | 3.69 MiB/s, done.
Resolving deltas: 100% (2267/2267), done.
步骤 2:创建模糊测试目标

创建一个包含LLVMFuzzerTestOneInput函数的模糊测试目标:

文件所在路径:fuzzer-test-suite/openssl-1.0.1f

// Copyright 2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");

#include <openssl/ssl.h> // OpenSSL 库,用于 SSL/TLS 功能
#include <openssl/err.h> // OpenSSL 错误处理
#include <assert.h> // 断言
#include <stdint.h> // 定义标准整数类型
#include <stddef.h> // 定义标准数据类型

// 初始化 OpenSSL 库并设置 SSL 上下文
SSL_CTX *Init() {
SSL_library_init(); // 初始化 OpenSSL 库
SSL_load_error_strings(); // 加载错误字符串
ERR_load_BIO_strings(); // 加载 BIO 错误字符串
OpenSSL_add_all_algorithms(); // 加载所有加密算法

SSL_CTX *sctx;
// 创建一个新的 SSL_CTX 对象,使用 TLSv1 协议
assert(sctx = SSL_CTX_new(TLSv1_method()));

/* 使用以下命令创建这两个文件:
openssl req -x509 -newkey rsa:512 -keyout server.key \
-out server.pem -days 9999 -nodes -subj /CN=a/
*/

// 加载服务器证书
assert(SSL_CTX_use_certificate_file(sctx, "runtime/server.pem",
SSL_FILETYPE_PEM));
// 加载服务器私钥
assert(SSL_CTX_use_PrivateKey_file(sctx, "runtime/server.key",
SSL_FILETYPE_PEM));

return sctx; // 返回 SSL_CTX 对象
}

// fuzzer 的入口函数
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static SSL_CTX *sctx = Init(); // 初始化 SSL_CTX,仅在第一次调用时执行
SSL *server = SSL_new(sctx); // 创建一个新的 SSL 对象

// BIO(Basic Input/Output)对象用于处理输入和输出操作
// 内存 BIO (Memory BIO):使用内存缓冲区进行读写操作
BIO *sinbio = BIO_new(BIO_s_mem());
BIO *soutbio = BIO_new(BIO_s_mem());

// 将 BIO 对象与 SSL 对象关联,使 SSL 对象可以通过 BIO 进行 I/O 操作
SSL_set_bio(server, sinbio, soutbio);
SSL_set_accept_state(server); // 将 SSL 对象设置为接受状态,准备进行 SSL/TLS 握手

// 将模糊测试输入数据写入 sinbio,以便模拟从客户端接收数据
BIO_write(sinbio, Data, Size);

// 执行 SSL/TLS 握手过程
SSL_do_handshake(server);

// 释放 SSL 对象,清理资源
SSL_free(server);

return 0; // 返回 0 表示成功
}

步骤 3:编译模糊测试目标

在项目根目录中,运行以下命令编译模糊测试目标,详细的编译选项可以查看build.sh :

#对目标项目进行clang插桩
[AFL++ 570d9dc7fa7e] /downloads/fuzzer-test-suite # ./openssl-1.0.1f/build.sh
Cloning into 'SRC'...
remote: Enumerating objects: 480247, done.
步骤 4:运行模糊测试

在项目根目录中,运行以下命令开始模糊测试,成功跑出堆溢出漏洞:

[AFL++ 570d9dc7fa7e] /downloads/fuzzer-test-suite # ./openssl-1.0.1f-fsanitize_fuzzer 
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 528530075
INFO: Loaded 1 modules (35481 inline 8-bit counters): 35481 [0x5da29cfd2410, 0x5da29cfdaea9),
INFO: Loaded 1 PC tables (35481 PCs): 35481 [0x5da29cfdaeb0,0x5da29d065840),
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2 INITED cov: 402 ft: 403 corp: 1/1b exec/s: 0 rss: 41Mb
#3 NEW cov: 402 ft: 404 corp: 2/3b lim: 4 exec/s: 0 rss: 41Mb L: 2/2 MS: 1 CrossOver-
#45 REDUCE cov: 402 ft: 404 corp: 2/2b lim: 4 exec/s: 0 rss: 43Mb L: 1/1 MS: 2 ChangeBinInt-....
suite/BUILD/crypto/rand/rand_lib.c:169
#23239 NEW cov: 532 ft: 775 corp: 35/784b lim: 110 exec/s: 23239 rss: 387Mb L: 11/88 MS: 1 CMP- DE: "\001\000\003R"-
#23380 NEW cov: 535 ft: 780 corp: 36/800b lim: 110 exec/s: 23380 rss: 387Mb L: 16/88 MS: 1 CrossOver-
#23802 REDUCE cov: 535 ft: 780 corp: 36/797b lim: 110 exec/s: 23802 rss: 387Mb L: 28/88 MS: 2 ChangeBinInt-EraseBytes-
=================================================================
==2346==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x629000009748 at pc 0x5da29cb00a7d bp 0x7ffd011caf10 sp 0x7ffd011ca6d8
READ of size 17731 at 0x629000009748 thread T0
#0 0x5da29cb00a7c in __asan_memcpy (/downloads/fuzzer-test-suite/openssl-1.0.1f-fsanitize_fuzzer+0x272a7c) (BuildId: b91eb95b107c49cb91fb52d711a75150508e5122)
#1 0x5da29cb4a42d in tls1_process_heartbeat /downloads/fuzzer-test-suite/BUILD/ssl/t1_lib.c:2586:3
#2 0x5da29cbb35c9 in ssl3_read_bytes /downloads/fuzzer-test-suite/BUILD/ssl/s3_pkt.c:1092:4
#3 0x5da29cbb7990 in ssl3_get_message /downloads/fuzzer-test-suite/BUILD/ssl/s3_both.c:457:7
....fsanitize_fuzzer+0x1c25d3) (BuildId: b91eb95b107c49cb91fb52d711a75150508e5122)
#10 0x5da29ca3e760 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/downloads/fuzzer-test-suite/openssl-1.0.1f-fsanitize_fuzzer+0x1b0760) (BuildId: b91eb95b107c49cb91fb52d711a75150508e5122)
#11 0x5da29ca67aa2 in main (/downloads/fuzzer-test-suite/openssl-1.0.1f-fsanitize_fuzzer+0x1d9aa2) (BuildId: b91eb95b107c49cb91fb52d711a75150508e5122)
#12 0x724301664d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/downloads/fuzzer-test-suite/openssl-1.0.1f-fsanitize_fuzzer+0x272a7c) (BuildId: b91eb95b107c49cb91fb52d711a75150508e5122) in __asan_memcpy
Shadow bytes around the buggy address:
0x629000009480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x629000009500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x629000009580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x629000009600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x629000009680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x629000009700: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa
0x629000009780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x629000009800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x629000009880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x629000009900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x629000009980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==2346==ABORTING
MS: 2 EraseBytes-PersAutoDict- DE: "ECDSA"-; base unit: 1fd5cf2beed57b0a1a2a477ff6e33cbf1a23c38e
0x18,0x3,0x5,0x0,0x5,0x1,0x45,0x43,0x44,0x53,0x41,
\030\003\005\000\005\001ECDSA
artifact_prefix='./'; Test unit written to ./crash-96ba5b3de75e70a2400b07afcf813e645282baa2
Base64: GAMFAAUBRUNEU0E=

看雪ID:Loserme

https://bbs.kanxue.com/user-home-970470.htm

*本文为看雪论坛精华文章,由 Losermea 原创,转载请注明来自看雪社区

# 往期推荐

1、记录一次BlackObfuscator去混淆流程

2、libEnccryptor vm 还原的探索

3、PHP PWN 入门调试

4、记录一次**App H5逆向

5、CAN协议分析

球分享

球点赞

球在看

点击阅读原文查看更多


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458578608&idx=2&sn=9cf61b9bd4ae9e89bf9f99946b0587ce&chksm=b18dde3a86fa572c7de09af99466b25cc4594157463cf67ef7bc3321e8793e370708f01d5af5&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh