From 32e23bbed09188cbb0fd737795ebb8e937e76f44 Mon Sep 17 00:00:00 2001 From: yunwei37 <1067852565@qq.com> Date: Mon, 16 Oct 2023 16:53:33 +0000 Subject: [PATCH] add example of 34 --- README.md | 1 + README_en.md | 1 + src/27-replace/replace.c | 2 - src/34-syscall/.gitignore | 15 +++++ src/34-syscall/Makefile | 2 + src/34-syscall/README.md | 20 ++++++ src/34-syscall/exechijack.bpf.c | 68 +++++++++++++++++++ src/34-syscall/exechijack.h | 18 +++++ src/34-syscall/open_modify.bpf.c | 112 +++++++++++++++++++++++++++++++ src/34-syscall/open_modify.h | 19 ++++++ src/34-syscall/victim.cpp | 33 +++++++++ 11 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 src/34-syscall/.gitignore create mode 100644 src/34-syscall/Makefile create mode 100644 src/34-syscall/README.md create mode 100644 src/34-syscall/exechijack.bpf.c create mode 100644 src/34-syscall/exechijack.h create mode 100644 src/34-syscall/open_modify.bpf.c create mode 100644 src/34-syscall/open_modify.h create mode 100644 src/34-syscall/victim.cpp diff --git a/README.md b/README.md index f120b9c..a9e2fac 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ Android: 安全: +- [使用 eBPF 修改系统调用参数](src/34-syscall/README.md) - [使用 eBPF 隐藏进程或文件信息](src/24-hide/README.md) - [使用 bpf_send_signal 发送信号终止进程](src/25-signal/README.md) - [使用 eBPF 添加 sudo 用户](src/26-sudo/README.md) diff --git a/README_en.md b/README_en.md index 6bb0e73..33a9fd6 100644 --- a/README_en.md +++ b/README_en.md @@ -55,6 +55,7 @@ Networking and tracing: Security: +- [Use eBPF to modify syscall parameters](src/34-syscall/README.md) - [Hiding process or file information using eBPF](src/24-hide/README_en.md) - [Terminating processes by sending signals using bpf_send_signal](src/25-signal/README_en.md) - [Adding sudo users using eBPF](src/26-sudo/README_en.md) diff --git a/src/27-replace/replace.c b/src/27-replace/replace.c index 943f9aa..6e0a472 100644 --- a/src/27-replace/replace.c +++ b/src/27-replace/replace.c @@ -3,8 +3,6 @@ #include #include "replace.skel.h" #include "replace.h" - - #include #include #include diff --git a/src/34-syscall/.gitignore b/src/34-syscall/.gitignore new file mode 100644 index 0000000..f9d8781 --- /dev/null +++ b/src/34-syscall/.gitignore @@ -0,0 +1,15 @@ +.vscode +package.json +*.o +*.skel.json +*.skel.yaml +package.yaml +ecli +bootstrap +.output +bpf-mocker +victim +victim2 +test.txt +hijacked +my_test.txt diff --git a/src/34-syscall/Makefile b/src/34-syscall/Makefile new file mode 100644 index 0000000..4da7003 --- /dev/null +++ b/src/34-syscall/Makefile @@ -0,0 +1,2 @@ +victim: victim.cpp + g++ victim.cpp -o victim \ No newline at end of file diff --git a/src/34-syscall/README.md b/src/34-syscall/README.md new file mode 100644 index 0000000..5e7278f --- /dev/null +++ b/src/34-syscall/README.md @@ -0,0 +1,20 @@ +# ebpf modify syscall parameters + +## modify open filename + +```bash +make +./victim +``` + +```bash +sudo ./ecli run package.json -- --rewrite --target_pid=$(pidof victim) +``` + +## modify exec commands + +TODO + +## reference + +- diff --git a/src/34-syscall/exechijack.bpf.c b/src/34-syscall/exechijack.bpf.c new file mode 100644 index 0000000..0f73e04 --- /dev/null +++ b/src/34-syscall/exechijack.bpf.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: BSD-3-Clause +#include "vmlinux.h" +#include +#include +#include +#include "exechijack.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +// Ringbuffer Map to pass messages from kernel to user +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +// Optional Target Parent PID +const volatile int target_ppid = 0; + +SEC("tp/syscalls/sys_enter_execve") +int handle_execve_enter(struct trace_event_raw_sys_enter *ctx) +{ + size_t pid_tgid = bpf_get_current_pid_tgid(); + // Check if we're a process of interest + if (target_ppid != 0) { + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + int ppid = BPF_CORE_READ(task, real_parent, tgid); + if (ppid != target_ppid) { + return 0; + } + } + + // Read in program from first arg of execve + char prog_name[TASK_COMM_LEN]; + char prog_name_orig[TASK_COMM_LEN]; + __builtin_memset(prog_name, '\x00', TASK_COMM_LEN); + bpf_probe_read_user(&prog_name, TASK_COMM_LEN, (void*)ctx->args[0]); + bpf_probe_read_user(&prog_name_orig, TASK_COMM_LEN, (void*)ctx->args[0]); + prog_name[TASK_COMM_LEN-1] = '\x00'; + bpf_printk("[EXECVE_HIJACK] %s\n", prog_name); + + // Program can't be less than out two-char name + if (prog_name[1] == '\x00') { + bpf_printk("[EXECVE_HIJACK] program name too small\n"); + return 0; + } + + // Attempt to overwrite with hijacked binary path + prog_name[0] = '/'; + prog_name[1] = 'a'; + for (int i = 2; i < TASK_COMM_LEN ; i++) { + prog_name[i] = '\x00'; + } + long ret = bpf_probe_write_user((void*)ctx->args[0], &prog_name, 3); + + // Send an event + struct event *e; + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (e) { + e->success = (ret == 0); + e->pid = (pid_tgid >> 32); + for (int i = 0; i < TASK_COMM_LEN; i++) { + e->comm[i] = prog_name_orig[i]; + } + bpf_ringbuf_submit(e, 0); + } + + return 0; +} \ No newline at end of file diff --git a/src/34-syscall/exechijack.h b/src/34-syscall/exechijack.h new file mode 100644 index 0000000..7dd4a44 --- /dev/null +++ b/src/34-syscall/exechijack.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: BSD-3-Clause +#ifndef BAD_BPF_COMMON_H +#define BAD_BPF_COMMON_H + +// Used when replacing text +#define FILENAME_LEN_MAX 50 +#define TEXT_LEN_MAX 20 + +// Simple message structure to get events from eBPF Programs +// in the kernel to user spcae +#define TASK_COMM_LEN 16 +struct event { + int pid; + char comm[TASK_COMM_LEN]; + bool success; +}; + +#endif // BAD_BPF_COMMON_H \ No newline at end of file diff --git a/src/34-syscall/open_modify.bpf.c b/src/34-syscall/open_modify.bpf.c new file mode 100644 index 0000000..d541817 --- /dev/null +++ b/src/34-syscall/open_modify.bpf.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Facebook +// Copyright (c) 2020 Netflix +#include +#include +#include "open_modify.h" + +const volatile bool targ_failed = false; +const volatile bool rewrite = false; +const volatile int target_pid = 0; + +struct args_t { + const char *fname; + int flags; +}; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, u32); + __type(value, struct args_t); +} start SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +SEC("tracepoint/syscalls/sys_enter_open") +int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter *ctx) +{ + u64 pid = bpf_get_current_pid_tgid() >> 32; + + /* store arg info for later lookup */ + struct args_t args = {}; + args.fname = (const char *)ctx->args[0]; + if (rewrite) { + bpf_probe_write_user((char*)ctx->args[1], "hijacked", 9); + } + args.flags = (int)ctx->args[1]; + bpf_map_update_elem(&start, &pid, &args, 0); + + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_openat") +int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx) +{ + u64 pid = bpf_get_current_pid_tgid() >> 32; + /* use kernel terminology here for tgid/pid: */ + if (target_pid && pid != target_pid) { + return 0; + } + /* store arg info for later lookup */ + // since we can manually specify the attach process in userspace, + // we don't need to check the process allowed here + + struct args_t args = {}; + args.fname = (const char *)ctx->args[1]; + args.flags = (int)ctx->args[2]; + if (rewrite) { + bpf_probe_write_user((char*)ctx->args[1], "hijacked", 9); + } + bpf_map_update_elem(&start, &pid, &args, 0); + return 0; +} + +static __always_inline int trace_exit(struct trace_event_raw_sys_exit *ctx) +{ + struct event *event; + struct args_t *ap; + int ret; + u32 pid = bpf_get_current_pid_tgid(); + + ap = bpf_map_lookup_elem(&start, &pid); + if (!ap) + return 0; /* missed entry */ + ret = ctx->ret; + + event = bpf_ringbuf_reserve(&rb, sizeof(*event), 0); + if (!event) + return 0; + + /* event data */ + event->pid = bpf_get_current_pid_tgid() >> 32; + event->uid = bpf_get_current_uid_gid(); + bpf_get_current_comm(&event->comm, sizeof(event->comm)); + bpf_probe_read_user_str(&event->fname, sizeof(event->fname), ap->fname); + event->flags = ap->flags; + event->ret = ret; + + /* emit event */ + bpf_ringbuf_submit(event, 0); + return 0; +cleanup: + bpf_map_delete_elem(&start, &pid); + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_open") +int tracepoint__syscalls__sys_exit_open(struct trace_event_raw_sys_exit *ctx) +{ + return trace_exit(ctx); +} + +SEC("tracepoint/syscalls/sys_exit_openat") +int tracepoint__syscalls__sys_exit_openat(struct trace_event_raw_sys_exit *ctx) +{ + return trace_exit(ctx); +} + +char LICENSE[] SEC("license") = "GPL"; diff --git a/src/34-syscall/open_modify.h b/src/34-syscall/open_modify.h new file mode 100644 index 0000000..39fe2af --- /dev/null +++ b/src/34-syscall/open_modify.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __SYSCALL_TRACER_H +#define __SYSCALL_TRACER_H + +#define TASK_COMM_LEN 16 +#define NAME_MAX 255 +#define INVALID_UID ((uid_t)-1) + +struct event { + /* user terminology for pid: */ + pid_t pid; + uid_t uid; + int ret; + int flags; + char comm[TASK_COMM_LEN]; + char fname[NAME_MAX]; +}; + +#endif /* __SYSCALL_TRACER_H */ diff --git a/src/34-syscall/victim.cpp b/src/34-syscall/victim.cpp new file mode 100644 index 0000000..9d9f2cb --- /dev/null +++ b/src/34-syscall/victim.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +int main() +{ + char filename[100] = "my_test.txt"; + // print pid + int pid = getpid(); + std::cout << "current pid: " << pid << std::endl; + system("echo \"hello\" > my_test.txt"); + system("echo \"world\" >> hijacked"); + while (true) { + std::cout << "Opening my_test.txt" << std::endl; + + int fd = open(filename, O_RDONLY); + assert(fd != -1); + + std::cout << "test.txt opened, fd=" << fd << std::endl; + usleep(1000 * 300); + // print the file content + char buf[100] = {0}; + int ret = read(fd, buf, 5); + std::cout << "read " << ret << " bytes: " << buf << std::endl; + std::cout << "Closing test.txt..." << std::endl; + close(fd); + std::cout << "test.txt closed" << std::endl; + } + return 0; +}