<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Web on 万屋猫Labs</title><link>https://yn-labs.com/en/tags/web/</link><description>Recent content in Web on 万屋猫Labs</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 29 Mar 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://yn-labs.com/en/tags/web/index.xml" rel="self" type="application/rss+xml"/><item><title>KalmarCTF 2026 RootBabyKalmarCTF Writeup — Zip Slip (CVE-2026-30345) for CTFd Root</title><link>https://yn-labs.com/en/writeups/ctf/kalmarctf-2026-rootbabykalmarctf-zip-slip/</link><pubDate>Sun, 29 Mar 2026 00:00:00 +0900</pubDate><guid>https://yn-labs.com/en/writeups/ctf/kalmarctf-2026-rootbabykalmarctf-zip-slip/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;KalmarCTF 2026 Web challenge &amp;ldquo;RootBabyKalmarCTF&amp;rdquo; (170pts).&lt;br&gt;
A CTFd 3.8.1 instance is provided with admin credentials for the management panel.&lt;br&gt;
The goal is to read &lt;code&gt;/flag2-&amp;lt;random&amp;gt;.txt&lt;/code&gt; as &lt;strong&gt;root&lt;/strong&gt;, not admin.&lt;/p&gt;
&lt;h2 id="vulnerability"&gt;Vulnerability&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;CVE-2026-30345: CTFd 3.8.1 Zip Slip (Path Traversal)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;/admin/import&lt;/code&gt; backup import function checks if ZIP file entry names contain &lt;code&gt;..&lt;/code&gt;.&lt;br&gt;
However, the check can be bypassed using the &lt;code&gt;uploads//absolute/path&lt;/code&gt; format (double slash).&lt;/p&gt;
&lt;h3 id="the-check"&gt;The Check&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; f &lt;span style="color:#f92672"&gt;in&lt;/span&gt; members:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; f&lt;span style="color:#f92672"&gt;.&lt;/span&gt;startswith(&lt;span style="color:#e6db74"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;) &lt;span style="color:#f92672"&gt;or&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;..&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;in&lt;/span&gt; f:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;raise&lt;/span&gt; zipfile&lt;span style="color:#f92672"&gt;.&lt;/span&gt;BadZipfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="the-bypass"&gt;The Bypass&lt;/h3&gt;
&lt;p&gt;Entry name: &lt;code&gt;uploads//opt/CTFd/manage.py&lt;/code&gt;&lt;/p&gt;</description></item></channel></rss>