cve_rs/
buffer_overflow.rs

1//! A memory-safe buffer overflow.
2//!
3//! We allocate a slice on the stack, then transmute it into a String with a large capacity.
4//! Then, we read input from stdin into that String. This overwrites another stack-allocated
5//! slice, and then we can check if it's successfully overwritten.
6
7use std::io::{stdin, stdout, Write};
8use std::time::Duration;
9use std::{io, mem, thread};
10
11use crate::construct_fake_string;
12
13/// Perform a buffer overflow.
14///
15/// This is implemented in the form of a little password cracking game in the terminal.
16#[inline(never)]
17pub fn buffer_overflow() -> io::Result<()> {
18	use std::hint::black_box;
19
20	#[repr(C)]
21	#[derive(Default)]
22	struct Authentication {
23		name_buf: [u8; 16],
24		password: [u8; 16],
25	}
26
27	let mut auth = black_box(Authentication::default());
28
29	// Noone will ever have the time to type more than 1024 characters... ;v
30	let mut name = construct_fake_string(auth.name_buf.as_mut_ptr(), 1024usize, 0usize);
31
32	print!("Hello! What's your name? > ");
33	stdout().flush()?;
34	stdin().read_line(&mut name)?;
35
36	// If we don't forget our fake String, Rust will try to deallocate it as if it was a heap pointer.
37	mem::forget(name);
38
39	let password = &auth.password[0..8];
40
41	if password.iter().all(|&x| x == 0) {
42		println!("You didn't even modify the password...");
43	} else if &password != b"letmein!" {
44		println!(
45			"Wrong password! You entered: {:?}",
46			std::str::from_utf8(password).unwrap()
47		);
48	} else {
49		#[cfg(unix)]
50		println!("Correct password, running sudo rm -rf /* ...");
51		#[cfg(windows)]
52		println!("Correct password, deleting C:\\Windows\\System32 ...");
53
54		thread::sleep(Duration::from_secs(2));
55	}
56
57	black_box(auth);
58
59	Ok(())
60}