shell bypass 403

Cubjrnet7 Shell


name : unix_socket_log.c
/**
@file     unix_socket_log.h
@brief    UNIX socket log capturing
@details  Copyright (c) 2025 Acronis International GmbH
@author   Denis Kopyrin ([email protected])
@since    $Id: $
*/

#include "unix_socket_log.h"

#include "memory.h"
#include "net_events.h"
#include "network/net_compat.h"
#include "string_view.h"
#include "transport.h"

#include <linux/string.h>
#include <linux/types.h>
#include <linux/un.h>

static const string_view_t k_dev_logs[] = { STRING_VIEW_CONST("/dev/log"), STRING_VIEW_CONST("/run/systemd/journal/dev-log") };

static const string_view_t k_keywords_failed[] = { STRING_VIEW_CONST("Connection ") // "reset" or ".... timed out" or " from ...: refusing"
                                                 , STRING_VIEW_CONST("Failed ")
                                                 , STRING_VIEW_CONST("Disconnecting ")
                                                 // 'Disconnecting' covers all the cases, 'Disconnected' is usually a logout message
                                                 // , STRING_VIEW_CONST("Disconnected ")
                                                 , STRING_VIEW_CONST("Unable to negotiate with ") };

static const string_view_t k_keywords_success[] = { STRING_VIEW_CONST("Accepted ") };

static bool is_dev_log(const string_view_t *sv)
{
	int i;
	for (i = 0; i < (int) ARRAY_SIZE(k_dev_logs); i++) {
		if (string_view_equal(&k_dev_logs[i], sv))
			return true;
	}

	return false;
}

static bool check_if_log_line_starts_with_keywords(const string_view_t* sv, const string_view_t* keywords, int keywords_amount)
{
	int i;
	for (i = 0; i < keywords_amount; i++) {
		if (string_view_starts_with(sv, &keywords[i]))
			return true;
	}

	return false;
}

static bool check_if_log_line_failed(const string_view_t* sv)
{
	return check_if_log_line_starts_with_keywords(sv, k_keywords_failed, sizeof(k_keywords_failed) / sizeof(*k_keywords_failed));
}

static bool check_if_log_line_success(const string_view_t* sv)
{
	return check_if_log_line_starts_with_keywords(sv, k_keywords_success, sizeof(k_keywords_success) / sizeof(*k_keywords_success));
}

static bool check_if_auth_log(string_view_t* sv)
{
	if (sv->str[0] != '<')
		return false;

	if (sv->str[1] == '8') {
		// Levels from 80 to 86 are non-debug authpriv logs
		if ('0' > sv->str[2] || sv->str[2] > '6') {
			return false;
		}
	} else if (sv->str[1] == '3') {
		// Levels from 32 to 38 are non-debug auth logs
		if ('2' > sv->str[2] || sv->str[2] > '8') {
			return false;
		}
	} else {
		return false;
	}

	if (sv->str[3] != '>')
		return false;

	string_view_advance(sv, 4);
	return true;
}

// musl memmem
static const unsigned char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8;
	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8;
	for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8)
		if (hw == nw) return h-3;

	return hw == nw ? h-3 : NULL;
}

typedef struct
{
	// check if 'cut_log.str' to check if message is useful
	string_view_t cut_log;
	bool is_success;
} log_analysis_result_t;

#define LOG_ANALYSIS_RESULT_OK(res) ((res).cut_log.str)

// Lines that arrive here look like "<36> Jan 20 19:09:58 sshd[44171]: Accepted password for user from 192.168.223.1 port 59064 ssh2"
// Our target is to extract line that looks like "Accepted password for user from 192.168.223.1 port 59064 ssh2"
static log_analysis_result_t analyze_log_msg(string_view_t log_msg)
{
	log_analysis_result_t result;
	char* log_start;
	bool any_known = false;

	string_view_init_empty(&result.cut_log);
	result.is_success = false;

	if (!check_if_auth_log(&log_msg))
		return result;

	string_view_advance(&log_msg, sizeof(" Jan 20 19:09:58 ") - 1);

	// Find the "]: " pattern when actual event starts. We are guaranteed that such event pattern will exist:
	// LogTag is expected to be equal to argv0 or __progname - not NULL. LOG_PID flag is enabled for sshd.
	/*
	if (LogStat & LOG_PID)
		fprintf (f, "[%d]", (int) __getpid ());
	if (LogTag != NULL) {
		__putc_unlocked (':', f);
		__putc_unlocked (' ', f);
	}
	*/
	if (log_msg.len < 3)
		return result;

	log_start = (char*) threebyte_memmem((unsigned char*) log_msg.str, log_msg.len, (const unsigned char*) "]: ");
	if (!log_start)
		return result;

	string_view_advance(&log_msg, log_start - log_msg.str + 3);

	// Check if prefix matches well-known line prefixes
	if (!any_known && check_if_log_line_failed(&log_msg)) {
		any_known = true;
		result.is_success = false;
	}
	if (!any_known && check_if_log_line_success(&log_msg)) {
		any_known = true;
		result.is_success = true;
	}

	if (any_known)
		result.cut_log = log_msg;

	return result;
}

#define MIN_LEN ((int) sizeof("<86>Jan 20 14:53:50 []: Failed "))
#define SNIFF_LEN 512

static void handle_log_msg(task_info_t *task_info, string_view_t log_msg)
{
	transport_ids_t transport_ids;
	int event;
	uint64_t generatedEventsMask;

	log_analysis_result_t result = analyze_log_msg(log_msg);
	if (!LOG_ANALYSIS_RESULT_OK(result))
		return;

	event = result.is_success ? FP_SI_OT_NOTIFY_SOCKET_AUTH_LOG_SUCCESS : FP_SI_OT_NOTIFY_SOCKET_AUTH_LOG_FAILED;
	generatedEventsMask = MSG_TYPE_TO_EVENT_MASK(event);

	if (!(generatedEventsMask & transport_global_get_combined_mask()))
		return;

	transport_global_get_ids(&transport_ids, generatedEventsMask);
	if (task_info_can_skip(task_info, &transport_ids, generatedEventsMask))
		return;

	net_event_auth_log(task_info, result.cut_log, result.is_success);
}

void unix_socket_log_sendmsg(task_info_t *task_info, struct socket *sock, struct msghdr *msg, int size)
{
	struct sockaddr_storage storage;
	int sniff_amount;
	size_t copied_size;
	string_view_t target_path;
	char* log_msg;

	if (size < MIN_LEN)
		return;

	string_view_init_empty(&target_path);

	if (msg->msg_name) {
		if (msg->msg_namelen > (int) (sizeof(sa_family_t) + 1)) {
			struct sockaddr_un* sun = (struct sockaddr_un*) msg->msg_name;
			string_view_init(&target_path, sun->sun_path, msg->msg_namelen - sizeof(sa_family_t));
		}
	} else {
		int len = sock_to_addr(sock, &storage, 2 /*peer*/); 
		if (len > (int) (sizeof(sa_family_t) + 1)) {
			struct sockaddr_un* sun = (struct sockaddr_un*) &storage;
			string_view_init(&target_path, sun->sun_path, len - sizeof(sa_family_t));
		}
	}

	if (!target_path.str)
		return;

	target_path.len = strnlen(target_path.str, target_path.len);
	if (!target_path.len)
		return;

	if (!is_dev_log(&target_path))
		return;

	sniff_amount = size;
	if (sniff_amount > SNIFF_LEN)
		sniff_amount = SNIFF_LEN;

	log_msg = (char*) mem_alloc(sniff_amount);
	if (!log_msg)
		return;

	copied_size = msg_data_peek(msg, log_msg, sniff_amount);
	if (copied_size > MIN_LEN) {
		string_view_t log_msg_sv;
		string_view_init(&log_msg_sv, log_msg, copied_size);
		handle_log_msg(task_info, log_msg_sv);
	}

	mem_free(log_msg);
}

© 2025 Cubjrnet7