From 7b1e83ec8200a7052fbb867de020336370ac3649 Mon Sep 17 00:00:00 2001 From: Matthew Ingwersen Date: Mon, 7 Jun 2021 20:52:24 -0400 Subject: [PATCH] Add regression test for directory traversal --- tests/data/directory_traversal.gmi | 1 + tests/tests.rs | 35 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/data/directory_traversal.gmi diff --git a/tests/data/directory_traversal.gmi b/tests/data/directory_traversal.gmi new file mode 100644 index 0000000..d66f0d6 --- /dev/null +++ b/tests/data/directory_traversal.gmi @@ -0,0 +1 @@ +This is a test file to check for directory traversal vulnerabilities. diff --git a/tests/tests.rs b/tests/tests.rs index 5be4b8f..07efe96 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -2,6 +2,7 @@ use anyhow::anyhow; use gemini_fetch::{Header, Page, Status}; use std::io::{BufRead, BufReader, Read}; use std::net::{SocketAddr, ToSocketAddrs}; +use std::path::PathBuf; use std::process::{Command, Stdio}; use url::Url; @@ -410,6 +411,40 @@ fn serve_secret() { assert_eq!(page.header.status, Status::Success); } +#[test] +/// - directory traversal attacks using percent-encoded path separators +/// fail (this addresses a previous vulnerability) +fn directory_traversal_regression() { + let base = Url::parse("gemini://localhost/").unwrap(); + + let mut absolute = base.clone(); + absolute + .path_segments_mut() + .unwrap() + .push(&env!("CARGO_MANIFEST_DIR")) // separators will be percent-encoded + .push("tests") + .push("data") + .push("directory_traversal.gmi"); + + let mut relative_escape_path = PathBuf::new(); + relative_escape_path.push("testdir"); + relative_escape_path.push(".."); + relative_escape_path.push(".."); + let mut relative = base.clone(); + relative + .path_segments_mut() + .unwrap() + .push(relative_escape_path.to_str().unwrap()) // separators will be percent-encoded + .push("directory_traversal.gmi"); + + let urls = [absolute, relative]; + for url in urls.iter() { + let page = + get(&["--addr", "[::]:1988"], addr(1988), url.as_str()).expect("could not get page"); + assert_eq!(page.header.status, Status::NotFound); + } +} + #[test] /// - if TLSv1.3 is selected, does not accept TLSv1.2 connections /// (lower versions do not have to be tested because rustls does not even