Heap Buffer Overflow blf_read_apptextmessage Function

May 22, 2023

CVE Number

CVE-2023-2854

Credits

Huascar Tejeda of Pentraze Cybersecurity

Summary

A heap buffer overflow vulnerability has been discovered in Wireshark’s g_strndup function, which could potentially lead to remote code execution.

CVSS

9.0 (Critical) - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

Details

The vulnerability lies within the blf_read_apptextmessage function (found in the blf.c file), which is used by the Wireshark BLF (Binary Logging Format) plugin. The Address Sanitizer (ASAN) and GDB backtrace revealed a heap-buffer-overflow when the g_strsplit_set function is called. This function splits the string on the specified delimiters and creates an array of tokens.

In the provided backtrace, g_strsplit_set is called with text and “;” as the input parameters. If this string is carefully crafted, it could lead to arbitrary code execution when the process attempts to read or write to a memory area it doesn’t own, which is typical behavior for a heap-buffer-overflow vulnerability.

Steps to reproduce:

Open the trigger file using a Wireshark binary compiled with the -DENABLE_ASAN option:

$ tshark -r trigger
=================================================================
==147490==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000311440 at pc 0x7ffff745be47 bp 0x7fffffffc730 sp 0x7fffffffbed8
READ of size 17 at 0x602000311440 thread T0
    #0 0x7ffff745be46 in __interceptor_strncpy ../../../../src/libsanitizer/asan/asan_interceptors.cpp:484
    #1 0x7fffdfd3982b in g_strndup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7382b)
    #2 0x7fffdfd3daba in g_strsplit_set (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x77aba)
    #3 0x7fffdfa5933f in blf_read_apptextmessage /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1646
    #4 0x7fffdfa5933f in blf_read_block /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1820
    #5 0x7fffdfa5a79f in blf_read /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1846
    #6 0x7fffdfb34583 in wtap_read /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/wtap.c:1555
    #7 0x55555558eb8f in process_cap_file_single_pass /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3534
    #8 0x55555558eb8f in process_cap_file /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3746
    #9 0x55555558eb8f in main /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:2260
    #10 0x7fffdf629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #11 0x7fffdf629e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #12 0x555555591754 in _start (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/tshark+0x3d754)

0x602000311440 is located 0 bytes to the right of 16-byte region [0x602000311430,0x602000311440)
allocated by thread T0 here:
    #0 0x7ffff74b4a37 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
    #1 0x7fffdfa592c2 in blf_read_apptextmessage /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1637
    #2 0x7fffdfa592c2 in blf_read_block /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1820
    #3 0x7fffffffdd2f  ([stack]+0x1fd2f)
...
...

ASAN

=================================================================
==147490==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000311440 at pc 0x7ffff745be47 bp 0x7fffffffc730 sp 0x7fffffffbed8
READ of size 17 at 0x602000311440 thread T0
    #0 0x7ffff745be46 in __interceptor_strncpy ../../../../src/libsanitizer/asan/asan_interceptors.cpp:484
    #1 0x7fffdfd3982b in g_strndup (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7382b)
    #2 0x7fffdfd3daba in g_strsplit_set (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x77aba)
    #3 0x7fffdfa5933f in blf_read_apptextmessage /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1646
    #4 0x7fffdfa5933f in blf_read_block /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1820
    #5 0x7fffdfa5a79f in blf_read /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1846
    #6 0x7fffdfb34583 in wtap_read /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/wtap.c:1555
    #7 0x55555558eb8f in process_cap_file_single_pass /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3534
    #8 0x55555558eb8f in process_cap_file /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3746
    #9 0x55555558eb8f in main /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:2260
    #10 0x7fffdf629d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #11 0x7fffdf629e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #12 0x555555591754 in _start (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/tshark+0x3d754)

0x602000311440 is located 0 bytes to the right of 16-byte region [0x602000311430,0x602000311440)
allocated by thread T0 here:
    #0 0x7ffff74b4a37 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
    #1 0x7fffdfa592c2 in blf_read_apptextmessage /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1637
    #2 0x7fffdfa592c2 in blf_read_block /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1820
    #3 0x7fffffffdd2f  ([stack]+0x1fd2f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/asan/asan_interceptors.cpp:484 in __interceptor_strncpy
Shadow bytes around the buggy address:
  0x0c048005a230: fa fa 00 03 fa fa 00 03 fa fa 00 fa fa fa 00 02
  0x0c048005a240: fa fa 00 fa fa fa 00 00 fa fa 00 00 fa fa fd fa
  0x0c048005a250: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
  0x0c048005a260: fa fa 00 05 fa fa fd fd fa fa 00 05 fa fa 00 00
  0x0c048005a270: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
=>0x0c048005a280: fa fa 00 00 fa fa 00 00[fa]fa 01 fa fa fa fa fa
  0x0c048005a290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c048005a2a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c048005a2b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c048005a2c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c048005a2d0: 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
==147490==ABORTING

Crash context:
Execution stopped here ==> 0x00007fffdf696a7c: mov    r13d,eax

Register info:
   rax - 0x0000000000000000 (0)
   rbx - 0x00007ffff72d5a80 (140737340332672)
   rcx - 0x00007fffdf696a7c (140736941615740)
   rdx - 0x0000000000000006 (6)
   rsi - 0x0000000000024022 (147490)
   rdi - 0x0000000000024022 (147490)
   rbp - 0x0000000000024022 (0x24022)
   rsp - 0x00007fffffffaf00 (0x7fffffffaf00)
    r8 - 0x00007fffffffafd0 (140737488334800)
    r9 - 0x0000000000000000 (0)
   r10 - 0x0000000000000008 (8)
   r11 - 0x0000000000000246 (582)
   r12 - 0x0000000000000006 (6)
   r13 - 0x0000000000000016 (22)
   r14 - 0x00007fffd6670000 (140736790462464)
   r15 - 0x0000000000010000 (65536)
   rip - 0x00007fffdf696a7c (0x7fffdf696a7c <__GI___pthread_kill+300>)
eflags - 0x00000246 ([ PF ZF IF ])
    cs - 0x00000033 (51)
    ss - 0x0000002b (43)
    ds - 0x00000000 (0)
    es - 0x00000000 (0)
    fs - 0x00000000 (0)
    gs - 0x00000000 (0)

GDB Backtrace

#0  0x00007fffdf696a7c in __pthread_kill_implementation (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:44

#1  0x00007fffdf696a7c in __pthread_kill_internal (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:78

#2  0x00007fffdf696a7c in __GI___pthread_kill (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./nptl/pthread_kill.c:89

#3  0x00007fffdf642476 in __GI_raise (/lib/x86_64-linux-gnu/libc.so.6)
                       at ../sysdeps/posix/raise.c:26

#4  0x00007fffdf6287f3 in __GI_abort (/lib/x86_64-linux-gnu/libc.so.6)
                       at ./stdlib/abort.c:79

#5  0x00007ffff74d26f2 in __sanitizer::Abort (/lib/x86_64-linux-gnu/libasan.so.6)
                       at ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:151

#6  0x00007ffff74de2ac in __sanitizer::Die (/lib/x86_64-linux-gnu/libasan.so.6)
                       at ../../../../src/libsanitizer/sanitizer_common/sanitizer_termination.cpp:58

#7  0x00007ffff74bd75c in __asan::ScopedInErrorReport::~ScopedInErrorReport (/lib/x86_64-linux-gnu/libasan.so.6)
                       at ../../../../src/libsanitizer/asan/asan_report.cpp:190

#8  0x00007ffff74bcff5 in __asan::ReportGenericError (/lib/x86_64-linux-gnu/libasan.so.6)
                       at ../../../../src/libsanitizer/asan/asan_report.cpp:478

#9  0x00007ffff745be66 in __interceptor_strncpy (/lib/x86_64-linux-gnu/libasan.so.6)
                       at ../../../../src/libsanitizer/asan/asan_interceptors.cpp:484

#10 0x00007fffdfd3982c in g_strndup (/lib/x86_64-linux-gnu/libglib-2.0.so.0)
#11 0x00007fffdfd3dabb in g_strsplit_set (/lib/x86_64-linux-gnu/libglib-2.0.so.0)
#12 0x00007fffdfa59340 in blf_read_apptextmessage (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/libwiretap.so.13)
                       ????: gboolean blf_read_apptextmessage(timestamp = (guint64)<optimized out>, object_length = (gint64)<optimized out>, data_start = (gint64)<optimized out>, block_start = (gint64)0, err_info = (gchar **)0x7fffffffd320, err = (int *)0x7fffffffd030, params = (blf_params_t *)0x7fffffffcd30) {
                       ||||:
                       ||||: /* Local reference: gchar ** tokens = <optimized out>; */
                       ||||: /* Local reference: gchar * text = 0x602000311430 ";3eff582ae\t5148b\002\021"; */
                       1644: 
                       1645:     /* returns a NULL terminated array of NULL terminates strings */
                       1646:     gchar **tokens = g_strsplit_set(text, ";", -1);
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1646

#13 0x00007fffdfa59340 in blf_read_block (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/libwiretap.so.13)
                       1693: gboolean blf_read_block(params = (blf_params_t *)0x7fffffffcd30, start_pos = (gint64)0, err = (int *)0x7fffffffd030, err_info = (gchar **)0x7fffffffd320) {
                       ||||:
                       ||||: /* Local reference: blf_params_t * params = 0x7fffffffcd30; */
                       ||||: /* Local reference: int * err = 0x7fffffffd030; */
                       ||||: /* Local reference: gchar ** err_info = 0x7fffffffd320; */
                       ||||: /* Local reference: gint64 start_pos = 0; */
                       1818: 
                       1819:         case BLF_OBJTYPE_APP_TEXT:
                       1820:             if (!blf_read_apptextmessage(params, err, err_info, start_pos, start_pos + header.header_length, header.object_length, timestamp)) {
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1820

#14 0x00007fffdfa5a7a0 in blf_read (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/libwiretap.so.13)
                       1837: gboolean blf_read(wth = (wtap *)<optimized out>, rec = (wtap_rec *)<optimized out>, buf = (Buffer *)<optimized out>, err = (int *)<optimized out>, err_info = (gchar **)<optimized out>, data_offset = (gint64 *)0x7fffffffd3c0) {
                       ||||:
                       ||||: /* Local reference: wtap * wth = <optimized out>; */
                       ||||: /* Local reference: int * err = <optimized out>; */
                       ||||: /* Local reference: gchar ** err_info = <optimized out>; */
                       1844:     blf_tmp.blf_data = (blf_t *)wth->priv;
                       1845: 
                       1846:     if (!blf_read_block(&blf_tmp, blf_tmp.blf_data->current_real_seek_pos, err, err_info)) {
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/blf.c:1846

#15 0x00007fffdfb34584 in wtap_read (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/libwiretap.so.13)
                       1545: gboolean wtap_read(wth = (wtap *)0x60f000001030, rec = (wtap_rec *)0x7fffffffdd30, buf = (Buffer *)0x7fffffffd4a0, err = (int *)0x7fffffffd030, err_info = (gchar **)0x7fffffffd320, offset = (gint64 *)0x7fffffffd3c0) {
                       ||||:
                       ||||: /* Local reference: int * err = 0x7fffffffd030; */
                       ||||: /* Local reference: gchar ** err_info = 0x7fffffffd320; */
                       ||||: /* Local reference: wtap * wth = 0x60f000001030; */
                       ||||: /* Local reference: wtap_rec * rec = 0x7fffffffdd30; */
                       ||||: /* Local reference: Buffer * buf = 0x7fffffffd4a0; */
                       ||||: /* Local reference: gint64 * offset = 0x7fffffffd3c0; */
                       1553: 	*err = 0;
                       1554: 	*err_info = NULL;
                       1555: 	if (!wth->subtype_read(wth, rec, buf, err, err_info, offset)) {
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/wiretap/wtap.c:1555

#16 0x000055555558eb90 in process_cap_file_single_pass (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/tshark)
                       ????: pass_status_t process_cap_file_single_pass(cf = (capture_file *)0x55555563d000 <cfile>, err_framenum = (volatile guint32 *)0x7fffffffd050, err_info = (gchar **)0x7fffffffd320, err = (int *)0x7fffffffd030, max_write_packet_count = (int)0, max_byte_count = (gint64)0, max_packet_count = (int)0, pdh = (wtap_dumper *)0x0) {
                       ||||:
                       ||||: /* Local reference: int * err = 0x7fffffffd030; */
                       ||||: /* Local reference: capture_file * cf = 0x55555563d000 <cfile>; */
                       ||||: /* Local reference: gchar ** err_info = 0x7fffffffd320; */
                       3532: 
                       3533:     *err = 0;
                       3534:     while (wtap_read(cf->provider.wth, &rec, &buf, err, err_info, &data_offset)) {
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3534

#17 0x000055555558eb90 in process_cap_file (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/tshark)
                       ????: process_file_status_t process_cap_file(cf = (capture_file *)0x55555563d000 <cfile>, max_write_packet_count = (int)0, max_byte_count = (gint64)0, max_packet_count = (int)0, out_file_name_res = (gboolean)0, out_file_type = (int)0, save_file = (char *)0x0) {
                       ||||:
                       ||||: /* Local reference: pass_status_t first_pass_status = PASS_SUCCEEDED; */
                       ||||: /* Local reference: pass_status_t second_pass_status = <optimized out>; */
                       ||||: /* Local reference: wtap_dumper * pdh = 0x0; */
                       ||||: /* Local reference: capture_file * cf = 0x55555563d000 <cfile>; */
                       3744: 
                       3745:         first_pass_status = PASS_SUCCEEDED; /* There is no first pass */
                       3746:         second_pass_status = process_cap_file_single_pass(cf, pdh,
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:3746

#18 0x000055555558eb90 in main (/home/htejeda/fuzzing/wireshark/wireshark-4.0.5/build-asan/run/tshark)
                        789: int main(argc = (int)<optimized out>, argv = (char **)<optimized out>) {
                       ||||:
                       2258:         ws_debug("tshark: invoking process_cap_file() to process the packets");
                       2259:         TRY {
                       2260:             status = process_cap_file(&cfile, output_file_name, out_file_type, out_file_name_res,
                       ||||:
                       ----: }
                       at /home/htejeda/fuzzing/wireshark/wireshark-4.0.5/tshark.c:2260

¿Ver el sitio en español?