krisnova / boopkit Goto Github PK
View Code? Open in Web Editor NEWLinux eBPF backdoor over TCP. Spawn reverse shells, RCE, on prior privileged access. Less Honkin, More Tonkin.
License: Apache License 2.0
Linux eBPF backdoor over TCP. Spawn reverse shells, RCE, on prior privileged access. Less Honkin, More Tonkin.
License: Apache License 2.0
I was going through the code and stumbled over the complex mechanism of intercepting TCP packages via pcap, reassembling them in the ring buffer and then searching through them.
Why is it not possible to simply take the command from the payload of the malformed TCP package (the one with the bad checksum), that triggers the rootkit in the first place?
The new #4 feature has noisy public servers firing off ncat
commands against it self alot.
Ideally we offer a "denylist" that can be plumbed through to boopkit at runtime so that we only are responding to specific blocks of IPs.
I wonder if there is a good CIDR library in C?
solved.closed.
I can not delete it.
Right now there are some encapsulation errors while transmitting the payload over a SYN packet.
Can be replicated:
Run boopkit in payload-only mode
boopkit -p
Boop with a single SYN packet
boopkit-boop -c "ls /"
Output:
** Boop EVENT_SRC_BAD_CSUM
** Boop source: 127.0.0.1
-> Search xCap Ring Buffer: 127.0.0.1
-> Taking snapshot of network traffic.
-> Snapshot complete!
-> Found RCE xCap!
-> Free Snapshot
<- Executing: ls /o
ls: cannot access '/o'$'\177': No such file or directory
Hello,
I wasn't able to build the bin I was receiving this errors:
~/bookit/boopkit-1.3.0$$ make
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
-> Building pr0be.boop.o
clang -S \
-target bpf \
-D __BPF_TRACING__ \
-I/usr/local/include \
-Wall \
-Werror \
-O2 -emit-llvm -c -g pr0be.boop.c
pr0be.boop.c:25:10: fatal error: 'bpf/bpf_endian.h' file not found
#include <bpf/bpf_endian.h>
^~~~~~~~~~~~~~~~~~
1 error generated.
make: *** [Makefile:91: pr0be.boop.o] Error 1
I'm using Ubuntu 20.04 / 5.13.0-1022-aws / bpftool v5.13.19
Please let me know if you need more information, thank you.
-> getuid() : 0
-> getpid() : 2468
-> getppid() : 2427
-> Logs : /sys/kernel/tracing/trace_pipe
-> Loading eBPF Probe : /root/.boopkit/pr0be.safe.o
-> Starting xCap Interface : lo
-> Initalizing Ring Buffer
libbpf: prog 'handle_getdents_patch': BPF program load failed: Invalid argument
libbpf: prog 'handle_getdents_patch': -- BEGIN PROG LOAD LOG --
R1 type=ctx expected=fp
0: R1=ctx(off=0,imm=0) R10=fp0
; size_t pid_tgid = bpf_get_current_pid_tgid();
0: (85) call bpf_get_current_pid_tgid#14 ; R0_w=scalar()
; size_t pid_tgid = bpf_get_current_pid_tgid();
1: (7b) *(u64 *)(r10 -8) = r0 ; R0_w=scalar() R10=fp0 fp-8_w=mmmmmmmm
2: (bf) r2 = r10 ; R2_w=fp0 R10=fp0
;
3: (07) r2 += -8 ; R2_w=fp-8
; long unsigned int *pbuff_addr = bpf_map_lookup_elem(&map_to_patch, &pid_tgid);
4: (18) r1 = 0xffff99f6c34db400 ; R1_w=map_ptr(off=0,ks=8,vs=8,imm=0)
6: (85) call bpf_map_lookup_elem#1 ; R0_w=map_value_or_null(id=1,off=0,ks=8,vs=8,imm=0)
; if (pbuff_addr == 0) {
7: (15) if r0 == 0x0 goto pc+56 ; R0_w=map_value(off=0,ks=8,vs=8,imm=0)
; long unsigned int buff_addr = *pbuff_addr;
8: (79) r7 = *(u64 *)(r0 +0) ; R0_w=map_value(off=0,ks=8,vs=8,imm=0) R7_w=scalar()
9: (b7) r8 = 0 ; R8_w=0
; short unsigned int d_reclen_previous = 0;
10: (6b) *(u16 *)(r10 -10) = r8 ; R8_w=P0 R10=fp0 fp-16=00??????
11: (b7) r9 = 16 ; R9_w=16
12: (bf) r6 = r7 ; R6_w=scalar(id=2) R7_w=scalar(id=2)
13: (0f) r6 += r9 ; R6_w=scalar() R9_w=16
14: (bf) r1 = r10 ; R1_w=fp0 R10=fp0
;
15: (07) r1 += -10 ; R1_w=fp-10
; bpf_probe_read_user(&d_reclen_previous, sizeof(d_reclen_previous),
16: (b7) r2 = 2 ; R2_w=2
17: (bf) r3 = r6 ; R3_w=scalar(id=3) R6_w=scalar(id=3)
18: (85) call bpf_probe_read_user#112 ; R0=scalar() fp-16=mm??????
; (struct linux_dirent64 *)(buff_addr + d_reclen_previous);
19: (69) r1 = *(u16 *)(r10 -10) ; R1_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R10=fp0
; (struct linux_dirent64 *)(buff_addr + d_reclen_previous);
20: (0f) r7 += r1 ; R1_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R7_w=scalar()
21: (0f) r7 += r9 ; R7_w=scalar() R9=16
; short unsigned int d_reclen = 0;
22: (6b) *(u16 *)(r10 -12) = r8 ; R8=P0 R10=fp0 fp-16=mm00????
23: (bf) r1 = r10 ; R1_w=fp0 R10=fp0
;
24: (07) r1 += -12 ; R1_w=fp-12
; bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
25: (b7) r2 = 2 ; R2_w=2
26: (bf) r3 = r7 ; R3_w=scalar(id=4) R7_w=scalar(id=4)
27: (85) call bpf_probe_read_user#112 ; R0_w=scalar() fp-16=mmmm????
; short unsigned int d_reclen_new = d_reclen_previous + d_reclen;
28: (69) r1 = *(u16 *)(r10 -10) ; R1_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R10=fp0
; short unsigned int d_reclen_new = d_reclen_previous + d_reclen;
29: (69) r2 = *(u16 *)(r10 -12) ; R2_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R10=fp0
; short unsigned int d_reclen_new = d_reclen_previous + d_reclen;
30: (0f) r2 += r1 ; R1_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R2_w=scalar(umax=131070,var_off=(0x0; 0x1ffff))
; short unsigned int d_reclen_new = d_reclen_previous + d_reclen;
31: (6b) *(u16 *)(r10 -14) = r2 ; R2_w=scalar(umax=131070,var_off=(0x0; 0x1ffff)) R10=fp0 fp-16=mmmmmm??
32: (bf) r2 = r10 ; R2_w=fp0 R10=fp0
;
33: (07) r2 += -14 ; R2_w=fp-14
; long ret = bpf_probe_write_user(&dirp_previous->d_reclen, &d_reclen_new,
34: (bf) r1 = r6 ; R1_w=scalar(id=3) R6=scalar(id=3)
35: (b7) r3 = 2 ; R3_w=2
36: (85) call bpf_probe_write_user#36
unknown func bpf_probe_write_user#36
processed 36 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1
-- END PROG LOAD LOG --
libbpf: prog 'handle_getdents_patch': failed to load: -22
libbpf: failed to load object 'pr0be_safe'
libbpf: failed to load BPF skeleton 'pr0be_safe': -22
Unable to load eBPF object: /root/.boopkit/pr0be.safe.o
Privileged access required to load eBPF probe!
Permission denied.
The README (and remote/remote
) makes reference to the trigger
binary, but it doesn't seem that there's source nor a Makefile rule to build it. Was this intentional?
I am opening an issue specifically for this, as I assume folks are going to find it very quickly.
Right now boopkit
works by sending a malformed TCP packet. That means, a TCP packet with a bad checksum. There are a few implications of this (for example IPv6 does not have a concept of a checksum) limitation to boopkit
.
Most enterprise grade networking hardware will not deal with these types of TCP packets. In other words, if a server is running behind a proxy, a firewall, or some other form of gateway there is a high chance that the networking hardware will drop the malformed TCP packet before it reaches the destination.
In this situation boopkit
will still be vulnerable to malformed TCP packets, simply the trigger will not be able to reach the destination.
I will open up other issues and features to try to address this limitation, but for now at least here is the explanation on what is going on.
Hey there, I was trying to build this project on a fresh Ubuntu 20.04 install
I installed the following for the main dependencies:
For xdp tools: https://github.com/xdp-project/xdp-tools
I also installed libbpf from source: https://github.com/libbpf/libbpf
When I tried to run make, I got this error:
user@xb2004d2:~/git/boopkit-1.3.0$ make
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
-> Building pr0be.boop.o
clang -S \
-target bpf \
-D __BPF_TRACING__ \
-I/usr/local/include \
-Wall \
-Werror \
-O2 -emit-llvm -c -g pr0be.boop.c
llc -march=bpf -filetype=obj -o pr0be.boop.o pr0be.boop.ll
-> Building pr0be.safe.o
clang -S \
-target bpf \
-D __BPF_TRACING__ \
-I/usr/local/include \
-Wall \
-Werror \
-O2 -emit-llvm -c -g pr0be.safe.c
llc -march=bpf -filetype=obj -o pr0be.safe.o pr0be.safe.ll
-> Building pr0be.xdp.o
clang -S \
-target bpf \
-D __BPF_TRACING__ \
-I/usr/local/include \
-Wall \
-Werror \
-O2 -emit-llvm -c -g pr0be.xdp.c
llc -march=bpf -filetype=obj -o pr0be.xdp.o pr0be.xdp.ll
-> Building eBPF pr0bes
-> Generating pr0be.skel.safe.h
bpftool gen skeleton pr0be.safe.o -p > pr0be.skel.safe.h
libbpf: prog 'handle_getdents_exit': invalid relo against 'pid_to_hide' in special section 0xfff2; forgot to initialize global var?..
make: *** [Makefile:47: skeleton] Error 255
During this process I also noticed that a file named 'm'$'\177'
appeared with the content stable\n
, which makes me think there was an environment variable or something that I may have not properly set up. In any case, would love some guidance on what the possible solution might be. Thank you!
Here is a good example for anyone interested: https://github.com/pqlx/CVE-2022-1015/blob/master/pwn.c#L476-L482
hi whitehat, coredump on ubuntu 21.04, and what env you used ?
os:ubuntu 21.04
kernel: Linux vm-server 5.11.0-49-generic #55-Ubuntu SMP Wed Jan 12 17:36:34 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
golang:go version go1.17.2 linux/amd64
clang:Ubuntu clang version 12.0.0-3ubuntu1~21.04.2
libbpf:0.6.1/0.7.0
make
sudo make install
boopkit -x 127.0.0.1
-> Logs: cat /sys/kernel/tracing/trace_pipe
-> Loading eBPF Probe: /root/.boopkit/pr0be.safe.o
-> Obfuscating PID: 12973
-> eBPF Probe loaded: /root/.boopkit/pr0be.safe.o
-> Loading eBPF Probe: /root/.boopkit/pr0be.boop.o
libbpf: failed to find BTF for extern 'inet_ntop' [28] section: -2
Segmentation fault
why linker create two *UND*
section into pr0be.boop.o
for inet_ntop
and inet_pton
.
how can it works?
thanks.
Because of #3 we need to entertain alternative triggers other than tcp_bad_csum
.
We can consider trying another trigger mechanism (tcp_receive_reset
) which will allow the trigger to establish a TCP connection with the server, and midway through the TCP handshake send a reset.
I need to research how far along in the TCP handshake we need to be in order to trigger the eBPF probe. Regardless, most TCP connections will allow for a full handshake and data transmission regardless of authentication status. This is how SSH, Kubernetes, etc works.
We want to pin the eBPF probe such that it will persist across reboot. This will allow us to hide the userspace component in clever ways.
Source: https://lwn.net/Articles/664688/
Logs from the report:
make
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
Error: failed to load BTF from /sys/kernel/btf/vmlinux: Invalid argument
make: *** [Makefile:87: autogen] Error 22
root@ddd:~/boopkit-1.4.0# bpftool --version
bpftool v5.10.106
Unacceptable options:
/usr/bin/init
)What I would like to do here is use the eBPF probe to hide itself! We should be able to hook into the systemcall filters for Linux and actually prevent userspace from finding the process itself. This would be a huge deal for eBPF backdoor communities!
Right now the saddr
is subject to change during every hop. Ideally we could find a few bytes of memory we can pass over TCP in order to tell the server what we want it to do.
We need a way to detect and ultimately stop boopkit :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.