Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
 
created the manual client for tavern so we can change callback url (#457)

* created the manual client for tavern so we can change callback url

* undoing needless change

* kyle fix
  • Loading branch information
Cictrone authored Jan 22, 2024
1 parent 93d885f commit 57c2878
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 19 deletions.
11 changes: 3 additions & 8 deletions implants/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
[workspace]
members = [
"imix",
"golem",
"lib/eldritch",
"lib/c2",
]
members = ["imix", "golem", "lib/eldritch", "lib/c2"]
resolver = "2"

[workspace.dependencies]
Expand Down Expand Up @@ -76,8 +71,8 @@ windows-sys = "0.45.0"
winreg = "0.51.0"

[profile.release]
strip = true # Automatically strip symbols from the binary.
opt-level = "z" # Optimize for size.
strip = true # Automatically strip symbols from the binary.
opt-level = "z" # Optimize for size.
lto = true
codegen-units = 1
panic = "abort"
Expand Down
6 changes: 3 additions & 3 deletions implants/imix/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use c2::pb::c2_client::C2Client;
use c2::pb::c2_manual_client::TavernClient;
use c2::pb::TaskOutput;
use clap::{arg, Command};
use imix::exec::AsyncTask;
Expand Down Expand Up @@ -61,8 +61,8 @@ async fn main_loop(config_path: String, _loop_count_max: Option<i32>) -> Result<
let cur_callback_uri = get_callback_uri(imix_config.clone())?;

// 1b) Setup the tavern client
let tavern_client = match C2Client::connect(cur_callback_uri.clone()).await {
Ok(tavern_client_local) => tavern_client_local,
let tavern_client = match TavernClient::connect(cur_callback_uri.clone()).await {
Ok(t) => t,
Err(_err) => {
#[cfg(debug_assertions)]
eprintln!("failed to create tavern client {}", _err);
Expand Down
8 changes: 4 additions & 4 deletions implants/imix/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::exec::{handle_exec_timeout_and_response, AsyncTask};
use crate::init::AgentProperties;
use crate::{Config, TaskID};
use anyhow::{Context, Result};
use c2::pb::c2_client::C2Client;
use c2::pb::c2_manual_client::TavernClient;
use c2::pb::{
Agent, Beacon, ClaimTasksRequest, Host, ReportTaskOutputRequest, ReportTaskOutputResponse,
Task, TaskOutput,
Expand All @@ -19,7 +19,7 @@ use tonic::Status;
pub async fn get_new_tasks(
agent_properties: AgentProperties,
imix_config: Config,
mut tavern_client: C2Client<Channel>,
mut tavern_client: TavernClient,
) -> Result<Vec<Task>> {
let req = tonic::Request::new(ClaimTasksRequest {
beacon: Some(Beacon {
Expand Down Expand Up @@ -174,7 +174,7 @@ fn queue_task_output(

pub async fn submit_task_output(
loop_start_time: Instant,
mut tavern_client: C2Client<Channel>,
mut tavern_client: TavernClient,
all_exec_futures: &mut HashMap<TaskID, AsyncTask>,
running_task_res_map: &mut HashMap<TaskID, Vec<TaskOutput>>,
) -> Result<()> {
Expand Down Expand Up @@ -217,7 +217,7 @@ pub async fn submit_task_output(
}

async fn send_tavern_output(
tavern_client: &mut C2Client<Channel>,
tavern_client: &mut TavernClient,
output: TaskOutput,
) -> Result<tonic::Response<ReportTaskOutputResponse>, Status> {
let req = tonic::Request::new(ReportTaskOutputRequest {
Expand Down
87 changes: 87 additions & 0 deletions implants/lib/c2/src/c2_manual.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
pub mod c2_manual_client {

use tonic::codec::ProstCodec;
use tonic::GrpcMethod;

static CLAIM_TASKS_PATH: &str = "/c2.C2/ClaimTasks";
static REPORT_TASK_OUTPUT_PATH: &str = "/c2.C2/ReportTaskOutput";
static DOWNLOAD_FILE_PATH: &str = "/c2.C2/DownloadFile";

#[derive(Debug, Clone)]
pub struct TavernClient {
grpc: tonic::client::Grpc<tonic::transport::Channel>,
}

impl TavernClient {
pub async fn connect(callback: String) -> Result<Self, tonic::transport::Error> {
let endpoint = tonic::transport::Endpoint::from_shared(callback)?;
let channel = endpoint.connect().await?;
let grpc = tonic::client::Grpc::new(channel);
Ok(Self { grpc })
}

pub async fn claim_tasks(
&mut self,
request: impl tonic::IntoRequest<super::ClaimTasksRequest>,
) -> std::result::Result<tonic::Response<super::ClaimTasksResponse>, tonic::Status>
{
self.grpc.ready().await.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e),
)
})?;
let codec: ProstCodec<super::ClaimTasksRequest, super::ClaimTasksResponse> =
tonic::codec::ProstCodec::default();

let path = tonic::codegen::http::uri::PathAndQuery::from_static(CLAIM_TASKS_PATH);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("c2.C2", "ClaimTasks"));
self.grpc.unary(req, path, codec).await
}

pub async fn report_task_output(
&mut self,
request: impl tonic::IntoRequest<super::ReportTaskOutputRequest>,
) -> std::result::Result<tonic::Response<super::ReportTaskOutputResponse>, tonic::Status>
{
self.grpc.ready().await.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e),
)
})?;
let codec: ProstCodec<super::ReportTaskOutputRequest, super::ReportTaskOutputResponse> =
tonic::codec::ProstCodec::default();
let path =
tonic::codegen::http::uri::PathAndQuery::from_static(REPORT_TASK_OUTPUT_PATH);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("c2.C2", "ReportTaskOutput"));
self.grpc.unary(req, path, codec).await
}

pub async fn download_file(
&mut self,
request: impl tonic::IntoRequest<super::DownloadFileRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::DownloadFileResponse>>,
tonic::Status,
> {
self.grpc.ready().await.map_err(|e| {
tonic::Status::new(
tonic::Code::Unknown,
format!("Service was not ready: {}", e),
)
})?;
let codec: ProstCodec<super::DownloadFileRequest, super::DownloadFileResponse> =
tonic::codec::ProstCodec::default();
let path = tonic::codegen::http::uri::PathAndQuery::from_static(DOWNLOAD_FILE_PATH);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("c2.C2", "DownloadFile"));
self.grpc.server_streaming(req, path, codec).await
}
}
}
1 change: 1 addition & 0 deletions implants/lib/c2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod pb {
include!("c2.rs");
include!("c2_manual.rs");
}
6 changes: 2 additions & 4 deletions tavern/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) {
httpLogger := log.New(os.Stderr, "[HTTP] ", log.Flags())

// Route Map
grpcHandler := newGRPCHandler(client)
routes := tavernhttp.RouteMap{
"/status": tavernhttp.Endpoint{Handler: newStatusHandler()},
"/oauth/login": tavernhttp.Endpoint{Handler: auth.NewOAuthLoginHandler(cfg.oauth, privKey)},
Expand All @@ -134,8 +133,7 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) {
"https://www.googleapis.com/oauth2/v3/userinfo",
)},
"/graphql": tavernhttp.Endpoint{Handler: newGraphQLHandler(client)},
"/c2.C2/": tavernhttp.Endpoint{Handler: grpcHandler},
"/grpc/": tavernhttp.Endpoint{Handler: grpcHandler},
"/c2.C2/": tavernhttp.Endpoint{Handler: newGRPCHandler(client)},
"/cdn/": tavernhttp.Endpoint{Handler: cdn.NewDownloadHandler(client)},
"/cdn/upload": tavernhttp.Endpoint{Handler: cdn.NewUploadHandler(client)},
"/": tavernhttp.Endpoint{
Expand Down Expand Up @@ -216,7 +214,7 @@ func newGraphQLHandler(client *ent.Client) http.Handler {
})
}

func newGRPCHandler(client *ent.Client) http.HandlerFunc {
func newGRPCHandler(client *ent.Client) http.Handler {
c2srv := c2.New(client)
grpcSrv := grpc.NewServer()
c2pb.RegisterC2Server(grpcSrv, c2srv)
Expand Down

0 comments on commit 57c2878

Please sign in to comment.