Skip to content

Commit

Permalink
Binary rules implementation
Browse files Browse the repository at this point in the history
1. Changed structure of archive_engine() to rely on lib.py functions
2. Implemented binary scanning for base64 decoded executable
3. Implemented unzipping
4. Added yara rules for binaries
  • Loading branch information
Mili-NT committed Apr 14, 2020
1 parent b5a5fd2 commit 3859ee4
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 26 deletions.
27 changes: 2 additions & 25 deletions BinBot.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@

import sys
import lib
import gzip
import json
import yara
import codecs
from time import sleep
from base64 import b64decode
from bs4 import BeautifulSoup
from sys import path as syspath
from os import path, listdir
Expand Down Expand Up @@ -115,7 +113,7 @@ def config(configpath):
finally:
print("\n")
return vars_dict
# YARA and Saving Function:
# Matching and Saving Function:
def archive_engine(prescan_text, proch, vars_dict):
"""
This function scans files for YARA matches (if enabled) and saves files.
Expand All @@ -138,28 +136,7 @@ def archive_engine(prescan_text, proch, vars_dict):
lib.print_status(f"Blacklisted term detected: [{components['term']}]")
# Otherwise, continue checking rules
else:
# The prebuilt rules:
if components['rule'] == 'b64Artifacts':
lib.print_success(f"Base64 Artifact Found: [{components['term']}]")
# If gzipped, decompress:
if components['term'] == "H4sI":
codecs.open(f"{vars_dict['workpath']}{proch}.file", 'w+', 'utf-8').write(gzip.decompress(bytes(b64decode(prescan_text), 'utf-8')))
# Otherwise, decode and save:
else:
codecs.open(f"{vars_dict['workpath']}{components['id']}_{proch}.txt", 'w+', 'utf-8').write(b64decode(prescan_text))
elif components['rule'] == 'powershellArtifacts':
lib.print_success(f"Powershell Artifact Found: [{components['term']}]")
codecs.open(f"{vars_dict['workpath']}{components['term']}_{proch}.ps1", 'w+', 'utf-8').write(prescan_text)
elif components['rule'] == 'keywords':
lib.print_success(f"Keyword found: [{components['term']}]")
codecs.open(f"{vars_dict['workpath']}{components['term']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
elif components['rule'] == 'regex_pattern':
lib.print_success(f"{components['rule']} match found: {components['id']}")
codecs.open(f"{vars_dict['workpath']}{components['id']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
# Custom rules will be saved by this statement:
else:
lib.print_success(f"{components['rule']} match found: {components['term']}")
codecs.open(f"{vars_dict['workpath']}{components['id']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
lib.general_matching(vars_dict, prescan_text, proch, components)
#If no matches are found, it just writes it with the parameter as a name
else:
lib.print_status(f"No matches in document: /{proch}")
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ If no path is passed, binbot will run a manual setup.

## TODO:
- API integration
- Binary rules implementation

50 changes: 50 additions & 0 deletions lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
# -----------------------------------------------------------------------

import os
import gzip
import codecs
import requests
from random import choice
from zipfile import ZipFile
from base64 import b64decode
from bs4 import BeautifulSoup
from datetime import datetime

Expand Down Expand Up @@ -96,6 +100,52 @@ def print_title(msg):
else:
print(f"\033[35m {msg}")
#
# YARA Functions:
#
def binary_matching(vars_dict, filepath):
matches = vars_dict['binary_rules'].match(data=codecs.open(filepath, 'rb', 'utf-8'))
if matches:
components = {'rule': matches[0].rule,
'term': ((matches[0]).strings[0])[2] if isinstance(((matches[0]).strings[0])[2], str) else
((matches[0]).strings[0])[2].decode('UTF-8'),
'id': (((matches[0]).strings[0])[1])[1:]}
print_success(f"{os.path.split(filepath)[1]} matches for {components['rule']}")
print_success(f"Matched item: {components['term']}")
os.rename(filepath, f"{os.path.split(filepath)[0]}/{components['rule']}.file")
def general_matching(vars_dict, prescan_text, proch, components):
if components['rule'] == 'b64Artifacts':
print_success(f"Base64 Artifact Found: [{components['term']}]")
# If gzipped, decompress:
if components['term'] == "H4sI":
filename = f"{vars_dict['workpath']}{proch}.file"
codecs.open(filename, 'w+', 'utf-8').write(gzip.decompress(bytes(b64decode(prescan_text), 'utf-8')))
# Otherwise, decode and save:
else:
filename = f"{vars_dict['workpath']}{components['id']}_{proch}.txt"
codecs.open(filename, 'w+', 'utf-8').write(b64decode(prescan_text))
# If zipped, unzip and pass all files in unzipped directory to binary_matching
if components['rule'] == "UEs":
zip_dir = f"{vars_dict['workpath']}/{os.path.split(filename)[1].split('.')[0]}"
ZipFile(filename, "r").extractall(zip_dir)
for file in [os.path.join(vars_dict['workpath'], f) for f in os.listdir(zip_dir)]:
binary_matching(vars_dict, file)
# If not zipped, pass the singular file to binary_matching
else:
binary_matching(vars_dict, filename)
elif components['rule'] == 'powershellArtifacts':
print_success(f"Powershell Artifact Found: [{components['term']}]")
codecs.open(f"{vars_dict['workpath']}{components['term']}_{proch}.ps1", 'w+', 'utf-8').write(prescan_text)
elif components['rule'] == 'keywords':
print_success(f"Keyword found: [{components['term']}]")
codecs.open(f"{vars_dict['workpath']}{components['term']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
elif components['rule'] == 'regex_pattern':
print_success(f"{components['rule']} match found: {components['id']}")
codecs.open(f"{vars_dict['workpath']}{components['id']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
# Custom rules will be saved by this statement:
else:
print_success(f"{components['rule']} match found: {components['term']}")
codecs.open(f"{vars_dict['workpath']}{components['id']}_{proch}.txt", 'w+', 'utf-8').write(prescan_text)
#
# Misc Program Functions:
#
def connect(url):
Expand Down
43 changes: 43 additions & 0 deletions yara_rules/binary_rules/mimikatz.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Credit: https://github.com/airbnb/binaryalert/blob/master/rules/public/hacktool/windows/
Assembled from multiple mimikatz rules from listed source
*/
rule windows_mimikatz
{
meta:
description = "Mimikatz credential dump tool"
reference = "https://github.com/gentilkiwi/mimikatz"
author = "@fusionrace"
SHA256_1 = "09054be3cc568f57321be32e769ae3ccaf21653e5d1e3db85b5af4421c200669"
SHA256_2 = "004c07dcd04b4e81f73aacd99c7351337f894e4dac6c91dcfaadb4a1510a967c"
strings:
$s1 = "dpapisrv!g_MasterKeyCacheList" fullword ascii wide
$s2 = "lsasrv!g_MasterKeyCacheList" fullword ascii wide
$s3 = "!SspCredentialList" ascii wide
$s4 = "livessp!LiveGlobalLogonSessionList" fullword ascii wide
$s5 = "wdigest!l_LogSessList" fullword ascii wide
$s6 = "tspkg!TSGlobalCredTable" fullword ascii wide
$s7 = "Kiwi en C" fullword ascii wide
$s8 = "Benjamin DELPY `gentilkiwi`" fullword ascii wide
$s9 = "http://blog.gentilkiwi.com/mimikatz" fullword ascii wide
$s10 = "Build with love for POC only" fullword ascii wide
$s11 = "gentilkiwi (Benjamin DELPY)" fullword wide
$s12 = "KiwiSSP" fullword wide
$s13 = "Kiwi Security Support Provider" fullword wide
$s14 = "kiwi flavor !" fullword wide
$s15 = "[ERROR] [LSA] Symbols" fullword ascii wide
$s16 = "[ERROR] [CRYPTO] Acquire keys" fullword ascii wide
$s17 = "[ERROR] [CRYPTO] Symbols" fullword ascii wide
$s18 = "[ERROR] [CRYPTO] Init" fullword ascii wide
$s19 = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%" wide ascii
$s20 = "0123456789012345678901234567890123456789" wide ascii
$s21 = "NTPASSWORD" wide ascii
$s22 = "LMPASSWORD" wide ascii
$s23 = "aad3b435b51404eeaad3b435b51404ee" wide ascii
$s24 = "31d6cfe0d16ae931b73c59d7e0c089c0" wide ascii
$s25 = "kiwifilter.log" fullword wide
$s26 = "kiwissp.log" fullword wide
$s27 = "mimilib.dll" fullword ascii wide
condition:
2 of ($s*)
}
70 changes: 70 additions & 0 deletions yara_rules/binary_rules/nanocore.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
This Yara ruleset is under the GNU-GPLv2 license (http://www.gnu.org/licenses/gpl-2.0.html) and open to any user or organization, as long as you use it under this license.
Credited: https://github.com/Yara-Rules/rules/blob/master/malware/RAT_Nanocore.yar
*/
rule Nanocore_G1 {
meta:
description = "Detetcs the Nanocore RAT and similar malware"
author = "Florian Roth"
reference = "https://www.sentinelone.com/blogs/teaching-an-old-rat-new-tricks/"
date = "2016-04-22"
score = 70
hash1 = "e707a7745e346c5df59b5aa4df084574ae7c204f4fb7f924c0586ae03b79bf06"
strings:
$x1 = "C:\\Users\\Logintech\\Dropbox\\Projects\\New folder\\Latest\\Benchmark\\Benchmark\\obj\\Release\\Benchmark.pdb" fullword ascii
$x2 = "RunPE1" fullword ascii
$x3 = "082B8C7D3F9105DC66A7E3267C9750CF43E9D325" fullword ascii
$x4 = "$374e0775-e893-4e72-806c-a8d880a49ae7" fullword ascii
$x5 = "Monitorinjection" fullword ascii
condition:
( uint16(0) == 0x5a4d and filesize < 100KB and ( 1 of them ) ) or ( 3 of them )
}

rule Nanocore_G2 {
meta:
description = "Detetcs the Nanocore RAT"
author = "Florian Roth"
score = 100
reference = "https://www.sentinelone.com/blogs/teaching-an-old-rat-new-tricks/"
date = "2016-04-22"
hash1 = "755f49a4ffef5b1b62f4b5a5de279868c0c1766b528648febf76628f1fe39050"
strings:
$x1 = "NanoCore.ClientPluginHost" fullword ascii
$x2 = "IClientNetworkHost" fullword ascii
$x3 = "#=qjgz7ljmpp0J7FvL9dmi8ctJILdgtcbw8JYUc6GC8MeJ9B11Crfg2Djxcf0p8PZGe" fullword ascii
condition:
( uint16(0) == 0x5a4d and filesize < 1000KB and 1 of them ) or ( all of them )
}

rule Nanocore_S1 {
meta:
description = "Detetcs a certain Nanocore RAT sample"
author = "Florian Roth"
score = 75
reference = "https://www.sentinelone.com/blogs/teaching-an-old-rat-new-tricks/"
date = "2016-04-22"
hash2 = "b7cfc7e9551b15319c068aae966f8a9ff563b522ed9b1b42d19c122778e018c8"
strings:
$x1 = "TbSiaEdJTf9m1uTnpjS.n9n9M7dZ7FH9JsBARgK" fullword wide
$x2 = "1EF0D55861681D4D208EC3070B720C21D885CB35" fullword ascii
$x3 = "popthatkitty.Resources.resources" fullword ascii
condition:
( uint16(0) == 0x5a4d and filesize < 900KB and ( 1 of ($x*) ) ) or ( all of them )
}

rule Nanocore_S2 {
meta:
description = "Detetcs a certain Nanocore RAT sample"
author = "Florian Roth"
score = 75
reference = "https://www.sentinelone.com/blogs/teaching-an-old-rat-new-tricks/"
date = "2016-04-22"
hash1 = "51142d1fb6c080b3b754a92e8f5826295f5da316ec72b480967cbd68432cede1"
strings:
$s1 = "U4tSOtmpM" fullword ascii
$s2 = ")U71UDAU_QU_YU_aU_iU_qU_yU_" fullword wide
$s3 = "Cy4tOtTmpMtTHVFOrR" fullword ascii
condition:
uint16(0) == 0x5a4d and filesize < 40KB and all of ($s*)
}
Empty file.
21 changes: 21 additions & 0 deletions yara_rules/binary_rules/pupy.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Credit: https://github.com/airbnb/binaryalert/edit/master/rules/public/malware/multi/malware_multi_pupy_rat.yara
Renamed for file naming simplicity
*/

rule pupy_rat
{
meta:
description = "pupy - opensource cross platform rat and post-exploitation tool"
reference = "https://github.com/n1nj4sec/pupy"
author = "@mimeframe"
strings:
$a1 = "dumping lsa secrets" nocase wide ascii
$a2 = "dumping cached domain passwords" nocase wide ascii
$a3 = "the keylogger is already started" nocase wide ascii
$a4 = "pupyutils.dns" wide ascii
$a5 = "pupwinutils.security" wide ascii
$a6 = "-PUPY_CONFIG_COMES_HERE-" wide ascii
condition:
3 of ($a*)
}
35 changes: 35 additions & 0 deletions yara_rules/binary_rules/quasar.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Credit: https://github.com/airbnb/binaryalert/edit/master/rules/public/malware/windows/malware_windows_xrat_quasarrat.yara
Renamed for file naming simplicity
*/
rule windows_quasar
{
meta:
description = "xRAT is a derivative of QuasarRAT; this catches both RATs."
reference = "https://github.com/quasar/QuasarRAT"
author = "@mimeframe"
strings:
// RemoteShell
$a1 = ">> New Session created" wide ascii
$a2 = ">> Session unexpectedly closed" wide ascii
$a3 = ">> Session closed" wide ascii
$a4 = "session unexpectedly closed" wide ascii
$a5 = "cmd" fullword wide ascii
$a6 = "/K" fullword wide ascii
// Commands
$b1 = "echo DONT CLOSE THIS WINDOW!" wide ascii
$b2 = "ping -n 20 localhost > nul" wide ascii
$b3 = "Downloading file..." wide ascii
$b4 = "Visited Website" wide ascii
$b5 = "Adding Autostart Item failed!" wide ascii
$b6 = ":Zone.Identifier" wide ascii
// System Handler
$c1 = "GetDrives I/O error" wide ascii
$c2 = "/r /t 0" wide ascii
$c3 = "desktop.ini" wide ascii
$c4 = "WAN IP Address" wide ascii
$c5 = "User refused the elevation request." wide ascii
$c6 = "Process already elevated." wide ascii
condition:
5 of ($a*) or 5 of ($b*) or 5 of ($c*)
}

0 comments on commit 3859ee4

Please sign in to comment.