Mythic icon indicating copy to clipboard operation
Mythic copied to clipboard

custom EKE problems

Open DarkC0ntributor opened this issue 1 month ago • 2 comments

Hi, I am trying to get my head around custom EKE. Simple DH. I end up with Unknown action for IterateAndAct: decrypt with value: comming from https://github.com/its-a-feature/Mythic/blob/274e41f1ee06d56e0ea12c4f16f2f1af3b0407f3/mythic-docker/src/rabbitmq/util_agent_message.go#L179. So apparently "crypto_type": 'aes256_hmac' is lost somewhere. Also, returning a list of bytes in the JSON seems odd. As does wrapping the message manually with b64encode(UUID+AES(<data>))

def wire_msg(crypt_key, data):
    """crypt if needed the mythic way"""
    from Crypto.Cipher import AES
    from hashlib import sha256
    from hmac import new as hmac
    from Crypto.Util.Padding import unpad, pad
    #SendMythicRPCCallbackEncryptBytes
    if crypt_key.Value == "aes256_hmac":
        iv = urandom(16)
        key = crypt_key.EncKey
        aescbc = AES.new(key, AES.MODE_CBC, iv)
        e = aescbc.encrypt(pad(data,16))
        data = iv + e + hmac(key, iv+e, sha256).digest()
        return data
    else:
        return data
def c22mythic(data: bytes) -> dict:
 """turn c2 bytes into mythics dict with action and so on"""
 # [...]
def mythic2c2(m: dict) -> bytes:
 """turn dict with action and so on into c2 bytes"""
 # [...]
class myPythonTranslation(TranslationContainer):
 name = "test"
 # [...]
 async def translate_from_c2_format(self, inputMsg: TrCustomMessageToMythicC2FormatMessage) -> TrCustomMessageToMythicC2FormatMessageResponse:
    # [...]
    m = c22mythic(inputMsg.Message)
    if m['action'] == 'eke_dh':
       # [...]
       from uuid import uuid4
       tmp = uuid4()
       bob_public = # [...]
       new_aes_key = # [...]
       m = {
                "action": "staging_translation",
                "session_id": "",#some string session id you want to save
                "enc_key": list(new_aes_key),#the bytes of an encryption key for the next message
                "dec_key": list(new_aes_key),#the bytes of a decryption key for the next message
                "crypto_type": 'aes256_hmac',
                "next_uuid": str(tmp),
                "message": list(b64encode(UUID(inputMsg.UUID).bytes+wire_msg(
                    inputMsg.CryptoKeys[0],
                    mythic2c2({
                    'action':'eke_dh',
                    'tmp': tmp.bytes,
                    'public':bob_public
                }))))
       }
        
    response = TrCustomMessageToMythicC2FormatMessageResponse(Success=True)
    response.Message = m
    return response

DarkC0ntributor avatar Nov 10 '25 13:11 DarkC0ntributor

Hey! I think you're the first person publicly to be doing something like this, so I definitely need to add docs and make them better surrounding this process.

Let's see if we can dive into what's going on though. Can you point me to the docs you are referencing for this? I want to make sure that as I add docs and update things that I'm updating what you're currently referencing.

For returning a list of bytes - you're right, that's weird. That enc_key and dec_key values should just be the base64 of the key. crypto_type here should just be type (which is probably why that value isn't getting carried over). That message value is what's just forwarded along to your agent. It also shouldn't be a list of the bytes, you should just base64 encode it.

its-a-feature avatar Nov 10 '25 14:11 its-a-feature

It felt like I might 😄 I used the docs here: https://docs.mythic-c2.net/customizing/payload-type-development/create_tasking/agent-side-coding/initial-checkin#your-own-custom-eke (2nd code box)

I first tried to return a dict with bytes (kinda like the docs suggest). That failed here https://github.com/MythicMeta/MythicContainerPyPi/blob/main/mythic_container/TranslationBase.py#L368 where this goes JSON. I figured that the keys are then probably (like everywhere else) base64 but that got me an error in the logs:

Failed to decode agent message into struct: 3 error(s) decoding:

* 'dec_key': source data must be an array or slice, got string
* 'enc_key': source data must be an array or slice, got string
* 'message': source data must be an array or slice, got map

and then I got illegal base64 data at input byte 0 This got me to the point where I opened the issue.

I changed crypto_type to type. Now it works! I still think mythic should do the encryption on the returned message and add the UUID and wrap it in base64. It would be closer to the rest of the translation containers workflow. If the Translation container is generic, It has no way to know if the payload wants a string UUID or just bytes.

BTW, if you too can't stand JSON and base64, have a look at a Drop-In-Replacement: https://msgpack.org/

DarkC0ntributor avatar Nov 10 '25 16:11 DarkC0ntributor