malduck icon indicating copy to clipboard operation
malduck copied to clipboard

Add support for embedded Yara rules

Open 0xThiebaut opened this issue 1 year ago • 1 comments

This PR introduces the capability to embed Yara rules within Extractors. This capability opens the door to shipping the Extractors as standalone scripts not relying on Karton. The Citadel example can be modified as follow, while remaining compatible with Karton's config extractor.

import argparse
import json

from malduck import Extractor
from malduck.extractor import ExtractManager, ExtractorModules

@Extractor.yara(r"""
rule citadel
{
    meta:
        author = "mak"
        module = "citadel"
    strings:
        $briankerbs = "Coded by BRIAN KREBS for personal use only. I love my job & wife."
        $cit_aes_xor = {81 30 [4] 0F B6 50 03 0F B6 78 02 81 70 04 [4] 81 70 08 [4] 81 70 0C [4] C1 E2 08 0B D7 }
        $cit_salt = { 8A D1 80 E2 07 C0 E9 03 47 83 FF 04 }
        $cit_login = { 30 [1-2] 8A 8? [4] 32  }
        $cit_getpes = { 68 [2] 00 00 8D ( 84 24 | 85) [4] 50 8D ( 85 ?? ?? ?? ?? | 44 24 ?? ) 50 E8 [4] B8 [2] 00 00 50 68 }
        $cit_base_off = { 5? 8D 85 [4] E8 [4] 6A 20 68 [4] 8D [2] 50 E8 [4] 8D 85 [4] 50 }
    condition:
        3 of them
}
""")
class Citadel(Extractor):
    family = "citadel"

    @Extractor.string("briankerbs")
    def citadel_found(self, p, addr, match):
        log.info('[+] `Coded by Brian Krebs` str @ %X' % addr)
        return True

    @Extractor.string
    def cit_login(self, p, addr, match):
        log.info('[+] Found login_key xor @ %X' % addr)
        hit = p.uint32v(addr + 4)
        print(hex(hit))
        if p.is_addr(hit):
            return {'login_key': p.asciiz(hit)}

        hit = p.uint32v(addr + 5)
        print(hex(hit))
        if p.is_addr(hit):
            return {'login_key': p.asciiz(hit)}

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('input', type=str)
    args = parser.parse_args()

    manager = ExtractManager(ExtractorModules())
    manager.push_file(args.input)
    for config in manager.config:
        print(json.dumps(config))

0xThiebaut avatar Nov 29 '23 16:11 0xThiebaut

Fixes #36

0xThiebaut avatar Nov 29 '23 16:11 0xThiebaut