Jekyll2021-08-30T13:37:19+00:00https://synzack.github.io/feed.xmlRed Team BlogAn amazing website.Zach SteinBlinding EDR On Windows2020-10-16T00:00:00+00:002020-10-16T00:00:00+00:00https://synzack.github.io/Blinding-EDR-On-Windows<h1 id="acknowledgements">Acknowledgements</h1>
<p>My understanding of EDRs would not be possible without the help of many great security researchers. Below are some write-ups and talks that really helped me gain the understanding needed and hit the ground running on the research that will be presented here. If you are interested to go deeper, be sure to check out the following research (in no particular order):</p>
<p><strong>Jackson T</strong>: <a href="http://jackson-t.ca/edr-reversing-evading-01.html">A Guide to Reversing and Evading EDRs</a></p>
<p><strong>Christopher Vella</strong>:</p>
<p><a href="https://www.youtube.com/watch?v=85H4RvPGIX4">CrikeyCon 2019 - Reversing & bypassing EDRs</a></p>
<p><a href="https://christopher-vella.com/2019/09/06/recent-edr-av-observations/">Recent EDR & AV Observations</a></p>
<p><strong>Matteo Malvica</strong>: <a href="https://www.matteomalvica.com/blog/2020/07/15/silencing-the-edr/">Silencing the EDR. How to disable process, threads and image-loading detection callbacks</a></p>
<p><strong>William Burgess</strong>: <a href="https://www.youtube.com/watch?v=l8nkXCOYQC4">Red Teaming in the EDR Age</a></p>
<p><strong>BatSec</strong>: <a href="https://blog.dylan.codes/evading-sysmon-and-windows-event-logging/">Universally Evading Sysmon and ETW</a></p>
<p><strong>Rui Reis (fdiskyou)</strong>: <a href="http://deniable.org/windows/windows-callbacks">Windows Kernel Ps Callbacks Experiments</a></p>
<p><strong>Hoang Bui</strong>: <a href="https://medium.com/@fsx30/bypass-edrs-memory-protection-introduction-to-hooking-2efb21acffd6">Bypass EDR’s Memory Protection, Introduction to Hooking</a></p>
<p><strong>Omri Misgav and Udi Yavo</strong>: <a href="https://www.first.org/resources/papers/telaviv2019/Ensilo-Omri-Misgav-Udi-Yavo-Analyzing-Malware-Evasion-Trend-Bypassing-User-Mode-Hooks.pdf">Bypassing User-Mode Hooks</a></p>
<p><strong>Ackroute</strong>: <a href="https://ackroute.com/post/2017/08/08/sysmon-enumeration-overview/">Sysmon Enumeration Overview</a></p>
<h1 id="intro">Intro</h1>
<p>Generally, when it comes to offensive operations and EDR systems, the techniques can fall into one of four categories.</p>
<ol>
<li>Just avoid them
<ul>
<li>If a host has EDR, move on to a host where the appliance is not installed</li>
<li>Proxy traffic through the host, as to not execute commands on the system</li>
</ul>
</li>
<li>Stick to the gray area
<ul>
<li>Blending in with typical network traffic. These actions may be slightly suspicious, but keep a low enough profile to need human eyes to analyze further</li>
</ul>
</li>
<li>Operate in the blind spots
<ul>
<li>Sticking to those techniques which may not be logged. (ex. APIs, removing userland hooks, creating your own syscalls)</li>
</ul>
</li>
<li>Disabling/tampering with EDR sensors
<ul>
<li>Patching the sensor, redirecting traffic, uninstalling, etc.</li>
</ul>
</li>
</ol>
<p>This paper will be discussing those methods that would more fall into the “tampering” category, messing with the inner workings of the sensors themselves and how they hook into the system. While EDRs can also be installed on MacOS and Linux, this paper will focus only on Windows systems.</p>
<p>We will be discussing topics such as:</p>
<ul>
<li>Brief overview of the Windows kernel</li>
<li>Kernel Callbacks in security appliances</li>
<li>How/Why EDRs work</li>
<li>Techniques to remove EDR visibility</li>
<li>Short insights into other fun topics
<ul>
<li>The videogame hacking community</li>
<li>Windows rootkits</li>
</ul>
</li>
</ul>
<p>As research into EDRs is relatively new, these topics are typically from independent researchers on individual aspects of the technology. My goal is to bring some of that research together in a high-level overview to increase general understanding, knowledge of new offensive techniques, and drive detection capabilities.</p>
<p>That being said, the purpose of this is paper not to be as in depth as some of the individual research (the rabbit hole goes <strong><em>deep</em></strong>) so if this topic sparks your interest, I encourage you to check out some of the links above.</p>
<h1 id="what-is-an-edr">What is an EDR?</h1>
<p>EDR stands for Endpoint Detection and Response. EDRs are the next generation of anti-virus and detecting suspicious activities on host systems. They provide the tools needed for continuous monitoring and advanced threats.</p>
<p>EDRs not only can look for malicious files, but also monitor endpoint and network events and record them in a database for further analysis, detection, and investigation. In many EDR consoles, you can see process trees, execution flows, process injections, and much more. If you were or are currently a security analyst, you may have even directly used these tools in your work.</p>
<p>Below are some common EDR vendors you may know.</p>
<p><img src="/images/Blinding-EDR-On-Windows/vendors.png" alt="image-center" class="align-center" /></p>
<h1 id="prerequisites">Prerequisites</h1>
<h3 id="the-windows-kernel">The Windows Kernel</h3>
<p>Before we get into how EDRs work, we need to have a basic understanding of the Windows Kernel. In the Windows architecture, there are different access modes. Two of the modes being user mode (informally called user land) and the kernel mode (kernel land).</p>
<p>You can think of user land as the part of Windows that you interact with. This includes applications available to the user such as Microsoft Office, Internet browsers (Chrome, Firefox, and others), etc. Generally, any application you would use in daily work or home use.</p>
<p>Kernel land is where system services run. These include operating system code, device drivers, system services, and much more. Kernel mode has permissions to all system memory and CPU instructions. You can think of the kernel like the heart of the operating system that bridges the gap between applications and the underlying hardware.</p>
<p>The reason for the split, is to protect critical Windows functions from being modified by the user or a user land application. If users were able to directly modify kernel code, it has not only huge security concerns, but also functionality concerns. If critical functions are tampered with, causing unhandled exceptions, it could cause critical errors and cause the system to crash.</p>
<center>Microsoft Documentation</center>
<p><img src="/images/Blinding-EDR-On-Windows/windows-kernel.png" alt="image-center" class="align-center" /></p>
<h3 id="patchguard">PatchGuard</h3>
<p>Back in the day (the x86 Windows XP days and before), there was not a clear permission divide between the user land and the kernel land. Applications were able to patch kernel functions for their own purposes (although the practice was discouraged by Microsoft). For example, applications may patch the kernel syscall table to their own memory space. So, when an application calls a certain kernel function, the AV or malicious application could direct execution to their own memory space.</p>
<p>Below is an example of a potential syscall table and how it could be modified. Before PatchGuard, an application could change the syscall table addresses. So, when another application tries to call the function, it would actually be calling the “rogue” function.</p>
<p><img src="/images/Blinding-EDR-On-Windows/syscall-table.png" alt="image-center" class="align-center" /></p>
<p>Granted, this was not always with malicious intent, as many antivirus engines used this functionality to increase their visibility (if a malicious application calls a function, it is redirected and analyzed by the AV function instead). By the same token though, this paved the way for malware families called “rootkits” that could run at the deepest levels of the kernel, take complete control of the operating system functions, and even persist past system recoveries. Not only this, but any application (good or bad) that made a bad patch to the kernel, and caused an unhandled exception, would result in the host to blue screening and crashing.</p>
<p>The Windows solution to this was <a href="https://en.wikipedia.org/wiki/Kernel_Patch_Protection"><strong>Kernel Patch Protection (KPP)</strong></a>, more commonly known as <strong>PatchGuard</strong>. This feature was first implemented in x64 editions of Windows XP and Server 2003 SP1. This functionality enforces restrictions on what can and cannot be modified within the kernel (like modifying syscall addresses). If any unauthorized patch is made, PatchGuard will perform a bug check and shut down the system through a blue screen/reboot with a <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-0x109---critical-structure-corruption">CRITICAL_STRUCTURE_CORRUPTION</a> error. Examples of modifications that may trigger a bug check are:</p>
<ul>
<li>Modifying system service tables</li>
<li>Modifying descriptor tables</li>
<li>Modifying or patching kernel libraries</li>
<li>Kernel stacks not allocated by the kernel</li>
</ul>
<p><em>**It should be noted, PatchGuard is not a silver security bullet. Due to the way the Windows system operates, there are bypasses to PatchGuard, and malicious patches and rootkits still exist (although rare). Going in depth into PatchGuard is not in the scope of our EDR research.**</em></p>
<p>The biggest thing to take away from this, is that because of these protections, it wouldn’t be in AV/EDR vendors best interests to continue using kernel patches to operate. Because:</p>
<ol>
<li>
<p>If an AV/EDR service was using a PatchGuard bypass vulnerability to modify kernel space, it could be patched anytime by Microsoft and ruin their functionality and operations model</p>
</li>
<li>
<p>If there was a bug in the software, they would risk crashing the entire operating system</p>
</li>
</ol>
<p>Because of this, if applications (including AV/EDR applications), want to redirect execution flow, it has to happen within <strong>user land</strong>. They do interact with the kernel through things like drivers, but we will get into that shortly.</p>
<h3 id="how-do-processes-interact-with-the-kernel">How Do Processes Interact with the Kernel?</h3>
<p>When an application calls the Windows API to execute its code, the flow looks something like this. (This specific graphic is from Christopher Vela’s 2019 <a href="https://www.youtube.com/watch?v=85H4RvPGIX4">CrikeyCon talk</a>). Granted this is for <a href="https://github.com/gentilkiwi/mimikatz">Mimikatz.exe</a>, but the same can be said for any program.</p>
<center>Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella1.png" alt="image-center" class="align-center" /></p>
<p>In this example, because Mimikatz wants to read the memory from LSASS, it must call the <a href="https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory"><em>ReadProcessMemory</em></a> function within the Kernel32 library (called by Kernel32.dll). The function call will eventually be forwarded to the <em>NtReadVirtualMemory</em> call within Ntdll.dll. (The inner workings are a little more complicated, but it’s not completely necessary to know how these Windows API calls work for the purposes of this example).</p>
<p>Since applications cannot interact with the kernel directly, they use what are called “<a href="https://www.tutorialspoint.com/what-are-system-calls-in-operating-system">Syscalls</a>.” Syscalls act as a proxy-like call to kernel land.</p>
<p><img src="/images/Blinding-EDR-On-Windows/syscalls.png" alt="image-center" class="align-center" /></p>
<p>Basically, NTDLL creates the syscall to the kernel, where the kernel will execute the system call for <em>NtReadVirtualMemory</em>. The kernel runs the necessary functions and the results of that function are returned from the syscall to the application. This way, the application is able to utilize the kernel functionality, without actually modifying or running in the kernel memory space</p>
<h3 id="windows-drivers">Windows Drivers</h3>
<p>There are situations where an application needs to access protected data in the kernel. For this, a corresponding driver is used. There are different types of drivers, such as hardware and software drivers. For the focus of this paper, we will focus on software drivers as we won’t be interacting with hardware such as a printer.</p>
<p>According to <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/what-is-a-driver-">Microsoft documentation</a>, a software driver is used when a tool needs to access core operating system data structures. The type of data structures that can only be accessed by code running in kernel mode. Typically, a tool that needs this functionality is split into two parts:</p>
<ol>
<li>User mode component (application)
<ul>
<li>This component runs in user mode and presents the user interface. In the scope of EDRs, think of this as the GUI console where you analyze the events</li>
</ul>
</li>
<li>Kernel mode component (driver)
<ul>
<li>This component runs in kernel mode and passes information back to the corresponding application.</li>
</ul>
</li>
</ol>
<p>Below is a graphic from the same Microsoft documentation:</p>
<p><img src="/images/Blinding-EDR-On-Windows/drivers.png" alt="image-center" class="align-center" /></p>
<p>In many EDR implementations, there is a software driver that allows the application to have access to the kernel and utilize it for the increased visibility into processes.</p>
<p>It is important to know that while drivers can run in kernel mode, they are still subject to the PatchGuard limitations. They cannot patch the protected memory without crashing the system.</p>
<h3 id="kernel-callbacks">Kernel Callbacks</h3>
<p>When Microsoft implemented PatchGuard, it was understood that this would remove functionality from some programs (such as AV). The compromise that was implemented was the use of what are called kernel callbacks.</p>
<p>The way a kernel callback works is that a driver can register a “callback” in its code for any supported action and receive a <strong>pre</strong> or <strong>post</strong> notification when that certain action is performed. Callbacks will not perform any modification to the underlying Windows Kernel.</p>
<p>A common implementation of these callbacks is <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex?redirectedfrom=MSDN">PsSetCreateProcessNotifyRoutine(Ex)</a>. When a driver implements this callback function, anytime a new process is created, this callback routine is called and sends a notification to the driver which requested it. The driver can then execute its own functions accordingly.</p>
<p>Remember, this can be a pre or post notification. If a security appliance receives a pre notification that process is being created, it can check if that is a known bad file and give the EDR driver a notification to prevent the process from occurring. Similarly, if the risk is unknown, it can take the post notification and record the process actions for further analysis and correlation later.</p>
<p>The simplest visual I could find for this is from <a href="https://www.opensourceforu.com/2012/02/function-pointers-and-callbacks-in-c-an-odyssey/">OpenSourceForU</a>. When a certain action occurs, the callback sends a notification to the specified kernel driver, which then sends instructions back to the user land application.</p>
<p><img src="/images/Blinding-EDR-On-Windows/kernel-callbacks.jpg" alt="image-center" class="align-center" /></p>
<h1 id="so-how-do-edrs-work">So How Do EDRs Work?</h1>
<p>So, I know that there was a lot of information in the prerequisite section, and you may be asking why you need to know about the Windows kernel to understand an EDR. This is fundamental to understanding EDRs because they touch all of the above topics.</p>
<p>To gain their visibility, EDRs perform some version the following actions.</p>
<ul>
<li>Kernel Callbacks</li>
<li>DLL hooking/patching</li>
<li>Redirection of execution flow</li>
</ul>
<p>For the next sections, remember our process tree from earlier. We will elaborate on this process tree when adding an EDR to the mix.</p>
<center>Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella1.png" alt="image-center" class="align-center" /></p>
<h3 id="kernel-callbacks-1">Kernel Callbacks</h3>
<p>As stated earlier, many EDR applications have a corresponding driver which implements kernel callbacks. This example will be on a “process create” callback. When an application is executed (such as Mimikatz.exe) the process needs to be created through a function such as “<a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw"><em>CreateProcessW</em></a>”. By calling this function, a corresponding callback function is triggered and any driver that implements that callback receives a notification. So, in our graphic below:</p>
<ol>
<li>
<p>A malicious user or programs wants to spawn “malware.exe”. To do this, <em>CreateProcessW</em> is called to create the new process and its primary thread. If you compare this to our Mimikatz process graph, this is in the Kernel32 step.</p>
</li>
<li>
<p>The “process create” callback function is executed, and sends a pre notification to the EDR driver stating that a new process is going to be created</p>
</li>
<li>
<p>The EDR driver instructs the EDR application (EDR_Process.exe) to inject and hook NTDLL in the memory space of the application (malware.exe) to redirect execution flow to itself. On the Mimikatz graph, this is the NTDLL section, <strong>right before</strong> the syscall is made.</p>
</li>
</ol>
<center>Modified Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella3.png" alt="image-center" class="align-center" /></p>
<h3 id="dll-hooking">DLL Hooking</h3>
<p>Now let’s discuss what the NTDLL hooking entails.</p>
<p>Looking at our Mimikatz graph, here is where we currently are in our execution. NTDLL has been hooked by the EDR application, as instructed by the driver after receiving the callback notification. By hooking NTDLL, execution flow is redirected to the EDR memory space and functions (such as a DLL). As it is patching the memory space in <strong>user land</strong>, there is no risk of crashing the kernel, and complies with PatchGuard.</p>
<center>Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella4.png" alt="image-center" class="align-center" /></p>
<p>Now you may be wondering what hooking means. Breaking this down further, below is an example of how an EDR might hook a DLL.</p>
<p>In the original NTDLL memory space (top box in red), the syscall instruction is seen to pass the execution to the kernel. This is the normal flow for an unhooked function.</p>
<p>In the hooked/patched function (bottom), an unconditional jump (or other instruction) is seen to the EDR memory space, in this graphic, <em>ctiuser</em> (in the scope of our graph this is EDR.dll).</p>
<p>Once the execution flow has been redirected, the EDR engine analyzes the request and determines the execution it is okay to run. If the execution is determined safe enough to run, it will redirect function back to the original <em>NtWriteVirtualMemory</em> address and execute the syscall to the kernel and return the response back to the requesting application. (left flow)</p>
<p>If the call is determined to be malicious, it will not make the system call, and terminate the process. (right flow)</p>
<center>Modified Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella5.png" alt="image-center" class="align-center" /></p>
<p>Going back to our Mimikatz graph, here is our flow including the callbacks and hooking.</p>
<center>Modified Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella-mod1.png" alt="image-center" class="align-center" /></p>
<h1 id="blinding-the-edr-sensor">Blinding the EDR Sensor</h1>
<p>Alright, so now that we have a <em>basic</em> understanding of how EDR appliances get their visibility, we can start to understand their weak points. From what we know so far, we have two main places where we can hinder execution flow</p>
<ol>
<li>Removing the DLL hooks</li>
<li>Removing the kernel callbacks</li>
</ol>
<p>While removing DLL hooks would work, it would likely have to be unhooked from each executable we run. This is not impossible, but we are going to be lazy and take the path of least resistance. If we remove the kernel callback entirely, in theory, ANY executable we run would not be subject to the judgement of the EDR. This is less stealthy than being more selective and doing it for each executable, but we won’t focus on DLL hooking for this demonstration.</p>
<p>Looking at our graph, here is where we are going to blind the sensor (blue).</p>
<center>Modified Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella-mod2.png" alt="image-center" class="align-center" /></p>
<p>If no callback is made, the EDR driver will be unaware of the function call that will be sent to the kernel, the EDR appliance will never instructed to hook the DLL, and no redirection will occur in the execution flow. Thus, returning a clean, unmonitored flow:</p>
<center>Slide from Christopher Vella</center>
<p><img src="/images/Blinding-EDR-On-Windows/vella-mod3.png" alt="image-center" class="align-center" /></p>
<h1 id="stopping-the-callback">Stopping the Callback</h1>
<p>To remove a callback, we can choose from one of three options (although I’m sure you can come up with more) depending how disruptive we want to be.</p>
<ol>
<li>Zero out the <strong>entire</strong> callback array</li>
<li>Zero out the <strong>specific process</strong> notify callback (delete only the EDR driver in the callback array)</li>
<li>Patch the EDR process notify callback</li>
</ol>
<p>Let’s break each down.</p>
<h4 id="zeroing-out-callback-arrays">Zeroing Out Callback Arrays</h4>
<p>There is a lot that goes into callback arrays, but to make it simple, you can think of it as <strong>an array that holds pointers to every driver that requests notification from the callback function</strong>. To show this, I will step into the Windows Kernel Debugger (KD). We won’t go into the details of how debugging works; this is more to show there is in-fact a callback array which exists.</p>
<p>First, we will unassemble (“u”) <em>PspSetCreateProcessNotifyRoutine</em>, all we need to know for now is this is the callback routine which runs when a new process is created. We will continue unassembling until we reach an “lea” instruction. Again, all you need to know, is that this address will hold the callback array containing the list of drivers requesting the callback.</p>
<p><img src="/images/Blinding-EDR-On-Windows/kd1.png" alt="image-center" class="align-center" /></p>
<p>Looking into this memory address, we see the following array. Everything highlighted in red is a different pointer to a driver.</p>
<p><img src="/images/Blinding-EDR-On-Windows/kd2.png" alt="image-center" class="align-center" /></p>
<p>Now, I am going to cheat a little bit and use a tool we will discuss later, but to prove these are driver callbacks, lets list them alongside their names. While I won’t mention which specific EDR this is, just take my word that the highlighted is the EDR driver.</p>
<p><img src="/images/Blinding-EDR-On-Windows/kd3.png" alt="image-center" class="align-center" /></p>
<p>We could zero out every address in this array, but that could cause the other drivers to potentially behave improperly, and you probably wouldn’t want to do that as an adversary or red teamer.</p>
<p>As we can see above, the value of the 6th element in our array is our EDR driver. If we zero out the callback address for the 6th element in the array (7th value, as arrays start with 0), in theory, we should be able to blind the EDR into process create events.</p>
<p>To demonstrate, let’s run Mimikatz (the most recent version on GitHub, no modifications) without modifying any callbacks. By running it, we are calling the “process create” function and triggering a callback that will notify the EDR, as its driver is in the callback array.</p>
<p><img src="/images/Blinding-EDR-On-Windows/mimi.png" alt="image-center" class="align-center" /></p>
<p>We see that the driver saw the malicious process being created and instructed termination of the process.</p>
<p>Now, let’s zero out the EDR callback, removing the EDR driver from the array, and see if we can stop a notification from being sent to the EDR application.</p>
<p><img src="/images/Blinding-EDR-On-Windows/mimi2.png" alt="image-center" class="align-center" /></p>
<p>Run Mimikatz. As there is no longer a callback notification, the EDR is unaware the process was created, and no analysis/termination is performed.</p>
<p><img src="/images/Blinding-EDR-On-Windows/mimi3.png" alt="image-center" class="align-center" /></p>
<p>If we return the driver address to our callback array, we can see the EDR functioning as intended when we run our program.</p>
<p><img src="/images/Blinding-EDR-On-Windows/mimi4.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/mimi5.png" alt="image-center" class="align-center" /></p>
<h4 id="patching-the-edr-process-notify-callback">Patching the EDR Process Notify Callback</h4>
<p>This method involved leaving the EDR driver callback in the array (not zeroing out) but changing the first instruction in the function to a “ret” function. In assembly instructions, this basically means just return.</p>
<p>Unassembling the EDR driver function further, we can see the beginning instruction before any changes.</p>
<p><img src="/images/Blinding-EDR-On-Windows/patching1.png" alt="image-center" class="align-center" /></p>
<p>Using our secret tool again, we will patch the first instruction with the ‘ret’ command.</p>
<p><img src="/images/Blinding-EDR-On-Windows/patching2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/patching3.png" alt="image-center" class="align-center" /></p>
<p>Now, when we run Mimikatz, the callback function will still be called, but it will immediately “return” to normal execution flow:</p>
<p><img src="/images/Blinding-EDR-On-Windows/patching4.png" alt="image-center" class="align-center" /></p>
<p>To prove this works, let’s return the original instruction back into the function:</p>
<p><img src="/images/Blinding-EDR-On-Windows/patching5.png" alt="image-center" class="align-center" /></p>
<p>We can see that the EDR once again is able to terminate the execution flow.</p>
<p><img src="/images/Blinding-EDR-On-Windows/patching6.png" alt="image-center" class="align-center" /></p>
<h1 id="optimizing-for-offensive-operations">Optimizing for Offensive Operations</h1>
<p>While we can demonstrate blinding the EDR with the Windows Kernel Debugger, obviously, this is not ideal for a red team campaign or covert offensive operation. It would not be stealthy nor effective to jump into the debugger on every host where you wanted to tamper with EDR. This is where our secret tool comes into play.</p>
<p>To do this automatically through a malicious application, we need to create our own evil driver/ evil application combination, much like the EDR driver and application working together. Basically, fighting the kernel with the kernel.</p>
<p>I am not a kernel programmer, and won’t pretend to be, so we are going to use the evil client/evil driver from fdiskyou’s GitHub project at:</p>
<ul>
<li><a href="https://github.com/fdiskyou/windows-ps-callbacks-experiments">https://github.com/fdiskyou/windows-ps-callbacks-experiments</a></li>
</ul>
<p>This is the accompanying repo for his <a href="http://deniable.org/windows/windows-callbacks">research</a>, which is listed in the acknowledgements.</p>
<p>Compiling the source code, you will get two files:</p>
<ol>
<li>evil.sys (driver)</li>
<li>evilcli.exe (application) – I renamed this to “<em>ninja.exe</em>” in our previous example
Below are the functions as outlined by the executable. It can zero out the callback arrays, as well as patch the function instructions with the “ret” command. It can also revert any changes back to how they were before the patching.</li>
</ol>
<p><img src="/images/Blinding-EDR-On-Windows/evilcli.png" alt="image-center" class="align-center" /></p>
<p>The application works in tangent with the driver. The driver is what has the permissions necessary to read and modify the callback arrays, as it is running within the kernel space. The application is the user panel to instruct the driver on which commands to execute.</p>
<h1 id="loading-a-driver-on-windows">Loading a Driver on Windows</h1>
<p>To load a driver on a Windows system, you need a certain permission set, and comply with certain security rules:</p>
<ol>
<li>To load a driver, you need to be running with at least Administrator permissions on the host</li>
<li>Windows does not let an unsigned kernel driver be loaded
<ul>
<li>The exception is if you enable “<a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/install/the-testsigning-boot-configuration-option"><em>test signing mode</em></a>” (not seen outside of maybe developer environments)</li>
<li>Otherwise, you have two options:
<ul>
<li>Exploit an existing driver</li>
<li>Acquire a signature for your driver</li>
</ul>
</li>
</ul>
</li>
<li>Any certificate issued after July 29th, 2015 will not be allowed to load on secure boot machines running on certain versions of Windows 10</li>
</ol>
<p>Looking at our requirements, local Administrator is a barrier, but it is not uncommon on an offensive engagement.</p>
<p>Loading the driver is where we run into more difficulty. I am not experienced in kernel driver exploitation, so I won’t choose this option. That leaves acquiring a signature for our evil.sys driver. The <a href="http://wrogn.com/tag/driver-signing/">process</a> of getting a certificate from Microsoft is getting more stringent, (which is a great thing) and requires driver review by Microsoft, their certificate, and hundreds of dollars. So that leaves finding an existing certificate.</p>
<p>Demonstrated below, we are unable to load our driver outside of “test signing mode” (not covered here).</p>
<p><img src="/images/Blinding-EDR-On-Windows/load-driver.png" alt="image-center" class="align-center" /></p>
<p>After going down a long rabbit hole, I discovered a community that is familiar with exploiting and creating their own drivers. To my surprise, video game hackers have a very similar problem set to us and EDR, with regards to anti-cheat engines.</p>
<p>Anti-cheat engines for videogames work somewhat similar to EDRs in their function. They typically come with a driver that has the same ability to inject into the videogame’s memory space to ensure that no memory nor function calls have been modified.</p>
<p>To get around these anti-cheat engines, these hackers will also either load their own driver or exploit an existing driver to disable the functionality of the engines, much like us with EDR. (Look into the well-known <a href="https://www.fuzzysecurity.com/tutorials/28.html">vulnerable Capcom driver</a> if you’re interested)</p>
<p><strong><em>Before we continue, I would like to emphasize that I do not encourage using the following techniques for malicious purposes such as unauthorized hacking or cheating in online games. This is simply a proof of concept on how they could be abused in an environment you have permission to test in.</em></strong></p>
<p>Digging through some forums, I quickly found someone who may have an answer to my problem set.</p>
<p><img src="/images/Blinding-EDR-On-Windows/forum.png" alt="image-center" class="align-center" /></p>
<p>Looking at the certificate, it was even created before our July 29th, 2015 cutoff date! Another interesting fact about driver certificates is that Microsoft generally doesn’t care if the certificate is expired. As long as it was valid at one point. This may change in the future, but for now this is allowed.</p>
<p><img src="/images/Blinding-EDR-On-Windows/cert.png" alt="image-center" class="align-center" /></p>
<p>Microsoft allows for signing drivers with their <a href="https://docs.microsoft.com/en-us/windows/win32/seccrypto/signtool">SignTool</a> and an appropriate <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/install/cross-certificates-for-kernel-mode-code-signing">cross-certificate</a>. A cross certificate is “a digital certificate issued by one Certificate Authority (CA) that is used to sign the public key for the root certificate of another Certificate Authority. Cross-certificates provide a means to create a chain of trust from a single, trusted, root CA to multiple other CAs”</p>
<p>Cross-Certificates:</p>
<ul>
<li>Allow the operating system kernel to have a single trusted Microsoft root authority</li>
<li>Extend the chain of trust to multiple commercial CAs that issue Software Publisher Certificates (SPCs), which are used for code-signing software for distribution, installation, and loading on Windows</li>
</ul>
<p>Microsoft’s official documentation page has downloads for each CA cross-certificate.</p>
<p><img src="/images/Blinding-EDR-On-Windows/cross-cert.png" alt="image-center" class="align-center" /></p>
<p>As our certificate is issued by “VeriSign Class 3 Public Primary Certification Authority,” we will download the corresponding certificate. Using the certificate and cross-certificate together, we can sign our evil driver.</p>
<p>To sign the certificate, we will use the SignTool mentioned before.</p>
<p><img src="/images/Blinding-EDR-On-Windows/sign-tool.png" alt="image-center" class="align-center" /></p>
<p>As we can see, we hit a small issue. It is saying we have no certificates that meet the criteria. Remember, the certificate expired in November of 2014. Turns out, we can pull some trickery with our system time.</p>
<p><img src="/images/Blinding-EDR-On-Windows/date-time.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/sign-tool2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/evil-cli-cert.png" alt="image-center" class="align-center" /></p>
<p>With a “valid” certificate, we should now be able to load the driver without a problem</p>
<p><img src="/images/Blinding-EDR-On-Windows/load-driver2.png" alt="image-center" class="align-center" /></p>
<p>When we run our corresponding evilcli.exe application, we now can utilize the power of our new driver.</p>
<p><img src="/images/Blinding-EDR-On-Windows/run-evilcli.png" alt="image-center" class="align-center" /></p>
<p>To show the correlation between the application and driver, below is what happens when you run the application without starting the driver.</p>
<p><img src="/images/Blinding-EDR-On-Windows/sc-evil.png" alt="image-center" class="align-center" /></p>
<h1 id="bringing-it-all-together">Bringing It All Together</h1>
<p>Finally, let’s use our new evil program to blind both the process, thread, and loadimage callbacks within our EDR driver and execute Mimikatz to get a full password dump.</p>
<p>First, we can see our EDR service is running (you’ll have to take my word again).</p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together1.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together3.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together4.png" alt="image-center" class="align-center" /></p>
<p>And to show restoring EDR callbacks:</p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together5.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Blinding-EDR-On-Windows/all-together6.png" alt="image-center" class="align-center" /></p>
<h1 id="potential-detections">Potential Detections</h1>
<p>Generally speaking, antivirus and other security appliances generally do not as heavily scrutinize drivers. They are typically treated with significantly more trust than typical user applications. Because of this, virus signatures are probably not the most reliable way to detect malicious drivers. (There were no AV detections from the EDR on my files).</p>
<p>In addition, many EDRs do not have anti-tampering measures implemented to check if their callbacks are zeroed out or changed. The reason for this is likely because as they are running in the kernel, they do not want to have the overhead of additional CPU cycles from continuously checking. This may change in the future with new research, but for now, we also can’t depend on the EDR to check for us.</p>
<p>What I did find, is that Windows event logs actually record when a driver is loaded within the System logs. Below is a normal EventID 7045 (A new service has been installed) for a legitimate Dell driver. These events happen when a new service/driver is installed on a machine. You may see this when you install printer/wifi/usb or another driver.</p>
<p>In all but one edge case (at least on my machine) the security identifier (SID) was always “S-1-5-18” (the local system account) when a kernel mode driver was loaded.</p>
<p><img src="/images/Blinding-EDR-On-Windows/detections1.png" alt="image-center" class="align-center" /></p>
<p>As you can see when loading our evil driver, it was installed by a user SID:</p>
<p><img src="/images/Blinding-EDR-On-Windows/detections2.png" alt="image-center" class="align-center" /></p>
<p>Granted, the driver is “evil.sys” and is installed in a user’s desktop, but in an actual campaign, it would likely have a legitimate name and be installed in the <em>System32\Drivers\</em> directory.</p>
<p>I am sure if you were creating services with SYSTEM permissions, it would look different, but typically this requires tools like PSEXEC or exploits which would likely be noisier and have more potential to be flagged by AV/EDR.</p>
<p>This may not be a perfect detection, as there are edge cases. Below is an installation of the Npcap Packet Driver which comes with Wireshark installations. But I would imagine that in a non-technical business environment, drivers like these probably wouldn’t be installing on a normal workstation.</p>
<p><img src="/images/Blinding-EDR-On-Windows/detections3.png" alt="image-center" class="align-center" /></p>Zach SteinAcknowledgements My understanding of EDRs would not be possible without the help of many great security researchers. Below are some write-ups and talks that really helped me gain the understanding needed and hit the ground running on the research that will be presented here. If you are interested to go deeper, be sure to check out the following research (in no particular order): Jackson T: A Guide to Reversing and Evading EDRs Christopher Vella: CrikeyCon 2019 - Reversing & bypassing EDRs Recent EDR & AV Observations Matteo Malvica: Silencing the EDR. How to disable process, threads and image-loading detection callbacks William Burgess: Red Teaming in the EDR Age BatSec: Universally Evading Sysmon and ETW Rui Reis (fdiskyou): Windows Kernel Ps Callbacks Experiments Hoang Bui: Bypass EDR’s Memory Protection, Introduction to Hooking Omri Misgav and Udi Yavo: Bypassing User-Mode Hooks Ackroute: Sysmon Enumeration Overview Intro Generally, when it comes to offensive operations and EDR systems, the techniques can fall into one of four categories. Just avoid them If a host has EDR, move on to a host where the appliance is not installed Proxy traffic through the host, as to not execute commands on the system Stick to the gray area Blending in with typical network traffic. These actions may be slightly suspicious, but keep a low enough profile to need human eyes to analyze further Operate in the blind spots Sticking to those techniques which may not be logged. (ex. APIs, removing userland hooks, creating your own syscalls) Disabling/tampering with EDR sensors Patching the sensor, redirecting traffic, uninstalling, etc. This paper will be discussing those methods that would more fall into the “tampering” category, messing with the inner workings of the sensors themselves and how they hook into the system. While EDRs can also be installed on MacOS and Linux, this paper will focus only on Windows systems. We will be discussing topics such as: Brief overview of the Windows kernel Kernel Callbacks in security appliances How/Why EDRs work Techniques to remove EDR visibility Short insights into other fun topics The videogame hacking community Windows rootkits As research into EDRs is relatively new, these topics are typically from independent researchers on individual aspects of the technology. My goal is to bring some of that research together in a high-level overview to increase general understanding, knowledge of new offensive techniques, and drive detection capabilities. That being said, the purpose of this is paper not to be as in depth as some of the individual research (the rabbit hole goes deep) so if this topic sparks your interest, I encourage you to check out some of the links above. What is an EDR? EDR stands for Endpoint Detection and Response. EDRs are the next generation of anti-virus and detecting suspicious activities on host systems. They provide the tools needed for continuous monitoring and advanced threats. EDRs not only can look for malicious files, but also monitor endpoint and network events and record them in a database for further analysis, detection, and investigation. In many EDR consoles, you can see process trees, execution flows, process injections, and much more. If you were or are currently a security analyst, you may have even directly used these tools in your work. Below are some common EDR vendors you may know. Prerequisites The Windows Kernel Before we get into how EDRs work, we need to have a basic understanding of the Windows Kernel. In the Windows architecture, there are different access modes. Two of the modes being user mode (informally called user land) and the kernel mode (kernel land). You can think of user land as the part of Windows that you interact with. This includes applications available to the user such as Microsoft Office, Internet browsers (Chrome, Firefox, and others), etc. Generally, any application you would use in daily work or home use. Kernel land is where system services run. These include operating system code, device drivers, system services, and much more. Kernel mode has permissions to all system memory and CPU instructions. You can think of the kernel like the heart of the operating system that bridges the gap between applications and the underlying hardware. The reason for the split, is to protect critical Windows functions from being modified by the user or a user land application. If users were able to directly modify kernel code, it has not only huge security concerns, but also functionality concerns. If critical functions are tampered with, causing unhandled exceptions, it could cause critical errors and cause the system to crash. Microsoft Documentation PatchGuard Back in the day (the x86 Windows XP days and before), there was not a clear permission divide between the user land and the kernel land. Applications were able to patch kernel functions for their own purposes (although the practice was discouraged by Microsoft). For example, applications may patch the kernel syscall table to their own memory space. So, when an application calls a certain kernel function, the AV or malicious application could direct execution to their own memory space. Below is an example of a potential syscall table and how it could be modified. Before PatchGuard, an application could change the syscall table addresses. So, when another application tries to call the function, it would actually be calling the “rogue” function. Granted, this was not always with malicious intent, as many antivirus engines used this functionality to increase their visibility (if a malicious application calls a function, it is redirected and analyzed by the AV function instead). By the same token though, this paved the way for malware families called “rootkits” that could run at the deepest levels of the kernel, take complete control of the operating system functions, and even persist past system recoveries. Not only this, but any application (good or bad) that made a bad patch to the kernel, and caused an unhandled exception, would result in the host to blue screening and crashing. The Windows solution to this was Kernel Patch Protection (KPP), more commonly known as PatchGuard. This feature was first implemented in x64 editions of Windows XP and Server 2003 SP1. This functionality enforces restrictions on what can and cannot be modified within the kernel (like modifying syscall addresses). If any unauthorized patch is made, PatchGuard will perform a bug check and shut down the system through a blue screen/reboot with a CRITICAL_STRUCTURE_CORRUPTION error. Examples of modifications that may trigger a bug check are: Modifying system service tables Modifying descriptor tables Modifying or patching kernel libraries Kernel stacks not allocated by the kernel **It should be noted, PatchGuard is not a silver security bullet. Due to the way the Windows system operates, there are bypasses to PatchGuard, and malicious patches and rootkits still exist (although rare). Going in depth into PatchGuard is not in the scope of our EDR research.** The biggest thing to take away from this, is that because of these protections, it wouldn’t be in AV/EDR vendors best interests to continue using kernel patches to operate. Because: If an AV/EDR service was using a PatchGuard bypass vulnerability to modify kernel space, it could be patched anytime by Microsoft and ruin their functionality and operations model If there was a bug in the software, they would risk crashing the entire operating system Because of this, if applications (including AV/EDR applications), want to redirect execution flow, it has to happen within user land. They do interact with the kernel through things like drivers, but we will get into that shortly. How Do Processes Interact with the Kernel? When an application calls the Windows API to execute its code, the flow looks something like this. (This specific graphic is from Christopher Vela’s 2019 CrikeyCon talk). Granted this is for Mimikatz.exe, but the same can be said for any program. Slide from Christopher Vella In this example, because Mimikatz wants to read the memory from LSASS, it must call the ReadProcessMemory function within the Kernel32 library (called by Kernel32.dll). The function call will eventually be forwarded to the NtReadVirtualMemory call within Ntdll.dll. (The inner workings are a little more complicated, but it’s not completely necessary to know how these Windows API calls work for the purposes of this example). Since applications cannot interact with the kernel directly, they use what are called “Syscalls.” Syscalls act as a proxy-like call to kernel land. Basically, NTDLL creates the syscall to the kernel, where the kernel will execute the system call for NtReadVirtualMemory. The kernel runs the necessary functions and the results of that function are returned from the syscall to the application. This way, the application is able to utilize the kernel functionality, without actually modifying or running in the kernel memory space Windows Drivers There are situations where an application needs to access protected data in the kernel. For this, a corresponding driver is used. There are different types of drivers, such as hardware and software drivers. For the focus of this paper, we will focus on software drivers as we won’t be interacting with hardware such as a printer. According to Microsoft documentation, a software driver is used when a tool needs to access core operating system data structures. The type of data structures that can only be accessed by code running in kernel mode. Typically, a tool that needs this functionality is split into two parts: User mode component (application) This component runs in user mode and presents the user interface. In the scope of EDRs, think of this as the GUI console where you analyze the events Kernel mode component (driver) This component runs in kernel mode and passes information back to the corresponding application. Below is a graphic from the same Microsoft documentation: In many EDR implementations, there is a software driver that allows the application to have access to the kernel and utilize it for the increased visibility into processes. It is important to know that while drivers can run in kernel mode, they are still subject to the PatchGuard limitations. They cannot patch the protected memory without crashing the system. Kernel Callbacks When Microsoft implemented PatchGuard, it was understood that this would remove functionality from some programs (such as AV). The compromise that was implemented was the use of what are called kernel callbacks. The way a kernel callback works is that a driver can register a “callback” in its code for any supported action and receive a pre or post notification when that certain action is performed. Callbacks will not perform any modification to the underlying Windows Kernel. A common implementation of these callbacks is PsSetCreateProcessNotifyRoutine(Ex). When a driver implements this callback function, anytime a new process is created, this callback routine is called and sends a notification to the driver which requested it. The driver can then execute its own functions accordingly. Remember, this can be a pre or post notification. If a security appliance receives a pre notification that process is being created, it can check if that is a known bad file and give the EDR driver a notification to prevent the process from occurring. Similarly, if the risk is unknown, it can take the post notification and record the process actions for further analysis and correlation later. The simplest visual I could find for this is from OpenSourceForU. When a certain action occurs, the callback sends a notification to the specified kernel driver, which then sends instructions back to the user land application. So How Do EDRs Work? So, I know that there was a lot of information in the prerequisite section, and you may be asking why you need to know about the Windows kernel to understand an EDR. This is fundamental to understanding EDRs because they touch all of the above topics. To gain their visibility, EDRs perform some version the following actions. Kernel Callbacks DLL hooking/patching Redirection of execution flow For the next sections, remember our process tree from earlier. We will elaborate on this process tree when adding an EDR to the mix. Slide from Christopher Vella Kernel Callbacks As stated earlier, many EDR applications have a corresponding driver which implements kernel callbacks. This example will be on a “process create” callback. When an application is executed (such as Mimikatz.exe) the process needs to be created through a function such as “CreateProcessW”. By calling this function, a corresponding callback function is triggered and any driver that implements that callback receives a notification. So, in our graphic below: A malicious user or programs wants to spawn “malware.exe”. To do this, CreateProcessW is called to create the new process and its primary thread. If you compare this to our Mimikatz process graph, this is in the Kernel32 step. The “process create” callback function is executed, and sends a pre notification to the EDR driver stating that a new process is going to be created The EDR driver instructs the EDR application (EDR_Process.exe) to inject and hook NTDLL in the memory space of the application (malware.exe) to redirect execution flow to itself. On the Mimikatz graph, this is the NTDLL section, right before the syscall is made. Modified Slide from Christopher Vella DLL Hooking Now let’s discuss what the NTDLL hooking entails. Looking at our Mimikatz graph, here is where we currently are in our execution. NTDLL has been hooked by the EDR application, as instructed by the driver after receiving the callback notification. By hooking NTDLL, execution flow is redirected to the EDR memory space and functions (such as a DLL). As it is patching the memory space in user land, there is no risk of crashing the kernel, and complies with PatchGuard. Slide from Christopher Vella Now you may be wondering what hooking means. Breaking this down further, below is an example of how an EDR might hook a DLL. In the original NTDLL memory space (top box in red), the syscall instruction is seen to pass the execution to the kernel. This is the normal flow for an unhooked function. In the hooked/patched function (bottom), an unconditional jump (or other instruction) is seen to the EDR memory space, in this graphic, ctiuser (in the scope of our graph this is EDR.dll). Once the execution flow has been redirected, the EDR engine analyzes the request and determines the execution it is okay to run. If the execution is determined safe enough to run, it will redirect function back to the original NtWriteVirtualMemory address and execute the syscall to the kernel and return the response back to the requesting application. (left flow) If the call is determined to be malicious, it will not make the system call, and terminate the process. (right flow) Modified Slide from Christopher Vella Going back to our Mimikatz graph, here is our flow including the callbacks and hooking. Modified Slide from Christopher Vella Blinding the EDR Sensor Alright, so now that we have a basic understanding of how EDR appliances get their visibility, we can start to understand their weak points. From what we know so far, we have two main places where we can hinder execution flow Removing the DLL hooks Removing the kernel callbacks While removing DLL hooks would work, it would likely have to be unhooked from each executable we run. This is not impossible, but we are going to be lazy and take the path of least resistance. If we remove the kernel callback entirely, in theory, ANY executable we run would not be subject to the judgement of the EDR. This is less stealthy than being more selective and doing it for each executable, but we won’t focus on DLL hooking for this demonstration. Looking at our graph, here is where we are going to blind the sensor (blue). Modified Slide from Christopher Vella If no callback is made, the EDR driver will be unaware of the function call that will be sent to the kernel, the EDR appliance will never instructed to hook the DLL, and no redirection will occur in the execution flow. Thus, returning a clean, unmonitored flow: Slide from Christopher Vella Stopping the Callback To remove a callback, we can choose from one of three options (although I’m sure you can come up with more) depending how disruptive we want to be. Zero out the entire callback array Zero out the specific process notify callback (delete only the EDR driver in the callback array) Patch the EDR process notify callback Let’s break each down. Zeroing Out Callback Arrays There is a lot that goes into callback arrays, but to make it simple, you can think of it as an array that holds pointers to every driver that requests notification from the callback function. To show this, I will step into the Windows Kernel Debugger (KD). We won’t go into the details of how debugging works; this is more to show there is in-fact a callback array which exists. First, we will unassemble (“u”) PspSetCreateProcessNotifyRoutine, all we need to know for now is this is the callback routine which runs when a new process is created. We will continue unassembling until we reach an “lea” instruction. Again, all you need to know, is that this address will hold the callback array containing the list of drivers requesting the callback. Looking into this memory address, we see the following array. Everything highlighted in red is a different pointer to a driver. Now, I am going to cheat a little bit and use a tool we will discuss later, but to prove these are driver callbacks, lets list them alongside their names. While I won’t mention which specific EDR this is, just take my word that the highlighted is the EDR driver. We could zero out every address in this array, but that could cause the other drivers to potentially behave improperly, and you probably wouldn’t want to do that as an adversary or red teamer. As we can see above, the value of the 6th element in our array is our EDR driver. If we zero out the callback address for the 6th element in the array (7th value, as arrays start with 0), in theory, we should be able to blind the EDR into process create events. To demonstrate, let’s run Mimikatz (the most recent version on GitHub, no modifications) without modifying any callbacks. By running it, we are calling the “process create” function and triggering a callback that will notify the EDR, as its driver is in the callback array. We see that the driver saw the malicious process being created and instructed termination of the process. Now, let’s zero out the EDR callback, removing the EDR driver from the array, and see if we can stop a notification from being sent to the EDR application. Run Mimikatz. As there is no longer a callback notification, the EDR is unaware the process was created, and no analysis/termination is performed. If we return the driver address to our callback array, we can see the EDR functioning as intended when we run our program. Patching the EDR Process Notify Callback This method involved leaving the EDR driver callback in the array (not zeroing out) but changing the first instruction in the function to a “ret” function. In assembly instructions, this basically means just return. Unassembling the EDR driver function further, we can see the beginning instruction before any changes. Using our secret tool again, we will patch the first instruction with the ‘ret’ command. Now, when we run Mimikatz, the callback function will still be called, but it will immediately “return” to normal execution flow: To prove this works, let’s return the original instruction back into the function: We can see that the EDR once again is able to terminate the execution flow. Optimizing for Offensive Operations While we can demonstrate blinding the EDR with the Windows Kernel Debugger, obviously, this is not ideal for a red team campaign or covert offensive operation. It would not be stealthy nor effective to jump into the debugger on every host where you wanted to tamper with EDR. This is where our secret tool comes into play. To do this automatically through a malicious application, we need to create our own evil driver/ evil application combination, much like the EDR driver and application working together. Basically, fighting the kernel with the kernel. I am not a kernel programmer, and won’t pretend to be, so we are going to use the evil client/evil driver from fdiskyou’s GitHub project at: https://github.com/fdiskyou/windows-ps-callbacks-experiments This is the accompanying repo for his research, which is listed in the acknowledgements. Compiling the source code, you will get two files: evil.sys (driver) evilcli.exe (application) – I renamed this to “ninja.exe” in our previous example Below are the functions as outlined by the executable. It can zero out the callback arrays, as well as patch the function instructions with the “ret” command. It can also revert any changes back to how they were before the patching. The application works in tangent with the driver. The driver is what has the permissions necessary to read and modify the callback arrays, as it is running within the kernel space. The application is the user panel to instruct the driver on which commands to execute. Loading a Driver on Windows To load a driver on a Windows system, you need a certain permission set, and comply with certain security rules: To load a driver, you need to be running with at least Administrator permissions on the host Windows does not let an unsigned kernel driver be loaded The exception is if you enable “test signing mode” (not seen outside of maybe developer environments) Otherwise, you have two options: Exploit an existing driver Acquire a signature for your driver Any certificate issued after July 29th, 2015 will not be allowed to load on secure boot machines running on certain versions of Windows 10 Looking at our requirements, local Administrator is a barrier, but it is not uncommon on an offensive engagement. Loading the driver is where we run into more difficulty. I am not experienced in kernel driver exploitation, so I won’t choose this option. That leaves acquiring a signature for our evil.sys driver. The process of getting a certificate from Microsoft is getting more stringent, (which is a great thing) and requires driver review by Microsoft, their certificate, and hundreds of dollars. So that leaves finding an existing certificate. Demonstrated below, we are unable to load our driver outside of “test signing mode” (not covered here). After going down a long rabbit hole, I discovered a community that is familiar with exploiting and creating their own drivers. To my surprise, video game hackers have a very similar problem set to us and EDR, with regards to anti-cheat engines. Anti-cheat engines for videogames work somewhat similar to EDRs in their function. They typically come with a driver that has the same ability to inject into the videogame’s memory space to ensure that no memory nor function calls have been modified. To get around these anti-cheat engines, these hackers will also either load their own driver or exploit an existing driver to disable the functionality of the engines, much like us with EDR. (Look into the well-known vulnerable Capcom driver if you’re interested) Before we continue, I would like to emphasize that I do not encourage using the following techniques for malicious purposes such as unauthorized hacking or cheating in online games. This is simply a proof of concept on how they could be abused in an environment you have permission to test in. Digging through some forums, I quickly found someone who may have an answer to my problem set. Looking at the certificate, it was even created before our July 29th, 2015 cutoff date! Another interesting fact about driver certificates is that Microsoft generally doesn’t care if the certificate is expired. As long as it was valid at one point. This may change in the future, but for now this is allowed. Microsoft allows for signing drivers with their SignTool and an appropriate cross-certificate. A cross certificate is “a digital certificate issued by one Certificate Authority (CA) that is used to sign the public key for the root certificate of another Certificate Authority. Cross-certificates provide a means to create a chain of trust from a single, trusted, root CA to multiple other CAs” Cross-Certificates: Allow the operating system kernel to have a single trusted Microsoft root authority Extend the chain of trust to multiple commercial CAs that issue Software Publisher Certificates (SPCs), which are used for code-signing software for distribution, installation, and loading on Windows Microsoft’s official documentation page has downloads for each CA cross-certificate. As our certificate is issued by “VeriSign Class 3 Public Primary Certification Authority,” we will download the corresponding certificate. Using the certificate and cross-certificate together, we can sign our evil driver. To sign the certificate, we will use the SignTool mentioned before. As we can see, we hit a small issue. It is saying we have no certificates that meet the criteria. Remember, the certificate expired in November of 2014. Turns out, we can pull some trickery with our system time. With a “valid” certificate, we should now be able to load the driver without a problem When we run our corresponding evilcli.exe application, we now can utilize the power of our new driver. To show the correlation between the application and driver, below is what happens when you run the application without starting the driver. Bringing It All Together Finally, let’s use our new evil program to blind both the process, thread, and loadimage callbacks within our EDR driver and execute Mimikatz to get a full password dump. First, we can see our EDR service is running (you’ll have to take my word again). And to show restoring EDR callbacks: Potential Detections Generally speaking, antivirus and other security appliances generally do not as heavily scrutinize drivers. They are typically treated with significantly more trust than typical user applications. Because of this, virus signatures are probably not the most reliable way to detect malicious drivers. (There were no AV detections from the EDR on my files). In addition, many EDRs do not have anti-tampering measures implemented to check if their callbacks are zeroed out or changed. The reason for this is likely because as they are running in the kernel, they do not want to have the overhead of additional CPU cycles from continuously checking. This may change in the future with new research, but for now, we also can’t depend on the EDR to check for us. What I did find, is that Windows event logs actually record when a driver is loaded within the System logs. Below is a normal EventID 7045 (A new service has been installed) for a legitimate Dell driver. These events happen when a new service/driver is installed on a machine. You may see this when you install printer/wifi/usb or another driver. In all but one edge case (at least on my machine) the security identifier (SID) was always “S-1-5-18” (the local system account) when a kernel mode driver was loaded. As you can see when loading our evil driver, it was installed by a user SID: Granted, the driver is “evil.sys” and is installed in a user’s desktop, but in an actual campaign, it would likely have a legitimate name and be installed in the System32\Drivers\ directory. I am sure if you were creating services with SYSTEM permissions, it would look different, but typically this requires tools like PSEXEC or exploits which would likely be noisier and have more potential to be flagged by AV/EDR. This may not be a perfect detection, as there are edge cases. Below is an installation of the Npcap Packet Driver which comes with Wireshark installations. But I would imagine that in a non-technical business environment, drivers like these probably wouldn’t be installing on a normal workstation.Bring Your Own Interpreter (BYOI)2020-10-15T00:00:00+00:002020-10-15T00:00:00+00:00https://synzack.github.io/Bring-Your-Own-Interpreter<h1 id="preface">Preface</h1>
<p>These techniques that will be discussed in this paper were not discovered by myself. This technique was made popular by <a href="https://github.com/byt3bl33d3r">Marcello Salvati</a>, a red teamer at Black Hills Information Security. He published an article on the topic that can be found on the Black Hills <a href="https://www.blackhillsinfosec.com/red-teamers-cookbook-byoi-bring-your-own-interpreter/">blog</a>. SILENTTRINITY is his C2 (command and control) implementation of the concept. Be sure to check out his work.</p>
<p>The purpose of this paper is to break down the concepts in a way that is (hopefully) easy to understand and increase awareness into the new offensive landscape when it comes to tooling and detection.</p>
<h1 id="the-offensive-problem-set">The (Offensive) Problem Set</h1>
<p>In the not so distant past, red teamers and malicious actors alike loved to utilize PowerShell for their offensive scripts, C2 channels, malware, basically everything. It was built into modern Windows operating systems by default, could pull down remote scripts, execute in memory, and was basically invisible due to lack of controls in place.</p>
<p>In the last couple years, defensive products and Microsoft caught on to the abuse of this scripting language. After PowerShell v1, protections started being integrated such as <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.host/start-transcript?view=powershell-7">Transcript logging</a>, <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_script_blocks?view=powershell-7">Script Block Logging</a>, <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_group_policy_settings?view=powershell-7">Module Logging</a>, and <a href="https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal">AMSI</a>.</p>
<p>Products such as EDRs started creating rules that looked for certain strings/commands, such as using “<em>IEX (New-Object Net.WebClient).DownloadString</em>” to download remote scripts or “exec bypass” to import custom scripts. Some environments block PowerShell altogether or alert anytime it is used.</p>
<p>While PowerShell may not be completely “dead”, as there are always new bypasses, it has become more trouble than it is worth in most red team engagements (and likely advanced threat actor campaigns). It has become high risk from a stealth perspective with all the detections associated with it.</p>
<h1 id="what-is-powershell-why-did-it-work-so-well">What is PowerShell? Why did it Work so Well?</h1>
<p>PowerShell was built by Microsoft for task automation and configuration management, with its own scripting language. The reason it was able to be integrated into virtually all new Windows operating systems is that it is built upon the .NET Framework. The best/easiest explanation I could find for the .NET Framework can be found <a href="https://www.howtogeek.com/253588/what-is-the-microsoft-net-framework-and-why-is-it-installed-on-my-pc/">here</a>.</p>
<p>The quick one sentence summary of this framework is that it is a shared library of code that contains Application Programming Interfaces (APIs) used to develop applications that can be used in programming languages.</p>
<p>The important thing to note, is that the .NET Framework is not specific to any language. There are many different languages that utilize the framework to function. The .NET Framework is the backbone for many common Microsoft programming languages you may know, including (but certainly are not limited to):</p>
<ul>
<li>C#</li>
<li>F#</li>
<li>Visual Basic</li>
<li>PowerShell</li>
<li>IronPython</li>
<li>IronRuby</li>
</ul>
<p>PowerShell and C# are built into Windows by default, so it makes them very easy to use and execute without any external DLLs. There are even many third-party programming languages as well. If you wanted to, you could create your own language from the .NET framework.</p>
<p>.NET Assemblies are the results of compiling a .NET language. Think of an EXE or DLL when you compile a C# program, these are .NET assemblies. These assemblies can be executed by ANY .NET language and can be loaded reflectively in memory using .NET’s <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=netcore-3.1">Assembly.Load()</a>. Remember these points moving forward in this paper.</p>
<h1 id="offensive-tooling-shift">Offensive Tooling Shift</h1>
<p>If you follow the offensive tooling community, you may have noticed a shift in methods, where C# is now the go-to language over PowerShell. Many of the common PowerShell tools have been ported to the C#.</p>
<p><ins><strong>PowerShell Tool -> C# Tool</strong></ins></p>
<ul>
<li>PowerUp -> SharpUp</li>
<li>BloodHound -> SharpHound</li>
<li>PowerView -> SharpView</li>
<li>MimiKatz -> SafetyKatz</li>
</ul>
<p>The reason for this is best described in Marcello’s <a href="https://www.youtube.com/watch?v=o6m6_TncrcI&feature=emb_logo">talks</a>, but basically the reason is that all the recent defenses and detections we have seen around PowerShell target <strong>PowerShell itself</strong>. They do not target the underlying .NET framework. Since C# is another .NET language, and arguably the most commonly known, this became the new offensive language of choice.</p>
<p>While there are new defenses such as AMSI updates coming to .NET 4.8, these are not present in prior .NET versions, which are running on most Windows hosts today.</p>
<p>Slides from Marcello’s BSides Talk:</p>
<p><img src="/images/BYOI/languages.png" alt="image-center" class="align-center" /></p>
<h1 id="downsides-to-c">Downsides to C#</h1>
<p>While C# can be a very powerful language, (and in theory can do anything PowerShell can do as it is built on the same framework), the largest downside is that to execute C# code, it must be compiled into an assembly, such as an EXE or DLL. This generally takes more time and must be re-compiled whenever a change is made. While these assemblies can be loaded reflectively into memory, many times, you may need to drop the file onto disk if this option is unavailable.</p>
<p>While these features are not deal-breakers, they are simply not as easy as loading a remote PowerShell script into memory and executing.</p>
<h1 id="bring-your-own-interpreter">Bring Your Own Interpreter</h1>
<p>How does BYOI come into all of this? Remember the point above that .NET assemblies can be executed by <strong><em>ANY</em></strong> .NET language? Because of this fact, any .NET language can be embedded in any other .NET language. There is no limit to how much embedding can be done.
For example,</p>
<ul>
<li>C# can be run in PowerShell</li>
<li>PowerShell can be run within IronPython</li>
<li>IronPython can be run within PowerShell within C#</li>
</ul>
<p>This is the idea that <strong><em>Bring Your Own Interpreter</em></strong> is built on. You can use a built-in Windows .NET language, such as C# or PowerShell to execute other .NET languages, and even in memory depending on the third-party language constraints.</p>
<h1 id="boo">Boo!</h1>
<p>So, .NET languages can be embedded in each other, but which one do you choose? From an offensive perspective, we would want a language that can compile to memory and be able to support <a href="https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke">PInvoke</a>, which is the ability to run unmanaged code (code not based in .NET, think importing non-.NET DLLs for example).</p>
<p>With the current research on the topic, <a href="https://github.com/boo-lang/boo">Boolang</a> seems to be the best language found (so far) to suit these needs. Boolang was developed in 2009 by Rodrigo B. de Oliveira. It is built on the .NET framework and its syntax is inspired by Python. If you work with the code, it feels like a cross between C# and Python. It can import unmanaged code and compile everything to memory. This is ideal from an offensive perspective because as soon as the code runs, it is gone. No evidence is left on disk, and there is a very minimal amount of information left in memory.</p>
<h1 id="making-your-interpreter">Making Your Interpreter</h1>
<p>Now we have the base knowledge and .NET language we want to use, let’s investigate how we embed the languages and make our interpreter.</p>
<h2 id="download-boolang">Download Boolang</h2>
<p>Go to the official <a href="https://github.com/boo-lang/boo/releases">GitHub page</a> and download the latest release of the programming language. The reason we need to do this is because there are 4 DLLs that need to be imported into our C# code to compile and execute the Boolang code. These are:</p>
<ul>
<li>Boo.Lang.dll</li>
<li>Boo.Lang.Parser.dll</li>
<li>Boo.Lang.Extensions.dll</li>
<li>Boo.Lang.Compiler.dll</li>
</ul>
<p>These DLLs can be put on the host, imported dynamically from the C# code, or even packed into the final compiled executable.</p>
<p>If you are interested, I encourage you to read the code documentation and learn how it runs independently of C#, but it will not be covered in the scope of this paper.</p>
<h1 id="create-the-c-compiler">Create the C# Compiler</h1>
<p>Let’s create a simple Boolang script. You can do this by opening your favorite text editor and creating a file named “<em>script.boo</em>” (or whatever you like).</p>
<p><img src="/images/BYOI/scriptboo.png" alt="image-center" class="align-center" /></p>
<p>For the proof of concept, we will use the official Boolang Compiler <a href="https://github.com/boo-lang/boo/wiki/Scripting-with-the-Boo.Lang.Compiler-API">API code</a> to run Boolang from C#, with a few modifications to call our Main class and <em>MainScript</em> method.</p>
<p><img src="/images/BYOI/script-code.png" alt="image-center" class="align-center" /></p>
<p>Alright, let’s run it.</p>
<p><img src="/images/BYOI/runboo.png" alt="image-center" class="align-center" /></p>
<p>We have successfully embedded a .NET language in another, compiled it, and executed it in memory!</p>
<h1 id="remote-scripting">Remote Scripting</h1>
<p>You may be thinking, this is cool, but now I must drop TWO files to disk. Well, let’s build on our code a little. We can use the <em>WebClient</em> class to get a remote URL and read in a remote script.</p>
<p><img src="/images/BYOI/remote-code.png" alt="image-center" class="align-center" /></p>
<p>Now we will host a remote script named “script” (the .boo extension isn’t necessary) at:</p>
<p><strong><em>http://pc-tech.pro/script</em></strong></p>
<p><img src="/images/BYOI/pctech-script.png" alt="image-center" class="align-center" /></p>
<p>Let’s run it.</p>
<p><img src="/images/BYOI/run-remote-boo.png" alt="image-center" class="align-center" /></p>
<p>Now, we have a fully functioning assembly that we can execute on the target host and compile ANY remote script we want to memory and execute it. There are some great offensive implications to this:</p>
<ul>
<li>Flexibility
<ul>
<li>No compiling needed every time you want to execute a script, just pull-down source code (like the PowerShell days)</li>
<li>Can run any script, using the same executable</li>
</ul>
</li>
<li>OPSEC (Operations Security)
<ul>
<li>Since it is compiled to memory, no traces of the script are left on disc</li>
<li>Even in memory, it leaves a very minimal footprint as it is discarded after use</li>
<li>From an analysis perspective, you would only see a non-malicious C# compiler spinning up and executing, making a single network connection</li>
<li>Only need to drop one file to disk (unless you reflectively load it or use other techniques)</li>
<li>Bypasses AMSI in .NET < 4.8 and other protections seen in PowerShell</li>
</ul>
</li>
</ul>
<h1 id="bypassing-protections">Bypassing Protections</h1>
<p>As mentioned previously, BYOI tactics have the ability to bypass AMSI, but what does that mean? <a href="https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal">AMSI</a> is the Windows Antimalware Scan Interface and allows applications and services to integrate with any antimalware product on the host. Some common windows components that integrate with AMSI are:</p>
<ul>
<li>User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation)</li>
<li>PowerShell (scripts, interactive use, and dynamic code evaluation)</li>
<li>Windows Script Host (wscript.exe and cscript.exe)</li>
<li>JavaScript and VBScript</li>
<li>Office VBA macros</li>
</ul>
<p>Basically, anything that is executed in an AMSI integrated component will be ran through the host’s antivirus program. To demonstrate this, there is a certain test string that can trigger AMSI:</p>
<p><em>Invoke-Expression ‘AMSI Test Sample: 7e72c3ce-861b-4339-8740-0ac1484c1386’</em></p>
<p><img src="/images/BYOI/amsi1.png" alt="image-center" class="align-center" /></p>
<p>In theory, anything that calls this string that is integrated with AMSI, should trigger a malware detection. We are going to create 2 scripts that call this string. One will be a PowerShell script; one will be an embedded Boolang script. Both will be hosted remotely. For all intents and purposes, they will do the same thing, which is printing the test string.</p>
<h1 id="powershell">PowerShell</h1>
<p><img src="/images/BYOI/amsi2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/amsi3.png" alt="image-center" class="align-center" /></p>
<h1 id="boolang">Boolang</h1>
<p><img src="/images/BYOI/amsi4.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/amsi5.png" alt="image-center" class="align-center" /></p>
<p>As you can see, we have just executed our “malicious” Boolang script in memory, without getting caught by AMSI, while it was immediately caught in PowerShell.</p>
<h1 id="what-about-edr">What About EDR?</h1>
<p>EDR is typically much more powerful than the built-in AV on Windows, so what does the execution look like in these tools? Again, we will just run our “Hello Boolang” script in memory from a remote source.</p>
<p>The first thing we notice is an informational alert saying the file meets the <strong>lowest-confidence</strong> threshold for a malicious file. This may vary from EDR to EDR, as this alert was based on this specific EDR’s own built in detections and custom rules. Ideally, we would want no detection, but overall, not bad for the first try with no obfuscation.</p>
<p><img src="/images/BYOI/edr1.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/edr2.png" alt="image-center" class="align-center" /></p>
<p>The following are the detection details from the process tree. As we can see, no files were quarantined, and no AV detections are present. Only network operations to our server and DLL loads were observed. Nothing from an analysis perspective that immediately sparks malicious actions.</p>
<p><img src="/images/BYOI/edr3.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/edr4.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/edr5.png" alt="image-center" class="align-center" /></p>
<h1 id="mimikatz">Mimikatz</h1>
<p>Let’s try doing something that is actually malicious on the host through our Boolang interpreter. Breaking down the below Boolang script, we are going to load in the 32-bit or 64-bit SharpSploit Mimikatz DLL (depending on architecture) with only Base64 encoding. We will then execute it in memory and print the results of “<em>privilege::debug sekurlsa::logonpasswords</em>”.</p>
<p>Specifically, this DLL (well known, definitely malicious):</p>
<p><img src="/images/BYOI/virustotal.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/vscode.png" alt="image-center" class="align-center" /></p>
<p>When we run it, we see that the EDR did in fact catch and terminate the program, but what did it actually detect?</p>
<p><img src="/images/BYOI/edr6.png" alt="image-center" class="align-center" /></p>
<p>Looking at the alert, it triggered a High severity alert, <strong>ONLY</strong> because we touched LSASS. (No matter how stealthy a program is, it would get caught for touching LSASS in this way). It did not alert because we loaded the script or DLL into memory or executed Mimikatz itself. We can see below, the only detections on the actual executable was that it still met the lowest-confidence threshold for malicious files.</p>
<p><img src="/images/BYOI/edr7.png" alt="image-center" class="align-center" /></p>
<p>When looking at the file details, we only see the same DLL loads and the network connections.</p>
<p><img src="/images/BYOI/edr8.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/BYOI/edr9.png" alt="image-center" class="align-center" /></p>
<h1 id="detections-and-mitigations">Detections and Mitigations</h1>
<p>While there will likely be more detection in the future, there are not many great ways of detecting the actual execution of BYOI tradecraft currently. Below are a few points that could help in aiding detection/mitigation of this.</p>
<ul>
<li>AMSI signatures for the third-party scripting languages. This is out of our control and we will have to see how Microsoft creates detections in AMSI for .NET 4.8. Likely, there will be work arounds until most edge cases are found. Similar to how the detections for PowerShell evolved</li>
<li>Detecting .NET scripting language assemblies being loaded in a managed processes’ AppDomain through technologies such as Event tracing for Windows</li>
<li>Application whitelisting to block unknown or unapproved files from being executed on the host</li>
<li>Focusing on TTPs (Tactics, Techniques, and Procedures) to catch the malicious behavior. For example, the EDR did not detect the file or the execution, but it did catch the act of touching LSASS.</li>
</ul>
<h1 id="in-conclusion">In Conclusion</h1>
<p>With the increasing detections and alerting around tools such as PowerShell, Bring Your Own Interpreter style tradecraft as well as spin offs will likely become more prevalent in advanced attacks. Until more detections and controls are developed into the underlying techniques, it is important to have robust and up to date malware signatures (more so TTPs than hashes/IP IOCs), application white lists, and tools to add additional visibility such as EDR technology.</p>Zach SteinPreface These techniques that will be discussed in this paper were not discovered by myself. This technique was made popular by Marcello Salvati, a red teamer at Black Hills Information Security. He published an article on the topic that can be found on the Black Hills blog. SILENTTRINITY is his C2 (command and control) implementation of the concept. Be sure to check out his work. The purpose of this paper is to break down the concepts in a way that is (hopefully) easy to understand and increase awareness into the new offensive landscape when it comes to tooling and detection. The (Offensive) Problem Set In the not so distant past, red teamers and malicious actors alike loved to utilize PowerShell for their offensive scripts, C2 channels, malware, basically everything. It was built into modern Windows operating systems by default, could pull down remote scripts, execute in memory, and was basically invisible due to lack of controls in place. In the last couple years, defensive products and Microsoft caught on to the abuse of this scripting language. After PowerShell v1, protections started being integrated such as Transcript logging, Script Block Logging, Module Logging, and AMSI. Products such as EDRs started creating rules that looked for certain strings/commands, such as using “IEX (New-Object Net.WebClient).DownloadString” to download remote scripts or “exec bypass” to import custom scripts. Some environments block PowerShell altogether or alert anytime it is used. While PowerShell may not be completely “dead”, as there are always new bypasses, it has become more trouble than it is worth in most red team engagements (and likely advanced threat actor campaigns). It has become high risk from a stealth perspective with all the detections associated with it. What is PowerShell? Why did it Work so Well? PowerShell was built by Microsoft for task automation and configuration management, with its own scripting language. The reason it was able to be integrated into virtually all new Windows operating systems is that it is built upon the .NET Framework. The best/easiest explanation I could find for the .NET Framework can be found here. The quick one sentence summary of this framework is that it is a shared library of code that contains Application Programming Interfaces (APIs) used to develop applications that can be used in programming languages. The important thing to note, is that the .NET Framework is not specific to any language. There are many different languages that utilize the framework to function. The .NET Framework is the backbone for many common Microsoft programming languages you may know, including (but certainly are not limited to): C# F# Visual Basic PowerShell IronPython IronRuby PowerShell and C# are built into Windows by default, so it makes them very easy to use and execute without any external DLLs. There are even many third-party programming languages as well. If you wanted to, you could create your own language from the .NET framework. .NET Assemblies are the results of compiling a .NET language. Think of an EXE or DLL when you compile a C# program, these are .NET assemblies. These assemblies can be executed by ANY .NET language and can be loaded reflectively in memory using .NET’s Assembly.Load(). Remember these points moving forward in this paper. Offensive Tooling Shift If you follow the offensive tooling community, you may have noticed a shift in methods, where C# is now the go-to language over PowerShell. Many of the common PowerShell tools have been ported to the C#. PowerShell Tool -> C# Tool PowerUp -> SharpUp BloodHound -> SharpHound PowerView -> SharpView MimiKatz -> SafetyKatz The reason for this is best described in Marcello’s talks, but basically the reason is that all the recent defenses and detections we have seen around PowerShell target PowerShell itself. They do not target the underlying .NET framework. Since C# is another .NET language, and arguably the most commonly known, this became the new offensive language of choice. While there are new defenses such as AMSI updates coming to .NET 4.8, these are not present in prior .NET versions, which are running on most Windows hosts today. Slides from Marcello’s BSides Talk: Downsides to C# While C# can be a very powerful language, (and in theory can do anything PowerShell can do as it is built on the same framework), the largest downside is that to execute C# code, it must be compiled into an assembly, such as an EXE or DLL. This generally takes more time and must be re-compiled whenever a change is made. While these assemblies can be loaded reflectively into memory, many times, you may need to drop the file onto disk if this option is unavailable. While these features are not deal-breakers, they are simply not as easy as loading a remote PowerShell script into memory and executing. Bring Your Own Interpreter How does BYOI come into all of this? Remember the point above that .NET assemblies can be executed by ANY .NET language? Because of this fact, any .NET language can be embedded in any other .NET language. There is no limit to how much embedding can be done. For example, C# can be run in PowerShell PowerShell can be run within IronPython IronPython can be run within PowerShell within C# This is the idea that Bring Your Own Interpreter is built on. You can use a built-in Windows .NET language, such as C# or PowerShell to execute other .NET languages, and even in memory depending on the third-party language constraints. Boo! So, .NET languages can be embedded in each other, but which one do you choose? From an offensive perspective, we would want a language that can compile to memory and be able to support PInvoke, which is the ability to run unmanaged code (code not based in .NET, think importing non-.NET DLLs for example). With the current research on the topic, Boolang seems to be the best language found (so far) to suit these needs. Boolang was developed in 2009 by Rodrigo B. de Oliveira. It is built on the .NET framework and its syntax is inspired by Python. If you work with the code, it feels like a cross between C# and Python. It can import unmanaged code and compile everything to memory. This is ideal from an offensive perspective because as soon as the code runs, it is gone. No evidence is left on disk, and there is a very minimal amount of information left in memory. Making Your Interpreter Now we have the base knowledge and .NET language we want to use, let’s investigate how we embed the languages and make our interpreter. Download Boolang Go to the official GitHub page and download the latest release of the programming language. The reason we need to do this is because there are 4 DLLs that need to be imported into our C# code to compile and execute the Boolang code. These are: Boo.Lang.dll Boo.Lang.Parser.dll Boo.Lang.Extensions.dll Boo.Lang.Compiler.dll These DLLs can be put on the host, imported dynamically from the C# code, or even packed into the final compiled executable. If you are interested, I encourage you to read the code documentation and learn how it runs independently of C#, but it will not be covered in the scope of this paper. Create the C# Compiler Let’s create a simple Boolang script. You can do this by opening your favorite text editor and creating a file named “script.boo” (or whatever you like). For the proof of concept, we will use the official Boolang Compiler API code to run Boolang from C#, with a few modifications to call our Main class and MainScript method. Alright, let’s run it. We have successfully embedded a .NET language in another, compiled it, and executed it in memory! Remote Scripting You may be thinking, this is cool, but now I must drop TWO files to disk. Well, let’s build on our code a little. We can use the WebClient class to get a remote URL and read in a remote script. Now we will host a remote script named “script” (the .boo extension isn’t necessary) at: http://pc-tech.pro/script Let’s run it. Now, we have a fully functioning assembly that we can execute on the target host and compile ANY remote script we want to memory and execute it. There are some great offensive implications to this: Flexibility No compiling needed every time you want to execute a script, just pull-down source code (like the PowerShell days) Can run any script, using the same executable OPSEC (Operations Security) Since it is compiled to memory, no traces of the script are left on disc Even in memory, it leaves a very minimal footprint as it is discarded after use From an analysis perspective, you would only see a non-malicious C# compiler spinning up and executing, making a single network connection Only need to drop one file to disk (unless you reflectively load it or use other techniques) Bypasses AMSI in .NET < 4.8 and other protections seen in PowerShell Bypassing Protections As mentioned previously, BYOI tactics have the ability to bypass AMSI, but what does that mean? AMSI is the Windows Antimalware Scan Interface and allows applications and services to integrate with any antimalware product on the host. Some common windows components that integrate with AMSI are: User Account Control, or UAC (elevation of EXE, COM, MSI, or ActiveX installation) PowerShell (scripts, interactive use, and dynamic code evaluation) Windows Script Host (wscript.exe and cscript.exe) JavaScript and VBScript Office VBA macros Basically, anything that is executed in an AMSI integrated component will be ran through the host’s antivirus program. To demonstrate this, there is a certain test string that can trigger AMSI: Invoke-Expression ‘AMSI Test Sample: 7e72c3ce-861b-4339-8740-0ac1484c1386’ In theory, anything that calls this string that is integrated with AMSI, should trigger a malware detection. We are going to create 2 scripts that call this string. One will be a PowerShell script; one will be an embedded Boolang script. Both will be hosted remotely. For all intents and purposes, they will do the same thing, which is printing the test string. PowerShell Boolang As you can see, we have just executed our “malicious” Boolang script in memory, without getting caught by AMSI, while it was immediately caught in PowerShell. What About EDR? EDR is typically much more powerful than the built-in AV on Windows, so what does the execution look like in these tools? Again, we will just run our “Hello Boolang” script in memory from a remote source. The first thing we notice is an informational alert saying the file meets the lowest-confidence threshold for a malicious file. This may vary from EDR to EDR, as this alert was based on this specific EDR’s own built in detections and custom rules. Ideally, we would want no detection, but overall, not bad for the first try with no obfuscation. The following are the detection details from the process tree. As we can see, no files were quarantined, and no AV detections are present. Only network operations to our server and DLL loads were observed. Nothing from an analysis perspective that immediately sparks malicious actions. Mimikatz Let’s try doing something that is actually malicious on the host through our Boolang interpreter. Breaking down the below Boolang script, we are going to load in the 32-bit or 64-bit SharpSploit Mimikatz DLL (depending on architecture) with only Base64 encoding. We will then execute it in memory and print the results of “privilege::debug sekurlsa::logonpasswords”. Specifically, this DLL (well known, definitely malicious): When we run it, we see that the EDR did in fact catch and terminate the program, but what did it actually detect? Looking at the alert, it triggered a High severity alert, ONLY because we touched LSASS. (No matter how stealthy a program is, it would get caught for touching LSASS in this way). It did not alert because we loaded the script or DLL into memory or executed Mimikatz itself. We can see below, the only detections on the actual executable was that it still met the lowest-confidence threshold for malicious files. When looking at the file details, we only see the same DLL loads and the network connections. Detections and Mitigations While there will likely be more detection in the future, there are not many great ways of detecting the actual execution of BYOI tradecraft currently. Below are a few points that could help in aiding detection/mitigation of this. AMSI signatures for the third-party scripting languages. This is out of our control and we will have to see how Microsoft creates detections in AMSI for .NET 4.8. Likely, there will be work arounds until most edge cases are found. Similar to how the detections for PowerShell evolved Detecting .NET scripting language assemblies being loaded in a managed processes’ AppDomain through technologies such as Event tracing for Windows Application whitelisting to block unknown or unapproved files from being executed on the host Focusing on TTPs (Tactics, Techniques, and Procedures) to catch the malicious behavior. For example, the EDR did not detect the file or the execution, but it did catch the act of touching LSASS. In Conclusion With the increasing detections and alerting around tools such as PowerShell, Bring Your Own Interpreter style tradecraft as well as spin offs will likely become more prevalent in advanced attacks. Until more detections and controls are developed into the underlying techniques, it is important to have robust and up to date malware signatures (more so TTPs than hashes/IP IOCs), application white lists, and tools to add additional visibility such as EDR technology.SSL/TLS Tunneling to Bypass Filters & Avoid Detection2020-10-14T00:00:00+00:002020-10-14T00:00:00+00:00https://synzack.github.io/Tunneling-Traffic-With-SSL-and-TLS<p>In certain environments, controls such as firewalls are in place that restrict outbound ports and protocols. For example, maybe only web traffic over ports 80 (HTTP) and 443 (HTTPS) are allowed outbound from a given workstation.</p>
<p>In campaigns I have performed, I have had scenarios where we needed to control a device remotely (such as a raspberry pi) where direct terminal access would be ideal (such as SSH). But this requires an established external connection, where there are a few issues to consider:</p>
<ol>
<li>Outbound SSH over port 22 may be blocked</li>
<li>Outbound SSH traffic over a non-standard port (22) may be blocked</li>
<li>Even if neither of the above is blocked, anomalous outbound SSH traffic on any port is suspicious and may trigger alerts and/or attract unwanted attention from a threat hunter or analyst</li>
</ol>
<p>What is a solution to this? Tunneling!</p>
<p>As an attacker we always want to make any inbound/outbound traffic look as normal as possible to ensure the operational security of our campaign. As the most common outbound traffic is likely web traffic, lets emulate this. There are a few tools we can use to make this happen. Best part is they are free and open source.</p>
<h1 id="socat">Socat</h1>
<p>The first step in emulating web traffic, is making our communication speak the same protocol as the normal traffic. HTTPS traffic (encrypted HTTP) uses <a href="https://www.websecurity.digicert.com/security-topics/what-is-ssl-tls-https">SSL/TLS</a> (Secure Socket Layer/ Transport Layer Security) encryption to ensure that all communication between the web browser and the web server are safe from a third party seeing what is being transferred. Any website where you see the lock icon next to the URL is using such encryption to protect your data. TLS is the preferred method, as TLS is an updated more secure version of SSL.</p>
<p>How does this benefit an attacker? Since these protocols encrypt the traffic within them, if we can use SSL/TLS to encapsulate SSH traffic, the SSH traffic would be shielded from detection (unless there is a security device in the middle that can decrypt the SSL/TLS traffic).</p>
<p>This is where <a href="https://medium.com/@copyconstruct/socat-29453e9fc8a6">Socat</a> comes into play. Socat is a tool that is used to transfer data between two addresses using a desired protocol. Since we want to communicate with our C2 server using TLS, we can create this transfer pipe using <a href="https://www.openssl.org/">OpenSSL</a>. For our demonstration, we will use our ‘<em>pc-tech.pro</em>’ domain for C2 (Ubuntu server hosted in Amazon AWS).</p>
<p>1) Install Socat on implanted/rogue device (<em>Sudo apt install socat</em>)</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/socat-install.png" alt="image-center" class="align-center" /></p>
<p>2) Modify our SSH config file for our user to use <em>ProxyCommand</em> to establish a tunnel using OpenSSL to our C2 domain using port 443.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/ssh-config.png" alt="image-center" class="align-center" /></p>
<p>What this configuration does, is that for any SSH connection to ‘<em>pc-tech.pro</em>’ socat will be used to create a TLS tunnel using the site’s certificates for the SSH traffic to be encapsulated in.</p>
<h1 id="stunnel">Stunnel</h1>
<p>Now that we have a means of encapsulating SSH traffic to our C2 server, we need something to receive and decrypt the traffic. For this, we will use the tool <a href="https://www.stunnel.org/">Stunnel</a>. In short, Stunnel is a tool designed to add TLS encryption to applications that do not speak the protocols natively. In our case, it will be used to host the TLS certificates used for our encapsulation, decode incoming traffic, and forward the traffic to another port.</p>
<p>1) The first step in our configuration is to install the software on the C2 server: (<em>Sudo apt install stunnel4</em>)</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/stunnel-install.png" alt="image-center" class="align-center" /></p>
<p>2) Set up the configuration file (/etc/stunnel/stunnel.conf):
<em>*This will need to be created as it does not exist by default*</em></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/stunnel-config.png" alt="image-center" class="align-center" /></p>
<p>Breaking this down by line:</p>
<ol>
<li>Set pid for the process</li>
<li>Add TLS certificate</li>
<li>Add TLS key</li>
<li>Define rules for specified traffic type (SSH for us)
<ul>
<li>Listen on all interfaces on port 443 (HTTPS)</li>
<li>Forward & decrypt all incoming SSH traffic to port 443 to a port of your choice (2222 for us)</li>
</ul>
</li>
</ol>
<p>For our TLS certificates, we used Let’s Encrypt certificates that can be used for webpages. Setting these up are outside the scope of this paper, but you can read more about this on their <a href="https://letsencrypt.org/getting-started/">website</a>.</p>
<p>3) Enable Stunnel in config (/etc/default/stunnel4):</p>
<p><em>*By default, the service is not enabled. To enable it change “Enabled=0” to “Enabled=1”*</em></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/stunnel-enable.png" alt="image-center" class="align-center" /></p>
<p>4) Start service: (<em>Sudo service stunnel start</em>)</p>
<p>The following diagram is a visual of the steps we have taken so far:</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/drawio.png" alt="image-center" class="align-center" /></p>
<p>You may be asking, “Why are we forwarding traffic to port 2222 instead of standard SSH (port 22)?”</p>
<p>This is because we are going to be hosting 3 services off this one port. SSH, HTTP, and HTTPS. This way, if we visit port 443 with a web browser, it will display a webpage to the user, while if we hit port 443 with SSH traffic, it will establish an SSH tunnel. This is done to avoid detection from an analyst and/or sandbox.This is where we get into our final tool, SSLH.</p>
<h1 id="sslh">SSLH</h1>
<p><a href="http://www.rutschle.net/tech/sslh/README.html">SSLH</a> is a “SSL/SSH Multiplexer” that acts like a switchboard for protocols it receives. It can be configured with any protocol that can be recognized with regular expressions. Simply put, depending on what traffic it receives, it will forward the traffic to a different port, based on the protocol. For our example, the following routes will be created.</p>
<ol>
<li>If SSLH receives SSH traffic, forward to port 22</li>
<li>If SSLH receives HTTP traffic, forward to port 8080</li>
<li>If SSLH receives HTTPS traffic, forward to port 8443</li>
</ol>
<p>To configure our server to use this tool, we will take the following steps:</p>
<p>1) Install the tool on our C2 server: (<em>Sudo apt install sslh</em>)</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/sslh-install.png" alt="image-center" class="align-center" /></p>
<p>2) Edit the configuration file in /etc/default/sslh:</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/sslh-config.png" alt="image-center" class="align-center" /></p>
<p>Breaking this down:</p>
<ol>
<li>Ensure “RUN” is set to “yes”</li>
<li>Set “—listen” to the port we are forwarding Stunnel traffic to (port 2222). This is the port SSLH will be running on</li>
<li>For SSH traffic, forward to localhost, port 22</li>
<li>For SSL/TLS traffic, forward to localhost, port 8443</li>
<li>For HTTP traffic, forward to localhost, port 8080</li>
</ol>
<p>3) Start the service: (<em>Sudo service sslh start</em>)</p>
<p>Now the only thing we need to do to complete our tunneling infrastructure is to set up our SSH and web services.</p>
<h1 id="configuring-web-service-and-ssh">Configuring Web Service and SSH</h1>
<p>To serve web content to browsers, we will use an Apache web service on our C2 server (although any webserver will do).</p>
<p>1) In your desired web server port configuration, point HTTP and HTTPS to the ports configured in SSLH.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/apache-config.png" alt="image-center" class="align-center" /></p>
<p>2) Start Web Server</p>
<p>For SSH, we will use the standard SSH service (<em>Sudo service ssh start</em>)</p>
<p>Now, if everything worked correctly, we should see all our ports listening accordingly:</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/listening-ports.png" alt="image-center" class="align-center" /></p>
<h1 id="testing-the-configuration">Testing the Configuration</h1>
<p>The following diagram is a visual of what the final configuration should look like. All return traffic in will be encapsulated in the TLS tunnel as well.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/drawio2.png" alt="image-center" class="align-center" /></p>
<h1 id="web-traffic">Web Traffic</h1>
<p>When visiting the site in a browser, we see a normal looking website that can host any content we desire:</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/totally-legit1.png" alt="image-center" class="align-center" /></p>
<p>Wireshark Capture:</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/totally-legit2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/totally-legit3.png" alt="image-center" class="align-center" /></p>
<h1 id="ssh-traffic">SSH Traffic</h1>
<p>When we SSH to port 443 of the server, the socat OpenSSL tunnel is created, and we can SSH over the same port our web traffic hit above (the -p443 is not needed as it is in our socat config, just used to explicitly show the port we are connecting to):</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/ssh1.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/ssh2.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/ssh3.png" alt="image-center" class="align-center" /></p>
<p>In both cases, the traffic looks like TLS encrypted web traffic.</p>
<h1 id="optimizing-for-offensive-operations">Optimizing for Offensive Operations</h1>
<p>Now that we have proven we can tunnel SSH traffic over TLS, we need to be able to access our implanted device at any time, from anywhere. To take it one step further, we will set up a reverse SSH tunnel to our C2 server, which we can access from our own device.</p>
<p>Host “Oasis” will simulate our rogue device. We will set up a reverse tunnel to our C2 server using SSH.</p>
<p>What the below command does, is open port 7777 on our C2 server to tunnel all traffic destined to port 7777 to the SSH port on the rogue device. All of this is encapsulated in our TLS tunnel.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/opt1.png" alt="image-center" class="align-center" /></p>
<p>Looking at the listening ports on our C2 server, we can see that this port is in-fact listening.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/opt2.png" alt="image-center" class="align-center" /></p>
<p>Now from our attacking machine, we can SSH to our C2 server, then SSH to our rogue device.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/opt3.png" alt="image-center" class="align-center" /></p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/opt4.png" alt="image-center" class="align-center" /></p>
<p>The following is a diagram of what this traffic looks like, using the C2 server as a jump box into the target environment. This allows us to have terminal access to the host, while masquerading as HTTPS traffic to a normal website.</p>
<p><img src="/images/Tunneling-Traffic-With-SSL-and-TLS/drawio3.png" alt="image-center" class="align-center" /></p>Zach SteinIn certain environments, controls such as firewalls are in place that restrict outbound ports and protocols. For example, maybe only web traffic over ports 80 (HTTP) and 443 (HTTPS) are allowed outbound from a given workstation. In campaigns I have performed, I have had scenarios where we needed to control a device remotely (such as a raspberry pi) where direct terminal access would be ideal (such as SSH). But this requires an established external connection, where there are a few issues to consider: Outbound SSH over port 22 may be blocked Outbound SSH traffic over a non-standard port (22) may be blocked Even if neither of the above is blocked, anomalous outbound SSH traffic on any port is suspicious and may trigger alerts and/or attract unwanted attention from a threat hunter or analyst What is a solution to this? Tunneling! As an attacker we always want to make any inbound/outbound traffic look as normal as possible to ensure the operational security of our campaign. As the most common outbound traffic is likely web traffic, lets emulate this. There are a few tools we can use to make this happen. Best part is they are free and open source. Socat The first step in emulating web traffic, is making our communication speak the same protocol as the normal traffic. HTTPS traffic (encrypted HTTP) uses SSL/TLS (Secure Socket Layer/ Transport Layer Security) encryption to ensure that all communication between the web browser and the web server are safe from a third party seeing what is being transferred. Any website where you see the lock icon next to the URL is using such encryption to protect your data. TLS is the preferred method, as TLS is an updated more secure version of SSL. How does this benefit an attacker? Since these protocols encrypt the traffic within them, if we can use SSL/TLS to encapsulate SSH traffic, the SSH traffic would be shielded from detection (unless there is a security device in the middle that can decrypt the SSL/TLS traffic). This is where Socat comes into play. Socat is a tool that is used to transfer data between two addresses using a desired protocol. Since we want to communicate with our C2 server using TLS, we can create this transfer pipe using OpenSSL. For our demonstration, we will use our ‘pc-tech.pro’ domain for C2 (Ubuntu server hosted in Amazon AWS). 1) Install Socat on implanted/rogue device (Sudo apt install socat) 2) Modify our SSH config file for our user to use ProxyCommand to establish a tunnel using OpenSSL to our C2 domain using port 443. What this configuration does, is that for any SSH connection to ‘pc-tech.pro’ socat will be used to create a TLS tunnel using the site’s certificates for the SSH traffic to be encapsulated in. Stunnel Now that we have a means of encapsulating SSH traffic to our C2 server, we need something to receive and decrypt the traffic. For this, we will use the tool Stunnel. In short, Stunnel is a tool designed to add TLS encryption to applications that do not speak the protocols natively. In our case, it will be used to host the TLS certificates used for our encapsulation, decode incoming traffic, and forward the traffic to another port. 1) The first step in our configuration is to install the software on the C2 server: (Sudo apt install stunnel4) 2) Set up the configuration file (/etc/stunnel/stunnel.conf): *This will need to be created as it does not exist by default* Breaking this down by line: Set pid for the process Add TLS certificate Add TLS key Define rules for specified traffic type (SSH for us) Listen on all interfaces on port 443 (HTTPS) Forward & decrypt all incoming SSH traffic to port 443 to a port of your choice (2222 for us) For our TLS certificates, we used Let’s Encrypt certificates that can be used for webpages. Setting these up are outside the scope of this paper, but you can read more about this on their website. 3) Enable Stunnel in config (/etc/default/stunnel4): *By default, the service is not enabled. To enable it change “Enabled=0” to “Enabled=1”* 4) Start service: (Sudo service stunnel start) The following diagram is a visual of the steps we have taken so far: You may be asking, “Why are we forwarding traffic to port 2222 instead of standard SSH (port 22)?” This is because we are going to be hosting 3 services off this one port. SSH, HTTP, and HTTPS. This way, if we visit port 443 with a web browser, it will display a webpage to the user, while if we hit port 443 with SSH traffic, it will establish an SSH tunnel. This is done to avoid detection from an analyst and/or sandbox.This is where we get into our final tool, SSLH. SSLH SSLH is a “SSL/SSH Multiplexer” that acts like a switchboard for protocols it receives. It can be configured with any protocol that can be recognized with regular expressions. Simply put, depending on what traffic it receives, it will forward the traffic to a different port, based on the protocol. For our example, the following routes will be created. If SSLH receives SSH traffic, forward to port 22 If SSLH receives HTTP traffic, forward to port 8080 If SSLH receives HTTPS traffic, forward to port 8443 To configure our server to use this tool, we will take the following steps: 1) Install the tool on our C2 server: (Sudo apt install sslh) 2) Edit the configuration file in /etc/default/sslh: Breaking this down: Ensure “RUN” is set to “yes” Set “—listen” to the port we are forwarding Stunnel traffic to (port 2222). This is the port SSLH will be running on For SSH traffic, forward to localhost, port 22 For SSL/TLS traffic, forward to localhost, port 8443 For HTTP traffic, forward to localhost, port 8080 3) Start the service: (Sudo service sslh start) Now the only thing we need to do to complete our tunneling infrastructure is to set up our SSH and web services. Configuring Web Service and SSH To serve web content to browsers, we will use an Apache web service on our C2 server (although any webserver will do). 1) In your desired web server port configuration, point HTTP and HTTPS to the ports configured in SSLH. 2) Start Web Server For SSH, we will use the standard SSH service (Sudo service ssh start) Now, if everything worked correctly, we should see all our ports listening accordingly: Testing the Configuration The following diagram is a visual of what the final configuration should look like. All return traffic in will be encapsulated in the TLS tunnel as well. Web Traffic When visiting the site in a browser, we see a normal looking website that can host any content we desire: Wireshark Capture: SSH Traffic When we SSH to port 443 of the server, the socat OpenSSL tunnel is created, and we can SSH over the same port our web traffic hit above (the -p443 is not needed as it is in our socat config, just used to explicitly show the port we are connecting to): In both cases, the traffic looks like TLS encrypted web traffic. Optimizing for Offensive Operations Now that we have proven we can tunnel SSH traffic over TLS, we need to be able to access our implanted device at any time, from anywhere. To take it one step further, we will set up a reverse SSH tunnel to our C2 server, which we can access from our own device. Host “Oasis” will simulate our rogue device. We will set up a reverse tunnel to our C2 server using SSH. What the below command does, is open port 7777 on our C2 server to tunnel all traffic destined to port 7777 to the SSH port on the rogue device. All of this is encapsulated in our TLS tunnel. Looking at the listening ports on our C2 server, we can see that this port is in-fact listening. Now from our attacking machine, we can SSH to our C2 server, then SSH to our rogue device. The following is a diagram of what this traffic looks like, using the C2 server as a jump box into the target environment. This allows us to have terminal access to the host, while masquerading as HTTPS traffic to a normal website.C2 Redirection For Offensive Operations2020-10-13T00:00:00+00:002020-10-13T00:00:00+00:00https://synzack.github.io/C2-Redirection-for-Offensive-Operations<p>When creating a command-and-control infrastructure, it is common for the callbacks to not communicate directly to the attacker’s C2 server. Many times, they will go through a compromised webpage, or a fake site used as a redirector. A redirector is basically a server that will take requests and forward them to another address, such as the real malicious server. This is to hide the underlying attacker address if the C2 traffic is ever discovered.</p>
<p>Have you ever analyzed a web address that was flagged as malicious, only to see a seemingly benign or a 404-error page? This may indicate that the page is not malicious or no longer existing, but it could also indicate the page is being used as a redirector/proxy.</p>
<p>Apache, Nginx, and other web servers have the ability to proxy/redirect traffic when desired conditions are met. This is useful from an attacking perspective as it can add an extra layer of obfuscation to an analyst observing the traffic.</p>
<p>To demonstrate this, we set up a public facing Apache server at domain “<em>pc-tech.pro</em>” as a redirector and configured the <a href="https://ithemes.com/what-is-the-htaccess-file/">.htaccess</a> file to proxy or redirect traffic based on different “rules”. This can be done through Apache’s <a href="https://httpd.apache.org/docs/2.4/mod/mod_rewrite.htmlhttps://httpd.apache.org/docs/2.4/mod/mod_rewrite.html">mod_rewrite</a>.</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/htaccess.png" alt="image-center" class="align-center" /></p>
<p>What the above .htaccess file does, is that every web request to our domain will be redirected or proxied based on the RewriteConditions. The logic of this file is as follows:</p>
<p><strong>IF:</strong></p>
<p>1) If the requested URL is any of:</p>
<ul>
<li>d/ref=ab_sb_ns_1/7888-0262949/field-keywords=ads</li>
<li>D15/afa/amzn.us.sr.aps</li>
<li>about-us</li>
<li>contact-us</li>
</ul>
<p><strong>AND:</strong></p>
<p>2) The user-agent string is:</p>
<ul>
<li>“Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko”</li>
</ul>
<p><strong>THEN:</strong></p>
<p>3) Proxy traffic to http://13.59.197.154 (our Cobalt Strike server) at the requested URL</p>
<p><strong>ELSE:</strong></p>
<p>4) Return a 302 (Found) response and redirect to <em>https://computertechpro.net</em> (some other legitimate site) at the requested URL</p>
<p>To demonstrate how these rules work, we added a plugin to a Firefox web browser to change the user-agent in the requests. We then hosted a file on our Cobalt Strike attacker server to show what conditions need to be met to observe it.</p>
<p><ins><strong>Making a request with the incorrect user-agent, but correct URL:</strong></ins></p>
<p>Request: <em>http://pc-tech.pro/contact-us</em></p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/example1.png" alt="image-center" class="align-center" /></p>
<p>Request: <em>http://pc-tech.pro/d/ref=ab_sb_ns_1/7888-0262949/field-keywords=ads</em></p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/example2.png" alt="image-center" class="align-center" /></p>
<p><ins><strong>Making a request with the correct user-agent and correct URL:</strong></ins></p>
<p>Request: <em>http://pc-tech.pro/contact-us</em></p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/example3.png" alt="image-center" class="align-center" /></p>
<p><ins><strong>Making a request with any user-agent and incorrect URL:</strong></ins></p>
<p>Request: <em>http://pc-tech.pro/test</em></p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/example4.png" alt="image-center" class="align-center" /></p>
<h1 id="modifying-for-c2-traffic">Modifying for C2 traffic</h1>
<p>Within Cobalt Strike’s malleable C2 <a href="https://www.cobaltstrike.com/help-malleable-c2">framework</a>, fields such as the user-agent and callback URLs can be modified based on the infrastructure needs. For this specific configuration, the malleable C2 user-agent was set to match that of our Apache mod_rewrite rules, as well as the URLs used for GET and POST requests.</p>
<p>User-Agent</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/user-agent.png" alt="image-center" class="align-center" /></p>
<p>GET Requests</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/get-request.png" alt="image-center" class="align-center" /></p>
<p>POST Requests</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/post-request.png" alt="image-center" class="align-center" /></p>
<p>The below Wireshark capture is from the Cobalt Strike payload being executed. The user-agent and the requested URL match that of the Apache webserver configuration, so the server responds with a 200 (OK) code and our traffic is proxied to our Cobalt Strike C2 server. The resulting beacon can be seen below.</p>
<p><em>*pc-tech.pro is located at IP 3.16.149.234*</em></p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/wireshark.png" alt="image-center" class="align-center" /></p>
<p>The source IP address can be seen as 3.16.149.234, which is our Apache server.</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/cobalt-strike.png" alt="image-center" class="align-center" /></p>
<p>The following Wireshark capture is that of a browser requesting the same URL, but as the user-agent string is not correct, the Apache webserver returns a 302-redirect response, and forwards the session to “<em>computertechpro.net</em>”. As this page does not exist, a 404-error page is returned.</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/wireshark2.png" alt="image-center" class="align-center" /></p>
<p>Below is a diagram which illustrates the above concept on a high-level.</p>
<p><img src="/images/C2-Redirection-for-Offensive-Operations/drawio.png" alt="image-center" class="align-center" /></p>
<p>This example is meant to be an introduction to the concept of redirection to hide C2 infrastructure. These tactics can become much more complex based on how complex the rule sets on the redirectors are.</p>
<p>These tactics can also be used in the instance of compromised domains. An attacker could compromise a legitimate website and modify the server configuration files to redirect certain users to malicious addresses. If this is a trusted site, it may not return as malicious on threat feeds or other intelligence.</p>Zach SteinWhen creating a command-and-control infrastructure, it is common for the callbacks to not communicate directly to the attacker’s C2 server. Many times, they will go through a compromised webpage, or a fake site used as a redirector. A redirector is basically a server that will take requests and forward them to another address, such as the real malicious server. This is to hide the underlying attacker address if the C2 traffic is ever discovered. Have you ever analyzed a web address that was flagged as malicious, only to see a seemingly benign or a 404-error page? This may indicate that the page is not malicious or no longer existing, but it could also indicate the page is being used as a redirector/proxy. Apache, Nginx, and other web servers have the ability to proxy/redirect traffic when desired conditions are met. This is useful from an attacking perspective as it can add an extra layer of obfuscation to an analyst observing the traffic. To demonstrate this, we set up a public facing Apache server at domain “pc-tech.pro” as a redirector and configured the .htaccess file to proxy or redirect traffic based on different “rules”. This can be done through Apache’s mod_rewrite. What the above .htaccess file does, is that every web request to our domain will be redirected or proxied based on the RewriteConditions. The logic of this file is as follows: IF: 1) If the requested URL is any of: d/ref=ab_sb_ns_1/7888-0262949/field-keywords=ads D15/afa/amzn.us.sr.aps about-us contact-us AND: 2) The user-agent string is: “Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko” THEN: 3) Proxy traffic to http://13.59.197.154 (our Cobalt Strike server) at the requested URL ELSE: 4) Return a 302 (Found) response and redirect to https://computertechpro.net (some other legitimate site) at the requested URL To demonstrate how these rules work, we added a plugin to a Firefox web browser to change the user-agent in the requests. We then hosted a file on our Cobalt Strike attacker server to show what conditions need to be met to observe it. Making a request with the incorrect user-agent, but correct URL: Request: http://pc-tech.pro/contact-us Request: http://pc-tech.pro/d/ref=ab_sb_ns_1/7888-0262949/field-keywords=ads Making a request with the correct user-agent and correct URL: Request: http://pc-tech.pro/contact-us Making a request with any user-agent and incorrect URL: Request: http://pc-tech.pro/test Modifying for C2 traffic Within Cobalt Strike’s malleable C2 framework, fields such as the user-agent and callback URLs can be modified based on the infrastructure needs. For this specific configuration, the malleable C2 user-agent was set to match that of our Apache mod_rewrite rules, as well as the URLs used for GET and POST requests. User-Agent GET Requests POST Requests The below Wireshark capture is from the Cobalt Strike payload being executed. The user-agent and the requested URL match that of the Apache webserver configuration, so the server responds with a 200 (OK) code and our traffic is proxied to our Cobalt Strike C2 server. The resulting beacon can be seen below. *pc-tech.pro is located at IP 3.16.149.234* The source IP address can be seen as 3.16.149.234, which is our Apache server. The following Wireshark capture is that of a browser requesting the same URL, but as the user-agent string is not correct, the Apache webserver returns a 302-redirect response, and forwards the session to “computertechpro.net”. As this page does not exist, a 404-error page is returned. Below is a diagram which illustrates the above concept on a high-level. This example is meant to be an introduction to the concept of redirection to hide C2 infrastructure. These tactics can become much more complex based on how complex the rule sets on the redirectors are. These tactics can also be used in the instance of compromised domains. An attacker could compromise a legitimate website and modify the server configuration files to redirect certain users to malicious addresses. If this is a trusted site, it may not return as malicious on threat feeds or other intelligence.Oauth Token Stealing2020-05-29T00:00:00+00:002020-05-29T00:00:00+00:00https://synzack.github.io/OAuth-Token-Stealing<h1 id="preface">Preface</h1>
<p>The techniques presented in this paper are not necessarily new and were not initially discovered by myself. There is notable research that was done by <a href="https://www.fireeye.com/blog/threat-research/2018/05/shining-a-light-on-oauth-abuse-with-pwnauth.html">FireEye</a> and <a href="https://www.mdsec.co.uk/2019/07/introducing-the-office-365-attack-toolkit/">MDSec</a> prior to this publication that sparked this report. The goal of this post is to build on their research, give a background of the techniques used, and present new tools for security teams to use as testing frameworks in the future.</p>
<p>In addition, this paper only covers OAuth abuse from the perspective of Microsoft accounts. This technique can be implemented on any service using similar OAuth protocols or permissions. Whether it be mobile apps, social media, personal email, or professional accounts, be sure to always review the permissions requested and the request source when granting third party access.</p>
<h1 id="oauth">OAuth</h1>
<h2 id="what-is-oauth">What is OAuth?</h2>
<p>OAuth is an open standard authorization protocol/framework that make it possible for applications, servers, and other unrelated services to have a way to have secure authenticated access. The protocol is designed to be able to do this without sharing any logon credentials (such as the user’s actual password). If you would like to learn more how the protocol works, check out this <a href="https://www.csoonline.com/article/3216404/what-is-oauth-how-the-open-authorization-framework-works.html">article</a>.</p>
<p>OAuth was released in 2010 and has been expanded upon in OAuth 2.0, released in 2012. It has become a widely used authentication platform used by corporations such as Amazon, Facebook, and Microsoft.</p>
<p>The general operational flow for this authentication is as follows:</p>
<ol>
<li>A user needs to authenticate to a website or service outside of their organization</li>
<li>The resource forwards the user to a second authorization website on behalf of the user, where OAuth is used to provide the user’s identity</li>
<li>If not already authenticated, the user may be asked to provide credentials</li>
<li>The second site confirms the user’s identity and returns an access-token to the first website</li>
<li>The first site uses this token to authenticate to the necessary services on behalf of the user</li>
</ol>
<p>Below is a general diagram of the OAuth flow from <a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2">Digital Ocean</a>.</p>
<p><img src="/images/OAuth-Token-Stealing/Dig-Ocean-OAuth.jpeg" alt="image-center" class="align-center" /></p>
<p>This is an oversimplified explanation, but you may use OAuth in your everyday workflow without even knowing. For example, let’s say you want to access your Office365 applications such as OneDrive, Office, and SharePoint. Here is the flow:</p>
<ol>
<li>You go to ‘Office.com’ and click the button to sign-in.</li>
<li>You enter your corporate email address, and the site says, “Taking you to your organization’s sign-in page”</li>
<li>You are forwarded to the corporate Okta (or other sign-in) page, where you input your domain credentials and two-factor authentication (if applicable)</li>
<li>Once authenticated to your organization, you are redirected back to ‘Office.com’ and have all your applications available to you</li>
<li>Behind the scenes, an access-token was given to Office365 to authenticate you, but your domain password was never exchanged</li>
</ol>
<h2 id="microsoft-graph-api">Microsoft Graph API</h2>
<p>In many modern-day environments, Microsoft Office products are typically integrated to increase productivity, collaboration, and create deliverables. Some common examples are the Microsoft Office Suite (Word, Excel, PowerPoint, etc.) for projects, Outlook for email, SharePoint for sharing company resources, and OneDrive for cloud storage.</p>
<p>To further integrate these tools, Microsoft as introduced the <a href="https://docs.microsoft.com/en-us/graph/use-the-api">Microsoft Graph API</a>, which is a <a href="https://restfulapi.net/">RESTful</a> web API that enables users and applications to access these services through their request system. In order to use these tools, an access-token needs to be granted to the application, through the same OAuth protocols we discussed above.</p>
<p>These API calls can be used to perform many actions on behalf of the user including reading email, sending email, accessing files, reading user information, and much more. If there is an action you would like to perform on a Microsoft cloud product, there is likely an API call for that. For a full list of permissions that can be granted to an app, please visit the official Microsoft permission references <a href="https://docs.microsoft.com/en-us/graph/permissions-reference">documentation</a>.</p>
<p>If you have ever seen a prompt such as the following, you have likely interreacted this service in some way, shape, or form.</p>
<p><img src="/images/OAuth-Token-Stealing/permission-prompt.jpeg" alt="image-center" class="align-center" /></p>
<p>Below are graphic from the Microsoft <a href="https://docs.microsoft.com/en-us/graph/overview">documentation</a> with a visualization of the Graph API.</p>
<p><img src="/images/OAuth-Token-Stealing/ms-graph1.jpeg" alt="image-center" class="align-center" /></p>
<p><img src="/images/OAuth-Token-Stealing/ms-graph2.jpeg" alt="image-center" class="align-center" />
<br /></p>
<h1 id="room-for-abuse">Room for Abuse</h1>
<h2 id="what-are-the-security-implications">What are the Security Implications?</h2>
<p>If you are reading this, you probably know that we are not here to discuss all the great, legitimate things these tools can be used for. Like most technology, if it can be used for good, it likely can be used for bad. So, if that is the case, what are the negative security implications of this technology?</p>
<p>On one hand, this method of authentication protects the user’s credential material. It also requires authorization from the user and, if configured, their organization. The issue arises when a rogue site or application requests these same access tokens and is given approval through methods such as phishing and social engineering, where security controls are not in place to block the authorization. We will be focusing on this scenario for the purposes of this paper.</p>
<p>Once granted permissions, the malicious service now has an access token that can act on behalf of the user for each service it has permissions to. One of the most interesting parts is that since no credential material is exchanged, the service will still have access after a password reset by the user. This also means this method can bypass multi-factor authentication. The access is only revoked if the token expires, or the permissions are explicitly revoked by either the user or the organization’s Office365/Azure administrator.</p>
<p>This technique was famously used in recent years by APT28 (most commonly known as Fancy Bear, Sofacy, and Pawn Storm). The group implemented OAuth phishing techniques within their 2016 campaigns against the German Christian Democratic Union (CDU), Turkish government, and arguably most famously (at least in the USA) the Democratic National Convention (DNC). Trend Micro has an excellent <a href="https://blog.trendmicro.com/trendlabs-security-intelligence/pawn-storm-abuses-open-authentication-advanced-social-engineering-attacks/">article</a> on this topic.</p>
<p>Through these technologies, this Russian nation-state group was able to gain unauthorized access to emails, files, and other sensitive information.</p>
<p>Below is a graphic from Trend Micro’s article which illustrates the attack chain of the above campaign.</p>
<p><img src="/images/OAuth-Token-Stealing/pawnstorm.jpeg" alt="image-center" class="align-center" /></p>
<h1 id="how-do-these-applications-work">How do these Applications Work?</h1>
<p>To gain an understanding of how these technologies can be abused, we will walk through how to create a proof of concept rogue application from a Red Team perspective. We will create a simple application using the Microsoft documentation.</p>
<p>The first step is to head over to the Azure portal at <a href="https://portal.azure.com">https://portal.azure.com</a>. Once you sign in with a Microsoft account, you should be presented with the home panel. To get to the application management page, we need to go to “Manage Azure Active Directory.”</p>
<p><img src="/images/OAuth-Token-Stealing/azure1.jpeg" alt="image-center" class="align-center" /></p>
<p>On the next page, you should see a panel that includes “App registrations.”</p>
<p><img src="/images/OAuth-Token-Stealing/azure2.jpeg" alt="image-center" class="align-center" /></p>
<p>Now, go to “New Registration”</p>
<p><img src="/images/OAuth-Token-Stealing/azure3.jpeg" alt="image-center" class="align-center" /></p>
<p>Give the application a name and set the supported account types to your choosing. For this demonstration, we chose accounts in any directory and personal Microsoft accounts to cover all target scenarios. We will set redirects later, so do not worry about this for now. Once complete, go ahead and click “Register”.</p>
<p><img src="/images/OAuth-Token-Stealing/azure4.jpeg" alt="image-center" class="align-center" /></p>
<p>After the app is registered, we can see a quickstart guide. I found this to be a great resource in creating an application.</p>
<p><img src="/images/OAuth-Token-Stealing/azure5.jpeg" alt="image-center" class="align-center" /></p>
<p>For this demonstration we will be using a web application.</p>
<p><img src="/images/OAuth-Token-Stealing/azure6.jpeg" alt="image-center" class="align-center" /></p>
<p>I prefer Python for creating my tools, so we will pick their Python option for this demonstration.</p>
<p><img src="/images/OAuth-Token-Stealing/azure7.jpeg" alt="image-center" class="align-center" /></p>
<p>Here we will find sample code and instructions on how to get started with a simple python-based web application.</p>
<p><img src="/images/OAuth-Token-Stealing/azure8.jpeg" alt="image-center" class="align-center" /></p>
<h1 id="creating-an-application">Creating an Application</h1>
<p>Step 1) Configure your application in Azure Portal</p>
<ul>
<li>Add a reply URL:
<ul>
<li>Head over to the “Authentication” tab on our app panel</li>
</ul>
</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure9.jpeg" alt="image-center" class="align-center" /></p>
<ul>
<li>Add a platform</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure10.jpeg" alt="image-center" class="align-center" /></p>
<ul>
<li>Choose Web Application</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure11.jpeg" alt="image-center" class="align-center" /></p>
<ul>
<li>Add the redirect URL (This can be any web server running your application)</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure12.jpeg" alt="image-center" class="align-center" /></p>
<p>Step 2) Create a Client Secret</p>
<ul>
<li>Go to the “Certificates & secrets” panel. Create a new secret</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure13.jpeg" alt="image-center" class="align-center" /></p>
<p><img src="/images/OAuth-Token-Stealing/azure14.jpeg" alt="image-center" class="align-center" /></p>
<ul>
<li>Add a name and expiration. Once confirmed, you should have secret value</li>
</ul>
<p><img src="/images/OAuth-Token-Stealing/azure15.jpeg" alt="image-center" class="align-center" /></p>
<p><img src="/images/OAuth-Token-Stealing/azure16.jpeg" alt="image-center" class="align-center" /></p>
<p>We now have everything we need to start creating our Python Application. Go ahead and download the code sample from the quickstart guide page and install requirements if you haven’t already.</p>
<p>There are two main programs we will be concerned with, ‘app.py’ and ‘app_config.py’. These are the backbone for our application.</p>
<p>To configure for use, we need to edit the app_config.py file with our client secret and client ID. These can be found on our application panel.</p>
<p><img src="/images/OAuth-Token-Stealing/config1.jpeg" alt="image-center" class="align-center" /></p>
<p>Notice the REDIRECT_PATH variable is the redirect URL we configured in our setup, if this were setup to a different path, we would need to change it here.</p>
<p>SCOPE is used to define the permissions needed. For the first demonstration, “<em>User.ReadBasic.All</em>’ will work with a work or school account. If you are using a personal account, add ‘<em>User.Read</em>.’</p>
<p>SCOPE will also need to be modified accordingly when adding more API calls as each requires a different permission set.</p>
<p>Now, with the configuration file set up, our application should be ready to test. <em>Run the app.py</em> program. This will create a web server using <a href="https://flask.palletsprojects.com/en/1.1.x/">Flask</a>. By default, it runs on localhost:5000, which is our redirect URL in the configuration.</p>
<p><img src="/images/OAuth-Token-Stealing/app1.jpeg" alt="image-center" class="align-center" /></p>
<p>In a browser, the application index page looks like the following:</p>
<p><img src="/images/OAuth-Token-Stealing/app2.jpeg" alt="image-center" class="align-center" /></p>
<p>When we click on “Sign-in” we are redirected to Microsoft to authenticate with OAuth.</p>
<p><img src="/images/OAuth-Token-Stealing/app3.jpeg" alt="image-center" class="align-center" /></p>
<p>Once authenticated, Microsoft will ask the user if they want to allow this application to access their info, based on the permissions outlined in our SCOPE. As we only have the user read permissions, it is the only permission requested in the prompt.</p>
<p><img src="/images/OAuth-Token-Stealing/app4.jpeg" alt="image-center" class="align-center" /></p>
<p>Once accepted, we can see a request to our token page and the user is authenticated with the application. Behind the scenes, an access-token was returned to our web application.</p>
<p><img src="/images/OAuth-Token-Stealing/app5.jpeg" alt="image-center" class="align-center" /></p>
<p>Microsoft has included a basic call to their Graph API in the demo, which we can see with “Call Microsoft Graph API” hyperlink.</p>
<p>When we go to this page, we can see a JSON response to the API call, displaying the user information.</p>
<p><img src="/images/OAuth-Token-Stealing/app6.jpeg" alt="image-center" class="align-center" /></p>
<p>We have successfully called the Microsoft Graph API!</p>
<h1 id="breaking-down-the-application-api-calls">Breaking Down the Application API Calls</h1>
<p>To make sure we know what is going on under the hood, let’s take a high-level look at the sample code that calls the API. I encourage you to review and understand the rest of the code, but we will not go over the whole program in this paper.</p>
<p>In the <em>app.py</em> code, we can see the API call in the <em>/graphcall</em> Flask route. This code contains the actual API call used on the page.</p>
<p><img src="/images/OAuth-Token-Stealing/api1.jpeg" alt="image-center" class="align-center" /></p>
<p>Here is the API call code:</p>
<p><em>graph_data = requests.get(app_config.ENDPOINT, headers={‘Authorization’: ‘Bearer ‘ + token[‘access_token’]},).json()</em></p>
<p>This is the heart of the application’s API. Let’s add some print statements to understand the actual request.</p>
<p><img src="/images/OAuth-Token-Stealing/api2.jpeg" alt="image-center" class="align-center" /></p>
<p>When we restart the web server and call the Graph API, we get the following output.</p>
<p><img src="/images/OAuth-Token-Stealing/api3.jpeg" alt="image-center" class="align-center" /></p>
<p>Breaking it down, the function is making an HTTP GET request to:</p>
<p><em>‘https://graph.microsoft.com/v1.0/users’ using the header: ”’Authorization’: ‘Bearer ‘ + UserAccesstoken”</em></p>
<p>According to the Microsoft Graph API documentation for “<a href="https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http"><em>Get a user</em></a>”, this is the exact API call you need to make to get the user information.</p>
<p>The token you see is what is passed to the application from Microsoft when the user authenticates with OAuth, along with some other parameters. The most important being the access-token, and the refresh-token. By default, the access-token has a lifespan of one hour and needs to be refreshed by calling the API with the refresh-token. By default, the refresh token is valid for 14 days.</p>
<p>With this token, the application has full access to any resources the user allowed in the permission prompt. With this token, we can create our own requests to the API and access resources such as emails, files, and shared sites.</p>
<p>For documentation on the different types of functionality and parameters, please visit the Microsoft Graph REST API v1.0 <a href="https://docs.microsoft.com/en-us/graph/api/overview?%5C=&view=graph-rest-1.0">Reference</a>.</p>
<h1 id="tools-for-red-teams">Tools for Red Teams</h1>
<h2 id="pwnauth">PwnAuth</h2>
<p>For red teamers and security researchers, there are already existing frameworks that can be used to test this activity. The first tool goes by the name ‘<a href="https://github.com/fireeye/PwnAuth"><em>PwnAuth</em></a>’ and was published in May of 2018 by FireEye. This tool uses a combination of Nginx, Django, and Docker to create an interactive web console for security researchers to test the techniques mentioned above.</p>
<p>This tool currently has the following functionality:</p>
<ul>
<li>Reading mail messages</li>
<li>Searching the user’s mailbox</li>
<li>Reading the user’s contacts</li>
<li>Downloading messages and attachments</li>
<li>Searching OneDrive and downloading files</li>
<li>Sending messages on behalf of the user</li>
</ul>
<p>Below is a quick snippet from their <a href="https://www.fireeye.com/blog/threat-research/2018/05/shining-a-light-on-oauth-abuse-with-pwnauth.html">website</a> of their web GUI:</p>
<p><img src="/images/OAuth-Token-Stealing/pwnauth.jpeg" alt="image-center" class="align-center" /></p>
<h2 id="office-365-attack-toolkit">Office 365 Attack Toolkit</h2>
<p>Another tool worth mentioning is the <a href="https://github.com/mdsecactivebreach/o365-attack-toolkit"><em>Office 365 Attack Toolkit</em></a>, published by MDSec in July 2019. This tool uses a web framework written in <a href="https://golang.org/">Go</a> with an SQLite database backend to create a similar web interface for security researchers to test their environments against OAuth token stealing with malicious applications.</p>
<p>This tool currently has the following functionality:</p>
<ul>
<li>Extraction of keyworded e-mails from Outlook.</li>
<li>Creation of Outlook Rules.</li>
<li>Extraction of files from OneDrive/Sharepoint.</li>
<li>Injection of macros on Word documents.</li>
</ul>
<p>Below is a quick snippet from their GitHub documentation:</p>
<p><img src="/images/OAuth-Token-Stealing/o365toolkit.jpeg" alt="image-center" class="align-center" /></p>
<h2 id="pynauth">PynAuth</h2>
<p>While the above tools are very useful and well put together, I had some learning curve when attempting to configure them properly. My tools of preference are those which I can quickly setup and takedown and can be quickly modified as needed, with little overhead.</p>
<p>As part of this research, I created a Python-based framework called <a href="https://github.com/Synzack/PynAuth"><em>PynAuth</em></a> which is a tool that utilizes the same techniques as the above tools. The difference is that it is written completely in Python. It is designed to be modular, and can be run right your terminal. The tool is meant to be easy to use and easily customizable depending on which API calls you wish to implement.</p>
<p>The tool’s name is a play on the <em>PwnAuth</em> tool name written by FireEye. <em>*Please note, while this tool is functional, it may contain bugs and is currently in a beta stage</em></p>
<p>Current capabilities:</p>
<ul>
<li>Get user information</li>
<li>Send email on behalf of the user</li>
<li>Query users’ email inbox for keywords, display message, and download attachments</li>
<li>Access users’ OneDrive folders and download files as desired</li>
<li>Create email inbox rules</li>
<li>List/Delete email inbox rules</li>
<li>Refresh the users’ tokens, which allow for access up to 14 days</li>
</ul>
<p>Terminal View:</p>
<p><img src="/images/OAuth-Token-Stealing/pynauth.jpeg" alt="image-center" class="align-center" /></p>
<p>Example: Query Email</p>
<p><img src="/images/OAuth-Token-Stealing/pynauth2.jpeg" alt="image-center" class="align-center" /></p>
<p><img src="/images/OAuth-Token-Stealing/pynauth3.jpeg" alt="image-center" class="align-center" /></p>
<p><img src="/images/OAuth-Token-Stealing/pynauth4.jpeg" alt="image-center" class="align-center" /></p>
<h1 id="defending-against-oauth-application-attacks">Defending Against OAuth Application Attacks</h1>
<p>While these techniques may provide a stealthy means to keep persistence in a target network, there are many measures that can be taken to prevent these attacks before they happen. Blocks for these applications will typically require proper configuration, as by default, no admin permission is needed for most resources the user already has permission to. These include things like read/write permissions to personal email and accessing both personal and corporate cloud storage resources.</p>
<p>Some security measures that can be implemented include:</p>
<ul>
<li>Limiting the permissions that can be requested by third-party applications</li>
<li>Banning third-party applications altogether</li>
<li>Creating application white lists to include only those in use by your organization</li>
<li>Query your organization’s users and the applications they have granted permissions to</li>
<li>Logging user consent events within your cloud environment</li>
</ul>
<p>FireEye has even published a PowerShell script which can help administrators hunt for malicious applications within their cloud environments. The tool can be found on <a href="https://github.com/dmb2168/OAuthHunting">GitHub</a>.</p>
<p>If you are an end user, be sure to always review third party permissions before granting access to your accounts, whether personal or professional. When in doubt, confirm with your administrator whether the application is legitimate or not.</p>Zach SteinPrefaceWeaponizing 28 Year Old XLM Macros2020-05-25T00:00:00+00:002020-05-25T00:00:00+00:00https://synzack.github.io/Weaponizing-28-Year-Old-XLM-Macros<h1 id="overview">Overview</h1>
<p>Excel 4.0 macros (XLM macros) are a feature of Microsoft Excel that date back to 1992. These macros can be embedded into an Excel sheet and do not use VBA. This is significant as many modern exploit campaigns utilize <a href="https://docs.microsoft.com/en-us/office/vba/api/overview/">VBA</a> (Visual Basic for Applications) macros, which many security appliances have signatures for.</p>
<p>While these macros have been around for many years, research into weaponizing them is relatively new. This paper is an extension of research done by <a href="https://outflank.nl/blog/2018/10/06/old-school-evil-excel-4-0-macros-xlm/">Outflank</a> and <a href="https://www.cybereason.com/blog/excel4.0-macros-now-with-twice-the-bits">Cyber Reason</a>.</p>
<h1 id="offensive-advantages">Offensive Advantages</h1>
<p>From an offensive perspective, Excel 4.0 macros provide the following advantages:</p>
<ul>
<li>4.0 macros are stored differently than VBA macros, evading many AV signatures</li>
<li>Utilizing 4.0 macros has the potential to bypass <a href="https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal">AMSI</a> (Antimalware Scan Interface)</li>
<li>4.0 macros be easily hidden within excel sheets</li>
</ul>
<h2 id="vba-vs-xlm-storage">VBA vs XLM Storage</h2>
<p>The following screenshot from Outflank demonstrates how VBA (left) and XLM (right) are stored in Excel containers in a 97-2003 format (.xls). VBA macros are stored in <a href="https://docs.microsoft.com/en-us/cpp/mfc/ole-background?view=vs-2019">OLE</a> (Object Linking and Embedding) streams under the containers, while XLM macros are embedded within the Workbook OLE stream. This adds an extra layer of stealth when trying to detect XLM macros with AV and other solutions.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/OLE-Streams.jpg" alt="image-center" class="align-center" /></p>
<h1 id="example-of-a-40-macro">Example of a 4.0 Macro</h1>
<p>In an excel sheet, the 4.0 macro option can be found by simply right-clicking on the current sheet and selecting <strong><em>Insert -> MS Excel 4.0 Macro</em></strong>.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/create-step1.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/create-step2.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/create-step3.jpg" alt="image-center" class="align-center" /></p>
<p>The macro functions are called directly in the sheet cells and can perform a wide range of commands. For example, we can run EXEC to execute system commands and ALERT to
create pop-up messages.</p>
<p><em>*A full list of Excel 4.0 Macro functions can be found at the following <a href="https://d13ot9o61jdzpp.cloudfront.net/files/Excel%204.0%20Macro%20Functions%20Reference.pdf">link</a></em>.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/run1.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/run2.jpg" alt="image-center" class="align-center" /></p>
<p><br /></p>
<h1 id="enhancing-execution-and-stealth">Enhancing Execution and Stealth</h1>
<p><strong>Auto_Open</strong></p>
<p>Just like the VBA counterpart, these macros can be set to automatically run when the document
is opened (assuming macros are enabled in the settings or the user enables them).
To do this, the starting cell just needs to be renamed to “<em>Auto_Open</em>”.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/auto-open1.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/auto-open2.jpg" alt="image-center" class="align-center" /></p>
<p><strong>Hiding the Macro</strong></p>
<p>As the macro is technically a sheet within excel, it contains many of the same functionality. For example, it can be hidden just like a regular cell.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/hide.jpg" alt="image-center" class="align-center" /></p>
<p><strong>Saving as an XLSM/XLS file</strong></p>
<p>While 4.0 macros are not the same as VBA macros, the document still needs to be saved as an
XLSM or XLS file to be a macro enabled document. If the excel settings are set to warn the user
before enabling macros, this banner will still display with a 4.0 macro document.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/enable1.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/enable2.jpg" alt="image-center" class="align-center" /></p>
<p>Now, we have a fully functioning macro that will open on start, be essentially invisible to the end
user, and will not show in the document macro ribbon. This will likely fool the unsuspecting
victim, even if they are aware of VBA macro risks.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/locations.jpg" alt="image-center" class="align-center" /></p>
<h1 id="weaponizing-the-macro">Weaponizing the Macro</h1>
<p>While command execution can result in compromise a machine, what if we were able to further
weaponize these macros?</p>
<p>The researchers at Outflank discovered that by utilizing the <em>REGISTER</em> and <em>CALL</em> functions of
these macros, they can call the Win32 API and can inject shellcode into the running process.</p>
<p>The following is a proof of concept from their publication for injecting shellcode (32 bit):</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/outflank32.jpg" alt="image-center" class="align-center" /></p>
<p>Breaking the above down (quoted from Outflank):</p>
<p><em>REGISTER(module_name, procedure_name, type, alias, argument, macro_type, category)</em></p>
<ul>
<li><em>Module_name is the name of the DLL, for example “Kernel32” for c:\windows\system32\kernel32.dll.</em></li>
<li><em>Procedure_name is the name of the exported function in the DLL, for example “VirtualAlloc“.</em></li>
<li><em>Type is a string specifying the types of return value and arguments of the functions.</em></li>
<li><em>Alias is a custom name that you can give to the function, by which you can call it later.</em></li>
<li><em>Argument can be used to name the arguments to the function, but is optional (and left blank in our code).</em></li>
<li><em>Macro_type should be 1, which stands for function.</em></li>
<li><em>Category is a category number (used in ancient Excel functionality). We can specify an arbitrary category number between 1 and 14 for our purpose</em></li>
</ul>
<p>By using these registers, system calls can be made directly from the macros. In this case, <a href="https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc">VirtualAlloc</a>, <a href="https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory">WriteProcessMemory</a>, and <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread">CreateThread</a> which in combination, can write data to a specified memory address. This can be used to inject shellcode into memory. Once the full shellcode is written, a thread is created to execute the code in the allocated memory.</p>
<h1 id="what-about-64-bit">What About 64 Bit?</h1>
<p>Most modern operating systems have 64-bit architectures, and 64-bit versions of Microsoft Office. For offensive operations, it would be beneficial to be able to embed 64-bit shellcode. This is where the <a href="https://www.cybereason.com/blog/excel4.0-macros-now-with-twice-the-bits">research</a> from Cyber Reason comes into play.</p>
<p>The initial issue is best described in the Cyber Reason research:</p>
<p>“<em>This macro functionality exists in 64-bit Excel, but if you try to implement a shellcode runner using the same approach, you will quickly encounter a problem. The pointer size for a 64-bit application is, unsurprisingly, 64-bits. The available data types remain the same, which means there is no native 8 byte integer type. Using one of the floating point types will use the XMM registers, which means the function will expect the arguments to be in rcx, rdx, r8, r9 and others, according to the x64 calling convention.</em></p>
<p><em>However, the string data types, which are passed by reference, still seem to work. The macro system knows how to handle at least some 8 byte pointers. That doesn’t directly help, as we can’t precisely supply and receive 8-byte values.</em></p>
<p><em>This problem disappears when our pointers are less than 0x0000001’00000000, as they will be representable using only 4 bytes. This is true for at least for the first 4 arguments of the function, which are passed through registers, not the stack.</em></p>
<p><em>When entering the register, these arguments will be zero-extended, and 0x50000000 will simply become 0x00000000’50000000. The higher bits will be discarded when used as a 32-bit value.</em></p>
<p><em>Because of this, we can use the lpAddress parameter of VirtualAlloc to specify that our memory must be allocated at a specific address in the 0x00000000-0xFFFFFFFF range, which we can supply via our available data-types. For the sake of the proof of concept, we chose 0x50000000 (1342177280) as our candidate address and attempted to run VirtualAlloc via 64-bit Excel.</em>”</p>
<p>Using the above information, the first call to Kernel32 will use the 0x50000000 (1342177280) value as the address. Our 64-bit macro looks like the following:</p>
<p><em>(The CALL function is used instead of REGISTER in this example)</em></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/call1.jpg" alt="image-center" class="align-center" /></p>
<h1 id="creating-excel-shellcode">Creating Excel Shellcode</h1>
<p>Now that we have a template to move data into memory, we need something to execute. Let’s create our own shellcode. For now, we will just create shellcode to spawn “calc.exe” for a proof of concept. We need to ensure that the shellcode does not contain null bytes, so we can encode it using a XOR encoder.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/msfvenom1.jpg" alt="image-center" class="align-center" /></p>
<p>Once our shellcode file has been created, there are tools such as <a href="https://github.com/mdsecactivebreach/SharpShooter">SharpShooter</a> contain functionality to convert this raw shellcode to a format Excel can understand.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/sharpshooter1.jpg" alt="image-center" class="align-center" /></p>
<p>The output of this tool is a .SLK (Symbolic Link) file which contains a macro very similar to the earlier 32-bit macro template and the associated shellcode we created. Since we are creating the 64-bit payload, we are only concerned with the shellcode for now.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/slk1.jpg" alt="image-center" class="align-center" /></p>
<p>We can copy and paste this shellcode into our proof-of-concept.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/poc1.jpg" alt="image-center" class="align-center" /></p>
<h1 id="breaking-down-the-macro">Breaking Down the Macro</h1>
<p>Let’s break down the code and what this macro is doing.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/breakdown.jpg" alt="image-center" class="align-center" /></p>
<h1 id="executing-shellcode">Executing Shellcode</h1>
<p>The macro is now ready to execute. To test, we can right-click on the first cell and click “Run”. This will execute the macro commands until it hits the <em>HALT()</em> command. The Excel document ultimately crashes, but the shellcode is executed and spawns the calculator.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/exec1.jpg" alt="image-center" class="align-center" /></p>
<h1 id="mitigating-the-crash">Mitigating the Crash</h1>
<p>While the current macro works great for running commands which do not require interaction, the crashing aspect is a problem for payloads containing shells, Metasploit sessions, cobalt strike beacons, etc. This crash results from a stack corruption in <em>CreateThread</em> after overwriting our memory address. This makes the exploit unreliable and only execute successfully some of the time.</p>
<p>According to Cyber Reason’s research, this can be solved by “Queuing an APC (Asynchronous Procedure Call)” instead of using <em>CreateThread</em>. According to Cyber Reason:</p>
<p>“<em>Queuing an APC (Asynchronous Procedure Call) to a thread will make the thread execute caller provide code in the context of that thread as soon as it enters an alertable state. The QueueUserAPC, used for this purpose, only needs three arguments and thus will not look for parameters on the stack. We use this function to queue an APC containing the address of our shellcode to the current thread. The current thread is the thread handling our CALL macro.</em></p>
<p><em>We can use a function like NtTestAlert to flush and execute the current thread’s APC queue and target the correct thread to execute our shellcode.</em>”</p>
<p>Going of off this statement, we can modify our macro code calling these functions instead of <em>CreateThread</em>. With this addition, the document should not crash until the shellcode is finished executing. This means that if there is a Metasploit/Cobalt Strike session, it will not close until the session is exited.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/qapc.jpg" alt="image-center" class="align-center" /></p>
<p>To fully demonstrate this functionality, we will create a Metasploit meterpreter payload. We will begin by creating meterpreter shellcode and converting it to Excel shellcode by using <em>MsfVenom</em> and <em>SharpShooter</em>, just as we did with the calc shellcode.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/shellcode64.jpg" alt="image-center" class="align-center" /></p>
<p>Once we have the shellcode, we will add it to our shellcode column in our Excel macro.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/poc2.jpg" alt="image-center" class="align-center" /></p>
<p>When we run the macro, we are greeted with a meterpreter shell and the excel doc will “spin” until the session is closed. This may also seem like an issue, but the beacon receiver can be configured to spawn a new shell under a different process and kill the excel process when complete. (Not demonstrated in this paper).</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/exec2.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/exec3.jpg" alt="image-center" class="align-center" /></p>
<p>As the shellcode is injected into memory, when viewed in Process Explorer, Excel has no child processes.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/procexplore.jpg" alt="image-center" class="align-center" /></p>
<h1 id="bringing-it-all-together">Bringing it All Together</h1>
<p>Now that we have a working shellcode injection macro, lets finish weaponizing it and upload to VirusTotal to see the detection. We will start by renaming the first cell to “<em>Auto_Open</em>” and then hide the cell from the user.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/biat1.jpg" alt="image-center" class="align-center" /></p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/biat2.jpg" alt="image-center" class="align-center" /></p>
<p>Finally, lets upload to VirusTotal and check the detection rate.</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/vt.jpg" alt="image-center" class="align-center" /></p>
<p>We now have an Excel document that executes a Meterpreter payload that is undetected by all AV products on VirusTotal (At least at the time of this test).</p>
<h1 id="tooling">Tooling</h1>
<p>When researching this technique, there were a few tools like SharpShooter which I could use to generate the required shellcode, but none that did exactly what I wanted. As part of this project, I have created a simple python script that uses the same methods as SharpShooter to create the CHAR() shellcode, but outputs to a CSV format rather than an .SLK. It takes both x86 and x64 shellcode bin files as arguments.</p>
<p>Another issue I ran into was assuming most computers would be running the 64 bit version of Excel. Turns out that 32 bit is the preferred version for ARM-based processors and computers with less than 4GB of RAM (regardless of whether the OS was 64 bit) according to <a href="https://support.office.com/en-us/article/choose-between-the-64-bit-or-32-bit-version-of-office-2dee7807-8f95-4d0c-b5fe-6c6f49b8d261">Microsoft</a>. Because of this, the script also has a check to see if Excel is running in a 32 or 64 bit process and executes the shellcode accordingly.</p>
<p>The script can be found on my GitHub <a href="https://github.com/Synzack/Excel-4.0-Shellcode-Generator">here</a>.</p>
<p><strong>Usage</strong></p>
<p>1) Generate your shellcode to bin files and ensure there are no null bytes</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/tools1.png" alt="image-center" class="align-center" /></p>
<p>2) Run script with x86 and x64 bin files as arguments</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/tools2.png" alt="image-center" class="align-center" /></p>
<p>3) Your output file should look like the following (you may need to zoom in):</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/output.png" alt="image-center" class="align-center" /></p>
<p>4) Copy and paste all columns to an Excel 4 Macro enabled document (including the blank first column). The macro begins at the <em>WORKBOOK.ACTIVATE</em> in column 4. Make this your <em>Auto_Open</em> cell and change the text in <em>WORKBOOK.ACTIVATE</em> to the name of your macro tab. Save as a macro enabled excel file (xls or xlsm).</p>
<p><img src="/images/Weaponizing-28-Year-Old-Macros/output2.png" alt="image-center" class="align-center" /></p>Zach SteinOverview