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
828 stars 444 forks source link

Out-of-Bound Read in BerDecoder_decodeBoolean /src/libiec61850/src/mms/asn1/ber_decode.c:218:9 #510

Open gnbon opened 3 weeks ago

gnbon commented 3 weeks ago

Summary:

An Out-of-Bound Read vulnerability was discovered in the BerDecoder_decodeBoolean function of the ber_decode.c file in the libiec61850 library through fuzzing. This vulnerability is triggered when parsing the 0x87 tag in the parseGoosePayload function of goose_receiver.c.

Detailed Description:

The vulnerability occurs in the parseGoosePayload function when processing the 0x87 tag. The BerDecoder_decodeBoolean function is called to decode the simulation value. However, the bufPos index used to read from the input buffer is not properly validated, leading to an out-of-bounds read.

The BerDecoder_decodeBoolean function reads a value from the buffer using the bufPos index. If bufPos is outside the valid range of the buffer, the function ends up accessing memory beyond the buffer's boundaries.

The AddressSanitizer (ASan) log confirms the presence of the vulnerability. It shows that a read operation of size 1 byte occurred at address 0x7f7a6fcff828, which corresponds to a previously freed (poisoned) memory region. This indicates that the BerDecoder_decodeBoolean function is accessing an invalid memory area.

The stack trace reveals that the issue originates from line 218 of the BerDecoder_decodeBoolean function, which is called from parseGoosePayload at line 796. The parseGoosePayload function, in turn, is called from parseGooseMessage at line 1002.

Root Cause:

The root cause of the vulnerability lies in the lack of proper validation of the bufPos value in the BerDecoder_decodeBoolean function. The function does not ensure that bufPos falls within the valid range of the input buffer, allowing out-of-bounds reads to occur.

When the parseGoosePayload function processes the 0x87 tag and calls BerDecoder_decodeBoolean, it passes the bufPos value without validating its range. If the bufPos is pointing to a location beyond the valid buffer size, it leads to accessing memory that is outside the allocated buffer, resulting in an out-of-bounds read.

The vulnerability arises due to insufficient input validation and improper handling of the bufPos value in the BerDecoder_decodeBoolean function. The lack of proper boundary checks allows the function to read from invalid memory locations, potentially leading to program crashes, information disclosure, or other unintended behavior.

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.

Proof of Concept (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. poc.zip

AddressSanitizer

The AddressSanitizer (ASan) log shows:

./fuzz_goose_parse poc-oobr-87                               
==50060==ERROR: AddressSanitizer: use-after-poison on address 0x7f7a6fcff828 at pc 0x55dc31217f57 bp 0x7ffe17533560 sp 0x7ffe17533558
READ of size 1 at 0x7f7a6fcff828 thread T0
    #0 0x55dc31217f56 in BerDecoder_decodeBoolean /src/libiec61850/src/mms/asn1/ber_decode.c:218:9
    #1 0x55dc31212e02 in parseGoosePayload /src/libiec61850/src/goose/goose_receiver.c:796:30
    #2 0x55dc31212e02 in parseGooseMessage /src/libiec61850/src/goose/goose_receiver.c:1002:9
    #3 0x55dc311e69e1 in LLVMFuzzerTestOneInput /src/libiec61850/build/../fuzz/fuzz_goose_parse.c:17:5
    #4 0x55dc311e68f9 in ExecuteFilesOnyByOne /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:255:7
    #5 0x55dc311e66f5 in LLVMFuzzerRunDriver /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c
    #6 0x55dc311e62ad in main /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:311:10
    #7 0x7f7a72ae2d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #8 0x7f7a72ae2e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #9 0x55dc3110bcbd in _start (/home/user/oss-fuzz/build/out/libiec61850/fuzz_goose_parse+0x71cbd)

0x7f7a6fcff828 is located 40 bytes inside of 1048576-byte region [0x7f7a6fcff800,0x7f7a6fdff800)
allocated by thread T0 here:
    #0 0x55dc311a708e in malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3
    #1 0x55dc311e6821 in ExecuteFilesOnyByOne /src/aflplusplus/utils/aflpp_driver/aflpp_driver.c:221:41

SUMMARY: AddressSanitizer: use-after-poison /src/libiec61850/src/mms/asn1/ber_decode.c:218:9 in BerDecoder_decodeBoolean
Shadow bytes around the buggy address:
  0x7f7a6fcff580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7f7a6fcff600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7f7a6fcff680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7f7a6fcff700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x7f7a6fcff780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x7f7a6fcff800: 00 00 00 00 00[f7]f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x7f7a6fcff880: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x7f7a6fcff900: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x7f7a6fcff980: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x7f7a6fcffa00: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
  0x7f7a6fcffa80: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
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
==50060==ABORTING

CVE Assignment Request:

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

mzillgith commented 3 weeks ago

Thank you for reporting the issue.

I think this is the same as #509 and not a separate issue. With the fix for #509 this is no longer triggered.