检测linux进程注入4:使用字节跳动HIDS实时检测
2023-2-16 08:1:15 Author: 奶牛安全(查看原文) 阅读量:67 收藏


使用字节跳动HIDS来检测ptrace进程注入

原理

字节跳动HIDS使用内核对象的方式挂钩内核里面的函数。它是使用了kprobe来对ptrace挂钩监控ptrace

kprobe是内核中一种手段,可以动态插入到任意内核流程,收集调试和性能信息。

在典型情况下,基于KProbe的插件被打包为内核模块。模块的init函数安装(“注册”)一个或多个探针,而exit函数注销它们。注册函数(如register_kprobe())指定插入探针的位置以及命中探针时要调用的处理程序。还有register_/unregister_*probes()函数,用于批量注册/取消注册一组探针。当您必须一次注销大量探针时,这些函数可以加快注销过程。

基于kprobe开发,根据include/linux/kprobes.hkprobe定义

typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *);
typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *,
           unsigned long flags)

struct kprobe 
{
 struct hlist_node hlist;

 /* list of kprobes for multi-handler support */
 struct list_head list;

 /*count the number of times this probe was temporarily disarmed */
 unsigned long nmissed;

 /* location of the probe point */
 kprobe_opcode_t *addr;

 /* Allow user to indicate symbol name of the probe point */
 const char *symbol_name;

 /* Offset into the symbol */
 unsigned int offset;

 /* Called before addr is executed. */
 kprobe_pre_handler_t pre_handler;

 /* Called after addr is executed, unless... */
 kprobe_post_handler_t post_handler;

 /* Saved opcode (which has been replaced with breakpoint) */
 kprobe_opcode_t opcode;

 /* copy of the original instruction */
 struct arch_specific_insn ainsn;

 /*
  * Indicates various status flags.
  * Protected by kprobe_mutex after this kprobe is registered.
  */

 u32 flags;
};

需要定义pre_handlerpost_handlersymbol_name(挂钩的符号)

而字节跳动HIDSdriver/LKM/src/smith_hook.c定义了挂钩对象和处理函数

struct kprobe ptrace_kprobe = {
        .symbol_name = P_GET_SYSCALL_NAME(ptrace),
        .pre_handler = ptrace_pre_handler,
};

和注册/注销函数

int register_ptrace_kprobe(void)
{
    int ret;
    ret = register_kprobe(&ptrace_kprobe);

    if (ret == 0)
        ptrace_kprobe_state = 0x1;

    return ret;
}

void unregister_ptrace_kprobe(void)
{
    unregister_kprobe(&ptrace_kprobe);
}

而这些钩子都是在这里控制

// Hook on-off
int CONNECT_HOOK = 0;
int BIND_HOOK = 0;
int EXECVE_HOOK = 0;
int CREATE_FILE_HOOK = 0;
int PTRACE_HOOK = 1;
int DO_INIT_MODULE_HOOK = 0;
int UPDATE_CRED_HOOK = 0;

int RENAME_HOOK = 0;
int LINK_HOOK = 0;
int SETSID_HOOK = 0;
int PRCTL_HOOK = 0;
int MEMFD_CREATE_HOOK = 0;

int DNS_HOOK = 0;
int CALL_USERMODEHELPER = 0;
int ACCEPT_HOOK = 0;
int OPEN_HOOK = 0;
int MPROTECT_HOOK = 0;
int NANOSLEEP_HOOK = 0;
int KILL_HOOK = 0;
int RM_HOOK = 0;
int EXIT_HOOK = 0;

编译和运行

由于我们只要看ptrace,所以把其它钩子都变为0.

编译和运行

make clean && make
insmod hids_driver.ko

看一下运行结果

[[email protected] LKM]# dmesg|grep "ELKEID"
[17127.251384] [ELKEID] Filter Init Success 
[17127.275594] [ELKEID] SANDBOX: 0
[17127.276001] [ELKEID] register_kprobe success: connect_hook: 0,load_module_hook: 0,execve_hook: 0,call_usermodehekoer_hook: 0,bind_hook: 0,create_file_hook: 0,ptrace_hook: 1, update_cred_hook: 0, dns_hook: 0, accept_hook:0, mprotect_hook: 0,link_hook: 0, memfd_create: 0, rename_hook: 0,setsid_hook:0, prctl_hook:0, open_hook:0, nanosleep_hook:0, kill_hook: 0, rm_hook: 0,  EXIT_HOOK: 0, EXIT_PROTECT: 0
[17127.319573] [ELKEID] ANTI_ROOTKIT_CHECK: 1

试验

拿一个进程做实验,下面的2738号进程

[[email protected] log]# systemctl status wazuh-manager.service 
● wazuh-manager.service - Wazuh manager
   Loaded: loaded (/etc/systemd/system/wazuh-manager.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2021-08-12 11:37:26 CST; 4h 53min ago
  Process: 976 ExecStart=/usr/bin/env ${DIRECTORY}/bin/ossec-control start (code=exited, status=0/SUCCESS)
    Tasks: 106 (limit: 23371)
   Memory: 1001.8M
   CGroup: /system.slice/wazuh-manager.service
           ├─2738 /var/ossec/bin/ossec-authd
           ├─2759 /var/ossec/bin/wazuh-db
           ├─2778 /var/ossec/bin/ossec-execd
           ├─2785 /var/ossec/bin/ossec-analysisd
           ├─2801 /var/ossec/bin/ossec-syscheckd
           ├─2819 /var/ossec/bin/ossec-remoted
           ├─2828 /var/ossec/bin/ossec-logcollector
           ├─2844 /var/ossec/bin/ossec-monitord
           └─2852 /var/ossec/bin/wazuh-modulesd

使用GDB

[[email protected] log]# gdb -p 2738 -ex "detach" -q -ex "q"
Attaching to process 2738
[New LWP 2754]
[New LWP 2755]
[New LWP 2756]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
0x00007f38761a629f in select () from /lib64/libc.so.6
Detaching from program: /var/ossec/bin/ossec-authd, process 2738
[Inferior 1 (process 2738) detached]

根据https://github.com/bytedance/Elkeid/blob/main/driver/README-zh_CN.md的说明,在/proc/hids_driver/1下看结果

[[email protected] LKM]# cat /proc/hids_driver/1 
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494745864-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494748408-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494757320-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494756696-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494812704-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494816856-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494817520-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494745864-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494757320-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494756696-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652755139880494816856-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652738139880494748408-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652738139880494812704-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd
0101/usr/libexec/gdb219632050821963219636879gdblocalhost.localdomain14026531836402653183652738139880494817520-121963.gdb<20508.bash<20507.su<6879.bash<6523.sshd<6507.sshd<1061.sshd<1.systemd 

呃,这个输出有点难阅读。它的打印格式是在driver/LKM/include/kprobe_print.h里定义

PRINT_EVENT_DEFINE(ptrace,

                   PE_PROTO(long request,
                           long owner_pid, void *addr, char *data_res, char *exe_path, char *pid_tree),

                   PE_ARGS(request,
                           owner_pid, addr, data_res, exe_path, pid_tree),

                   PE_STRUCT__entry(
                           __field(int, uid)
                           __field(long, request)
                           __field(long, owner_pid)
                           __field(long, addr)
                           __string(data_res, data_res)
                           __string(exe_path, exe_path)
                           __string(pid_tree, pid_tree)
                           __field(int, pid)
                           __field(int, ppid)
                           __field(int, pgid)
                           __field(int, tgid)
                           __field(int, sid)
                           __array(char, comm, TASK_COMM_LEN)
                           __string(nodename, current->nsproxy->uts_ns->name.nodename)
                           __field(unsigned int, sessionid)
                           __field(unsigned int, pid_inum)
                           __field(unsigned int, root_pid_inum)
                   ),

                   PE_fast_assign(
                           __entry->uid = __get_current_uid();
                           __entry->request = request;
                           __entry->owner_pid = owner_pid;
                           __entry->addr = (long) addr;
                           __assign_str(data_res, data_res);
                           __assign_str(exe_path, exe_path);
                           __assign_str(pid_tree, pid_tree);
                           __entry->pid = current->pid;
                           __entry->ppid = current->real_parent->tgid;
                           __entry->pgid = __get_pgid();
                           __entry->sid = __get_sid();
                           __entry->tgid = current->tgid;
                           memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
                           __assign_str(nodename, current->nsproxy->uts_ns->name.nodename);
                           __entry->sessionid = __get_sessionid();
                           __entry->pid_inum = __get_pid_ns_inum();
                           __entry->root_pid_inum = ROOT_PID_NS_INUM;
                   ),

                   PE_printk(
                           "%d" RS "101" RS "%s" RS "%d" RS "%d" RS "%d" RS "%d" RS "%d" RS "%s" RS "%s" RS "%u" RS "%u" RS "%u" RS "%ld" RS "%ld" RS "%ld" RS "%s" RS "%s",
                           __entry->uid, __get_str(exe_path),__entry->pid, __entry->ppid,
                           __entry->pgid, __entry->tgid, __entry->sid,__entry->comm, __get_str(nodename),
                           __entry->sessionid, __entry->pid_inum, __entry->root_pid_inum, __entry->request, __entry->owner_pid,
                           __entry->addr, __get_str(data_res),__get_str(pid_tree))
);

按照这种格式,至少可以知道gdb是21963对2738号进程进行PTRACE_POKEDATA(2738前面的5)。

可以看到,字节跳动HIDS是可以对ptrace进行检测,也能够记录ptrace进行的操作。

=========================================

文中和文末的小广广,渴望你手指的触碰!!!

请关注,转发,点“在看”,谢谢!!

如需要转载,请在公众号留言!!

暗号:556e7


文章来源: http://mp.weixin.qq.com/s?__biz=MzU4NjY0NTExNA==&mid=2247488485&idx=1&sn=8d3d910600f9b98f11b2f7ccdfec8abf&chksm=fdf978f0ca8ef1e6c3a4e1c17afba78a6c07cb1052933548593328baa3d076fef9b67cdf8a97#rd
如有侵权请联系:admin#unsafe.sh