Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
gnbon opened this issue Jun 11, 2024 · 1 comment

Comments

@gnbon
Copy link

gnbon commented Jun 11, 2024

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:

while (bufPos < maxBufPos) {
uint8_t tag = buffer[bufPos++];
int len;
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);

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:

case 0xa7: /* calling AE qualifier */
{
if (buffer[bufPos] == 0x02) { /* ae-qualifier-form2 */

The same occurs when parsing the 0xa6, 0xbe tags here:

case 0xa6: /* calling AP title */
{
if (buffer[bufPos] == 0x06) { /* ap-title-form2 */

case 0xbe: /* user information */
if (buffer[bufPos] != 0x28) {

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 gnbon changed the title Out-of-Bound Read in parseAarqPdu /src/libiec61850/src/mms/iso_acse/acse.c:306:21 Multiple Out-of-Bound Read in parseAarqPdu /src/libiec61850/src/mms/iso_acse/acse.c Jun 11, 2024
@gnbon
Copy link
Author

gnbon commented Jun 12, 2024

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.

while (bufPos < maxBufPos)
{
uint8_t tag = buffer[bufPos++];
int len;
bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos);
if (len == 0)
continue;

In this case, line 278 will end up referencing buffer[-1].
poc-oobr-60.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant