#----------------------------------------------------------- # malware.pl # # This plugin is essentially a 'container' for a lot of other individual # plugins, running the queries against any hive. # # References: # # # Change history: # 20161210 - added WebRoot check # 20160615 - added new Sofacy persistence # 20160412 - added Ramdo checks # 20160217 - added check for Locky ransomware # 20160127 - added Helminth entry # 20151203 - added DCOM port config detection # 20151013 - added Warood.B # 20151012 - 9002 ref/checks added # 20151008 - added keys # 20150828 - created # # copyright 2015 Quantum Analytics Research, LLC # Author: H. Carvey, keydet89@yahoo.com #----------------------------------------------------------- package malware; use strict; my %config = (hive => "All", hasShortDescr => 1, hasDescr => 0, hasRefs => 0, osmask => 22, category => "malware", version => 20161210); sub getConfig{return %config} sub getShortDescr { return "Checks for malware-related keys/values"; } sub getDescr{} sub getRefs {} sub getHive {return $config{hive};} sub getVersion {return $config{version};} my $VERSION = getVersion(); sub pluginmain { my $class = shift; my $hive = shift; ::logMsg("Launching malware v.".$VERSION); ::rptMsg("malware v.".$VERSION); # banner ::rptMsg("(".getHive().") ".getShortDescr()."\n"); # banner my $reg = Parse::Win32Registry->new($hive); my $root_key = $reg->get_root_key; my $key_path; my $key; # Security Hive # This is the same code as the secrets.pl plugin - provides an indication # regarding the use of GSecDump on systems; see "The Art of Memory Forensics", # eval { $key_path = "Policy\\Secrets"; $key; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); ::rptMsg(""); } }; # System Hive # First, need to get the value for the CurrentControlSet my $ccs; my $current; eval { if ($key = $root_key->get_subkey("Select")) { $current = $key->get_value("Current")->get_data(); $ccs = "ControlSet00".$current; } }; # If we've got a populated $ccs value, other checks will now likely work # Look for known/observed PlugX services my @services = ("RasTLS","Macfee MC","usta","emproxy","mproxysvr3","gzQkNtWeabrwf","brwTRsulGqj","sock5proxy"); eval { foreach my $svc (@services) { if ($key = $root_key->get_subkey($ccs."\\services\\".$svc)) { ::rptMsg("Possible PlugX variant found in ".$svc." service"); eval { ::rptMsg(" ImagePath : ".$key->get_value("ImagePath")->get_data()); }; eval { ::rptMsg(" Description: ".$key->get_value("Description")->get_data()); }; } } }; # Software Hive # Check for several PlugX variants # http://www.symantec.com/security_response/earthlink_writeup.jsp?docid=2013-112101-0135-99 # http://www.trendmicro.com/vinfo/us/threat-encyclopedia/malware/PLUGX eval { $key_path = "Classes\\FAST"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible PlugX variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); } }; eval { $key_path = "Classes\\XXXX"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible PlugX variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); } }; eval { $key_path = "BINARY"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible PlugX variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("SXLOC\.ZAP")) { ::rptMsg("Value SXLOC\.ZAP found."); } } }; # https://www.sophos.com/en-us/threat-center/threat-analyses/viruses-and-spyware/Troj~DwnLdr-GWF/detailed-analysis.aspx eval { $key_path = "Begin"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible Downloader variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); } }; # check Classes\Network\SharingHandler default value for modification # in most cases, it's "ntshrui.dll" # http://www.trendmicro.com/vinfo/us/threat-encyclopedia/malware/worm_cosmu.elg eval { $key_path = "Classes\\Network\\SharingHandler"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg(" LastWrite Time : ".gmtime($key->get_timestamp())." (UTC)"); ::rptMsg(" (Default) value: ".$key->get_value("")->get_data()); ::rptMsg("If the (Default) value is not ntshrui\.dll, there may be an infection."); } ::rptMsg(""); }; # Poison Ivy variant # http://blog.jpcert.or.jp/2015/07/poisonivy-adapts-to-communicate-through-authentication-proxies.html eval { $key_path = "Classes\\BJ\\Static"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); if ($key->get_value("MessageFile")) { ::rptMsg("MessageFile value found."); } ::rptMsg(""); } }; # Warood.A # https://www.microsoft.com/security/portal/threat/encyclopedia/entry.aspx?Name=Backdoor:Win32/Warood.A#tab=2 eval { $key_path = "Clients\\Netrau"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); if ($key->get_value("HostGUID") || $key->get_value("InstallTime")) { ::rptMsg("Warood.A value(s) found."); } ::rptMsg(""); } }; # Warood.B # https://www.microsoft.com/security/portal/threat/encyclopedia/entry.aspx?Name=Backdoor:Win32/Warood.B#tab=2 eval { $key_path = "Clients\\sdata"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); if ($key->get_value("sdata")) { ::rptMsg("sdata value found."); } ::rptMsg(""); } }; # From FireEye APT30 report, ShipShape malware eval { $key_path = "Microsoft\\ShipUp"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible ShipShape malware found: ".$key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); if ($key->get_value("lnk")) { ::rptMsg("lnk value found."); } ::rptMsg(""); } }; # From FireEye APT30 report, SpaceShip malware eval { $key_path = "Microsoft\\ShipTr"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible SpaceShip malware found: ".$key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); if ($key->get_value("lnk")) { ::rptMsg("lnk value found."); } ::rptMsg(""); } }; # From MIRCon 2014 presentation on WMI # HKLM/Software/Microsoft/WBEM/ESS///./root/CIMV2/Win32ClockProvider # $$$PROTO.HIV\Microsoft\WBEM\ESS\//./root/CIMV2\Win32ClockProvider eval { $key_path = "Microsoft\\WBEM\\ESS\\//./root/CIMV2\\Win32ClockProvider"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg($key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); ::rptMsg("Possible use of WMI time trigger found."); ::rptMsg(""); } }; # Bledoor/RbDoor - added 20151117 # https://www.microsoft.com/security/portal/threat/encyclopedia/entry.aspx?Name=Trojan:Win64/Bledoor.A#tab=2 eval { $key_path = "Microsoft\\HTMLHelp"; if ($key = $root_key->get_subkey($key_path)) { if ($key->get_value("data")) { ::rptMsg("Possible BleDoor/Rbdoor malware found: ".$key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); ::rptMsg("data value found: ".$key->get_value("data")->get_value()); } ::rptMsg(""); } }; # Detect DCOM port change # https://www.blackhat.com/docs/us-15/materials/us-15-Graeber-Abusing-Windows-Management # -Instrumentation-WMI-To-Build-A-Persistent%20Asynchronous-And-Fileless-Backdoor-wp.pdf # http://blog.backslasher.net/setting-dynamic-rpc-port-ranges.html eval { $key_path = "Microsoft\\Rpc\\Internet"; if ($key = $root_key->get_subkey($key_path)) { if ($key->get_value("Ports")) { ::rptMsg("Possible DCOM port config change found: ".$key_path); ::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)"); ::rptMsg("Ports value: ".$key->get_value("Ports")->get_value()); } ::rptMsg(""); } }; # WebRoot Threat checks eval { $key_path = "WRData\\Threats\\History"; if ($key = $root_key->get_subkey($key_path)) { my @vals = $key->get_list_of_values(); if (scalar @vals > 0) { ::rptMsg($key_path); ::rptMsg("LastWrite Time : ".gmtime($key->get_timestamp())." UTC"); foreach my $v (@vals) { ::rptMsg($v->get_name()." - ".$v->get_data()); } } else { ::rptMsg($key_path." has no values."); } ::rptMsg(""); } }; eval { $key_path = "Wow6432Node\\WRData\\Threats\\History"; if ($key = $root_key->get_subkey($key_path)) { my @vals = $key->get_list_of_values(); if (scalar @vals > 0) { ::rptMsg($key_path); ::rptMsg("LastWrite Time : ".gmtime($key->get_timestamp())." UTC"); foreach my $v (@vals) { ::rptMsg($v->get_name()." - ".$v->get_data()); } } else { ::rptMsg($key_path." has no values."); } ::rptMsg(""); } }; # NTUSER.DAT/USRCLASS.DAT # Possible PlugX # http://www.symantec.com/security_response/earthlink_writeup.jsp?docid=2013-112101-0135-99 eval { $key_path = "Software\\BINARY"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible PlugX variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("SXLOC\.ZAP")) { ::rptMsg("Value SXLOC\.ZAP found."); } } }; # Nflog, et al. # http://www.microsoft.com/security/portal/threat/encyclopedia/entry.aspx?name=TROJAN:WIN32/NFLOG.A#tab=2 # https://www.sophos.com/en-us/threat-center/threat-analyses/viruses-and-spyware/Troj~DwnLdr-GWF/detailed-analysis.aspx eval { $key_path = "Software\\Microsoft\\Clock"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible Nflog variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("HID")) { ::rptMsg("Value HID found: ".$key->get_value("HID")->get_data()); } } }; # 9002 RAT # http://researchcenter.paloaltonetworks.com/2015/09/chinese-actors-use-3102-malware-in-attacks-on-us-government-and-eu-media/ # http://blog.cylance.com/another-9002-trojan-variant eval { $key_path = "Software\\TransPan"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible 9002 RAT variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("RunPath") || $key->get_value("mshtm")) { ::rptMsg(" Possible 9002 config value(s) found."); } } }; # From FireEye report on APT30/BackSpace RAT eval { $key_path = "Software\\Microsoft\\CurrentHalInf"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible BACKSPACE RAT variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("hFlag")) { ::rptMsg(" Possible hFlag value found: ".$key->get_value("hFlag")->get_data()); } } }; eval { $key_path = "Software\\Microsoft\\CurrentPnpSetup"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg("Possible BACKSPACE RAT variant (".$key_path.") found."); ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("lnk") || $key->get_value("hostid")) { ::rptMsg(" Possible BACKSPACE value(s) found."); } } }; # TEST - this addition was derived from malware write-ups, which may not be correct # Helminth # http://www.threatexpert.com/report.aspx?md5=3448c57a2dfc824098fca500478ab405 # http://www.trendmicro.no/vinfo/no/threat-encyclopedia/malware/troj_battoexe.dv eval { $key_path = "Software\\Microsoft\\Wbem\\WMIC"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("WMICLC")) { ::rptMsg(sprintf " WMICLC: 0x%x",$key->get_value("WMICLC")->get_data()); } if ($key->get_value("mofcompMUIStatus")) { ::rptMsg(sprintf " mofcompMUIStatus: 0x%x",$key->get_value("mofcompMUIStatus")->get_data()); } } }; # https://www.carbonblack.com/2016/01/31/tackling-latentbot-look-big-picture-not-just-individual-functions/ eval { $key_path = "Software\\Google\\Update\\network\\secure"; if ($key = $root_key->get_subkey($key_path)) { if ($key->get_value("0")) { ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); ::rptMsg(" Possible LatentBot malware located."); ::rptMsg(sprintf " 0: 0x%x",$key->get_value("0")->get_data()); } if ($key->get_value("1")) { ::rptMsg(sprintf " 1: 0x%x",$key->get_value("1")->get_data()); } } }; # Locky check # http://www.bleepingcomputer.com/news/security/the-locky-ransomware-encrypts-local-files-and-unmapped-network-shares/ eval { $key_path = "Software\\Locky"; if ($key = $root_key->get_subkey($key_path)) { ::rptMsg(" LastWrite time: ".gmtime($key->get_timestamp())); if ($key->get_value("id")) { ::rptMsg(" Possible Locky ransomware located."); ::rptMsg(" Value 'id': ".$key->get_value("id")->get_data()); } } }; # Ramdo checks, added 20160412 # https://blogs.technet.microsoft.com/mmpc/2014/04/02/msrt-april-2014-ramdo/ # https://www.symantec.com/security_response/writeup.jsp?docid=2014-021912-3653-99&tabid=2 eval { my @val_names = ("tLast_ReadedSpec", "tLastCollab_doc"); $key_path = "Software\\Adobe\\Adobe ARM\\1.0\\ARM"; if ($key = $root_key->get_subkey($key_path)) { foreach my $val (@val_names) { if (my $v = $key->get_value($val)) { ::rptMsg("Possible Ramdo value found."); ::rptMsg(" ".$val." = ".$v->get_data()); } } } }; eval { my @versions = ("9.0", "10.0","11.0","12.0","13.0"); my @val_names = ("iTestPropulsion", "iTestShears"); foreach my $version (@versions) { $key_path = "Software\\Adobe\\Adobe Reader\\".$version."\\IPM"; if ($key = $root_key->get_subkey($key_path)) { foreach my $val (@val_names) { if (my $v = $key->get_value($val)) { ::rptMsg("Possible Ramdo value found: ".$val." = ".$v->get_data()); } } } } }; eval { $key_path = "Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"; if ($key = $root_key->get_subkey($key_path)) { if ($key->get_value("twunk_32.exe")->get_data() == 9000) { ::rptMsg("Possible Ramdo value found: twunk_32.exe = 9000"); } if ($key->get_value("winhlp32.exe")->get_data() == 9000) { ::rptMsg("Possible Ramdo value found: winhlp32.exe = 9000"); } } }; # Sofacy # http://researchcenter.paloaltonetworks.com/2016/06/unit42-new-sofacy-attacks-against-us-government-agency/ # http://www.trendmicro.com/vinfo/us/threat-encyclopedia/malware/troj_cve20151641.bzd # http://www.hexacorn.com/blog/2014/04/16/beyond-good-ol-run-key-part-10/ eval { $key_path = "Software\\Microsoft\\Office test\\Special\\Perf"; if ($key = $root_key->get_subkey($key_path)) { my $bte; if ($bte = $key->get_value("")->get_data()) { ::rptMsg("Possible Sofacy value found: ".$bte); ::rptMsg("**Be sure to examine the ".$bte." file\."); } } }; } 1;