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.
- However,
Exeinfo PE
reports that there is no evidence of packing.
- 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.
- This is further confirmed with
bytehist
.
- 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.
- At this point,
urlmon.dll
is the library we will pay close attention to first.
Important API Calls
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- Network Operations
- URLDownloadToFileA: Downloads a file from the Internet to the local machine.
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
- What better way to find hardcoded network-based indicators apart from using strings? Let's take a look.
- We start by doing some basic string extraction with
Floss
and outputting to a.txt
file.
-
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.
-
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.
- As we continue to scroll through the
floss
output, we don't see any noteworthy network-based indicators. But I did notice the use ofRtlVirtualUnwind
.
- 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.
- 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.
-
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).
- We can immediately see the addresses where internet file download activity occurs (above), as well as XOR encryption (below).
- 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.
- We proceed to start up
fakedns
,inetsim
, andWireshark
.
-
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 oniptables
, and launch Wireshark.'
- We get a packet capture going, and then re-infect the victim machine, and boom - this is what we were looking for.
-
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).
-
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.
- 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.
- The next thing we need to do is follow the TCP stream.
-
The TCP flow starts with a GET request for what looks like a PE file named
pcfix.exe
with a pretty obviousaffid
(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:
-
At this point, if we want to, we could turn on
OpenVPN
and send acurl
request to grab a copy ofpcfix.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.
-
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 👍
-
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
.
-
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.
- Next, we check out
Symbol References
for the location of the call toURLDownloadToFileA
.
- According the MSDN,
URLDownloadToFile
takes "A pointer to a string value that contains the URL to download."
- The API call is contained in the function
FUN_140001000
.
-
Let's take a closer look at that function and try to figure out what it does.
-
At first glance, it looks pretty simple:
- Checks for a debugger
- If a debugger is found, it jumps to another location, changes around some registers and flags, and then eventually exits the program.
- If a debugger is not found, it continues with execution.
- Eventually, the program triggers a fatal exit.
- After that, it vanishes. 😶🌫️
- 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.
- I'll also set a Breakpoint on the call to
IsDebuggerPresent
.
- With the
ScyllaHide
plugin active this time, we have successfully skipped thejne
instruction.
- 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.
- Next, it does the same thing with the same thing with the Affiliate ID.
- It then prepares to drop the downloadable PE file under
%UserProfile%\AppData\Local\Temp
- It also assigns it a temporary file name - in this case,
BrB505C.tmp
- The
main
function makes a call toFUN_1400015A4
, which makes a call to the function that performs most of the important work.
- Stepping into
FUN_1400015a4
, we see a call the function that is responsible for most of the main features of this specimen.
-
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 toUrlDownloadToFileA
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).
- If no debugger is found, it initializes variables and performs XOR operations on some data in memory with key
- 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.
- Performs a simple debugger check with
- 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.