本文为看雪论坛优秀文章
看雪论坛作者ID:FSTARK
一
理论篇
第一类是基于生成的Generation Based通过对目标协议或文件格式建模的方法,从零开始产生测试用例,没有先前的状态;
第二类为基于突变的Evolutionary基于一些规则,从已有的数据样本或存在的状态变异而来;
最后一种就是基于进化的Evolutionary包含了上述两种,同时会根据代码覆盖率的回馈进行变异。
搜索空间过于广泛
无法fuzz特定的函数
难以fuzz网络协议
常规fuzz速度太慢
In-process, in-memory
会主动引导fuzz过程
针对函数/协议级别的fuzz非常有效率
1000x的快
编写基于libfuzzer的fuzzer很容易
可以单独跟随一个单元进行检测
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
.......
.......
}
二
实践篇
#!/bin/bash -eux
# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get autoremove -y
sudo apt-get install -y libc6-dev binutils libgcc-5-dev
LLVM_DEP_PACKAGES="build-essential make cmake ninja-build git python2.7"
sudo apt-get install -y $LLVM_DEP_PACKAGES
WORK_DIR=$PWD
mkdir -p $WORK_DIR/src
# Checkout
cd $WORK_DIR/src && git clone --depth 1 http://llvm.org/git/llvm.git
cd $WORK_DIR/src/llvm/tools && git clone --depth 1 http://llvm.org/git/clang.git
cd $WORK_DIR/src/llvm/projects && git clone --depth 1 http://llvm.org/git/compiler-rt.git
cd $WORK_DIR/src/llvm/projects && git clone --depth 1 http://llvm.org/git/libcxx.git
cd $WORK_DIR/src/llvm/projects && git clone --depth 1 http://llvm.org/git/libcxxabi.git
# Uncomment if you want *fresh* libFuzzer from checkouted repository.
#rm -r $WORK_DIR/libFuzzer/Fuzzer
#cp -r $WORK_DIR/src/llvm/projects/compiler-rt/lib/fuzzer/ $WORK_DIR/libFuzzer/Fuzzer
# Build & Install
mkdir -p $WORK_DIR/work/llvm
cd $WORK_DIR/work/llvm
# Consider adding of -DCMAKE_INSTALL_PREFIX=%PATH% flag, if you do not want to
# install fresh llvm binaries into standard system paths.
cmake -G "Ninja" \
-DLIBCXX_ENABLE_SHARED=OFF -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD="X86" \
$WORK_DIR/src/llvm
ninja -j$(nproc)
sudo ninja install
rm -rf $WORK_DIR/work/llvm
// fuzz_target.cc
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoSomethingInterestingWithMyAPI(Data, Size);
return 0; // Non-zero return values are reserved for future use.
}
data 是 libFuzzer 生成的 测试数据, size 是数据的长度
fuzz 引擎会在一个进程中进行多次 fuzz, 所以其效率非常高
要能处理各种各样的输入 (空数据, 大量的 或者 畸形的数据...)
内部不会调用 exit()
如果使用多线程的话,在函数末尾要把 线程 join
clang++ -g -O1 -fsanitize=fuzzer,address -fsanitize-coverage=trace-pc-guard \
fuzz_target.cc ../../libFuzzer/Fuzzer/libFuzzer.a \
-o mytarget_fuzzer
AddressSanitizer: 检测 uaf, 缓冲区溢出,stack-use-after-return, container-overflow等内存访问错误,使用-fsanitize = address。
MemorySanitizer(MSAN): 检测未初始化内存的访问,使用-fsanitize = memory。MSAN不能与其他消毒剂结合使用,应单独使用。
UndefinedBehaviorSanitizer(UBSAN): 检测一些其他的漏洞,整数溢出,类型混淆等,检测到C / C ++的各种功能的使用,这些功能已明确列出来导致未定义的行为。使用-fsanitize = undefined,也可以将ASAN和UBSAN合并到一个版本中。
./your-fuzzer -flag1=val1 -flag2=val2 ... dir1 dir2 ...
选项前导用单横线,即使选项是一个词而非单个字符。
选项必须要提供对应的值,即使只是一个开关选项如-help,必须要写作-help=1,且选项与值中间只能用等号,不能用空格。
./your-fuzzer -flag1=val1 -flag2=val2 ... file1 file2 ...
mkdir MY_CORPUS
./your-fuzzer MY_CORPUS/ seeds/
mkdir corpus1_min
./your-fuzzer -merge=1 corpus1_min corpus1
./your-fuzzer MY_CORPUS/ seeds/ -jobs=8
fuzzer -jobs=8
├─sh -c ./fuzzer >fuzz-0.log 2>&1
│ └─fuzzer
│ └─{fuzzer}
├─sh -c ./fuzzer >fuzz-1.log 2>&1
│ └─fuzzer
│ └─{fuzzer}
├─sh -c ./fuzzer >fuzz-2.log 2>&1
│ └─fuzzer
│ └─{fuzzer}
├─sh -c ./fuzzer >fuzz-3.log 2>&1
│ └─fuzzer
│ └─{fuzzer}
# Lines starting with '#' and empty lines are ignored.
# Adds "blah" (w/o quotes) to the dictionary.
kw1="blah"
# Use \\ for backslash and \" for quotes.
kw2="\"ac\\dc\""
# Use \xAB for hex values
kw3="\xF7\xF8"
# the name of the keyword followed by '=' may be omitted:
"foo\x0Abar"
./your-fuzzer -dict=DICTIONARY_FILE
INFO: Seed: 1608565063
INFO: Loaded 1 modules (37 guards): [0x788ec0, 0x788f54),
INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus
#0 READ units: 1
#1 INITED cov: 3 ft: 3 corp: 1/1b exec/s: 0 rss: 11Mb
#3 NEW cov: 4 ft: 4 corp: 2/4b exec/s: 0 rss: 12Mb L: 3 MS: 2 InsertByte-InsertByte-
#3348 NEW cov: 5 ft: 5 corp: 3/65b exec/s: 0 rss: 12Mb L: 61 MS: 2 ChangeByte-InsertRepeatedBytes-
#468765 NEW cov: 6 ft: 6 corp: 4/78b exec/s: 0 rss: 49Mb L: 13 MS: 4 CrossOver-ChangeBit-EraseBytes-ChangeByte-
#564131 NEW cov: 7 ft: 7 corp: 5/97b exec/s: 0 rss: 56Mb L: 19 MS: 5 InsertRepeatedBytes-InsertByte-ChangeByte-InsertByte-InsertByte-
=================================================================
==32049==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200072bb93 at pc 0x000000528540 bp 0x7ffdb3439100 sp 0x7ffdb34390f8
READ of size 1 at 0x60200072bb93 thread T0
......................................................
......................................................
......................................................
0x60200072bb93 is located 0 bytes to the right of 3-byte region [0x60200072bb90,0x60200072bb93)
allocated by thread T0 here:
......................................................
......................................................
......................................................
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/haclh/vmdk_kernel/libfuzzer-workshop-master/lessons/04/./vulnerable_functions.h:22:14 in VulnerableFunction1(unsigned char const*, unsigned long)
Shadow bytes around the buggy address:
0x0c04800dd720: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa
0x0c04800dd730: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
0x0c04800dd740: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c04800dd750: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
0x0c04800dd760: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
=>0x0c04800dd770: fa fa[03]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800dd780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800dd790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800dd7a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800dd7b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c04800dd7c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
......................................................
......................................................
==32049==ABORTING
MS: 1 CrossOver-; base unit: 38a223b0988bd9576fb17f5947af80b80203f0ef
0x46,0x55,0x5a,
FUZ
artifact_prefix='./'; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60
Base64: RlVa
# 564131 NEW cov: 7 ft: 7 corp: 5/97b exec/s: 0 rss: 56Mb L: 19 MS: 5 InsertRepeatedBytes-InsertByte-ChangeByte-InsertByte-InsertByte-
==32049==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200072bb93 at pc 0x000000528540 bp 0x7ffdb3439100 sp 0x7ffdb34390f8
READ of size 1 at 0x60200072bb93 thread T0
artifact_prefix='./'; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60
ASAN_OPTIONS=symbolize=1 ./first_fuzzer ./crash-0eb8e4ed029b774d80f2b66408203801
# ASAN_OPTIONS=symbolize=1 用于显示栈的符号信息
###### Recommended dictionary. ######
"X\x00\x00\x00\x00\x00\x00\x00" # Uses: 1228
"prin" # Uses: 1353
...........................
...........................
...........................
"U</UTrri\x09</UTD" # Uses: 61
###### End of recommended dictionary. ######
Done 1464491 runs in 301 second(s)
stat::number_of_executed_units: 1464491
stat::average_exec_per_sec: 4865
stat::new_units_added: 1407
stat::slowest_unit_time_sec: 0
stat::peak_rss_mb: 407
三
实例篇
wget https://downloads.sourceforge.net/freeimage/FreeImage3180.zip
unzip FreeImage3180.zip
pushd FreeImage
# b44ExpLogTable.cpp only contains a definition of main().
sed -i 's/Source\/OpenEXR\/IlmImf\/b44ExpLogTable.cpp//' Makefile.srcs
make LIBRARIES=-lc++ -j$(nproc)
popd
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <vector>
#include <FreeImage.h>
namespace {
// Returns true if the format should be attempted to loaded from memory.
bool SafeToLoadFromMemory(FREE_IMAGE_FORMAT fif) {
// For now, just load if it is a BMP. Future heuristics may need to be based
// on the expected size in different formats for memory regions to avoid OOMs.
return fif == FIF_BMP;
}
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static bool initialized = false;
if (!initialized) {
FreeImage_Initialise();
}
if (size > 100 * 1000) {
return 0;
}
std::vector<uint8_t> fuzzer_data_vector(data, data + size);
FIMEMORY* fiMem = FreeImage_OpenMemory(
reinterpret_cast<unsigned char*>(fuzzer_data_vector.data()),
fuzzer_data_vector.size());
FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(fiMem, 0);
if (SafeToLoadFromMemory(fif)) {
FIBITMAP* fiBitmap = FreeImage_LoadFromMemory(fif, fiMem);
FreeImage_Unload(fiBitmap);
}
FreeImage_CloseMemory(fiMem);
return 0;
}
clang++ -g -fsanitize=fuzzer,address \
load_from_memory_fuzzer.cc ./FreeImage/Dist/libfreeimage.a \
-o load_from_memory_fuzzer
clang++ -g -fsanitize=fuzzer,address -I'/home/fstark/FreeImage/Dist' \
load_from_memory_fuzzer.cc ./FreeImage/Dist/libfreeimage.a \
-o load_from_memory_fuzzer
四
附件一
看雪ID:FSTARK
https://bbs.pediy.com/user-home-832012.htm
峰会回顾:https://mp.weixin.qq.com/s/eEbc8k8H9Pc2K0d_AHG3BA
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!