23 July 2019

ServHelper Vigenère encryption

MD5:  eb7cdf5a96ae5f5a596a6ed423f786a7
Post: https://twitter.com/VK_Intel/status/1152669759382654976
ServHelper: https://www.proofpoint.com/us/threat-insight/post/servhelper-and-flawedgrace-new-malware-introduced-ta505


Threat: ServHelper
Campaign ID: "ju11"
Key:  "exchanger"
Xor Key: "lol"
Vigenère Key: "XMGG"


C&Cs:
  • towerprod3[.]com/docs/saz.php
  • lotmoji[.]com/docs/saz.php
  • gdr55asf3145zadgsgsdw[.]icu/docs/saz.php

Previous ServHelper samples had all their strings unencrypted. 


1.Early version example


As for the communication with the C&C observed only later versions of tunnel variant to encrypt/decrypt the request/response data with a simple xor function.

2. Xor encryption of request parameters values


In latest version of ServHelper (Campaign ju11) most of the string are encrypted with Vigenère cipher (Keys observed: XMGG, XBJB, ...)

3. Encrypted strings



IDA PRO Decryption script.
# ServHelper vigenere decrypt
# @Tera0017
from idc import *
from idaapi import *


def prepare_string(s, alphabet):
    temp = s
    alphaList = list(alphabet)
    sList = list(temp)
    for index in range(len(sList)):
        for index2 in range(len(alphaList)):
            if temp[index] == alphaList[index2]:
                break
            if index2 + 1 == len(alphaList):
                sList.remove(temp[index])

    final = ''.join(sList)
    return final


def c2i(c, alphabet):
    return alphabet.index(c)


def i2c(i, alphabet):
    return alphabet[i]


def vigenere_decode(ciphertext, key, alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    cipherList = list(ciphertext)
    keyList = list(key)
    alphaList = list(alphabet)
    decodeText = ""

    for index in range(len(ciphertext)):
        if ciphertext[index] not in alphaList:
            decodeText += ciphertext[index]
        else:
            cipherIndex = c2i(cipherList[index], alphabet)
            keyIndex = c2i((keyList[index % len(key)]), alphabet)
            decodeTextIndex = (cipherIndex - keyIndex) % 26
            decodeText += i2c(decodeTextIndex, alphabet)

    return decodeText


def get_string(addr):
    out = ""
    bytes2zero = 0
    while True:
        if Byte(addr) != 0:
            out += chr(Byte(addr))
            bytes2zero = 0
        else:
            bytes2zero += 1
            if bytes2zero == 2:
                break
        addr += 1
    return out


def decrypt_str(addr, KEY):
    print 'org:', '%08x  ' % addr,
    addr_c = addr
    for i in range(5):
        addr = idc.PrevHead(addr)
        mnem = GetMnem(addr)
        # X86 and X64 support
        if ((mnem == "mov" and GetOpnd(addr, 0) == "eax" and i == 0 and 'offset' in GetOpnd(addr, 1)) or (mnem == "lea" and GetOpnd(addr, 0) == "rdx" and i == 1)):
            off_addr = GetOperandValue(addr, 1)
            encrypted = get_string(off_addr)
            decrypted = vigenere_decode(encrypted, KEY)
            print decrypted
            MakeComm(addr_c, decrypted)
     MakeComm(off_addr, decrypted)
            break
        elif i >= 1:
            print 'Error finding encrypted'
            break

# TODO find vigenere function and add address + add the Key
decrstr_func = 0x50f4d8
refs = [addr.frm for addr in XrefsTo(decrstr_func, flags=0)]
for ref in refs:
    decrypt_str(ref, KEY='XMGG')
 




No comments:

Post a Comment