<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Writeups on RORO's blog</title><link>https://blog.rodolpheg.xyz/writeups/</link><description>Recent content in Writeups on RORO's blog</description><generator>Hugo</generator><language>fr-fr</language><managingEditor>contact@rodolpheg.xyz (0xRo)</managingEditor><webMaster>contact@rodolpheg.xyz (0xRo)</webMaster><lastBuildDate>Sun, 29 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.rodolpheg.xyz/writeups/index.xml" rel="self" type="application/rss+xml"/><item><title>Une nuit pour hacker 2026: Thread of Doom</title><link>https://blog.rodolpheg.xyz/writeups/threadofdoom/</link><pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate><author>contact@rodolpheg.xyz (0xRo)</author><guid>https://blog.rodolpheg.xyz/writeups/threadofdoom/</guid><description>&lt;h2 id="executive-summary">Executive Summary&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Challenge&lt;/strong>: Thread of Doom&lt;/li>
&lt;li>&lt;strong>Category&lt;/strong>: Reverse Engineering&lt;/li>
&lt;li>&lt;strong>Flags&lt;/strong>: &lt;code>NHK26{VirtualProtect_Overwritten}&lt;/code>&lt;/li>
&lt;li>&lt;strong>Binary:&lt;/strong> &lt;code>NHK_CrackMe_V3.exe&lt;/code> (PE32, x86, 43520 bytes)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>Thread of Doom is a Windows crackme that presents a dialog with a &amp;ldquo;Demo&amp;rdquo; button. Clicking the button displays an error: &lt;em>&amp;ldquo;Tu n&amp;rsquo;es pas premium ! Prix : 2 BTC&amp;rdquo;&lt;/em>. The goal is to understand the binary&amp;rsquo;s protection mechanisms and extract the hidden flag.&lt;/p>
&lt;p>The flag is XOR-encrypted in memory with a single-byte key (&lt;code>0x55&lt;/code>). The binary only decrypts it at runtime when several anti-tampering checks pass, but since both the ciphertext and key are visible in the decompilation, we can extract it statically without running the binary at all.&lt;/p></description></item><item><title>Amazon AppSec CTF: HalCrypto</title><link>https://blog.rodolpheg.xyz/writeups/halcrypto/</link><pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate><author>contact@rodolpheg.xyz (0xRo)</author><guid>https://blog.rodolpheg.xyz/writeups/halcrypto/</guid><description>&lt;h2 id="executive-summary">Executive Summary&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Challenge&lt;/strong>: HalCrypto&lt;/li>
&lt;li>&lt;strong>Category&lt;/strong>: Web Security&lt;/li>
&lt;li>&lt;strong>Vulnerability&lt;/strong>: JWT validation bypass via URL confusion with @ symbol&lt;/li>
&lt;li>&lt;strong>Impact&lt;/strong>: Authentication bypass leading to admin access&lt;/li>
&lt;li>&lt;strong>Flag&lt;/strong>: &lt;code>HTB{r3d1r3c73d_70_my_s3cr37s}&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="vulnerability-overview">Vulnerability Overview&lt;/h2>
&lt;h3 id="attack-flow-diagram">Attack Flow Diagram&lt;/h3>
&lt;p>&lt;img src="https://blog.rodolpheg.xyz/img/halcrypto/attack-flow.png" alt="Attack Flow Diagram">&lt;/p>
&lt;h2 id="source-to-sink-analysis">Source-to-Sink Analysis&lt;/h2>
&lt;h3 id="1-entry-point---jwt-authentication-source">1. Entry Point - JWT Authentication (Source)&lt;/h3>
&lt;p>The vulnerability starts when the AuthMiddleware processes JWT tokens:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// middleware/AuthMiddleware.js:5-34
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">module&lt;/span>.&lt;span style="color:#a6e22e">exports&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> (&lt;span style="color:#a6e22e">req&lt;/span>, &lt;span style="color:#a6e22e">res&lt;/span>, &lt;span style="color:#a6e22e">next&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">cookies&lt;/span>.&lt;span style="color:#a6e22e">session&lt;/span> &lt;span style="color:#f92672">===&lt;/span> &lt;span style="color:#66d9ef">undefined&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#f92672">!&lt;/span>&lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">is&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;application/json&amp;#39;&lt;/span>)) &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">redirect&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;/&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">401&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Authentication required!&amp;#39;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">JWTHelper&lt;/span>.&lt;span style="color:#a6e22e">getHeader&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">cookies&lt;/span>.&lt;span style="color:#a6e22e">session&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">then&lt;/span>(&lt;span style="color:#a6e22e">header&lt;/span> =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">header&lt;/span>.&lt;span style="color:#a6e22e">jku&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#a6e22e">header&lt;/span>.&lt;span style="color:#a6e22e">kid&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// VULNERABILITY: Weak URL validation using lastIndexOf
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">header&lt;/span>.&lt;span style="color:#a6e22e">jku&lt;/span>.&lt;span style="color:#a6e22e">lastIndexOf&lt;/span>(&lt;span style="color:#a6e22e">config&lt;/span>.&lt;span style="color:#a6e22e">AUTH_PROVIDER&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>) &lt;span style="color:#f92672">!==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">500&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;The JWKS endpoint is not from localhost!&amp;#39;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">JWTHelper&lt;/span>.&lt;span style="color:#a6e22e">getPublicKey&lt;/span>(&lt;span style="color:#a6e22e">header&lt;/span>.&lt;span style="color:#a6e22e">jku&lt;/span>, &lt;span style="color:#a6e22e">header&lt;/span>.&lt;span style="color:#a6e22e">kid&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">then&lt;/span>(&lt;span style="color:#a6e22e">pubkey&lt;/span> =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">JWTHelper&lt;/span>.&lt;span style="color:#a6e22e">verify&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">cookies&lt;/span>.&lt;span style="color:#a6e22e">session&lt;/span>, &lt;span style="color:#a6e22e">pubkey&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#a6e22e">then&lt;/span>(&lt;span style="color:#a6e22e">data&lt;/span> =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">user&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">data&lt;/span>.&lt;span style="color:#a6e22e">user&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">next&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#66d9ef">catch&lt;/span>(() =&amp;gt; &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">403&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Authentication token could not be verified!&amp;#39;&lt;/span>)));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#66d9ef">catch&lt;/span>(() =&amp;gt; &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">redirect&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;/logout&amp;#39;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">500&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Missing required claims in JWT!&amp;#39;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> })
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#66d9ef">catch&lt;/span>(&lt;span style="color:#a6e22e">err&lt;/span> =&amp;gt; &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">500&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;Invalid session token supplied!&amp;#34;&lt;/span>)));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">catch&lt;/span> (&lt;span style="color:#a6e22e">e&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">500&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#a6e22e">e&lt;/span>.&lt;span style="color:#a6e22e">toString&lt;/span>()));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-the-vulnerable-validation---string-based-url-check">2. The Vulnerable Validation - String-based URL Check&lt;/h3>
&lt;p>The critical vulnerability lies in line 14 of &lt;code>AuthMiddleware.js&lt;/code>:&lt;/p></description></item><item><title>Amazon AppSec CTF: PageOneHTML</title><link>https://blog.rodolpheg.xyz/writeups/pageronehtlm/</link><pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate><author>contact@rodolpheg.xyz (0xRo)</author><guid>https://blog.rodolpheg.xyz/writeups/pageronehtlm/</guid><description>&lt;h2 id="executive-summary">Executive Summary&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Challenge&lt;/strong>: PageOneHTML&lt;/li>
&lt;li>&lt;strong>Category&lt;/strong>: Web Security&lt;/li>
&lt;li>&lt;strong>Vulnerability&lt;/strong>: Server-Side Request Forgery (SSRF) via gopher:// protocol&lt;/li>
&lt;li>&lt;strong>Impact&lt;/strong>: Access to internal API endpoint leading to flag disclosure&lt;/li>
&lt;li>&lt;strong>Flags&lt;/strong>:
&lt;ul>
&lt;li>Local: &lt;code>HTB{f4k3_fl4g_f0r_t3st1ng}&lt;/code>&lt;/li>
&lt;li>Remote: &lt;code>HTB{l1bcurL_pla7h0r4_0f_pr0tocOl5}&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="source-to-sink-analysis">Source-to-Sink Analysis&lt;/h2>
&lt;h3 id="1-entry-point---user-input-source">1. Entry Point - User Input (Source)&lt;/h3>
&lt;p>The vulnerability starts at &lt;code>/api/convert&lt;/code> endpoint which accepts user-controlled markdown content:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// routes/index.js:15-28
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">router&lt;/span>.&lt;span style="color:#a6e22e">post&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;/api/convert&amp;#39;&lt;/span>, &lt;span style="color:#66d9ef">async&lt;/span> (&lt;span style="color:#a6e22e">req&lt;/span>, &lt;span style="color:#a6e22e">res&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> { &lt;span style="color:#a6e22e">markdown_content&lt;/span>, &lt;span style="color:#a6e22e">port_images&lt;/span> } &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">body&lt;/span>; &lt;span style="color:#75715e">// User input
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">markdown_content&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">html&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">MDHelper&lt;/span>.&lt;span style="color:#a6e22e">makeHtml&lt;/span>(&lt;span style="color:#a6e22e">markdown_content&lt;/span>); &lt;span style="color:#75715e">// Convert MD to HTML
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">port_images&lt;/span>) { &lt;span style="color:#75715e">// If port_images is true
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">ImageConverter&lt;/span>.&lt;span style="color:#a6e22e">PortImages&lt;/span>(&lt;span style="color:#a6e22e">html&lt;/span>) &lt;span style="color:#75715e">// Process images
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> .&lt;span style="color:#a6e22e">then&lt;/span>(&lt;span style="color:#a6e22e">newHTML&lt;/span> =&amp;gt; &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">json&lt;/span>({ &lt;span style="color:#a6e22e">content&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">newHTML&lt;/span> }))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .&lt;span style="color:#66d9ef">catch&lt;/span>(() =&amp;gt; &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">json&lt;/span>({ &lt;span style="color:#a6e22e">content&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">html&lt;/span> }));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">json&lt;/span>({ &lt;span style="color:#a6e22e">content&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">html&lt;/span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">status&lt;/span>(&lt;span style="color:#ae81ff">403&lt;/span>).&lt;span style="color:#a6e22e">send&lt;/span>(&lt;span style="color:#a6e22e">response&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Missing parameters!&amp;#39;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-image-processing---protocol-confusion">2. Image Processing - Protocol Confusion&lt;/h3>
&lt;p>The &lt;code>ImageConverter&lt;/code> extracts all &lt;code>&amp;lt;img&amp;gt;&lt;/code> tags and processes their &lt;code>src&lt;/code> attributes:&lt;/p></description></item></channel></rss>