The Chemistry Of Code

During a discussion with hackers, one idea stuck: every hacker must be able to understand code, no matter how cryptic.

Hidden within obfuscated Rust code is a function that holds the flag. But it only unlocks when you reverse its logic and uncover the correct username and password.

Do you have what it takes to decode this tangled masterpiece? Dive into the chemistry of code and prove your skills.

Hint: Some secrets are worth their salt.

use base64::{engine::general_purpose::STANDARD, Engine};
use hex::encode as hex_encode;
use num_bigint::BigUint;
use std::io::{self, Write};

const FERROUS_OXIDE_USERNAME: &str = "AdminFeroxide";
const ANIONIC_PASSWORD: &str = "NjQzMzcyNzUzNTM3MzE2Njc5MzE2ZTM2";
const ALKALINE_SECRET: &str = "4143454354467B34707072336E373163335F3634322C28010D3461302C392E";

fn ionic_bond(cation_input: &str, anion_input: &str) {
    let cation_hex = hex_encode(cation_input);
    let anion_hex = hex_encode(anion_input);

    let cation_value = BigUint::parse_bytes(cation_hex.as_bytes(), 16).unwrap();
    let anion_value = BigUint::parse_bytes(anion_hex.as_bytes(), 16).unwrap();

    let covalent_link = &cation_value ^ &anion_value;

    let alkaline_secret_value = BigUint::parse_bytes(ALKALINE_SECRET.as_bytes(), 16).unwrap();
    let metallic_alloy = &covalent_link ^ &alkaline_secret_value;

    let precipitate = format!("{:x}", metallic_alloy);

    let alloy_compound = (0..precipitate.len())
        .step_by(2)
        .map(|i| u8::from_str_radix(&precipitate[i..i + 2], 16).unwrap() as char)
        .collect::<String>();

    println!("Crystallized Flag (ASCII): {}", alloy_compound);
}

fn reaction_chamber() {
    let mut username = String::new();
    print!("Introduce the Catalyst: ");
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut username).unwrap();
    let username = username.trim();

    let mut password = String::new();
    print!("Introduce the Reagent: ");
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut password).unwrap();
    let password = password.trim();
    
    if username != FERROUS_OXIDE_USERNAME {
        println!("Reaction denied: Unstable molecule detected.");
        return;
    }
    
    let reagent_ion = STANDARD.encode(hex_encode(password).as_bytes());
    if reagent_ion != ANIONIC_PASSWORD {
        println!("Reaction denied: Unstable molecule detected.");
        return;
    }

    ionic_bond(username, password);
}

fn main() {
    reaction_chamber();
}

Solution

Overall, one of the easier ones, reaction_chamber acts as the main function.

The program does the following:

  • Read the username from stdin as a line
  • Read the password from stdin as a line
  • Early returns if username is not equal to AdminFeroxide
  • Encodes the password as follows:
    • Consider the password as raw bytes and encode that as hex
    • Encode the result of previous step as base64
  • Early returns if the encoded password is not equal to the constant ANIONIC_PASSWORD
  • Proceeds to print the flag

So, to get the correct password, we need to reverse the encoding process.

We decode the ANIONIC_PASSWORD from base64 and get

643372753537316679316e36

Decoding this as hex, we get

d3ru571fy1n6

Inputting this as the password, we get:

Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/chemistryofcode`

Introduce the Catalyst: AdminFeroxide
Introduce the Reagent: d3ru571fy1n6
Crystallized Flag (ASCII): ACECTF{4ppr3n71c3_w4l73r_wh1t3}

ACECTF{4ppr3n71c3_w4l73r_wh1t3}