picoCTF Writeup: Rust Fixme 2 - Battling the Borrow Checker

picoCTFRustBorrow CheckerCTF Writeup

picoCTF Writeup: Rust Fixme 2 - Battling the Borrow Checker

For unzip tar -xzvf fixme2.tar.gz

use xor_cryptor::XORCryptor;

fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &String){ // How do we pass values to a function that we want to change?

    // Key for decryption
    let key = String::from("CSUCKS");

    // Editing our borrowed value
    borrowed_string.push_str("PARTY FOUL! Here is your flag: ");

    // Create decrpytion object
    let res = XORCryptor::new(&key);
    if res.is_err() {
        return; // How do we return in rust?
    }
    let xrc = res.unwrap();

    // Decrypt flag and print it out
    let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
    borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer));
    println!("{}", borrowed_string);
}


fn main() {
    // Encrypted flag values
    let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "01", "1c", "7e", "59", "63", "e1", "61", "25", "0d", "c4", "60", "f2", "12", "a0", "18", "03", "51", "03", "36", "05", "0e", "f9", "42", "5b"];

    // Convert the hexadecimal strings to bytes and collect them into a vector
    let encrypted_buffer: Vec<u8> = hex_values.iter()
        .map(|&hex| u8::from_str_radix(hex, 16).unwrap())
        .collect();

    let party_foul = String::from("Using memory unsafe languages is a: "); // Is this variable changeable?
    decrypt(encrypted_buffer, &party_foul); // Is this the correct way to pass a value to a function so that it can be changed?
}

cargo run to tun the progarm


┌──(nirmal㉿NirmalsFLOWX16)-[~/CTF/RustFixme_2/fixme2]
└─$ cargo run
   Compiling crossbeam-utils v0.8.20
   Compiling rayon-core v1.12.1
   Compiling either v1.13.0
   Compiling crossbeam-epoch v0.9.18
   Compiling crossbeam-deque v0.8.5
   Compiling rayon v1.10.0
   Compiling xor_cryptor v1.2.3
   Compiling rust_proj v0.1.0 (/home/nirmal/CTF/RustFixme_2/fixme2)
error[E0596]: cannot borrow `*borrowed_string` as mutable, as it is behind a `&` reference
 --> src/main.rs:9:5
  |
9 |     borrowed_string.push_str("PARTY FOUL! Here is your flag: ");
  |     ^^^^^^^^^^^^^^^ `borrowed_string` is a `&` reference, so it cannot be borrowed as mutable
  |
help: consider changing this to be a mutable reference
  |
3 | fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){ // How do we pass values to a function that we want to change?
  |                                                        +++

error[E0596]: cannot borrow `*borrowed_string` as mutable, as it is behind a `&` reference
  --> src/main.rs:20:5
   |
20 |     borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer));
   |     ^^^^^^^^^^^^^^^ `borrowed_string` is a `&` reference, so it cannot be borrowed as mutable
   |
help: consider changing this to be a mutable reference
   |
 3 | fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){ // How do we pass values to a function that we want to change?
   |                                                        +++

For more information about this error, try `rustc --explain E0596`.
error: could not compile `rust_proj` (bin "rust_proj") due to 2 previous errors

After running the program.

I asked Gemini and...

Passing Values You Want to Change (Mutable References)

In your first snippet, the function signature is currently giving you "read-only" access to the string, and it is entirely consuming the buffer:

  • encrypted_buffer: Vec<u8>: This takes ownership of the vector. Once this function runs, the original vector in the calling code is destroyed (moved).

  • borrowed_string: &String: The & symbol means it is an immutable reference. You can read the string, but the compiler will throw an error if you try to modify it.

The Fix: To modify a variable inside a function without destroying the original or triggering a compiler error, you must pass a mutable reference using &mut.

line 19 was changed to this As the compiler suggests. let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer.to_vec());

line 35 to this. Because we are using mutable ones. decrypt(&mut encrypted_buffer, &mut party_foul);

and then, let mut encrypted_buffer: and let mut party_foul as the rules.

┌──(nirmal㉿NirmalsFLOWX16)-[~/CTF/RustFixme_2/fixme2]
└─$ cargo run
   Compiling rust_proj v0.1.0 (/home/nirmal/CTF/RustFixme_2/fixme2)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/rust_proj`
Using memory unsafe languages is a: PARTY FOUL! Here is your flag: picoCTF{4r3_y0u_h4v1n5_fun_y31?}

Got the flag.