From 31b813129b57c5a5570228264458da3051b7357a Mon Sep 17 00:00:00 2001 From: Nicholas O'Brien Date: Wed, 21 Feb 2024 15:36:00 +0000 Subject: [PATCH 1/2] made things less secure and also less async --- .../lib/eldritch/src/http/download_impl.rs | 5 +- implants/lib/eldritch/src/http/get_impl.rs | 27 ++++------ implants/lib/eldritch/src/http/post_impl.rs | 54 ++++++++++--------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/implants/lib/eldritch/src/http/download_impl.rs b/implants/lib/eldritch/src/http/download_impl.rs index 294526b72..26d0a95cb 100644 --- a/implants/lib/eldritch/src/http/download_impl.rs +++ b/implants/lib/eldritch/src/http/download_impl.rs @@ -12,7 +12,10 @@ async fn handle_download(uri: String, dst: String) -> Result<()> { // Download as a stream of bytes. // there's no checking at all happening here, for anything - let mut stream = reqwest::get(uri).await?.bytes_stream(); + let client = reqwest::Client::builder() + .danger_accept_invalid_certs(true) + .build()?; + let mut stream = client.get(uri).send().await?.bytes_stream(); // Write the stream of bytes to the file in chunks while let Some(chunk_result) = stream.next().await { diff --git a/implants/lib/eldritch/src/http/get_impl.rs b/implants/lib/eldritch/src/http/get_impl.rs index e724d3f3a..7bb082447 100644 --- a/implants/lib/eldritch/src/http/get_impl.rs +++ b/implants/lib/eldritch/src/http/get_impl.rs @@ -10,9 +10,6 @@ pub fn get( ) -> Result { let mut query_map = HashMap::new(); let mut headers_map = HeaderMap::new(); - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build()?; if let Some(q) = query_params { for (k, v) in q { @@ -28,26 +25,20 @@ pub fn get( } } - runtime.block_on(handle_get(uri, query_map, headers_map)) -} - -async fn handle_get( - uri: String, - query_params: HashMap, - headers: HeaderMap, -) -> Result { #[cfg(debug_assertions)] log::info!( - "eldritch sending HTTP GET request to '{}' with headers '{:#?}'", + "eldritch sending HTTP GET request to '{}' with headers '{:#?}' and query_params '{:#?}'", uri, - headers + headers_map, + query_map ); - let client = reqwest::Client::new() - .get(uri) - .headers(headers) - .query(&query_params); - let resp = client.send().await?.text().await?; + let client = reqwest::blocking::Client::builder() + .danger_accept_invalid_certs(true) + .build()?; + + let req = client.get(uri).headers(headers_map).query(&query_map); + let resp = req.send()?.text()?; Ok(resp) } diff --git a/implants/lib/eldritch/src/http/post_impl.rs b/implants/lib/eldritch/src/http/post_impl.rs index 091d32b88..af6d06286 100644 --- a/implants/lib/eldritch/src/http/post_impl.rs +++ b/implants/lib/eldritch/src/http/post_impl.rs @@ -10,9 +10,6 @@ pub fn post( headers: Option>, ) -> Result { let mut headers_map = HeaderMap::new(); - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build()?; if let Some(h) = headers { for (k, v) in h { @@ -22,8 +19,22 @@ pub fn post( } } - if body.is_some() { - return runtime.block_on(handle_post(uri, body, None, headers_map)); + let client = reqwest::blocking::Client::builder() + .danger_accept_invalid_certs(true) + .build()?; + let req = client.post(uri.clone()).headers(headers_map.clone()); + + if let Some(b) = body { + #[cfg(debug_assertions)] + log::info!( + "eldritch sending HTTP POST request to '{}' with headers '{:#?}' and body '{}'", + uri, + headers_map, + b.clone() + ); + + let resp = req.body(b).send()?.text()?; + return Ok(resp); } if let Some(f) = form { @@ -32,35 +43,26 @@ pub fn post( form_map.insert(k, v); } - return runtime.block_on(handle_post(uri, None, Some(form_map), headers_map)); - } + #[cfg(debug_assertions)] + log::info!( + "eldritch sending HTTP POST request to '{}' with headers '{:#?}' and form '{:#?}'", + uri, + headers_map, + form_map.clone() + ); - runtime.block_on(handle_post(uri, None, None, headers_map)) -} + let resp = req.form(&form_map).send()?.text()?; + return Ok(resp); + } -async fn handle_post( - uri: String, - body: Option, - form: Option>, - headers: HeaderMap, -) -> Result { #[cfg(debug_assertions)] log::info!( "eldritch sending HTTP POST request to '{}' with headers '{:#?}'", uri, - headers + headers_map ); - let client = reqwest::Client::new().post(uri).headers(headers); - if let Some(b) = body { - let resp = client.body(b).send().await?.text().await?; - return Ok(resp); - } - if let Some(f) = form { - let resp = client.form(&f).send().await?.text().await?; - return Ok(resp); - } - let resp = client.send().await?.text().await?; + let resp = req.send()?.text()?; Ok(resp) } From b044ca07105ab248274837325d4b0a121de0ed88 Mon Sep 17 00:00:00 2001 From: Nicholas O'Brien Date: Wed, 21 Feb 2024 15:49:35 +0000 Subject: [PATCH 2/2] make things slightly more secure --- docs/_docs/user-guide/eldritch.md | 8 +++--- .../lib/eldritch/src/http/download_impl.rs | 15 +++++++---- implants/lib/eldritch/src/http/get_impl.rs | 20 +++++++++------ implants/lib/eldritch/src/http/mod.rs | 12 ++++----- implants/lib/eldritch/src/http/post_impl.rs | 25 ++++++++++++++----- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/docs/_docs/user-guide/eldritch.md b/docs/_docs/user-guide/eldritch.md index 361729a12..2132a69be 100644 --- a/docs/_docs/user-guide/eldritch.md +++ b/docs/_docs/user-guide/eldritch.md @@ -414,21 +414,23 @@ The file.find method finds all files matching the used parameters. Return ## HTTP +The HTTP library also allows the user to allow the http client to ignore TLS validation via the `allow_insecure` optional parameter (defaults to `false`). + ### http.download -`http.download(uri: str, dst: str) -> None` +`http.download(uri: str, dst: str, allow_insecure: Option) -> None` The http.download method downloads a file at the URI specified in `uri` to the path specified in `dst`. If a file already exists at that location, it will be overwritten. ### http.get -`http.get(uri: str, query_params: Option>, headers: Option>) -> str` +`http.get(uri: str, query_params: Option>, headers: Option>, allow_insecure: Option) -> str` The http.get method sends an HTTP GET request to the URI specified in `uri` with the optional query paramters specified in `query_params` and headers specified in `headers`, then return the response body as a string. Note: in order to conform with HTTP2+ all header names are transmuted to lowercase. ### http.post -`http.post(uri: str, body: Option, form: Option>, headers: Option>) -> str` +`http.post(uri: str, body: Option, form: Option>, headers: Option>, allow_insecure: Option) -> str` The http.post method sends an HTTP POST request to the URI specified in `uri` with the optional request body specified by `body`, form paramters specified in `form`, and headers specified in `headers`, then return the response body as a string. Note: in order to conform with HTTP2+ all header names are transmuted to lowercase. Other Note: if a `body` and a `form` are supplied the value of `body` will be used. diff --git a/implants/lib/eldritch/src/http/download_impl.rs b/implants/lib/eldritch/src/http/download_impl.rs index 26d0a95cb..6057d4854 100644 --- a/implants/lib/eldritch/src/http/download_impl.rs +++ b/implants/lib/eldritch/src/http/download_impl.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use tokio::{fs::File, io::AsyncWriteExt}; use tokio_stream::StreamExt; -async fn handle_download(uri: String, dst: String) -> Result<()> { +async fn handle_download(uri: String, dst: String, allow_insecure: bool) -> Result<()> { // Create our file let mut dest = { let fname = PathBuf::from(dst); @@ -13,7 +13,7 @@ async fn handle_download(uri: String, dst: String) -> Result<()> { // Download as a stream of bytes. // there's no checking at all happening here, for anything let client = reqwest::Client::builder() - .danger_accept_invalid_certs(true) + .danger_accept_invalid_certs(allow_insecure) .build()?; let mut stream = client.get(uri).send().await?.bytes_stream(); @@ -28,12 +28,17 @@ async fn handle_download(uri: String, dst: String) -> Result<()> { Ok(()) } -pub fn download(uri: String, dst: String) -> Result<()> { +pub fn download(uri: String, dst: String, allow_insecure: Option) -> Result<()> { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build()?; - let response = runtime.block_on(handle_download(uri, dst)); + let mut insecure = false; + if let Some(a) = allow_insecure { + insecure = a; + } + + let response = runtime.block_on(handle_download(uri, dst, insecure)); match response { Ok(_) => Ok(()), @@ -66,7 +71,7 @@ mod tests { let url = server.url("/foo").to_string(); // run our code - download(url, path.clone())?; + download(url, path.clone(), None)?; // Read the file let contents = read_to_string(path.clone())?; diff --git a/implants/lib/eldritch/src/http/get_impl.rs b/implants/lib/eldritch/src/http/get_impl.rs index 7bb082447..1a469f6e6 100644 --- a/implants/lib/eldritch/src/http/get_impl.rs +++ b/implants/lib/eldritch/src/http/get_impl.rs @@ -7,6 +7,7 @@ pub fn get( uri: String, query_params: Option>, headers: Option>, + allow_insecure: Option, ) -> Result { let mut query_map = HashMap::new(); let mut headers_map = HeaderMap::new(); @@ -33,8 +34,13 @@ pub fn get( query_map ); + let mut insecure = false; + if let Some(a) = allow_insecure { + insecure = a; + } + let client = reqwest::blocking::Client::builder() - .danger_accept_invalid_certs(true) + .danger_accept_invalid_certs(insecure) .build()?; let req = client.get(uri).headers(headers_map).query(&query_map); @@ -62,7 +68,7 @@ mod tests { let url = server.url("/foo").to_string(); // run our code - let contents = get(url, None, None)?; + let contents = get(url, None, None, None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -83,7 +89,7 @@ mod tests { let url = server.url("/foo").to_string(); // run our code - let contents = get(url, Some(SmallMap::new()), Some(SmallMap::new()))?; + let contents = get(url, Some(SmallMap::new()), Some(SmallMap::new()), None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -111,7 +117,7 @@ mod tests { params.insert("a".to_string(), "true".to_string()); params.insert("b".to_string(), "bar".to_string()); params.insert("c".to_string(), "3".to_string()); - let contents = get(url, Some(params), None)?; + let contents = get(url, Some(params), None, None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -138,7 +144,7 @@ mod tests { let mut params = SmallMap::new(); params.insert("b".to_string(), "bar".to_string()); params.insert("c".to_string(), "3".to_string()); - let contents = get(url, Some(params), None)?; + let contents = get(url, Some(params), None, None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -164,7 +170,7 @@ mod tests { let mut headers = SmallMap::new(); headers.insert("A".to_string(), "TRUE".to_string()); headers.insert("b".to_string(), "bar".to_string()); - let contents = get(url, None, Some(headers))?; + let contents = get(url, None, Some(headers), None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -193,7 +199,7 @@ mod tests { headers.insert("b".to_string(), "bar".to_string()); let mut params = SmallMap::new(); params.insert("c".to_string(), "3".to_string()); - let contents = get(url, Some(params), Some(headers))?; + let contents = get(url, Some(params), Some(headers), None)?; // check request returned correctly assert_eq!(contents, "test body"); diff --git a/implants/lib/eldritch/src/http/mod.rs b/implants/lib/eldritch/src/http/mod.rs index 148013415..6069087b7 100644 --- a/implants/lib/eldritch/src/http/mod.rs +++ b/implants/lib/eldritch/src/http/mod.rs @@ -23,18 +23,18 @@ crate::eldritch_lib!(HTTPLibrary, "http_library"); #[allow(clippy::needless_lifetimes, clippy::type_complexity, clippy::too_many_arguments)] fn methods(builder: &mut MethodsBuilder) { #[allow(unused_variables)] - fn download(this: &HTTPLibrary, uri: String, dst: String) -> anyhow::Result { - download_impl::download(uri, dst)?; + fn download(this: &HTTPLibrary, uri: String, dst: String, allow_insecure: Option) -> anyhow::Result { + download_impl::download(uri, dst, allow_insecure)?; Ok(NoneType{}) } #[allow(unused_variables)] - fn get(this: &HTTPLibrary, uri: String, query_params: Option>, headers: Option>) -> anyhow::Result { - get_impl::get(uri, query_params, headers) + fn get(this: &HTTPLibrary, uri: String, query_params: Option>, headers: Option>, allow_insecure: Option) -> anyhow::Result { + get_impl::get(uri, query_params, headers, allow_insecure) } #[allow(unused_variables)] - fn post(this: &HTTPLibrary, uri: String, body: Option, form: Option>, headers: Option>) -> anyhow::Result { - post_impl::post(uri, body, form, headers) + fn post(this: &HTTPLibrary, uri: String, body: Option, form: Option>, headers: Option>, allow_insecure: Option) -> anyhow::Result { + post_impl::post(uri, body, form, headers, allow_insecure) } } diff --git a/implants/lib/eldritch/src/http/post_impl.rs b/implants/lib/eldritch/src/http/post_impl.rs index af6d06286..d10f97e95 100644 --- a/implants/lib/eldritch/src/http/post_impl.rs +++ b/implants/lib/eldritch/src/http/post_impl.rs @@ -8,6 +8,7 @@ pub fn post( body: Option, form: Option>, headers: Option>, + allow_insecure: Option, ) -> Result { let mut headers_map = HeaderMap::new(); @@ -19,8 +20,13 @@ pub fn post( } } + let mut insecure = false; + if let Some(a) = allow_insecure { + insecure = a; + } + let client = reqwest::blocking::Client::builder() - .danger_accept_invalid_certs(true) + .danger_accept_invalid_certs(insecure) .build()?; let req = client.post(uri.clone()).headers(headers_map.clone()); @@ -86,7 +92,7 @@ mod tests { let url = server.url("/foo").to_string(); // run our code - let contents = post(url, None, None, None)?; + let contents = post(url, None, None, None, None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -107,7 +113,13 @@ mod tests { let url = server.url("/foo").to_string(); // run our code - let contents = post(url, None, Some(SmallMap::new()), Some(SmallMap::new()))?; + let contents = post( + url, + None, + Some(SmallMap::new()), + Some(SmallMap::new()), + None, + )?; // check request returned correctly assert_eq!(contents, "test body"); @@ -135,7 +147,7 @@ mod tests { params.insert("a".to_string(), "true".to_string()); params.insert("b".to_string(), "bar".to_string()); params.insert("c".to_string(), "3".to_string()); - let contents = post(url, None, Some(params), None)?; + let contents = post(url, None, Some(params), None, None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -161,7 +173,7 @@ mod tests { let mut headers = SmallMap::new(); headers.insert("A".to_string(), "TRUE".to_string()); headers.insert("b".to_string(), "bar".to_string()); - let contents = post(url, None, None, Some(headers))?; + let contents = post(url, None, None, Some(headers), None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -190,7 +202,7 @@ mod tests { headers.insert("b".to_string(), "bar".to_string()); let mut params = SmallMap::new(); params.insert("c".to_string(), "3".to_string()); - let contents = post(url, None, Some(params), Some(headers))?; + let contents = post(url, None, Some(params), Some(headers), None)?; // check request returned correctly assert_eq!(contents, "test body"); @@ -220,6 +232,7 @@ mod tests { Some(String::from("the quick brown fox jumps over the lazy dog")), None, Some(headers), + None, )?; // check request returned correctly