1 min read

Insights - Cobalt Strike (data_jitter)

The following outlines observations when analyzing cobalt strike traffic. The method of decrypting and analyzing cobalt strike c2 traffic is left as an exercise for the reader (however, I will dive into different topics here :))

According to the cobalt strike documentation, data_jitter is defined as "Append random-length string (up to data_jitter value) to http-get and http-post server output."

However, the question then arises - how exactly does it do this?

In this scenario, we will set the data_jitter to set data_jitter "45"; in our malleable profile. This means the teamserver's response to both the GET/POST will contain a random amount of bytes from zero up to 45 bytes. When we decrypt the c2 traffic with our custom implant, we notice the following

00000000: 66 5a 10 4a 00 00 00 23 00 00 00 06 00 00 00 1b  fZ.J...#........
00000010: 81 3f ee 1d 30 27 2c 4c 58 fe 92 8e 55 18 ce 2f  .?..0',LX...U../
00000020: 3c 41 04 0c 26 b1 91 2f 33 7e a6 41 41 41 41 41  <A..&../3~.AAAAA

The custom implant interprets this as a separate command. As a refresher, the teamserver embeds commands sequentially. All of the bytes in the previous output are part of one "command". The following provides a breakdown of the message

66 5a 10 4a = message id
00 00 00 23 = total # of bytes to follow
00 00 00 06 = command type (6)
00 00 00 1b = length of string (0x1b = 27 bytes
81 3f ee 1d 30 27 2c 4c 58 fe 92 8e 55 18 ce 2f  
3c 41 04 0c 26 b1 91 2f 33 7e a6 
41 41 41 41 41  AAAAA (random A's)

We can also observe that the length of the string doesn't necessarily account for the A's (0x23 = 35 bytes which corresponds to sizeof(command type) + sizeof(length of string) = 35). This leads me to speculate that the implant simply recognizes the command type (6) and ignores it.

This leads us to the following observation - each appended data is of the following format:

[message-id][# of bytes to fllow][command type] [size of string] [random bytes] [random number of As]