
CVE-2022-44318에 대한 개념 증명
PicoC 버전 3.2.2는 ExpressionParseFunctionCall에서 호출할 때 cstdlib/string.c의 StringStrcat 함수에 힙 버퍼 오버플로우가 포함된 것으로 발견되었습니다. Picoc를 사용하는 모든 프로젝트나 라이브러리도 이 문제의 영향을 받습니다. 예를 들어 picoc-js가 있습니다.
PicoC에서 힙 오버플로우 취약점을 재현하려면 먼저 취약한 버전(v3.2.2)의 PicoC 라이브러리와 인터프리터를 다운로드하여 컴파일해야 합니다:
git clone https://github.com/jpoirier/picoc.git
cd picoc
git checkout a97d94fa3d4d35c6b78b7de69faac7643e34de22
make
이 저장소에 포함된 StringStrcat_heap_overflow.c 파일에 대해 스크립트 모드로 인터프리터를 실행하세요:
$ ./picoc -s StringStrcat_heap_overflow.c
세그멘테이션 오류가 발생하여 프로그램이 충돌합니다. 이는 라이브러리나 인터프리터가 포착하거나 처리하지 못하는 힙 오버플로우의 결과입니다. 주소 살균기(ASAN)로 프로젝트를 다시 컴파일하여 문제가 발생하는 위치를 더 잘 파악할 수 있습니다. Makefile의 CFLAGS 변수에 -fsanitize=address를 추가하고 라이브러리를 다시 컴파일해 보겠습니다:
CFLAGS=-Wall -g -std=gnu11 -pedantic -DUNIX_HOST -DVER=\"`git show-ref --abbrev=8 --head --hash head`\" -DTAG=\"`git describe --abbrev=0 --tags`\" -fsanitize=address
라이브러리와 인터프리터를 다시 컴파일하세요 (picoc 루트 디렉토리에서):
make clean
make
프로그램을 실행하면 ASAN에서 다음과 같은 출력을 얻을 수 있으며, 힙 버퍼 오버플로우가 StringStrcat cstdlib/string.c, line 40에서 발생함을 보여줍니다:
==308939==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x606000000892 at pc 0x7f489c03a590 bp 0x7ffc052778f0 sp 0x7ffc052770a0
WRITE of size 26 at 0x606000000892 thread T0
#0 0x7f489c03a58f in __interceptor_strcat ../../../../src/libsanitizer/asan/asan_interceptors.cpp:392
#1 0x55facf0eb418 in StringStrcat cstdlib/string.c:40
#2 0x55facf0d4edd in ExpressionParseFunctionCall /dev/shm/picoc/expression.c:1909
#3 0x55facf0d237c in ExpressionParse /dev/shm/picoc/expression.c:1607
#4 0x55facf0c66a0 in ParseStatement /dev/shm/picoc/parse.c:646
#5 0x55facf0c8380 in PicocParse /dev/shm/picoc/parse.c:897
#6 0x55facf0e0d0e in PicocPlatformScanFile platform/platform_unix.c:129
#7 0x55facf0b7213 in main /dev/shm/picoc/picoc.c:62
#8 0x7f489be46189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#9 0x7f489be46244 in __libc_start_main_impl ../csu/libc-start.c:381
#10 0x55facf0b6d40 in _start (/dev/shm/picoc/picoc+0x16d40)
0x606000000892 is located 0 bytes to the right of 50-byte region [0x606000000860,0x606000000892)
allocated by thread T0 here:
#0 0x7f489c0ae987 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
#1 0x55facf0d5b80 in HeapAllocMem /dev/shm/picoc/heap.c:127
#2 0x55facf0da3a9 in VariableAlloc /dev/shm/picoc/variable.c:77
#3 0x55facf0da429 in VariableAllocValueAndData /dev/shm/picoc/variable.c:97
#4 0x55facf0da701 in VariableAllocValueFromType /dev/shm/picoc/variable.c:119
#5 0x55facf0dbaa7 in VariableDefine /dev/shm/picoc/variable.c:303
#6 0x55facf0dc6aa in VariableDefineButIgnoreIdentical /dev/shm/picoc/variable.c:383
#7 0x55facf0c4540 in ParseDeclaration /dev/shm/picoc/parse.c:366
#8 0x55facf0c6f6e in ParseStatement /dev/shm/picoc/parse.c:738
#9 0x55facf0c8380 in PicocParse /dev/shm/picoc/parse.c:897
#10 0x55facf0e0d0e in PicocPlatformScanFile platform/platform_unix.c:129
#11 0x55facf0b7213 in main /dev/shm/picoc/picoc.c:62
#12 0x7f489be46189 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/asan/asan_interceptors.cpp:392 in __interceptor_strcat
Shadow bytes around the buggy address:
0x0c0c7fff80c0: fa fa fa fa fd fd fd fd fd fd fd fa fa fa fa fa
0x0c0c7fff80d0: 00 00 00 00 00 00 06 fa fa fa fa fa 00 00 00 00
0x0c0c7fff80e0: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 05 fa
0x0c0c7fff80f0: fa fa fa fa 00 00 00 00 00 00 02 fa fa fa fa fa
0x0c0c7fff8100: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
=>0x0c0c7fff8110: 00 00[02]fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fff8120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fff8130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fff8150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0c7fff8160: 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
Shadow gap: cc
==308939==ABORTING
void StringStrcat(struct ParseState *Parser, struct Value *ReturnValue,
struct Value **Param, int NumArgs)
{
ReturnValue->Val->Pointer = strcat(Param[0]->Val->Pointer,
Param[1]->Val->Pointer);
}