安全矩阵

 找回密码
 立即注册
搜索
查看: 5263|回复: 0

【表哥有话说 第72期】honggfuzz 学习笔记

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-10-6 19:17:02 | 显示全部楼层 |阅读模式
原文链接:【表哥有话说 第72期】honggfuzz 学习笔记

相关概念

Feedback-driven fuzzing
中文直译就是反馈驱动型模糊测试。通过提高 Code coverage (代码覆盖率),来进行变异样本,增加发现漏洞的概率。
Persistent fuzzing
中文直译就是持续型模糊测试。之前的 Fuzzer 都是不断 fork() 出新进程,然后再将变异生成的样本放入程序中,最后查看结果,这样会消耗一定的系统资源。所以 honggfuzz 就实现了这个模式,只要在一个循环中不断的将变异样本输入到下面这个函数中,然后看函数执行的结果,就可以减少 fork() 的使用了。
  1. int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
  2. TestAPI(buf, len);
  3. return 0;
  4. }
复制代码

编译也很简单,使用 honggfuzz 封装好的 clang 就可以生成可以运行的程序了。
  1. # honggfuzz 根目录下
  2. hfuzz_cc/hfuzz-clang test.c -o test # 编译
  3. honggfuzz -P -- ./test # 进行模糊测试
复制代码

Sanitizer
直译就是消毒剂,在 Fuzz 时候可以使用 Address Sanitizer 辅助排查内存使用的问题。例如 use-after-free,heap overflow。当然还有其他的消毒剂可以配合使用。
Dict 和 Corpus
中文直译就是字典和资料,这些可以辅助样本的生成。
环境搭建
这次使用实机上的 Debian Testing 作为开发环境。首先用 tmpfs 建立 ramdisk,因为 Fuzz 中内存读写非常大。
  1. mkdir /mnt/ramdisk
  2. mount -t tmpfs -o size=2048M tmpfs /mnt/ramdisk
复制代码
然后按照 Usage 安装 binutilslibunwind-dev,编译 honggfuzz。
  1. apt install binutils binutils-dev libunwind-dev
  2. git clone https://github.com/google/honggfuzz --depth=1
  3. cd honggfuzz
  4. make -j$(nproc)
复制代码

实战:OpenSSL HeartBleed
首先编译一份有漏洞的 OpenSSL 库,主要是启用了消毒剂-fsanitize,代码覆盖率检测-fsanitize-coverage,还有调试信息-g。
  1. tar xzf openssl1.0.1f.tgz
  2. cd openssl1.0.1f/

  3. ./config
  4. make clean
  5. make CC="clang -O2 -fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div" -j$(nproc)
复制代码
接下来实现 Fuzzer 的框架。从 libfuzzer-workshop 复制来了相应的文件,可以看到代码主要是实现了 SSL 服务端。注意代码中使用了私钥文件得自己生成。
  1. / Copyright 2016 Google Inc. All Rights Reserved.
  2. // Licensed under the Apache License, Version 2.0 (the "License");
  3. #include <openssl/ssl.h>
  4. #include <openssl/err.h>
  5. #include <assert.h>
  6. #include <stdint.h>
  7. #include <stddef.h>

  8. #ifndef CERT_PATH
  9. # define CERT_PATH
  10. #endif

  11. SSL_CTX *Init() {
  12. SSL_library_init();
  13. SSL_load_error_strings();
  14. ERR_load_BIO_strings();
  15. OpenSSL_add_all_algorithms();
  16. SSL_CTX *sctx;
  17. assert (sctx = SSL_CTX_new(TLSv1_method()));
  18. /* These two file were created with this command:
  19.      openssl req -x509 -newkey rsa:512 -keyout server.key \
  20.     -out server.pem -days 9999 -nodes -subj /CN=a/

  21. assert(SSL_CTX_use_certificate_file(sctx, CERT_PATH "server.pem",
  22.                                      SSL_FILETYPE_PEM));
  23. */
  24. assert(SSL_CTX_use_PrivateKey_file(sctx, CERT_PATH "server.key",
  25.                                     SSL_FILETYPE_PEM));
  26. return sctx;
  27. }

  28. extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  29. static SSL_CTX *sctx = Init();
  30. SSL *server = SSL_new(sctx);
  31. BIO *sinbio = BIO_new(BIO_s_mem());
  32. BIO *soutbio = BIO_new(BIO_s_mem());
  33. SSL_set_bio(server, sinbio, soutbio);
  34. SSL_set_accept_state(server);
  35. BIO_write(sinbio, Data, Size);
  36. SSL_do_handshake(server);
  37. SSL_free(server);
  38. return 0;
  39. }
复制代码
然后写个编译脚本辅助编译,主要操作就是将 OpenSSL,libstdc++,pthread 和我们写的 Fuzzer 使用 hfuzz_cc/hfuzz-clang 进行链接。当然还启用了消毒剂 -fsanitize,代码覆盖率检测 -fsanitize-coverage,还有调试信息 -g。
  1. set -x
  2. FUZZER_SRC="openssl_fuzzer.cc"
  3. HFUZZ_SRC="/data/remote/honggfuzz"
  4. OPENSSL_SRC="openssl1.0.1f"
  5. CC="$HFUZZ_SRC/hfuzz_cc/hfuzz-clang"
  6. COMMON_FLAGS="-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE \
  7.   -DBORINGSSL_UNSAFE_FUZZER_MODE \
  8.   -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION \
  9.   -DBN_DEBUG \
  10.   -DLIBRESSL_HAS_TLS1_3 \
  11.   -O3 \
  12.   -g \
  13.   -DFuzzerInitialize=LLVMFuzzerInitialize \
  14.   -DFuzzerTestOneInput=LLVMFuzzerTestOneInput \
  15.   -I./$OPENSSL_SRC/include -I$HFUZZ_SRC"
  16. COMMON_LDFLAGS="-lpthread -lz"
  17. SAN_COMPILE="-fsanitize=address"
  18. SAN_COV="-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div"
  19. $CC $FUZZER_SRC $COMMON_FLAGS $COMMON_LDFLAGS $SAN_COMPILE $SAN_COV \
  20.    -I$OPENSSL_SRC/include $OPENSSL_SRC/libssl.a $OPENSSL_SRC/libcrypto.a \
  21.    -lstdc++ \
  22.    -o openssl_fuzzer
复制代码
接下来就是跑 Fuzzer 了。
  1. $ $HONGGFUZZ_SRC/honggfuzz --input corpus_server --persistent --workspace out -- ./openssl_fuzzer
  2. ------------------------[  0 days 00 hrs 00 mins 04 secs ]----------------------
  3. Iterations : 78093 [78.09k]
  4. Mode [3/3] : Feedback Driven Mode
  5.     Target : ./openssl_fuzzer
  6.     Threads : 4, CPUs: 8, CPU%: 436% [54%/CPU]
  7.       Speed : 19169/sec [avg: 19523]
  8.     Crashes : 18 [unique: 1, blacklist: 0, verified: 0]
  9.   Timeouts : 0 [1 sec]
  10. Corpus Size : 165, max: 131072 bytes, init: 1944 files
  11. Cov Update : 0 days 00 hrs 00 mins 01 secs ago
  12.   Coverage : edge: 1361/44726 [3%] pc: 86 cmp: 34115
  13. ---------------------------------- [ LOGS ] ------------------/ honggfuzz 2.3 /-
  14. Crash (dup): 'out/SIGABRT.PC.436767.STACK.18647aae6e.CODE.-6.ADDR.0.INSTR.lea____-0x840(%rbp),%rdx.f
  15. uzz' already exists, skipping
  16. [2020-08-13T19:30:44+0800][W][55426] arch_checkWait():232 Persistent mode: pid=55456 exited with sta
  17. tus: SIGNALED, signal: 6 (Aborted)
  18. Persistent mode: Launched new persistent pid=55466
  19. Crash (dup): 'out/SIGABRT.PC.436767.STACK.18647aae6e.CODE.-6.ADDR.0.INSTR.lea____-0x840(%rbp),%rdx.f
  20. uzz' already exists, skipping
  21. [2020-08-13T19:30:44+0800][W][55425] arch_checkWait():232 Persistent mode: pid=55464 exited with sta
  22. tus: SIGNALED, signal: 6 (Aborted)
  23. Persistent mode: Launched new persistent pid=55468
  24. Signal 2 (Interrupt) received, terminating
  25. Terminating thread no. #2, left: 3
  26. Terminating thread no. #1, left: 2
  27. Terminating thread no. #3, left: 1
  28. Terminating thread no. #0, left: 0
  29. Summary iterations:78101 time:4 speed:19525 crashes_count:18 timeout_count:0 new_units_added:4 slowe
  30. st_unit_ms:269 guard_nb:44726 branch_coverage_percent:3 peak_rss_mb:370
复制代码

然后查看生成的样本,我们设置工作目录为 out,可以在这个文件夹下发现 .log 结尾的文件,记录消毒剂的运行情况,还有 .fuzz 结尾的文件存放着输入样例,还有 HONGGFUZZ.REPORT.TXT 存放着所有的崩溃情况。
将样本输入到程序中,可以发现 tls1_process_heartbeat() 这个函数出现了使用 memcpy() 造成的崩溃,即发现了漏洞。
  1. $ ./openssl_fuzzer < /mnt/ramdisk/out/SIGABRT.PC.436767.STACK.18647aae6e.CODE.-6.ADDR.0.INSTR.lea____-0x840\(%rbp\),%rdx.fuzz
  2. Accepting input from '[STDIN]'
  3. Usage for fuzzing: honggfuzz -P [flags] -- ./openssl_fuzzer
  4. =================================================================
  5. ==55483==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x629000009748 at pc 0x000000436767 bp 0x7fff50095080 sp 0x7fff50094840
  6. READ of size 61684 at 0x629000009748 thread T0
  7.    #0 0x436766 in memcpy (/data/remote/openssl_fuzz/openssl_fuzzer+0x436766)
  8.    #1 0x4ccc30 in tls1_process_heartbeat /data/remote/openssl1.0.1f/ssl/t1_lib.c:2586:3
  9.    #2 0x5176c8 in ssl3_read_bytes /data/remote/openssl1.0.1f/ssl/s3_pkt.c:1092:4
  10.    #3 0x519314 in ssl3_get_message /data/remote/openssl1.0.1f/ssl/s3_both.c:457:7
  11.    #4 0x4fb244 in ssl3_get_client_hello /data/remote/openssl1.0.1f/ssl/s3_srvr.c:941:4
  12.    #5 0x4f7d05 in ssl3_accept /data/remote/openssl1.0.1f/ssl/s3_srvr.c:357:9
  13.    #6 0x4c6f42 in LLVMFuzzerTestOneInput /data/remote/openssl_fuzz/openssl_fuzzer.cc:40:3
  14.    #7 0x7007b1 in HonggfuzzMain (/data/remote/openssl_fuzz/openssl_fuzzer+0x7007b1)
  15.    #8 0x7fa9723f6cc9 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26cc9)
  16.    #9 0x41f7e9 in _start (/data/remote/openssl_fuzz/openssl_fuzzer+0x41f7e9)

  17. 0x629000009748 is located 0 bytes to the right of 17736-byte region [0x629000005200,0x629000009748)
  18. allocated by thread T0 here:
  19.    #0 0x4976ed in malloc (/data/remote/openssl_fuzz/openssl_fuzzer+0x4976ed)
  20.    #1 0x534676 in CRYPTO_malloc /data/remote/openssl1.0.1f/crypto/mem.c:308:8
  21.    #2 0x51a217 in freelist_extract /data/remote/openssl1.0.1f/ssl/s3_both.c:708:12
  22.    #3 0x51a217 in ssl3_setup_read_buffer /data/remote/openssl1.0.1f/ssl/s3_both.c:770:10
  23.    #4 0x51a217 in ssl3_setup_buffers /data/remote/openssl1.0.1f/ssl/s3_both.c:827:7
  24.    #5 0x4f8aac in ssl3_accept /data/remote/openssl1.0.1f/ssl/s3_srvr.c:292:9
  25.    #6 0x4c6f42 in LLVMFuzzerTestOneInput /data/remote/openssl_fuzz/openssl_fuzzer.cc:40:3
  26.    #7 0x7007b1 in HonggfuzzMain (/data/remote/openssl_fuzz/openssl_fuzzer+0x7007b1)

  27. SUMMARY: AddressSanitizer: heap-buffer-overflow (/data/remote/openssl_fuzz/openssl_fuzzer+0x436766) in memcpy
  28. Shadow bytes around the buggy address:
  29. 0x0c527fff9290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  30. 0x0c527fff92a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  31. 0x0c527fff92b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  32. 0x0c527fff92c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  33. 0x0c527fff92d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  34. =>0x0c527fff92e0: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa
  35. 0x0c527fff92f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  36. 0x0c527fff9300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  37. 0x0c527fff9310: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  38. 0x0c527fff9320: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  39. 0x0c527fff9330: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  40. Shadow byte legend (one shadow byte represents 8 application bytes):
  41. Addressable:           00
  42. Partially addressable: 01 02 03 04 05 06 07
  43. Heap left redzone:       fa
  44. Freed heap region:       fd
  45. Stack left redzone:     f1
  46. Stack mid redzone:       f2
  47. Stack right redzone:     f3
  48. Stack after return:     f5
  49. Stack use after scope:   f8
  50. Global redzone:         f9
  51. Global init order:       f6
  52. Poisoned by user:       f7
  53. Container overflow:     fc
  54. Array cookie:           ac
  55. Intra object redzone:   bb
  56. ASan internal:           fe
  57. Left alloca redzone:     ca
  58. Right alloca redzone:   cb
  59. Shadow gap:              cc
  60. ==55483==ABORTING
复制代码

实战:PCRE2
和 OpenSSL 的 Fuzz 类似,先实现测试框架。
  1. // Copyright 2016 Google Inc. All Rights Reserved.
  2. // Licensed under the Apache License, Version 2.0 (the "License");

  3. #include <stdint.h>
  4. #include <stddef.h>

  5. #include <string>

  6. #include "pcre2posix.h"

  7. using std::string;

  8. extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
  9. if (size < 1) return 0;
  10. regex_t preg;
  11. string str(reinterpret_cast<const char*>(data), size);
  12. string pat(str);
  13. int flags = data[size/2] - 'a';  // Make it 0 when the byte is 'a'.
  14. if (0 == regcomp(&preg, pat.c_str(), flags)) {
  15.    regmatch_t pmatch[5];
  16.    regexec(&preg, str.c_str(), 5, pmatch, 0);
  17.    regfree(&preg);
  18. }
  19. return 0;
  20. }
复制代码
编译 PCRE2 和 Fuzzer,然后链接起来。
  1. set -x
  2. FUZZER_SRC="pcre2_fuzzer.cc"
  3. HFUZZ_SRC="/data/remote/honggfuzz"
  4. PCRE2_SRC="pcre2-10.00"
  5. CC="$HFUZZ_SRC/hfuzz_cc/hfuzz-clang"
  6. COMMON_FLAGS="-O3 \
  7.   -g \
  8.   -DFuzzerInitialize=LLVMFuzzerInitialize \
  9.   -DFuzzerTestOneInput=LLVMFuzzerTestOneInput \
  10.   -I./$PCRE2_SRC/include -I$HFUZZ_SRC"
  11. COMMON_LDFLAGS="-lpthread -lz"
  12. SAN_COMPILE="-fsanitize=address"
  13. SAN_COV="-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-gep,trace-div"
  14. $CC $FUZZER_SRC $COMMON_FLAGS $COMMON_LDFLAGS $SAN_COMPILE $SAN_COV \
  15.    -I$PCRE2_SRC/src \
  16.    -Wl,--whole-archive $PCRE2_SRC/.libs/*.a -Wl,-no-whole-archive \
  17.    -lstdc++ \
  18.    -o pcre2_fuzzer
复制代码
在 Fuzz 时可以准备字典和资料进行辅助。
  1. "?"
  2. "abc"
  3. "()"
  4. "[]"
  5. "abc|def"
  6. "abc|def|ghi"
  7. "^xxx[        DISCUZ_CODE_11        ]quot;
  8. "ab\\b\\d\\bcd"
  9. "\\w|\\d"
  10. "a*?"
  11. "abc+"
  12. "abc+?"
  13. #...
复制代码
跑了应该有 30 分钟吧,生成了差不多 60 个崩溃事例,例如下面两句错误的正则都会导致程序崩溃。
  1. (?(?=a){0,10}a)
  2. (|)(?(?!a)?aa)\d*
复制代码

拓展阅读

Double-Free RCE in VLC. A honggfuzz how-to(https://www.pentestpartners.com/ ... a-honggfuzz-how-to/)

fuzzing-openssh-daemon-using-afl(http://www.vegardno.net/2017/03/ ... emon-using-afl.html)

peruvian-were-rabbit(https://countuponsecurity.com/tag/peruvian-were-rabbit/)

Dor1s/libfuzzer-workshop(https://github.com/Dor1s/libfuzzer-workshop)

google/fuzzing(https://github.com/google/fuzzing)

refs

honggfuzz(https://github.com/google/honggfuzz)

honggfuzz漏洞挖掘技术深究系列(https://bbs.pediy.com/thread-247954.htm)

AFL(American Fuzzy Lop)实现细节与文件变异(https://paper.seebug.org/496/)









回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-20 10:32 , Processed in 0.015297 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表