This commit is contained in:
Officeyutong
2024-02-22 13:14:00 +00:00
parent 403aff5b66
commit 55d5e641bf
47 changed files with 1483 additions and 1918 deletions

View File

@@ -186,7 +186,7 @@
</ol>
<p>如果该技术被恶意软件利用,攻击者可以重定向文件操作,导致数据泄漏或者破坏数据完整性。例如,程序写入日志文件时,攻击者可能将数据重定向到控制的文件中,干扰审计跟踪。</p>
<p>内核态代码(部分,完整内容请参考 Github bpf-developer-tutorial</p>
<pre><code class="language-c">SEC(&quot;tracepoint/syscalls/sys_enter_openat&quot;)
<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() &gt;&gt; 32;
@@ -202,7 +202,7 @@ int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter *ctx
args.fname = (const char *)ctx-&gt;args[1];
args.flags = (int)ctx-&gt;args[2];
if (rewrite) {
bpf_probe_write_user((char*)ctx-&gt;args[1], &quot;hijacked&quot;, 9);
bpf_probe_write_user((char*)ctx-&gt;args[1], "hijacked", 9);
}
bpf_map_update_elem(&amp;start, &amp;pid, &amp;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> 修改用户空间内存中的文件名为 &quot;hijacked&quot;</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] = &quot;my_test.txt&quot;;
char filename[100] = "my_test.txt";
// print pid
int pid = getpid();
std::cout &lt;&lt; &quot;current pid: &quot; &lt;&lt; pid &lt;&lt; std::endl;
system(&quot;echo \&quot;hello\&quot; &gt; my_test.txt&quot;);
system(&quot;echo \&quot;world\&quot; &gt;&gt; hijacked&quot;);
std::cout &lt;&lt; "current pid: " &lt;&lt; pid &lt;&lt; std::endl;
system("echo \"hello\" &gt; my_test.txt");
system("echo \"world\" &gt;&gt; hijacked");
while (true) {
std::cout &lt;&lt; &quot;Opening my_test.txt&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; "Opening my_test.txt" &lt;&lt; std::endl;
int fd = open(filename, O_RDONLY);
assert(fd != -1);
std::cout &lt;&lt; &quot;test.txt opened, fd=&quot; &lt;&lt; fd &lt;&lt; std::endl;
std::cout &lt;&lt; "test.txt opened, fd=" &lt;&lt; fd &lt;&lt; std::endl;
usleep(1000 * 300);
// print the file content
char buf[100] = {0};
int ret = read(fd, buf, 5);
std::cout &lt;&lt; &quot;read &quot; &lt;&lt; ret &lt;&lt; &quot; bytes: &quot; &lt;&lt; buf &lt;&lt; std::endl;
std::cout &lt;&lt; &quot;Closing test.txt...&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; "read " &lt;&lt; ret &lt;&lt; " bytes: " &lt;&lt; buf &lt;&lt; std::endl;
std::cout &lt;&lt; "Closing test.txt..." &lt;&lt; std::endl;
close(fd);
std::cout &lt;&lt; &quot;test.txt closed&quot; &lt;&lt; std::endl;
std::cout &lt;&lt; "test.txt closed" &lt;&lt; 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可以看到我们原先想要打开 &quot;my_test.txt&quot; 文件,但是实际上被劫持打开了 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(&quot;tp/syscalls/sys_enter_execve&quot;)
<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(&amp;prog_name, TASK_COMM_LEN, (void*)ctx-&gt;args[0]);
bpf_probe_read_user(&amp;prog_name_orig, TASK_COMM_LEN, (void*)ctx-&gt;args[0]);
prog_name[TASK_COMM_LEN-1] = '\x00';
bpf_printk(&quot;[EXECVE_HIJACK] %s\n&quot;, 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(&quot;[EXECVE_HIJACK] program name too small\n&quot;);
bpf_printk("[EXECVE_HIJACK] program name too small\n");
return 0;
}