Skip to content

Latest commit

 

History

History
339 lines (200 loc) · 20.8 KB

0x2 - Ursu.md

File metadata and controls

339 lines (200 loc) · 20.8 KB

Static Analysis

Hash Type File Hash
MD5 2A8668A6D0E12C7380A26910D504ECBF
SHA1 414300597938D64B3486BE6004003D90D565360D
SHA-256 CD78CF4AF8E37B4A9DE479867167027887A28527E2738C481A1C6891D707F21A
  • First, we notice moderate-high entropy in the .text section, which might suggest packing.

Pasted image 20240620063754

  • However, Exeinfo PE reports that there is no evidence of packing.

Pasted image 20240620063822

  • Graphical byte analysis results from Exeinfo PE come back normal. Visual distribution does not indicate the entropy patterns we would see with a packed sample.

Pasted image 20240620063907

  • This is further confirmed with bytehist.

Pasted image 20240620063938

Pasted image 20240620064011

  • In PE Studio, we only see 2 imported DLLs
    • kernel32.dll - Core Windows system library that provides essential functions for memory management, input/output operations, process and thread creation, and synchronization. Found in almost every PE.
    • urlmon.dll - This library provides functions for handling URLs and internet protocols, primarily used by Internet Explorer and other applications that need to download and manage web content.

Pasted image 20240620064122

  • At this point, urlmon.dll is the library we will pay close attention to first.

Important API Calls

  1. Execution
  • CreateProcessA: Starts a new process.
  • ExitProcess: Terminates the current process.
  • FreeEnvironmentStringsW: Frees environment strings.
  • GetCommandLineA: Retrieves the command-line string.
  • GetCurrentProcess: Retrieves a pseudo handle for the current process.
  • GetCurrentProcessId: Retrieves the process identifier of the current process.
  • GetCurrentThreadId: Retrieves the thread identifier of the calling thread.
  • GetEnvironmentStringsW: Retrieves environment strings.
  • Sleep: Suspends the execution of the current thread.
  • TerminateProcess: Terminates a specified process.

High-Level Overview: These functions manage the creation, execution, and termination of processes and threads, as well as handle environment strings and process identifiers.

  1. Synchronization
  • DeleteCriticalSection: Deletes a critical section object.
  • EnterCriticalSection: Waits for ownership of a critical section object.
  • InitializeCriticalSectionAndSpinCount: Initializes a critical section object with a spin count.
  • LeaveCriticalSection: Releases ownership of a critical section object.

High-Level Overview: These functions manage critical sections, which are used to synchronize access to shared resources in multi-threaded applications.

  1. File Operations
  • GetFileType: Retrieves the file type of the specified file.
  • GetSystemTimeAsFileTime: Retrieves the current system date and time.
  • GetTempFileNameA: Creates a temporary file name.
  • GetTempPathA: Retrieves the path of the directory designated for temporary files.
  • WriteFile: Writes data to a file.

High-Level Overview: These functions handle file-related operations such as determining file types, retrieving temporary file paths, and writing data to files.

  1. Memory Management
  • GetStringTypeW: Retrieves character type information.
  • HeapAlloc: Allocates a block of memory from a heap.
  • HeapCreate: Creates a heap object.
  • HeapFree: Frees a memory block allocated from a heap.
  • HeapReAlloc: Reallocates a block of memory from a heap.
  • HeapSetInformation: Sets information for the specified heap.
  • HeapSize: Retrieves the size of a memory block allocated from a heap.
  • RtlVirtualUnwind: Unwinds the stack frame.

High-Level Overview: These functions manage memory allocation, deallocation, and reallocation, as well as handle heap management and stack unwinding.

  1. Dynamic Library Management
  • GetModuleFileNameA: Retrieves the fully qualified path for the file containing the specified module.
  • GetModuleFileNameW: Retrieves the fully qualified path for the file containing the specified module.
  • GetModuleHandleW: Retrieves a module handle for the specified module.
  • GetProcAddress: Retrieves the address of an exported function or variable.
  • LoadLibraryW: Loads the specified module into the address space of the calling process.

High-Level Overview: These functions manage the loading and handling of dynamic link libraries (DLLs) and the retrieval of function addresses within those libraries.

  1. Reckoning and Timing
  • GetStartupInfoW: Retrieves the contents of the STARTUPINFO structure.
  • GetTickCount: Retrieves the number of milliseconds that have elapsed since the system was started.
  • IsDebuggerPresent: Determines whether the calling process is being debugged.
  • QueryPerformanceCounter: Retrieves the current value of the performance counter.

High-Level Overview: These functions handle system timing, process startup information, and debugging detection.

  1. Exception Handling
  • RtlCaptureContext: Captures the context of the current thread.
  • SetUnhandledExceptionFilter: Sets a function to be called when an unhandled exception occurs.
  • UnhandledExceptionFilter: Filters unhandled exceptions.

High-Level Overview: These functions manage exception handling by capturing thread contexts and setting filters for unhandled exceptions.

  1. Diagnostic and Error Handling
  • GetLastError: Retrieves the calling thread's last-error code.
  • RtlLookupFunctionEntry: Retrieves the function entry corresponding to a specified address.
  • SetLastError: Sets the last-error code for the calling thread.

High-Level Overview: These functions manage error codes and diagnostic information, helping in debugging and error reporting.

  1. Network Operations
  • URLDownloadToFileA: Downloads a file from the Internet to the local machine.

Attack Plan

We're going to pay close attention to the following:

  • Temp file creation(s), file downloads, and file write events
  • C2 traffic + network-based indicators such as URLs/IP addresses

Strings

  • What better way to find hardcoded network-based indicators apart from using strings? Let's take a look.

Pasted image 20240620065648

  • We start by doing some basic string extraction with Floss and outputting to a .txt file.

Pasted image 20240620065839

  • All static strings - no stack strings, decoded strings, etc. That's very convenient. This probably won't be a terribly complicated sample to analyze.

  • Once we get past the junk byte patterns in the beginning of the file, there is some possible evidence of context-aware behavior, indicated by the use of GetActiveWindow and a quick debugger check, followed by the C2 kickoff.

Pasted image 20240620070147

  • It's also interesting that we see GetCommandLineA. Just from the strings output, the context of that call isn't clear, but I suppose it could be used for context-aware behavior.

  • According to to MSDN, it retrieves the command-line string for the current process and returns it as a long pointer to (a) string in memory.

Pasted image 20240620070354

  • As we continue to scroll through the floss output, we don't see any noteworthy network-based indicators. But I did notice the use of RtlVirtualUnwind.

Pasted image 20240620070822

  • Apparently this can be used for anti-debugging, obfuscation, evasion, and some other tactics. However, at this point in my malware analysis career, it's outside the scope of my understanding.

Anti-Debugging Capabilities

  • There are a few API calls worth taking a look at here:
    • GetStartupInfoW: Retrieves the contents of the STARTUPINFO structure.
    • GetTickCount: Retrieves the number of milliseconds that have elapsed since the system was started.
    • IsDebuggerPresent: Determines whether the calling process is being debugged.
    • QueryPerformanceCounter: Retrieves the current value of the performance counter.

Dynamic Analysis

  • First, I want to take a look at this program with capa and get a good understanding of its capabilities.

  • We're going to use the -vv switch for a verbose output, which will provide a lot of granular details, including important locations in the program (example below).

Pasted image 20240620071243

  • We can immediately see the addresses where internet file download activity occurs (above), as well as XOR encryption (below).

Pasted image 20240620071358

  • As previously seen, there are references to temporary file paths & file names. We'll take a look at disk, system, and file system activity later in our analysis.

Pasted image 20240620071425

  • We proceed to start up fakedns, inetsim, and Wireshark.

Pasted image 20240620072852

Pasted image 20240620072859

Pasted image 20240620072913

  • When we trigger an infection with the above programs running, the sample spawns a process under explorer.exe as expected, then exits shortly after loading the required DLLs for network comms.

  • Additionally, we see no network-based indicators in Wireshark logs, which means the sample didn't even reach out to anything.

  • There is an alternative option - we can set the default gateway to the IP address of the Remnux machine and trigger another infection without any extra processes running (maybe there is some sort of environment check, or something else).

  • We start an Apache server (httpd), turn on iptables, and launch Wireshark.'

Pasted image 20240620074139

  • We get a packet capture going, and then re-infect the victim machine, and boom - this is what we were looking for.

Pasted image 20240620074220

  • We see some TCP traffic with an external IP - 1.234.27[.]146.

  • Let's pull up Maxmind (shout out to Chad Tilbury for recommending this tool in the SANS GCFE course).

Pasted image 20240620074421

  • Looks like a broadband IP in South Korea. That's definitely not normal background traffic.

  • VirusTotal shows this IP address is known for having relationships with a bunch of malicious PEs.

Pasted image 20240620075549

  • Taking a closer look at the malware samples that are known to communicate with it, the most commonly found signatures are generic trojans - mostly droppers & downloaders.

Pasted image 20240620075655

  • The next thing we need to do is follow the TCP stream.

Pasted image 20240620074526

  • The TCP flow starts with a GET request for what looks like a PE file named pcfix.exe with a pretty obvious affid (affiliate ID) parameter.

  • This was followed by a generic 404 response from the server.

  • If you're not familiar with how malware affiliates work, here's a snippet from SafeGuardCyber:

Pasted image 20240620074750

  • At this point, if we want to, we could turn on OpenVPN and send a curl request to grab a copy of pcfix.exe but I'd be shocked if that file is still available from that public IP address.

  • Out of curiosity, I gave it a go with urlscan.io, to no avail.

Pasted image 20240620075035

  • The JSON output mentions something about a temporary redirect due to HttpsUpgrades.

  • Well, once those threat actors finally finish that upgrade, we can all go and grab a fresh up-to-date copy 👍

Analysis of Execution Flow

  • Going back to the victim machine, we can see that the process doesn't stick around for long (it should be at the bottom under explorer.exe.

  • This particular sample closely matches the characteristics of a simple dropper.

Pasted image 20240620075328

  • I want to take a look at this sample in Ghidra and x64dbg next.

  • I'm going to take a look at the most crucial API calls as well as behavior related to internet connectivity (I want to try and understand how the TA enabled it to communicate with the foreign IP address without hardcoding the IP in the program).

  • Let's start by importing it into Ghidra and letting Ghidra analyze & decompile it for a few minutes.

Pasted image 20240620080006

  • Next, we check out Symbol References for the location of the call to URLDownloadToFileA.

Pasted image 20240620080947

  • According the MSDN, URLDownloadToFile takes "A pointer to a string value that contains the URL to download."

Pasted image 20240620080922

  • The API call is contained in the function FUN_140001000.

Pasted image 20240620081412

  • Let's take a closer look at that function and try to figure out what it does.

  • At first glance, it looks pretty simple:

    1. Checks for a debugger
    2. If a debugger is found, it jumps to another location, changes around some registers and flags, and then eventually exits the program.
    3. If a debugger is not found, it continues with execution.

Pasted image 20240620081656

Pasted image 20240620082348

Pasted image 20240620082604

  • Eventually, the program triggers a fatal exit.

Pasted image 20240620082941

  • After that, it vanishes. 😶‍🌫️

Pasted image 20240620083017

  • I still want to understand the communication with the IP address a little better, so this time, I'll restart the debugger with the ScyllaHide plugin.

Pasted image 20240620083139

  • I'll also set a Breakpoint on the call to IsDebuggerPresent.

Pasted image 20240620083250

Pasted image 20240620083237

  • With the ScyllaHide plugin active this time, we have successfully skipped the jne instruction.

Pasted image 20240620084132

Pasted image 20240620084214

Pasted image 20240620084228

  • Finally got it. The program uses a simple XOR de-obfuscation loop with the key 0x83 to de-obfuscate the URL string stored in memory.

Pasted image 20240620084616

  • Next, it does the same thing with the same thing with the Affiliate ID.

Pasted image 20240620084801

  • It then prepares to drop the downloadable PE file under %UserProfile%\AppData\Local\Temp

Pasted image 20240620084925

  • It also assigns it a temporary file name - in this case, BrB505C.tmp

Pasted image 20240620085011

Reversing

  • The main function makes a call to FUN_1400015A4, which makes a call to the function that performs most of the important work.

Pasted image 20240703184851

  • Stepping into FUN_1400015a4, we see a call the function that is responsible for most of the main features of this specimen.

Pasted image 20240703184945

Pasted image 20240703184954

  • When FUN_14001c5c is invoked, the parameter passed is the return value of the function which performs a debugger check and drops the file (named appropriately in the screenshot above).

  • The function debugger_check_&_file_dropper does the following:

    • Performs a simple debugger check with IsDebuggerPresent
      • If no debugger is found, it initializes variables and performs XOR operations on some data in memory with key 0x83 and copies one of the results to a variable, which it passes to UrlDownloadToFileA as the URL parameter. This is a basic obfuscation technique that basically prevents the hardcoded URI from being detected during static analysis (i.e. string extraction).
    • The downloaded file gets placed in the temp folder with its own randomly generated temp file name with a BrB prefix. This exact pattern was observed during the dynamic analysis phase earlier.

Summary

  • This Ursu sample is a dropper that downloads a second-stage PE file from a remote server (providing an affiliate ID as a URI parameter), stores it in the user's /Temp/ folder as a .tmp file, and then launches it before exiting.