Skip to content

Commit

Permalink
Merge pull request #40 from maclarel/add_netstat
Browse files Browse the repository at this point in the history
Add basic netstat functionality
  • Loading branch information
MEhrn00 committed Dec 19, 2024
2 parents f30082f + 10ea7c4 commit e3aae0a
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 1 deletion.
1 change: 1 addition & 0 deletions Payload_Type/thanatos/thanatos/agent_code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ path-clean = "0.1.0"
rand = "0.8"
serde_json = "1.0"
sha2 = "0.9.8"
netstat2 = "0.11.1"

[dependencies.minreq]
version = "2.4.2"
Expand Down
1 change: 1 addition & 0 deletions Payload_Type/thanatos/thanatos/agent_code/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod jobs;
mod ls;
mod mkdir;
mod mv;
mod netstat;
mod payloadvars;
mod portscan;
mod profiles;
Expand Down
64 changes: 64 additions & 0 deletions Payload_Type/thanatos/thanatos/agent_code/src/netstat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::agent::AgentTask;
use crate::mythic_success;
use netstat2::{get_sockets_info, AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
use serde::Serialize;

/// Struct holding the information for network connections
#[derive(Default, Serialize)]
pub struct NetworkListingEntry {
/// Protocol
pub proto: String,

/// Local address
pub local_addr: String,

/// Local Port
pub local_port: u16,

/// Remote address
pub remote_addr: Option<String>,

/// Remote port
pub remote_port: Option<u16>,

/// Associated PIDs
pub associated_pids: Vec<u32>,

/// State
pub state: Option<String>,
}

pub fn netstat(task: &AgentTask) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let af_flags = AddressFamilyFlags::IPV4 | AddressFamilyFlags::IPV6;
let proto_flags = ProtocolFlags::TCP | ProtocolFlags::UDP;
let sockets_info = get_sockets_info(af_flags, proto_flags)?;

let mut conn: Vec<NetworkListingEntry> = Vec::new();

for si in sockets_info {
match si.protocol_socket_info {
ProtocolSocketInfo::Tcp(tcp_si) => conn.push(NetworkListingEntry {
proto: "TCP".to_string(),
local_addr: tcp_si.local_addr.to_string(),
local_port: tcp_si.local_port,
remote_addr: Some(tcp_si.remote_addr.to_string()),
remote_port: Some(tcp_si.remote_port),
associated_pids: si.associated_pids,
state: Some(tcp_si.state.to_string()),
}),
ProtocolSocketInfo::Udp(udp_si) => conn.push(NetworkListingEntry {
proto: "UDP".to_string(),
local_addr: udp_si.local_addr.to_string(),
local_port: udp_si.local_port,
remote_addr: None,
remote_port: None,
associated_pids: si.associated_pids,
state: None,
}),
}
}

let user_output = serde_json::to_string(&conn)?;
/// Return the output to Mythic
Ok(mythic_success!(task.id, user_output))
}
7 changes: 6 additions & 1 deletion Payload_Type/thanatos/thanatos/agent_code/src/tasking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::sync::{

// Import all of the commands
use crate::{
cat, cd, cp, download, exit, getenv, getprivs, jobs, ls, mkdir, mv, portscan, ps, pwd,
cat, cd, cp, download, exit, getenv, getprivs, jobs, ls, mkdir, mv, netstat, portscan, ps, pwd,
redirect, rm, setenv, shell, sleep, ssh, unsetenv, upload, workinghours,
};

Expand Down Expand Up @@ -364,6 +364,11 @@ fn process_task(task: &agent::AgentTask) -> serde_json::Value {
Err(e) => mythic_error!(task.id, e.to_string()),
},

"netstat" => match netstat::netstat(task) {
Ok(res) => res,
Err(e) => mythic_error!(task.id, e.to_string()),
},

"ps" => match ps::get_process_list(task) {
Ok(res) => res,
Err(e) => mythic_error!(task.id, e.to_string()),
Expand Down
41 changes: 41 additions & 0 deletions Payload_Type/thanatos/thanatos/mythic/agent_functions/netstat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from mythic_container.MythicCommandBase import (
BrowserScript,
TaskArguments,
CommandBase,
CommandAttributes,
SupportedOS,
MythicTask,
PTTaskMessageAllData,
PTTaskProcessResponseMessageResponse,
)


class NetstatArguments(TaskArguments):
def __init__(self, command_line, **kwargs):
super().__init__(command_line, **kwargs)
self.args = []

async def parse_arguments(self):
pass


class NetstatCommand(CommandBase):
cmd = "netstat"
needs_admin = False
help_cmd = "netstat"
description = "Get all active network connections & sockets"
version = 1
author = "@maclarel"
argument_class = NetstatArguments
attackmapping = ["T1049"]
attributes = CommandAttributes(
supported_os=[SupportedOS.Linux, SupportedOS.Windows],
)

async def create_tasking(self, task: MythicTask) -> MythicTask:
return task

async def process_response(
self, task: PTTaskMessageAllData, response: str
) -> PTTaskProcessResponseMessageResponse:
pass
53 changes: 53 additions & 0 deletions documentation-payload/thanatos/commands/netstat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
+++
title = "netstat"
chapter = false
weight = 103
hidden = true
+++

## Description
Report on all active network connections. Note that this may require the agent to be running in a `root` context for complete enumeration.

## Usage
```
netstat
```

### Examples
```
netstat
```
```
[
{
"proto": "TCP",
"local_addr": "127.0.0.53",
"local_port": 53,
"remote_addr": "0.0.0.0",
"remote_port": 0,
"associated_pids": "",
"state": "LISTEN"
},
{
"proto": "TCP",
"local_addr": "0.0.0.0",
"local_port": 22,
"remote_addr": "0.0.0.0",
"remote_port": 0,
"associated_pids": "",
"state": "LISTEN"
},
{
"proto": "TCP",
"local_addr": "10.0.0.1",
"local_port": 22,
"remote_addr": "10.0.0.2",
"remote_port": 40803,
"associated_pids": "",
"state": "ESTABLISHED"
}
]
```

## MITRE ATT&CK Mapping
- T1049

0 comments on commit e3aae0a

Please sign in to comment.