Description
Dear jsoncpp dev team,
I have faced with this bug, which could lead to security issues.
Prerequisites:
jsoncpp-1.8.4
Affected OS: Linux
Test sources:
`
e
#include
#include "/usr/local/include/json/json.h"
using namespace std;
int main(int argc,char *argv[])
{
Json::Value jsonRoot;
Json::Value jsonItem;
ifstream ifs;
ifs.open(argv[1]);
jsonRoot.clear();
Json::CharReaderBuilder builder;
builder["collectComments"]=false;
JSONCPP_STRING errs;
if (!parseFromStream(builder,ifs,&jsonRoot,&errs))
{
return -1;
}
string jsonStr = jsonRoot.toStyledString();
jsonRoot.clear();
Json::CharReader* reader = builder.newCharReader();
if (!reader->parse(jsonStr.data(), jsonStr.data() + jsonStr.size(), &jsonRoot, &errs))
{
return -1;
}
return 0;
}
`
Steps to reproduce:
afl-g++ -g test.cpp -I /usr/local/lib/ -L /usr/local/lib/libjsoncpp.a -ljsoncpp -o test1
valgrind -v --tool=memcheck --leak-check=full ./test1 poc1
(attach poc1.zip
poc1.zip
)
==74710== Memcheck, a memory error detector
==74710== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==74710== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==74710== Command: ./test1 fuzzouput/crashes/id:000000,sig:06,src:000000,op:havoc,rep:8
==74710==
--74710-- Valgrind options:
--74710-- -v
--74710-- --tool=memcheck
--74710-- --leak-check=full
--74710-- Contents of /proc/version:
--74710-- Linux version 4.17.0-kali1-amd64 (devel@kali.org) (gcc version 7.3.0 (Debian 7.3.0-25)) #1 SMP Debian 4.17.8-1kali1 (2018-07-24)
--74710--
--74710-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-avx-avx2-bmi
--74710-- Page sizes: currently 4096, max supported 4096
--74710-- Valgrind library directory: /usr/lib/valgrind
--74710-- Reading syms from /root/jsoncpp/test1
--74710-- Reading syms from /usr/lib/x86_64-linux-gnu/ld-2.27.so
--74710-- Considering /usr/lib/debug/.build-id/dc/5cb16f5e644116cac64a4c3f5da4d081b81a4f.debug ..
--74710-- .. build-id is valid
--74710-- Reading syms from /usr/lib/valgrind/memcheck-amd64-linux
--74710-- Considering /usr/lib/valgrind/memcheck-amd64-linux ..
--74710-- .. CRC mismatch (computed 7680f3df wanted 92e0f93c)
--74710-- Considering /usr/lib/debug/usr/lib/valgrind/memcheck-amd64-linux ..
--74710-- .. CRC is valid
--74710-- object doesn't have a dynamic symbol table
--74710-- Scheduler: using generic scheduler lock implementation.
--74710-- Reading suppressions file: /usr/lib/valgrind/default.supp
==74710== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-74710-by-root-on-???
==74710== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-74710-by-root-on-???
==74710== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-74710-by-root-on-???
==74710==
==74710== TO CONTROL THIS PROCESS USING vgdb (which you probably
==74710== don't want to do, unless you know exactly what you're doing,
==74710== or are doing some strange experiment):
==74710== /usr/lib/valgrind/../../bin/vgdb --pid=74710 ...command...
==74710==
==74710== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==74710== /path/to/gdb ./test1
==74710== and then give GDB the following command
==74710== target remote | /usr/lib/valgrind/../../bin/vgdb --pid=74710
==74710== --pid is optional if only one valgrind process is running
==74710==
--74710-- REDIR: 0x401e290 (ld-linux-x86-64.so.2:strlen) redirected to 0x58061781 (vgPlain_amd64_linux_REDIR_FOR_strlen)
--74710-- REDIR: 0x401e070 (ld-linux-x86-64.so.2:index) redirected to 0x5806179b (vgPlain_amd64_linux_REDIR_FOR_index)
--74710-- Reading syms from /usr/lib/valgrind/vgpreload_core-amd64-linux.so
--74710-- Considering /usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--74710-- .. CRC mismatch (computed 66a2a561 wanted 3789c7eb)
--74710-- Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--74710-- .. CRC is valid
--74710-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
--74710-- Considering /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--74710-- .. CRC mismatch (computed 8487a070 wanted 8af30a91)
--74710-- Considering /usr/lib/debug/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--74710-- .. CRC is valid
==74710== WARNING: new redirection conflicts with existing -- ignoring it
--74710-- old: 0x0401e290 (strlen ) R-> (0000.0) 0x58061781 vgPlain_amd64_linux_REDIR_FOR_strlen
--74710-- new: 0x0401e290 (strlen ) R-> (2007.0) 0x04838a60 strlen
--74710-- REDIR: 0x401aab0 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4839b90 (strcmp)
--74710-- REDIR: 0x401e7d0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x483d1a0 (mempcpy)
--74710-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25
--74710-- object doesn't have a symbol table
--74710-- Reading syms from /usr/lib/x86_64-linux-gnu/libm-2.27.so
--74710-- Considering /usr/lib/debug/.build-id/fa/b2857727406caccd7ab22e1729b09ccf2c3eb7.debug ..
--74710-- .. build-id is valid
--74710-- Reading syms from /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
--74710-- object doesn't have a symbol table
--74710-- Reading syms from /usr/lib/x86_64-linux-gnu/libc-2.27.so
--74710-- Considering /usr/lib/debug/.build-id/dc/87cd1e2b171a4c51139cb4e1f2ec630e711de3.debug ..
--74710-- .. build-id is valid
--74710-- REDIR: 0x4c1c050 (libc.so.6:memmove) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b280 (libc.so.6:strncpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c330 (libc.so.6:strcasecmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1acd0 (libc.so.6:strcat) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b2b0 (libc.so.6:rindex) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1d900 (libc.so.6:rawmemchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c1c0 (libc.so.6:mempcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1bff0 (libc.so.6:bcmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b240 (libc.so.6:strncmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1ad40 (libc.so.6:strcmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c120 (libc.so.6:memset) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c35b60 (libc.so.6:wcschr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b1e0 (libc.so.6:strnlen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1adb0 (libc.so.6:strcspn) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c380 (libc.so.6:strncasecmp) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1ad80 (libc.so.6:strcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c4c0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b2e0 (libc.so.6:strpbrk) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1ad00 (libc.so.6:index) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b1b0 (libc.so.6:strlen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c221b0 (libc.so.6:memrchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c3d0 (libc.so.6:strcasecmp_l) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1bfc0 (libc.so.6:memchr) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c36920 (libc.so.6:wcslen) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1b590 (libc.so.6:strspn) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c300 (libc.so.6:stpncpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c2d0 (libc.so.6:stpcpy) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1d930 (libc.so.6:strchrnul) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4c1c420 (libc.so.6:strncasecmp_l) redirected to 0x482b1c0 (_vgnU_ifunc_wrapper)
--74710-- REDIR: 0x4cee700 (libc.so.6:__strrchr_avx2) redirected to 0x48383e0 (rindex)
--74710-- REDIR: 0x4c175c0 (libc.so.6:malloc) redirected to 0x4835750 (malloc)
--74710-- REDIR: 0x4cee8d0 (libc.so.6:__strlen_avx2) redirected to 0x48389a0 (strlen)
--74710-- REDIR: 0x4ceaee0 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x483bab0 (bcmp)
--74710-- REDIR: 0x4cca0a0 (libc.so.6:__strcmp_ssse3) redirected to 0x4839a50 (strcmp)
--74710-- REDIR: 0x4c1ba70 (libc.so.6:__GI_strstr) redirected to 0x483d410 (__strstr_sse2)
--74710-- REDIR: 0x48f6040 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x48364e0 (operator new[](unsigned long))
--74710-- REDIR: 0x48f5f90 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x4835dc0 (operator new(unsigned long))
--74710-- REDIR: 0x4ceee10 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x483c390 (memmove)
--74710-- REDIR: 0x4c17c50 (libc.so.6:free) redirected to 0x4836980 (free)
--74710-- REDIR: 0x48f4220 (libstdc++.so.6:operator delete(void*)) redirected to 0x4836e80 (operator delete(void*))
--74710-- REDIR: 0x4c17d60 (libc.so.6:realloc) redirected to 0x4837960 (realloc)
terminate called after throwing an instance of 'Json::LogicError'
what(): in Json::Value::clear(): requires complex value
==74710==
==74710== Process terminating with default action of signal 6 (SIGABRT)
==74710== at 0x4BC9F3B: raise (raise.c:51)
==74710== by 0x4BCB2F0: abort (abort.c:79)
==74710== by 0x48EF942: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==74710== by 0x48F5895: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==74710== by 0x48F58D0: std::terminate() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==74710== by 0x48F5B03: __cxa_throw (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==74710== by 0x111643: Json::throwLogicError(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) [clone .cold.183] (json_value.cpp:202)
==74710== by 0x172494: Json::Value::clear() (json_value.cpp:930)
==74710== by 0x11A422: main (test.cpp:22)
==74710==
==74710== HEAP SUMMARY:
==74710== in use at exit: 10,610 bytes in 27 blocks
==74710== total heap usage: 70 allocs, 43 frees, 86,103 bytes allocated
==74710==
==74710== Searching for pointers to 27 not-freed blocks
==74710== Checked 109,232 bytes
==74710==
==74710== 168 bytes in 1 blocks are possibly lost in loss record 24 of 27
==74710== at 0x48357BF: malloc (vg_replace_malloc.c:299)
==74710== by 0x48F475F: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==74710== by 0x1640BA: Json::throwLogicError(std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) (json_value.cpp:202)
==74710== by 0x172494: Json::Value::clear() (json_value.cpp:930)
==74710== by 0x11A422: main (test.cpp:22)
==74710==
==74710== LEAK SUMMARY:
==74710== definitely lost: 0 bytes in 0 blocks
==74710== indirectly lost: 0 bytes in 0 blocks
==74710== possibly lost: 168 bytes in 1 blocks
==74710== still reachable: 10,442 bytes in 26 blocks
==74710== suppressed: 0 bytes in 0 blocks
==74710== Reachable blocks (those to which a pointer was found) are not shown.
==74710== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==74710==
==74710== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==74710== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Aborted
Bug analysis:
test.cpp jsonRoot.clear()——》json_value.cpp:930——》JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value");