espilon-source/espilon_bot/components/mod_honeypot/services/svc_http.c
Eun0us 6d45770d98 epsilon: merge command system into core + add 5 new modules
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.
2026-02-28 20:07:59 +01:00

107 lines
3.6 KiB
C

/*
* svc_http.c
* HTTP honeypot handler — request logging + POST body capture.
* Serves a fake login page to capture credentials.
*/
#include "sdkconfig.h"
#ifdef CONFIG_MODULE_HONEYPOT
#include "svc_common.h"
/* Extract server name from NVS banner (e.g. "Apache/2.4.54 (Ubuntu)") */
static void extract_server_name(char *out, size_t out_len)
{
char banner[128];
hp_config_get_banner("http", banner, sizeof(banner));
/* Banner format: "HTTP/1.1 200 OK\r\nServer: Apache/2.4.54 (Ubuntu)\r\n" */
char *srv = strstr(banner, "Server: ");
if (srv) {
srv += 8;
char *end = strstr(srv, "\r\n");
size_t len = end ? (size_t)(end - srv) : strlen(srv);
if (len >= out_len) len = out_len - 1;
memcpy(out, srv, len);
out[len] = '\0';
} else {
snprintf(out, out_len, "Apache/2.4.54");
}
}
/* Login page body */
static const char LOGIN_PAGE[] =
"<html><head><title>Admin Panel</title>"
"<style>body{font-family:sans-serif;background:#f0f0f0;display:flex;"
"justify-content:center;align-items:center;height:100vh;margin:0}"
".box{background:#fff;padding:2rem;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.2)}"
"input{display:block;margin:0.5rem 0;padding:0.4rem;width:200px}"
"button{padding:0.5rem 1rem;cursor:pointer}</style></head>"
"<body><div class='box'><h2>Authentication Required</h2>"
"<form method='POST' action='/login'>"
"<input name='user' placeholder='Username'>"
"<input name='pass' type='password' placeholder='Password'>"
"<button type='submit'>Login</button>"
"</form></div></body></html>";
void handle_http_client(int client_fd, const char *client_ip,
uint16_t client_port, hp_svc_desc_t *svc)
{
svc->connections++;
char buf[MAX_CLIENT_BUF];
int n = recv(client_fd, buf, sizeof(buf) - 1, 0);
if (n <= 0) return;
buf[n] = '\0';
/* Extract first line without modifying buf (needed for POST body search) */
char first_line[130];
char *eol = strstr(buf, "\r\n");
size_t fl_len = eol ? (size_t)(eol - buf) : (size_t)n;
if (fl_len >= sizeof(first_line)) fl_len = sizeof(first_line) - 1;
memcpy(first_line, buf, fl_len);
first_line[fl_len] = '\0';
char detail[192];
snprintf(detail, sizeof(detail), "service=http request='%.128s'", first_line);
event_send("SVC_CONNECT", "MEDIUM", "00:00:00:00:00:00",
client_ip, client_port, 80, detail, NULL);
/* Check for POST data → auth attempt */
if (strncmp(buf, "POST", 4) == 0) {
svc->auth_attempts++;
char *body = strstr(buf, "\r\n\r\n");
if (body) {
body += 4;
char post_detail[192];
snprintf(post_detail, sizeof(post_detail),
"service=http post='%.128s'", body);
event_send("SVC_AUTH_ATTEMPT", "HIGH", "00:00:00:00:00:00",
client_ip, client_port, 80, post_detail, NULL);
}
}
/* Build proper HTTP response */
char server_name[64];
extract_server_name(server_name, sizeof(server_name));
int body_len = (int)sizeof(LOGIN_PAGE) - 1;
char resp_hdr[256];
int hdr_len = snprintf(resp_hdr, sizeof(resp_hdr),
"HTTP/1.1 200 OK\r\n"
"Server: %s\r\n"
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n\r\n",
server_name, body_len);
send(client_fd, resp_hdr, hdr_len, 0);
send(client_fd, LOGIN_PAGE, body_len, 0);
int tarpit = hp_config_get_threshold("tarpit_ms");
if (tarpit > 0)
vTaskDelay(pdMS_TO_TICKS(tarpit));
}
#endif