|
| 1 | +--- |
| 2 | +title: Rust fixme 2 |
| 3 | +date: 2025-08-18 |
| 4 | +categories: [Capture The Flags, picoCTF] |
| 5 | +tags: [ctf, picoctf, general skills, writeups] |
| 6 | +description: picoCTF Rust fixme 2 Challenge |
| 7 | +--- |
| 8 | + |
| 9 | + |
| 10 | +> Challenge description: |
| 11 | +> |
| 12 | +>The Rust saga continues? I ask you, can I borrow that, pleeeeeaaaasseeeee? |
| 13 | +{: .prompt-info } |
| 14 | + |
| 15 | + |
| 16 | +Another challenge in the PicoCTF Rust fixme saga! if you haven't caught the previous challenge, check it out [here](https://slavetomints.com/posts/picoctf-rust-fixme-1/). |
| 17 | + |
| 18 | +After copying this project and extracting it, let's see what happens when we try to run it. |
| 19 | + |
| 20 | +```terminal |
| 21 | +❯ cargo run |
| 22 | + Compiling crossbeam-utils v0.8.20 |
| 23 | + Compiling rayon-core v1.12.1 |
| 24 | + Compiling either v1.13.0 |
| 25 | + Compiling crossbeam-epoch v0.9.18 |
| 26 | + Compiling crossbeam-deque v0.8.5 |
| 27 | + Compiling rayon v1.10.0 |
| 28 | + Compiling xor_cryptor v1.2.3 |
| 29 | + Compiling rust_proj v0.1.0 (/home/slavetomints/training/picoCTF/rust-fixme-2/fixme2) |
| 30 | +error[E0596]: cannot borrow `*borrowed_string` as mutable, as it is behind a `&` reference |
| 31 | + --> src/main.rs:9:5 |
| 32 | + | |
| 33 | +9 | borrowed_string.push_str("PARTY FOUL! Here is your flag: "); |
| 34 | + | ^^^^^^^^^^^^^^^ `borrowed_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable |
| 35 | + | |
| 36 | +help: consider changing this to be a mutable reference |
| 37 | + | |
| 38 | +3 | fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){ // How do we pass values to a function that we want to change? |
| 39 | + | +++ |
| 40 | +
|
| 41 | +error[E0596]: cannot borrow `*borrowed_string` as mutable, as it is behind a `&` reference |
| 42 | + --> src/main.rs:20:5 |
| 43 | + | |
| 44 | +20 | borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer)); |
| 45 | + | ^^^^^^^^^^^^^^^ `borrowed_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable |
| 46 | + | |
| 47 | +help: consider changing this to be a mutable reference |
| 48 | + | |
| 49 | +3 | fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){ // How do we pass values to a function that we want to change? |
| 50 | + | +++ |
| 51 | +
|
| 52 | +For more information about this error, try `rustc --explain E0596`. |
| 53 | +error: could not compile `rust_proj` (bin "rust_proj") due to 2 previous errors |
| 54 | +``` |
| 55 | + |
| 56 | + |
| 57 | +Alrighty, with these error, let's take a look at the source code. |
| 58 | + |
| 59 | +```rust |
| 60 | +use xor_cryptor::XORCryptor; |
| 61 | + |
| 62 | +fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &String){ // How do we pass values to a function that we want to change? |
| 63 | + |
| 64 | + // Key for decryption |
| 65 | + let key = String::from("CSUCKS"); |
| 66 | + |
| 67 | + // Editing our borrowed value |
| 68 | + borrowed_string.push_str("PARTY FOUL! Here is your flag: "); |
| 69 | + |
| 70 | + // Create decrpytion object |
| 71 | + let res = XORCryptor::new(&key); |
| 72 | + if res.is_err() { |
| 73 | + return; // How do we return in rust? |
| 74 | + } |
| 75 | + let xrc = res.unwrap(); |
| 76 | + |
| 77 | + // Decrypt flag and print it out |
| 78 | + let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer); |
| 79 | + borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer)); |
| 80 | + println!("{}", borrowed_string); |
| 81 | +} |
| 82 | + |
| 83 | + |
| 84 | +fn main() { |
| 85 | + // Encrypted flag values |
| 86 | + 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"]; |
| 87 | + |
| 88 | + // Convert the hexadecimal strings to bytes and collect them into a vector |
| 89 | + let encrypted_buffer: Vec<u8> = hex_values.iter() |
| 90 | + .map(|&hex| u8::from_str_radix(hex, 16).unwrap()) |
| 91 | + .collect(); |
| 92 | + |
| 93 | + let party_foul = String::from("Using memory unsafe languages is a: "); // Is this variable changeable? |
| 94 | + decrypt(encrypted_buffer, &party_foul); // Is this the correct way to pass a value to a function so that it can be changed? |
| 95 | +} |
| 96 | +``` |
| 97 | +Okay, so now I see the issue. Whats happening in the `decrypt` function is that the `borrowed_string` variable is being edited via the `push_str` method, which appends a string onto another string. |
| 98 | + |
| 99 | +The first issue is that the `borrowed_string` variable isn't mutable, meaning that the variable's value can not change. By trying to change its value, we encounter an error during compilation and so the program wont run. We can fix this issue by changing the definition of the variable from `borrowed_string: $String` to `borrowed_string: $mut String`. |
| 100 | + |
| 101 | +However, this creates a new issue. The new issue with this is that that string that is passed to the `borrowed_string` in the function call isn't mutable either, so we need to make it mutable as well. We can do this by adding the `mut` keyword to the variable definition before the variable name, so `let party_foul` becomes `let mut party_foul`. And then we'll change how the variable is passed in the `main` function so that it is now `decrypt(encrypted_buffer, &mut party_foul);` |
| 102 | + |
| 103 | +Here's what the final code should look like: |
| 104 | +```rust |
| 105 | +use xor_cryptor::XORCryptor; |
| 106 | + |
| 107 | +fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){ // How do we pass values to a function that we want to change? |
| 108 | + |
| 109 | + // Key for decryption |
| 110 | + let key = String::from("CSUCKS"); |
| 111 | + |
| 112 | + // Editing our borrowed value |
| 113 | + borrowed_string.push_str("PARTY FOUL! Here is your flag: "); |
| 114 | + |
| 115 | + // Create decrpytion object |
| 116 | + let res = XORCryptor::new(&key); |
| 117 | + if res.is_err() { |
| 118 | + return; // How do we return in rust? |
| 119 | + } |
| 120 | + let xrc = res.unwrap(); |
| 121 | + |
| 122 | + // Decrypt flag and print it out |
| 123 | + let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer); |
| 124 | + borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer)); |
| 125 | + println!("{}", borrowed_string); |
| 126 | +} |
| 127 | + |
| 128 | + |
| 129 | +fn main() { |
| 130 | + // Encrypted flag values |
| 131 | + 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"]; |
| 132 | + |
| 133 | + // Convert the hexadecimal strings to bytes and collect them into a vector |
| 134 | + let encrypted_buffer: Vec<u8> = hex_values.iter() |
| 135 | + .map(|&hex| u8::from_str_radix(hex, 16).unwrap()) |
| 136 | + .collect(); |
| 137 | + |
| 138 | + let mut party_foul = String::from("Using memory unsafe languages is a: "); // Is this variable changeable? |
| 139 | + decrypt(encrypted_buffer, &mut party_foul); // Is this the correct way to pass a value to a function so that it can be changed? |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +And rerunning it gives us this: |
| 144 | + |
| 145 | +```terminal |
| 146 | +❯ cargo run |
| 147 | + Compiling rust_proj v0.1.0 (/home/slavetomints/training/picoCTF/rust-fixme-2/fixme2) |
| 148 | + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s |
| 149 | + Running `target/debug/rust_proj` |
| 150 | +Using memory unsafe languages is a: PARTY FOUL! Here is your flag: picoCTF{4r3_y0u_h4v1n5_fun_y31?} |
| 151 | +``` |
| 152 | + |
| 153 | +Success!!! |
| 154 | + |
| 155 | +FLAG: `picoCTF{4r3_y0u_h4v1n5_fun_y31?}` |
0 commit comments