mz-automation / libiec61850

Official repository for libIEC61850, the open-source library for the IEC 61850 protocols
http://libiec61850.com/libiec61850
GNU General Public License v3.0
863 stars 461 forks source link

Multiple Out-of-Bound Read in parseAarqPdu /src/libiec61850/src/mms/iso_acse/acse.c #512

Open gnbon opened 3 months ago

gnbon commented 3 months ago

Summary

An Out-of-Bound Read vulnerability was discovered in the parseAarqPdu function of the acse.c file in the libiec61850 library through fuzzing. This vulnerability is triggered when parsing the 0xa6, 0xa7, 0xbe tags.

Details

The vulnerability occurs in the parseAarqPdu function when processing the 0xa6, 0xa7, 0xbe tags. When bufPos index used to read from the input buffer is not properly validated, leading to an out-of-bounds read.

Let's consider when the execution reaches the following code: https://github.com/mz-automation/libiec61850/blob/790e3e6714919f4902733082ccfc32fbff71b187/src/mms/iso_acse/acse.c#L266-L270

If the end of the file contains bytes like a7 00, the tag variable will be set to 0xa7, and bufPos will point to the end of the file + 1. Due to the lack of proper boundary checks after this point, an out-of-bound read vulnerability can occur. For example, when processing the 0xa7 tag: https://github.com/mz-automation/libiec61850/blob/790e3e6714919f4902733082ccfc32fbff71b187/src/mms/iso_acse/acse.c#L304-L306

The same occurs when parsing the 0xa6, 0xbe tags here: https://github.com/mz-automation/libiec61850/blob/790e3e6714919f4902733082ccfc32fbff71b187/src/mms/iso_acse/acse.c#L291-L293 https://github.com/mz-automation/libiec61850/blob/790e3e6714919f4902733082ccfc32fbff71b187/src/mms/iso_acse/acse.c#L342-L343

Impact:

An attacker can use this vulnerability to leak data by sending deliberately crafted input data to trigger abnormal behavior in the program. This can potentially lead to information disclosure or other unintended consequences.

Recommendation:

To mitigate this vulnerability, it is crucial to perform thorough boundary checks regardless of the size of the input data. The code should be modified to ensure that bufPos never exceeds the valid range of the buffer. Additionally, proper input validation and error handling should be implemented to gracefully handle cases where the input data size is unexpected or malformed.

PoC

A proof-of-concept exploit has been provided in the attached file. This PoC demonstrates how the vulnerability can be triggered by sending specially crafted input data to the affected functions. acse-crash-a7-poc.zip

Address Sanitizer

==17651==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50300000005a at pc 0x5629a61a1679 bp 0x7fff9a414bb0 sp 0x7fff9a414ba8
READ of size 1 at 0x50300000005a thread T0
    #0 0x5629a61a1678 in parseAarqPdu /src/libiec61850/src/mms/iso_acse/acse.c:306:21
    #1 0x5629a61a1678 in AcseConnection_parseMessage /src/libiec61850/src/mms/iso_acse/acse.c:454:22
    #2 0x5629a619f364 in LLVMFuzzerTestOneInput /src/libiec61850/build/../fuzz/fuzz_acse_parse.c:10:5
    #3 0x5629a619f209 in ExecuteFilesOnyByOne /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:255:7
    #4 0x5629a619f005 in LLVMFuzzerRunDriver /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c
    #5 0x5629a619ebbd in main /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:311:10
    #6 0x7f986a97fd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #7 0x7f986a97fe3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #8 0x5629a60c45cd in _start (/home/user/oss-fuzz/build/out/libiec61850/fuzz_acse_parse+0x6d5cd)

0x50300000005a is located 0 bytes after 26-byte region [0x503000000040,0x50300000005a)
allocated by thread T0 here:
    #0 0x5629a615fb88 in calloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:77:3
    #1 0x5629a61aacb9 in Memory_calloc /src/libiec61850/hal/memory/lib_memory.c:44:20
    #2 0x5629a619f4c2 in ByteBuffer_create /src/libiec61850/src/common/byte_buffer.c:34:28
    #3 0x5629a619f347 in LLVMFuzzerTestOneInput /src/libiec61850/build/../fuzz/fuzz_acse_parse.c:8:30
    #4 0x5629a619f209 in ExecuteFilesOnyByOne /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:255:7

SUMMARY: AddressSanitizer: heap-buffer-overflow /src/libiec61850/src/mms/iso_acse/acse.c:306:21 in parseAarqPdu
Shadow bytes around the buggy address:
  0x502ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x502ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x502ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x502fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x502fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x503000000000: fa fa 00 00 00 fa fa fa 00 00 00[02]fa fa fa fa
  0x503000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x503000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x503000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x503000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x503000000280: 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
==17651==ABORTING

CVE Assignment Request: I kindly request the assignment of a Common Vulnerabilities and Exposures (CVE) identifier for the Out-of-Bound Read vulnerability.

gnbon commented 3 months ago

In fix 501dffe, there is still an issue that can occur below: If the BerDecoder_decodeLength function is called at the end of the file and returns -1, the boundary check will fail to detect the problem. This is because when len is equal to 0, the code will continue at line 284. https://github.com/mz-automation/libiec61850/blob/d0f52a28241d5f9e5d3afeb18d695ba7bbc0f9f1/src/mms/iso_acse/acse.c#L276-L284 In this case, line 278 will end up referencing buffer[-1]. poc-oobr-60.zip