Rust Fixme 1

Download and extract the files.

gzip -d fixme1.tar.gz
tar -xvf fixme1.tar

Here’s the Rust file (main.rs).

use xor_cryptor::XORCryptor;

fn main() {
    // Key for decryption
    let key = String::from("CSUCKS") // How do we end statements in Rust?

    // Encrypted flag values
    let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "01", "1c", "7e", "59", "63", "e1", "61", "25", "7f", "5a", "60", "50", "11", "38", "1f", "3a", "60", "e9", "62", "20", "0c", "e6", "50", "d3", "35"];

    // 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();

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

    // Decrypt flag and print it out
    let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
    println!(
        ":?", // How do we print out a variable in the println function? 
        String::from_utf8_lossy(&decrypted_buffer)
    );
}

You can use cargo run or cargo run main.rs to run the rust file.

Running Cargo prints out three errors.

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/hwkim301/picoctf/pwn/rust_fixme/fixme1)
error: expected `;`, found keyword `let`
 --> src/main.rs:5:37
  |
5 |     let key = String::from("CSUCKS") // How do we end statements in Rust?
  |                                     ^ help: add `;` here
...
8 |     let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "01", "1c", "7e", "59", "63", "e1", "61", "25", "7f", "5a", "60", "50", "11", "38"...
  |     --- unexpected token

error: argument never used
  --> src/main.rs:26:9
   |
25 |         ":?", // How do we print out a variable in the println function? 
   |         ---- formatting specifier missing
26 |         String::from_utf8_lossy(&decrypted_buffer)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument never used

error[E0425]: cannot find value `ret` in this scope
  --> src/main.rs:18:9
   |
18 |         ret; // How do we return in rust?
   |         ^^^ help: a local variable with a similar name exists: `res`

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

Explanation

The first error can be fixed by adding a ; at the end, since Rust is similar to C and C++ in this regard.

let key = String::from("CSUCKS"); // How do we end statements in Rust?

The second error was a bit tricky, if you look carefully there isn’t a ret variable.

So return ret, which I initially tried didn’t work.

Instead, we should just quit the program using return.

if res.is_err() {
    return;  // How do we return in rust?
  }

The third error was tricky as well.

To print a variable using println in Rust you need to use "{ }".

println!(
      "{}", // How do we print out a variable in the println function? 
      String::from_utf8_lossy(&decrypted_buffer)
  );

After fixing the code and running cargo run main.rs, gets you the flag.

picoCTF{4r3_y0u_4_ru$t4c30n_n0w?}

I don’t think I’m a Rustacean yet, lol.

I even have to look at a writeup because the Rust code was a bit daunting for me.

Rust Fixme 2

Here’s the second challenge.

I solved the following 2 challenges on my own without any Googling or with the help of writeups.

I’m proud of myself.

Extract the files as usual.

gzip -d fixme2.tar.gz
tar -xvf fixme2.tar

Here’s the Rust code.

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?
}

Let’s run the code.

cargo run main.rs

We get three errors when running the code this time.

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 the data it refers to 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 the data it refers to 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

Explanation

The nice thing about Rust and Cargo is that when I get an error, it gives a detailed explanation on the error and a possible solution as well.

Even if you don’t know barely any Rust, it tells you how you can fix the errors with the green modifications, similar to what we see in git.

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

Cargo tells us to use the mut keyword when we want to pass values to a function that we want to change.

So I added a mut before String.

fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){
}

The second error tells us that even though borrowed_string is a mutable, it’s currently a & reference.

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 the data it refers to cannot be borrowed
   as mutable

Simply adding the mut keyword before String in borrowed_string fixes the problem.

borrowed_string.push_str(&mut String::from_utf8_lossy(&decrypted_buffer));

The decrypt function call doesn’t match the decrypt function declaration above; the second argument needs a &mut type as well.

Be careful to not add any spaces between & and mut; it needs to be &mut.

decrypt(encrypted_buffer, &mut party_foul); // Is this the correct way to pass a value to a function so that it can be changed?

You need to add mut to the party_foul variable because it’s a mutable.

let mut party_foul = String::from("Using memory unsafe languages is a: "); // Is this variable changeable?

Fixing the code and running cargo will give you the flag.

cargo run main.rs
picoCTF{4r3_y0u_h4v1n5_fun_y31?}

Rust Fixme 3

Here’s the final Rust challenge.

Download and extract the files.

gzip -d fixme3.tar.gz
tar -xvf fixme3.tar

Here’s the code, it’s quite different from the first two.

use xor_cryptor::XORCryptor;

fn decrypt(encrypted_buffer: Vec<u8>, borrowed_string: &mut String) {
    // Key for decryption
    let key = String::from("CSUCKS");

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

    // Create decryption object
    let res = XORCryptor::new(&key);
    if res.is_err() {
        return;
    }
    let xrc = res.unwrap();

    // Did you know you have to do "unsafe operations in Rust?
    // https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
    // Even though we have these memory safe languages, sometimes we need to do things outside of the rules
    // This is where unsafe rust comes in, something that is important to know about in order to keep things in perspective
    
    // unsafe {
        // Decrypt the flag operations 
        let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);

        // Creating a pointer 
        let decrypted_ptr = decrypted_buffer.as_ptr();
        let decrypted_len = decrypted_buffer.len();
        
        // Unsafe operation: calling an unsafe function that dereferences a raw pointer
        let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len);

        borrowed_string.push_str(&String::from_utf8_lossy(decrypted_slice));
    // }
    println!("{}", borrowed_string);
}

fn main() {
    // Encrypted flag values
    let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "12", "90", "7e", "53", "63", "e1", "01", "35", "7e", "59", "60", "f6", "03", "86", "7f", "56", "41", "29", "30", "6f", "08", "c3", "61", "f9", "35"];

    // 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 mut party_foul = String::from("Using memory unsafe languages is a: ");
    decrypt(encrypted_buffer, &mut party_foul);
}

Running the code prints an error.

error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
  --> src/main.rs:31:31
   |
31 |         let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len);
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
   |
   = note: consult the function's documentation for information on how to avoid undefined behavior

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

I don’t know what an unsafe function is in Rust.

Cargo tells us that this line is unsafe.

You can use rustc --explain E0133 to get some more details on the error.

Here’s what --explain flag prints out.

Unsafe code was used outside of an unsafe block.

Erroneous code example:

unsafe fn f() { return; } // This is the unsafe code

fn main() {
    f(); // error: call to unsafe function requires unsafe function or block
}

Using unsafe functionality is potentially dangerous and disallowed by safety checks. Examples:

*   Dereferencing raw pointers
*   Calling functions via FFI
*   Calling functions marked unsafe

These safety checks can be relaxed for a section of the code by wrapping the unsafe instructions with an unsafe block. For instance:

unsafe fn f() { return; }

fn main() {
    unsafe { f(); } // ok!
}

See the unsafe section of the Book for more details.

Unsafe code in functions
Unsafe code is currently accepted in unsafe functions, but that is being phased out in favor of requiring unsafe
blocks here too.

unsafe fn f() { return; }

unsafe fn g() {
    f(); // Is accepted, but no longer recommended
    unsafe { f(); } // Recommended way to write this
}

Linting against this is controlled via the unsafe_op_in_unsafe_fn lint, which is allow by default but will be upgraded to warn in a future
edition.

Explanation

rustc --explain E0133 guides us that if we want to run unsafe functions in Rust we should use wrap the function with unsafe { }.

I added the unsafe {}.

// let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len);
let decrypted_slice = unsafe { std::slice::from_raw_parts(decrypted_ptr, decrypted_len) };

Ran cargo with cargo run main.rs and got the flag.

picoCTF{n0w_y0uv3_f1x3d_1h3m_411}

I remember I couldn’t solve any of the Rust challenges in this year’s CTF.

If you haven’t written Rust code before, it can be a bit intimidating to solve these Rust challenges.

However Cargo will guide you so you can solve the problems without any prior knowledge.

Having heard of Cargo is probably the only prior knowledge you need, but I’m sure most people know that from installing pwninit.

Reference Writeup