cisco / mercury

Mercury: network metadata capture and analysis
Other
430 stars 75 forks source link

buffer overflow when accessing std::vector #16

Closed imarom closed 2 years ago

imarom commented 2 years ago

Hi,

While running AddressSanitizer on a real traffic I hit the following crash:

READ of size 8 at 0x6030036242c8 thread T0 (ntdp-builtin)                                                                                                                                                            
    #0 0x7f379598c744 in std::vector<os_information, std::allocator<os_information> >::data() /usr/include/c++/8/bits/stl_vector.h:1056
    #1 0x7f379597db7e in fingerprint_data::perform_analysis(char const*, char const*, unsigned short) ../../src/engine/features/mercury/dp/analysis.h:433
    #2 0x7f379597f194 in classifier::perform_analysis(char const*, char const*, char const*, unsigned short) ../../src/engine/features/mercury/dp/analysis.h:832
    #3 0x7f379597f595 in classifier::analyze_fingerprint_and_destination_context(fingerprint const&, destination_context const&, analysis_result&) ../../src/engine/features/mercury/dp/analysis.h:842
    #4 0x7f3795988e89 in do_analysis::operator()(tls_client_hello&) ../../src/engine/features/mercury/dp/pkt_proc.cc:716
    #5 0x7f3795993701 in bool std::__invoke_impl<bool, do_analysis, tls_client_hello&>(std::__invoke_other, do_analysis&&, tls_client_hello&) /usr/include/c++/8/bits/invoke.h:60
    #6 0x7f379598e8c2 in std::__invoke_result<do_analysis, tls_client_hello&>::type std::__invoke<do_analysis, tls_client_hello&>(do_analysis&&, tls_client_hello&) /usr/include/c++/8/bits/invoke.h:95
    #7 0x7f379598ae78 in std::__detail::__variant::__gen_vtable_impl<std::__detail::__variant::_Multi_array<bool (*)(do_analysis&&, std::variant<std::monostate, http_request, http_response, tls_client_hello, tls_server_hello_and_certificate, ssh_init_packet, ssh_kex_init, smtp_client, smtp_server, unknown_initial_packet>&)>, std::tuple<std::variant<std::monostate, http_request, http_response, tls_client_hello, tls_server_hello_and_certificate, ssh_init_packet, ssh_kex_init, smtp_client, smtp_server, unknown_initial_packet>&>, std::integer_sequence<unsigned long, 3ul> >::__visit_invoke(do_analysis&&, std::variant<std::monostate, http_request, http_response, tls_client_hello, tls_server_hello_and_certificate, ssh_init_packet, ssh_kex_init, smtp_client, smtp_server, unknown_initial_packet>&) /usr/include/c++/8/variant:830
    #8 0x7f379598b0f7 in decltype(auto) std::visit<do_analysis, std::variant<std::monostate, http_request, http_response, tls_client_hello, tls_server_hello_and_certificate, ssh_init_packet, ssh_kex_init, smtp_client, smtp_server, unknown_initial_packet>&>(do_analysis&&, std::variant<std::monostate, http_request, http_response, tls_client_hello, tls_server_hello_and_certificate, ssh_init_packet, ssh_kex_init, smtp_client, smtp_server, unknown_initial_packet>&) /usr/include/c++/8/variant:1386

Memory was allocated here:

0x6030036242c8 is located 0 bytes to the right of 24-byte region [0x6030036242b0,0x6030036242c8)
allocated by thread T1 here:                                                                                                                                                                                         
    #0 0x7f3795f0fd30 in operator new(unsigned long) (/lib/x86_64-linux-gnu/libasan.so.5+0xead30)
    #1 0x7f379585d5f3 in __gnu_cxx::new_allocator<std::vector<os_information, std::allocator<os_information> > >::allocate(unsigned long, void const*) /usr/include/c++/8/ext/new_allocator.h:111
    #2 0x7f3795855ac1 in std::allocator_traits<std::allocator<std::vector<os_information, std::allocator<os_information> > > >::allocate(std::allocator<std::vector<os_information, std::allocator<os_information> > >&, unsigned long) (../lib/libntdp.so+0x368ac1)
    #3 0x7f379584a323 in std::_Vector_base<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > >::_M_allocate(unsigned long) (../lib/libntdp.so+0x35d323)
    #4 0x7f379583c85c in std::vector<os_information, std::allocator<os_information> >* std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > >::_M_allocate_and_copy<__gnu_cxx::__normal_iterator<std::vector<os_information, std::allocator<os_information> > const*, std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > > > >(unsigned long, __gnu_cxx::__normal_iterator<std::vector<os_information, std::allocator<os_information> > const*, std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > > >, __gnu_cxx::__normal_iterator<std::vector<os_information, std::allocator<os_information> > const*, std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > > >) (../lib/libntdp.so+0x34f85c)
    #5 0x7f379582b67d in std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > >::operator=(std::vector<std::vector<os_information, std::allocator<os_information> >, std::allocator<std::vector<os_information, std::allocator<os_information> > > > const&) (../lib/libntdp.so+0x33e67d)
    #6 0x7f379581b8a3 in fingerprint_data::operator=(fingerprint_data const&) (../lib/libntdp.so+0x32e8a3)
    #7 0x7f379581e763 in classifier::process_fp_db_line(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, float, float, bool) (../lib/libntdp.so+0x331763)
    #8 0x7f379581fe3a in classifier::classifier(encrypted_compressed_archive&, float, float, bool) (../lib/libntdp.so+0x332e3a)
    #9 0x7f379580ef4b in analysis_init_from_archive(int, char const*, unsigned char const*, enc_key_type, float, float, bool) ../../src/engine/features/mercury/dp/analysis.cc:49
    #10 0x7f379589e092 in mercury::mercury(libmerc_config const*, int) ../../src/engine/features/mercury/dp/pkt_proc.h:42
    #11 0x7f3795893bbb in mercury_init ../../src/engine/features/mercury/dp/libmerc.cc:49

Seems like the issue hits here: os_info_data = process_os_info_vector[index_max].data();

where index_max is hitting just at the end: 0x6030036242c8 is located 0 bytes to the right of 24-byte region

imarom commented 2 years ago
(gdb) p process_os_info_vector      
$1 = std::vector of length 1, capacity 1 = {std::vector of length 2, capacity 2 = {{os_name = 0x60600007cf40 "cpe:2.3:o:canonical:ubuntu_linux:20.04.2:*:*:*:*:*:*:*", os_prevalence = 12}, {
      os_name = 0x6060015a67c0 "cpe:2.3:o:canonical:ubuntu_linux:20.04.3:*:*:*:*:*:*:*", os_prevalence = 3}}}

 (gdb) p index_max
$2 = 2

so a vector of size 1, being accessed at index 2

each element size is of 24 bytes - so this corresponds exactly to the AddressSanitizer issue

davidmcgrew commented 2 years ago

Hi Itay, thanks for reporting this issue, I think that I know exactly what the root cause is. Should be able to push a fix soon, but need some time to verify and test.

davidmcgrew commented 2 years ago

Fixed in 2.5.1.