mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-03 18:24:27 +08:00
Deploying to gh-pages from @ eunomia-bpf/bpf-developer-tutorial@c120bb4912 🚀
This commit is contained in:
@@ -186,7 +186,7 @@
|
||||
</ol>
|
||||
<p>如果该技术被恶意软件利用,攻击者可以重定向文件操作,导致数据泄漏或者破坏数据完整性。例如,程序写入日志文件时,攻击者可能将数据重定向到控制的文件中,干扰审计跟踪。</p>
|
||||
<p>内核态代码(部分,完整内容请参考 Github bpf-developer-tutorial):</p>
|
||||
<pre><code class="language-c">SEC("tracepoint/syscalls/sys_enter_openat")
|
||||
<pre><code class="language-c">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;
|
||||
@@ -202,7 +202,7 @@ int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx
|
||||
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_probe_write_user((char*)ctx->args[1], "hijacked", 9);
|
||||
}
|
||||
bpf_map_update_elem(&start, &pid, &args, 0);
|
||||
return 0;
|
||||
@@ -213,7 +213,7 @@ int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx
|
||||
<li><code>bpf_get_current_pid_tgid()</code> 获取当前进程ID。</li>
|
||||
<li>如果指定了 <code>target_pid</code> 并且不匹配当前进程ID,函数直接返回。</li>
|
||||
<li>我们创建一个 <code>args_t</code> 结构来存储文件名和标志。</li>
|
||||
<li>使用 <code>bpf_probe_write_user</code> 修改用户空间内存中的文件名为 "hijacked"。</li>
|
||||
<li>使用 <code>bpf_probe_write_user</code> 修改用户空间内存中的文件名为 "hijacked"。</li>
|
||||
</ul>
|
||||
<p>eunomia-bpf 是一个开源的 eBPF 动态加载运行时和开发工具链,它的目的是简化 eBPF 程序的开发、构建、分发、运行。可以参考 <a href="https://github.com/eunomia-bpf/eunomia-bpf">https://github.com/eunomia-bpf/eunomia-bpf</a> 或 <a href="https://eunomia.dev/tutorials/1-helloworld/">https://eunomia.dev/tutorials/1-helloworld/</a> 下载和安装 ecc 编译工具链和 ecli 运行时。我们使用 eunomia-bpf 编译运行这个例子。</p>
|
||||
<p>编译:</p>
|
||||
@@ -222,27 +222,27 @@ int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx
|
||||
<p>使用 make 构建一个简单的 victim 程序,用来测试:</p>
|
||||
<pre><code class="language-c">int main()
|
||||
{
|
||||
char filename[100] = "my_test.txt";
|
||||
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");
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
std::cout << "read " << ret << " bytes: " << buf << std::endl;
|
||||
std::cout << "Closing test.txt..." << std::endl;
|
||||
close(fd);
|
||||
std::cout << "test.txt closed" << std::endl;
|
||||
std::cout << "test.txt closed" << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -257,7 +257,7 @@ test.txt closed
|
||||
<p>可以使用以下命令指定应修改其 <code>openat</code> 系统调用参数的目标进程ID:</p>
|
||||
<pre><code class="language-bash">sudo ./ecli run package.json --rewrite --target_pid=$(pidof victim)
|
||||
</code></pre>
|
||||
<p>然后就会发现输出变成了 world,可以看到我们原先想要打开 "my_test.txt" 文件,但是实际上被劫持打开了 hijacked 文件:</p>
|
||||
<p>然后就会发现输出变成了 world,可以看到我们原先想要打开 "my_test.txt" 文件,但是实际上被劫持打开了 hijacked 文件:</p>
|
||||
<pre><code class="language-console">test.txt opened, fd=3
|
||||
read 5 bytes: hello
|
||||
Closing test.txt...
|
||||
@@ -274,7 +274,7 @@ read 5 bytes: world
|
||||
<p>包含测试用例的完整代码可以在 <a href="https://github.com/eunomia-bpf/bpf-developer-tutorial">https://github.com/eunomia-bpf/bpf-developer-tutorial</a> 找到。</p>
|
||||
<h2 id="修改-bash-execve-的进程名称"><a class="header" href="#修改-bash-execve-的进程名称">修改 bash execve 的进程名称</a></h2>
|
||||
<p>这段功能用于当 <code>execve</code> 系统调用进行时修改执行程序名称。在一些审计或监控场景,这可能用于记录特定进程的行为或修改其行为。然而,此类篡改可能会造成混淆,使得用户或管理员难以确定系统实际执行的程序是什么。最严重的风险是,如果恶意用户能够控制 eBPF 程序,他们可以将合法的系统命令重定向到恶意软件,造成严重的安全威胁。</p>
|
||||
<pre><code class="language-c">SEC("tp/syscalls/sys_enter_execve")
|
||||
<pre><code class="language-c">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();
|
||||
@@ -294,11 +294,11 @@ int handle_execve_enter(struct trace_event_raw_sys_enter *ctx)
|
||||
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);
|
||||
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");
|
||||
bpf_printk("[EXECVE_HIJACK] program name too small\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user