本文由Bruno Oliveira于2024年4月25日发表于IncludeSec的官方网站上。作为IncludeSec的安全研究人员,在他们日常的安全审计和渗透测试工作中,有时需要为客户开发一些模糊测试工具。在安全评估方法中使用模糊测试技术,可以有效地在复杂的现代化软件产品中发现和识别安全漏洞,并为应用程序快速提供高度结构化的输入数据。
当我们的客户要求在手动和传统自动化测试之外进行更全面的工作,以提供额外的分析来发现更复杂的漏洞时,通常会应用此技术。在这篇文章中,我们将跟大家介绍于模糊测试相关的内容,并详细阐述如何通过扩展指令增强基于覆盖引导的模糊测试。
1、选择种子; 2、变异过程需要获取种子作为初始的执行输入; 3、程序执行; 4、触发漏洞,或者...; 5、输入命中了目标程序中的一个新的边,模糊测试工具继续对种子执行变异操作,或者...; 6、输入没有命中新的边,模糊测试工具选择一个新的种子执行变异;
Clang
1、AddressSanitizer (ASAN); 2、UndefinedBehaviorSanitizer (UBSAN); 3、MemorySanitizer (MSAN); 4、ThreadSanitizer (TSAN); 5、LeakSanitizer (LSAN);
$ clang -o targetprogram -g -fsanitize=address -fsanitize-coverage=trace-pc-guard targetprogram.c
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
uint32_t index = *guard;
__shmem->edges[index / 8] |= 1 << (index % 8);
*guard = 0;
}
当找到一个新的边时,__sanitizer_cov_trace_pc_guard()函数会持续执行,因此无需任何条件来处理新的边被发现时要做什么。接下来,函数会将共享位图中的__shmem->edges设置为1,Fuzzilli会在执行后对位图进行分析。
其他工具,比如说LLVM-COV,能够静态地捕获代码覆盖率信息,在执行之后提供人类可读的文档。但是,需要高效读取磁盘中文档的模糊测试工具,可能会影响性能。
获取更多的信息
我们可以修改Fuzzilli的指令,并观察__sanitizer_cov_trace_pc_guard()能够给代码覆盖率带来什么其他的东西。下列代码段演示了我们对Fuzzilli指令的部分修改:
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
uint32_t index = *guard;
void *PC = __builtin_return_address(0);
char PcDescr[1024];
__sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
printf("guard: %p %x PC %sn", guard, *guard, PcDescr);
__shmem->edges[index / 8] |= 1 << (index % 8);
*guard = 0;
}
我们已经知道的是,__sanitizer_cov_trace_pc_guard()函数在每次程序命中新的边时便会执行。此时,我们可以利用__builtin_return_address()函数来收集每一个命中的新的边所返回的地址。现在,PC指针已经获取到了返回的地址信息。我们可以利用__sanitizer_symbolize_pc()函数来将地址与符号相关联,从而提供有关执行过程中所使用的源代码文件的更多信息。
大多数模糊测试工具只会使用边的信息来引导模糊测试。然而,正如我们接下来会给大家演示的那样,我们可以使用Sanitizer接口来为安全评估提供更多有价值的信息。
动手实操 在我们的演示过程中,我们将利用一个旧版本的JerryScript JavaScript引擎来创建一个环境,环境信息如下:
1、操作系统(OS):Ubuntu 22.04; 2、目标程序:JerryScript; 3、漏洞:CVE-2023-36109; 环境搭建
我们可以使用下列命令构建JerryScript,首先克隆项目代码库:
$ git clone https://github.com/jerryscript-project/jerryscript.git
切换到JerryScript目录,并校验8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc commit:
$ git checkout 8ba0d1b6ee5a065a42f3b306771ad8e3c0d819bc
然后应用Fuzziilli库提供的修补程序:
$ cd jerry-main
$ wget https://github.com/googleprojectzero/fuzzilli/raw/main/Targets/Jerryscript/Patches/jerryscript.patch
$ patch < jerryscript.patch
patching file CMakeLists.txt
patching file main-fuzzilli.c
patching file main-fuzzilli.h
patching file main-options.c
patching file main-options.h
patching file main-unix.c
Fuzziilli修补程序提供的指令文件为jerry-main/main-fuzzilli.c,其中也包含了简单的代码覆盖功能,但这还远远不够。因此 ,我们还需要像之前一样在编译代码之前更新__sanitizer_cov_trace_pc_guard()函数。除此之外,还需要将下列Header添加到jerry-main/main-fuzzilli.c文件中:
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
uint32_t index = *guard;
if(!index) return;
index--;
void *PC = __builtin_return_address(0);
char PcDescr[1024];
__sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
printf("guard: %p %x PC %sn", (void *)guard, *guard, PcDescr);
__shmem->edges[index / 8] |= 1 << (index % 8);
*guard = 0;
}
我们现在更改编译配置并禁用strip,这些符号仅用于识别我们演示中可能存在的易受攻击功能。修改根目录中的CMakeLists.txt文件:
# Strip binary
if(ENABLE_STRIP AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
jerry_add_link_flags(-g)
endif()
确保jerry-main/CMakeLists.txt包含了main-fuzzilli.c文件之后,我们就可以准备编译代码并使用Fuzzilli指令完成构建了:
python jerryscript/tools/build.py --compile-flag=-fsanitize-coverage=trace-pc-guard --profile=es2015-subset --lto=off --compile-flag=-D_POSIX_C_SOURCE=200809 --compile-flag=-Wno-strict-prototypes --stack-limit=15
如果你安装了Clang,但CMAKE_C_COMPILER_ID却显示 GNU或其他内容的话,你可能构建过程出错了:
$ python tools/build.py --compile-flag=-fsanitize-coverage=trace-pc-guard --profile=es2015-subset --lto=off --compile-flag=-D_POSIX_C_SOURCE=200809 --compile-flag=-Wno-strict-prototypes --stack-limit=15
-- CMAKE_BUILD_TYPE MinSizeRel
-- CMAKE_C_COMPILER_ID GNU
-- CMAKE_SYSTEM_NAME Linux
-- CMAKE_SYSTEM_PROCESSOR x86_64
你可以直接修改CMakeLists.txt文件中的28-42行,通过将USING_GCC 1修改为USING_CLANG 1来强制使用Clang:
# Determining compiler
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
set(USING_CLANG 1)
endif()
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(USING_CLANG 1)
endif()
构建出的代码路径为「build/bin/jerry」。 测试执行
首先,我们先禁用掉ASLR:
$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
测试完成后,我们可以通过将值设置为2来重新启用ASLR:
$ echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
现在,我们可以先尝试跟踪源码文件的地址,禁用ASLR将有助于我们在分析过程中不受干扰,且不会影响我们的结果。
现在,我们使用针对CVE-2023-36109的PoC文件来执行JerryScript,并尝试触发漏洞。根据漏洞描述,该漏洞位于jerry-core/ecma/base/ecma-helpers-string.c文件的ecma_stringbuilder_append_raw函数中,具体如下所示:
$ ./build/bin/jerry ./poc.js
[...]
guard: 0x55e17d12ac88 7bb PC 0x55e17d07ac6b in ecma_string_get_ascii_size ecma-helpers-string.c
guard: 0x55e17d12ac84 7ba PC 0x55e17d07acfe in ecma_string_get_ascii_size ecma-helpers-string.c
guard: 0x55e17d12ac94 7be PC 0x55e17d07ad46 in ecma_string_get_size (/jerryscript/build/bin/jerry+0x44d46) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e87c 16b8 PC 0x55e17d09dfe1 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x67fe1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12ae04 81a PC 0x55e17d07bb64 in ecma_stringbuilder_append_raw (/jerryscript/build/bin/jerry+0x45b64) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e890 16bd PC 0x55e17d09e053 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x68053) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12e8b8 16c7 PC 0x55e17d09e0f1 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x680f1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d133508 29db PC 0x55e17d0cc292 in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x96292) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d133528 29e3 PC 0x55e17d0cc5bd in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x965bd) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f078 18b7 PC 0x55e17d040a78 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaa78) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f088 18bb PC 0x55e17d040ab4 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaab4) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f08c 18bc PC 0x55e17d040c26 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xac26) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
guard: 0x55e17d12f094 18be PC 0x55e17d040ca3 in jmem_heap_realloc_block (/jerryscript/build/bin/jerry+0xaca3) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==27636==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x55e27da7950c (pc 0x7fe341fa092b bp 0x000000000000 sp 0x7ffc77634f18 T27636)
==27636==The signal is caused by a READ memory access.
#0 0x7fe341fa092b string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
#1 0x55e17d0cc3bb in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x963bb) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#2 0x55e17d09e103 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x68103) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#3 0x55e17d084a23 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4ea23) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#4 0x55e17d090ddc in ecma_op_function_call_native ecma-function-object.c
#5 0x55e17d0909c1 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a9c1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#6 0x55e17d0d4743 in ecma_builtin_string_prototype_object_replace_helper ecma-builtin-string-prototype.c
#7 0x55e17d084a23 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4ea23) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#8 0x55e17d090ddc in ecma_op_function_call_native ecma-function-object.c
#9 0x55e17d0909c1 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a9c1) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#10 0x55e17d0b929f in vm_execute (/jerryscript/build/bin/jerry+0x8329f) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#11 0x55e17d0b8d4a in vm_run (/jerryscript/build/bin/jerry+0x82d4a) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#12 0x55e17d0b8dd0 in vm_run_global (/jerryscript/build/bin/jerry+0x82dd0) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#13 0x55e17d06d4a5 in jerry_run (/jerryscript/build/bin/jerry+0x374a5) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#14 0x55e17d069e32 in main (/jerryscript/build/bin/jerry+0x33e32) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
#15 0x7fe341e29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#16 0x7fe341e29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#17 0x55e17d0412d4 in _start (/jerryscript/build/bin/jerry+0xb2d4) (BuildId: 9588e1efabff4190fd492d05d3710c7810323407)
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
==27636==ABORTING
通过使用这种技术,我们可以识别出ecma_stringbuilder_append_raw()中漏洞存在根本原因的栈地址。
如果我们仅仅依赖于Sanitizer来检测堆栈记录的话,我们将无法在输出中看到存在漏洞的函数名称:
$ ./build/bin/jerry ./poc.js
[COV] no shared memory bitmap available, skipping
[COV] edge counters initialized. Shared memory: (null) with 14587 edges
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==54331==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x5622ae01350c (pc 0x7fc1925a092b bp 0x000000000000 sp 0x7ffed516b838 T54331)
==54331==The signal is caused by a READ memory access.
#0 0x7fc1925a092b string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
#1 0x5621ad66636b in ecma_builtin_replace_substitute (/jerryscript/build/bin/jerry+0x9636b) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#2 0x5621ad6380b3 in ecma_regexp_replace_helper (/jerryscript/build/bin/jerry+0x680b3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#3 0x5621ad61e9d3 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4e9d3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#4 0x5621ad62ad8c in ecma_op_function_call_native ecma-function-object.c
#5 0x5621ad62a971 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a971) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#6 0x5621ad66e6f3 in ecma_builtin_string_prototype_object_replace_helper ecma-builtin-string-prototype.c
#7 0x5621ad61e9d3 in ecma_builtin_dispatch_call (/jerryscript/build/bin/jerry+0x4e9d3) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#8 0x5621ad62ad8c in ecma_op_function_call_native ecma-function-object.c
#9 0x5621ad62a971 in ecma_op_function_call (/jerryscript/build/bin/jerry+0x5a971) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#10 0x5621ad65324f in vm_execute (/jerryscript/build/bin/jerry+0x8324f) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#11 0x5621ad652cfa in vm_run (/jerryscript/build/bin/jerry+0x82cfa) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#12 0x5621ad652d80 in vm_run_global (/jerryscript/build/bin/jerry+0x82d80) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#13 0x5621ad607455 in jerry_run (/jerryscript/build/bin/jerry+0x37455) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#14 0x5621ad603e32 in main (/jerryscript/build/bin/jerry+0x33e32) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
#15 0x7fc192429d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#16 0x7fc192429e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#17 0x5621ad5db2d4 in _start (/jerryscript/build/bin/jerry+0xb2d4) (BuildId: 15a3c1cd9721e9f1b4e15fade2028ddca6dc542a)
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV string/../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:513
==54331==ABORTING
总结 在这篇文章中,我们演示了如何通过扩展Fuzzilli的指令来对目标应用程序的栈进行实施跟踪,以更好地了解返回地址信息以及相关的源代码文件信息,从而给模糊测试工具提供更多的路径,最终产生更多有价值的测试结果。
https://www.ndss-symposium.org/ndss-paper/not-all-coverage-measurements-are-equal-fuzzing-by-coverage-accounting-for-input-prioritization/ https://clang.llvm.org/ https://clang.llvm.org/docs/SanitizerCoverage.html https://github.com/googleprojectzero/fuzzilli https://github.com/googleprojectzero/fuzzilli/blob/main/Targets/Jerryscript/Patches/jerryscript.patch https://github.com/Limesss/CVE-2023-36109 https://blog.includesecurity.com/2024/04/coverage-guided-fuzzing-extending-instrumentation/ 原文始发于微信公众号(FreeBuf):通过扩展指令增强基于覆盖引导的模糊测试
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论