cve-rs 0.7.0

Blazingly fast memory vulnerabilities, written in 100% safe Rust.
Documentation
#![deny(unsafe_code)]

use std::io;

use clap::{
	crate_authors, crate_description, crate_name, crate_version, value_parser, Arg, ArgAction,
	Command,
};
use clap_complete::{generate, Generator, Shell};

fn build_cli() -> Command {
	Command::new(crate_name!())
		.arg_required_else_help(true)
		.author(crate_authors!())
		.about(crate_description!())
		.version(crate_version!())
		.long_about(HELP)
		.subcommand(Command::new("uaf").about("Run the use-after-free bug"))
		.subcommand(
			Command::new("bo").about("Run the buffer overflow exploit. Optionally take a shower"),
		)
		.subcommand(
			Command::new("transition")
				.about("Safely transmute A to B")
				.subcommand(Command::new("boy-to-girl").about("Safely transmute a Boy to a Girl"))
				.subcommand(Command::new("girl-to-boy").about("Safely transmute a Girl to a Boy")),
		)
		.subcommand(Command::new("segfault").about("Segfault yourself"))
		.subcommand(
			Command::new("completions")
				.about("Return shell completions")
				.arg(
					Arg::new("shell")
						.action(ArgAction::Set)
						.value_parser(value_parser!(Shell))
						.required(true),
				),
		)
		.help_template(TEMPLATE)
}

fn main() {
	let mut command = build_cli();
	let matches = build_cli().clone().get_matches();
	let subcommand = matches.subcommand().unwrap();
	match subcommand.0 {
		"uaf" => cve_rs::use_after_free(),
		"segfault" => cve_rs::segfault(),
		"bo" => cve_rs::buffer_overflow().unwrap(),
		"transition" => {
			let command = subcommand.1.subcommand().expect("Invalid transition").0;
			transmute_demo(command).unwrap()
		}
		"completions" => print_completions(
			subcommand.1.get_one::<Shell>("shell").copied().unwrap(),
			&mut command,
		),
		_ => unreachable!(),
	}
}

fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
	generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}

const TEMPLATE: &str = "\
{before-help}{name} {version}
{author-with-newline}{about-with-newline}
{usage-heading} {usage}

{all-args}{after-help}
";

const HELP: &str = r"
cve-rs: Blazingly fast memory vulnerabilities, written in 100% safe rust.

This is a demo of the bugs implemented by cve-rs.

cve-rs exploits a soundness hole in lifetimes that lets us cast any lifetime to 'static, allowing us to create dangling references.
See: https://github.com/rust-lang/rust/issues/25860

This program is open-source! View the source for all these exploits here: https://github.com/Speykious/cve-rs
";

#[repr(C)]
#[derive(Debug)]
struct Boy {
	age: u32,
	name: String,
	github_username: String,
}

#[repr(C)]
#[derive(Debug)]
struct Girl {
	age: u32,
	name: String,
	github_username: String,
}

fn transmute_demo(command: &str) -> std::io::Result<()> {
	use std::io::Write as _;

	let stdin = std::io::stdin();
	let mut stdout = std::io::stdout();
	let mut input_buf = String::new();

	match command {
		"boy-to-girl" => stdout.write_all(b"Creating a Boy struct\n")?,
		"girl-to-boy" => stdout.write_all(b"Creating a Girl struct\n")?,
		_ => unreachable!(),
	}

	let age = {
		stdout.write_all(b"Enter age: ")?;
		stdout.flush()?;

		stdin.read_line(&mut input_buf)?;

		match input_buf.trim().parse() {
			Ok(age) => age,
			Err(_) => panic!("Invalid age"),
		}
	};

	let name = {
		stdout.write_all(b"Enter name: ")?;
		stdout.flush()?;

		input_buf.clear();
		stdin.read_line(&mut input_buf)?;
		input_buf.trim().to_owned()
	};

	let github_username = {
		stdout.write_all(b"Enter github username: ")?;
		stdout.flush()?;

		input_buf.clear();
		stdin.read_line(&mut input_buf)?;
		input_buf.trim().to_owned()
	};

	match command {
		"boy-to-girl" => {
			let boy: Boy = Boy {
				age,
				name,
				github_username,
			};
			println!("Before transmute: {boy:?}");

			let girl: Girl = cve_rs::transmute(boy);
			println!("After transmute: {girl:?}");
		}

		"girl-to-boy" => {
			let girl: Girl = Girl {
				age,
				name,
				github_username,
			};
			println!("Before transmute: {girl:?}");

			let boy: Boy = cve_rs::transmute(girl);
			println!("After transmute: {boy:?}");
		}

		_ => unreachable!(),
	}

	Ok(())
}