Executing Cobalt Strike's BOFs on ARM-based Linux devices
We designed and implemented bof-launcher with a portability in mind so running BOFs on Linux ARM-based devices is a snap. Below, we’re running our uname
BOF on Raspberry Pi device. For convenience we use our cli4bofs tool to execute BOF directly from command line. So let’s jump to our device:
With Zig and our carefully crafted build.zig files (i.e. Makefiles on steroids) cross-compilation is happening out-of-the-box no matter on which platform (Linux / Windows) you’re building, so usual build zig
will build BOFs from bofs/
drectory for every supported platform:
[bof-launcher]$ zig build >/dev/null; ls -al zig-out/bin/uname.elf.*
-rw-r--r-- 1 mz mz 5032 05-10 11:11 zig-out/bin/uname.elf.aarch64.o
-rw-r--r-- 1 mz mz 4012 05-10 11:11 zig-out/bin/uname.elf.arm.o
-rw-r--r-- 1 mz mz 4952 05-10 11:11 zig-out/bin/uname.elf.x64.o
-rw-r--r-- 1 mz mz 3592 05-10 11:11 zig-out/bin/uname.elf.x86.o
Finally we will fetch latest binaries of cli4bofs tool (see the releases at: https://github.com/The-Z-Labs/cli4bofs/tags
) onto the device and (after uploading uname
BOF onto the device) run our BOF:
As a second example we will run BOF from TRUSTEDSEC’s ELFLoader project. We will build their cat
BOF using bof-launcher to demonstrate how easy and convenient it is to build 3rd party BOFs with it. In bof-launcher/bofs/
directory we will find build.zig
file that defines which BOFs should be built and for which architectures, as shown below:
const bofs_included_in_launcher = [_]Bof{
.{ .name = "helloBof", .formats = &.{.elf}, .archs = &.{ .x64, .x86, .aarch64, .arm } },
.{ .name = "udpScanner", .formats = &.{ .elf, .coff }, .archs = &.{ .x64, .x86, .aarch64, .arm } },
.{ .name = "ifconfig", .dir = "net-tools/", .formats = &.{.elf}, .archs = &.{ .x64, .x86, .aarch64, .arm } },
// ...
};
There’s also second array specifically for adding 3rd party BOFs, let’s uncomment it and add cat
BOF there for desired architectures, for clarity we will also expect it in a seperate directory trustedsec
:
// ...
const bofs_my_custom = [_]Bof{
.{ .name = "cat", .dir = "trustedsec/", .formats = &.{ .elf }, .archs = &.{ .x64, .x86, .aarch64, .arm } },
};
fn addBofsToBuild(bofs_to_build: *std.ArrayList(Bof)) !void {
try bofs_to_build.appendSlice(bofs_included_in_launcher[0..]);
try bofs_to_build.appendSlice(bofs_my_custom[0..]);
}
// ...
Now, let’s fetch the sources:
cd bof-launcher/bofs/src
mkdir trustedsec
wget https://raw.githubusercontent.com/trustedsec/ELFLoader/main/SA/src/cat.c -O trustedsec/cat.c
One last step before building it is to change name of beacon header file (ELFloader project uses beacon_api.h
instead of beacon.h
):
sed -i s/beacon_api.h/beacon.h/g trustedsec/cat.c
Let’s return to bof-launcher
main directory and build it:
cd ../../
zig build >/dev/null
$ ls zig-out/bin/cat.elf.*
zig-out/bin/cat.elf.aarch64.o zig-out/bin/cat.elf.arm.o zig-out/bin/cat.elf.x64.o zig-out/bin/cat.elf.x86.o
After copying it onto the Pi device, we can run it: