<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://pdparla.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://pdparla.github.io/" rel="alternate" type="text/html" /><updated>2025-11-16T15:21:50+00:00</updated><id>https://pdparla.github.io/feed.xml</id><title type="html">PDParla</title><subtitle>Mind fucked</subtitle><entry><title type="html">Decentralized Write Up</title><link href="https://pdparla.github.io/Decentralized/" rel="alternate" type="text/html" title="Decentralized Write Up" /><published>2018-11-10T00:00:00+00:00</published><updated>2018-11-10T00:00:00+00:00</updated><id>https://pdparla.github.io/Decentralized</id><content type="html" xml:base="https://pdparla.github.io/Decentralized/"><![CDATA[<p>Buenas a todos !
En esta primera entrada del Blog os traigo la resolución a un reto muy interesante
planteado en el CTF del congreso <a href="https://honeycon.eu">HoneyCon</a>, organizado por la gente de <a href="https://www.fwhibbit.es">Follow the White Rabbit</a>.
Muchas gracias a los organizadores por el tremendo curro.</p>

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

<p>Nuestro equipo de inteligencia ha detectado una serie de transacciones maliciosas en una conocida criptomoneda, se han podido extraer dos transacciones importantes que aseguran ser de procedencia relacionada con el terrorismo y el narcotráfico, es mandatorio que consigas extraer la clave privada para que nuestro equipo pueda desproveer de fondos a esta terrorifica organización.</p>

<p>El formato de la flag es la clave privada en hexadecimal (0x010203..) dentro del formato habitual, es decir:
<strong>honeyCON18{0x..}</strong></p>

<p>Informacion extraida:</p>

<p><strong>PublicKey: 0x02 33 c3 4b c8 d6 fa a1 51 ad c5 07 34 c6 fb 6a c7 ff 8c fa 76 d8 02 87 2c a2 06 76 87 3b 70 3e 5a</strong></p>

<p><strong>Transaction Hash: 0x71 c3 42 95 40 57 28 ea 65 f8 ca b8 72 34 80 75 b5 15 93 ab 16 30 ff 0d 35 9f c1 7e 68 89 2c f2</strong></p>

<p><strong>Signature:0x7d0543872fd6dda231d31b3d42a6717ed162a1a5124ef67cb9f84</strong>
<strong>3bb555ec6d6648b78d767616c2c91e2bf75dbca6fdbeb8fb19ff53420fcac937c937ff291b0</strong></p>

<hr />

<p><strong>PublicKey: 0x02 33 c3 4b c8 d6 fa a1 51 ad c5 07 34 c6 fb 6a c7 ff 8c fa 76 d8 02 87 2c a2 06 76 87 3b 70 3e 5a</strong></p>

<p><strong>Transaction Hash: 0x8a 3a 8d fc d2 77 be b4 aa 59 ba 5b 93 6f 3a f3 8f 08 dc 03 92 85 8c f4 75 c5 1d c6 24 7c 3d 90</strong></p>

<p><strong>Signature:0x7d0543872fd6dda231d31b3d42a6717ed162a1a5124ef67cb9f843</strong>
<strong>bb555ec6d68e5685ba5e526f5923e2c07e9bf757b5ab2c6f9648f0f769a2669a1a34f8a243</strong></p>

<p>Vamos al lío.
Lo primero, averiguar el tipo de criptomoneda utilizada. Por el tamaño de clave pública (32 bytes + 1 cabecera), y el hash de las transacciones (32 bytes), se trata de dos transacciones de <strong>bitcoin</strong>.
El algoritmo de criptografía detrás de esta criptomoneda está basado en curvas elípticas, más en concreto en
<a href="https://es.bitcoin.it/wiki/Secp256k1">secp256k1</a>.</p>

<p>Despues de entender un poco como funciona <a href="http://learnmeabitcoin.com/guide/digital_signatures_signing_verifying">la firma</a> en bitcoin, buscamos ataques a este algoritmo, donde nos encontramos con <a href="https://www.youtube.com/watch?v=zlKAci67I5Y">Same k attack</a>. Resumiendo el vídeo porque <del>es un tostón</del> no todos tenemos tiempo para verlos, es posible recuperar una clave privada de dos transacciones las cuales la r de cada firma <strong>se halla formado con la misma k</strong> (que es un valor aleatorio que no se debería repetir, que quede claro).</p>

<p>Para ejecutar este ataque a nuestras transacciones, utilizo un script en ruby, el cuál encontre tras horas de búsqueda
en un post de <a href="https://bitcoin.stackexchange.com/questions/35848/recovering-private-key-when-someone-uses-the-same-k-twice-in-ecdsa-signatures">stackexchange</a>, y al que he tuneado un poco.</p>

<p>El hash de la firma de bytes no estaba en formato <a href="https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long">DER</a>, luego los parseamos:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sig1_hex</span> <span class="o">=</span> <span class="s1">'304402207d0543872fd6dda231d31b3d42a6717ed162a1a5124ef67cb9f843bb555ec6d60220648b78d767616c2c91e2bf75dbca6fdbeb8fb19ff53420fcac937c937ff291b0'</span>
<span class="n">sig2_hex</span> <span class="o">=</span> <span class="s1">'304402207d0543872fd6dda231d31b3d42a6717ed162a1a5124ef67cb9f843bb555ec6d602208e5685ba5e526f5923e2c07e9bf757b5ab2c6f9648f0f769a2669a1a34f8a243'</span>
</code></pre></div></div>
<p>Introducimos los mensajes(Transaction hash) y la clave pública, y ejecutamos.</p>

<p><img src="/images/falloecdsa.png" alt="_config.yml" /></p>

<p>No entiendo ruby, pero al tratar el segundo s, interpretaba 08 como f y petaba.
La solución a esto, es simplemente meter el entero a mano en cada llamada a sig2.s (eran 4).</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">field</span><span class="p">.</span><span class="nf">mod</span><span class="p">((</span><span class="n">z1</span> <span class="o">-</span> <span class="n">z2</span><span class="p">)</span> <span class="o">*</span> <span class="n">field</span><span class="p">.</span><span class="nf">inverse</span><span class="p">(</span><span class="n">sig1</span><span class="p">.</span><span class="nf">s</span> <span class="o">-</span> <span class="n">sig2</span><span class="p">.</span><span class="nf">s</span><span class="p">))</span>
<span class="n">lo</span> <span class="n">cambiamos</span> <span class="n">a</span>
<span class="n">field</span><span class="p">.</span><span class="nf">mod</span><span class="p">((</span><span class="n">z1</span> <span class="o">-</span> <span class="n">z2</span><span class="p">)</span> <span class="o">*</span> <span class="n">field</span><span class="p">.</span><span class="nf">inverse</span><span class="p">(</span><span class="n">sig1</span><span class="p">.</span><span class="nf">s</span> <span class="o">-</span> <span class="no">Integer</span><span class="p">(</span><span class="s2">"0x8e5685ba5e526f5923e2c07e9bf757b5ab2c6f9648f0f769a2669a1a34f8a243"</span><span class="p">)</span>
</code></pre></div></div>
<p>Con esto, tendriamos la clave.</p>

<p><img src="/images/aciertoecdsa.png" alt="_config.yml" /></p>

<p>El código completo está <a href="https://github.com/pdparla/CTFResolved/blob/master/HoneyCon/Decentralized/ecdsa.rb">aquí</a></p>

<p>Dentro de poco más.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Buenas a todos ! En esta primera entrada del Blog os traigo la resolución a un reto muy interesante planteado en el CTF del congreso HoneyCon, organizado por la gente de Follow the White Rabbit. Muchas gracias a los organizadores por el tremendo curro.]]></summary></entry></feed>