<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>WATKORN.ME</title>
    <link>https://watkorn.me/</link>
    <description>CTF writeups, security notes and tools by watkorn.</description>
    <language>en</language>
    <atom:link href="https://watkorn.me/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Writeup: the watkorn.me mini CTF</title>
      <link>https://watkorn.me/blogs/mini-ctf-writeup/</link>
      <guid isPermaLink="true">https://watkorn.me/blogs/mini-ctf-writeup/</guid>
      <pubDate>Sat, 26 Sep 2026 00:00:00 GMT</pubDate>
      <description>Full solutions for all five flags hidden on this site: dotfiles, view-source, robots.txt and a yeti with a secret. Spoilers, obviously.</description>
      <category>ctf</category>
      <category>writeup</category>
      <category>beginner</category>
      <content:encoded><![CDATA[<blockquote>
<p><strong>Spoiler alert.</strong> This post solves every level of the mini CTF on this site. If you haven&#39;t tried it yet, go to the <a href="https://watkorn.me/">home page</a>, type <code>ls</code>, and come back when you&#39;re stuck. Hints are free on the <a href="https://watkorn.me/achievements">achievements page</a>. The flags themselves are folded away below each level, so you can read the method without seeing the answer.</p>
</blockquote>
<p>The mini CTF has five levels, worth 10 to 50 points (150 in total). The terminal checks your answers with <code>submit &lt;flag&gt;</code>, and it only knows the <strong>SHA-256 hashes</strong> of the flags, so the answers aren&#39;t sitting in the JavaScript in plain text. Well, mostly. Let&#39;s go.</p>
<h2>Level 1: Warm-up (10 pts)</h2>
<p><em>&quot;Some files are just lying around in the home folder.&quot;</em></p>
<p>The classic first move in any shell is to look around:</p>
<pre><code class="hljs language-bash">watkorn@me:~$ <span class="hljs-built_in">ls</span>
flag.txt  README.md
watkorn@me:~$ <span class="hljs-built_in">cat</span> flag.txt
</code></pre><p>That&#39;s it. The warm-up is literally a file called <code>flag.txt</code>. There&#39;s also a sneaky second path: <code>echo</code> with the word &quot;flag&quot; in it prints the flag too.</p>
<details>
<summary>Show flag</summary><p><code>my_w3b_is_c00ler_th4n_u_th1nk</code></p>
</details><p><strong>Lesson:</strong> always enumerate before you get clever. <code>ls</code>, <code>cat</code>, <code>file</code>, <code>strings</code>.</p>
<h2>Level 2: Hidden in plain sight (20 pts)</h2>
<p><em>&quot;ls shows files. ls -la shows all of them.&quot;</em></p>
<p>On Linux, files starting with a dot are hidden from a plain <code>ls</code>. Add <code>-a</code> (all) and <code>-l</code> (long):</p>
<pre><code class="hljs language-bash">watkorn@me:~$ <span class="hljs-built_in">ls</span> -la
drwxr-xr-x 3 watkorn <span class="hljs-built_in">users</span> 4096 Oct 8 2025 .
drwxr-xr-x 3 watkorn <span class="hljs-built_in">users</span> 4096 Oct 8 2025 ..
drwx------ 2 watkorn <span class="hljs-built_in">users</span> 4096 Oct 8 2025 .secret
-rw-r--r-- 1 watkorn <span class="hljs-built_in">users</span>   67 Oct 8 2025 flag.txt
-rw-r--r-- 1 watkorn <span class="hljs-built_in">users</span>  123 Oct 8 2025 README.md
watkorn@me:~$ <span class="hljs-built_in">cd</span> .secret
watkorn@me:~/.secret$ <span class="hljs-built_in">cat</span> note.b64
d2F0a29ybntkMHRmMWwzc180cjNfbjB0X3MzY3IzdHN9
</code></pre><p>The <code>.b64</code> extension gives it away: letters, digits and a length that&#39;s a multiple of 4 all scream <strong>Base64</strong>. Decode it anywhere except the site&#39;s terminal:</p>
<pre><code class="hljs language-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">&#x27;d2F0a29ybntkMHRmMWwzc180cjNfbjB0X3MzY3IzdHN9&#x27;</span> | <span class="hljs-built_in">base64</span> -d
</code></pre><p>Or use <a href="https://gchq.github.io/CyberChef/" target="_blank" rel="noopener noreferrer">CyberChef</a> with the &quot;From Base64&quot; operation.</p>
<details>
<summary>Show flag</summary><p><code>watkorn{d0tf1l3s_4r3_n0t_s3cr3ts}</code></p>
</details><p><strong>Lesson:</strong> Base64 is <strong>encoding, not encryption</strong>. Anyone can reverse it, no key needed. And &quot;hidden&quot; dotfiles hide nothing from someone who types <code>-a</code>.</p>
<h2>Level 3: View source (30 pts)</h2>
<p><em>&quot;The page you see isn&#39;t the whole page.&quot;</em></p>
<p>What the browser renders is only part of what the server sends. Open the raw HTML with <strong>Ctrl+U</strong> (or <code>view-source:https://watkorn.me/</code>), or fetch it:</p>
<pre><code class="hljs language-bash">curl -s https://watkorn.me/ | grep -i <span class="hljs-string">&quot;note to self&quot;</span>
</code></pre><p>Near the top of <code>&lt;body&gt;</code> there&#39;s an HTML comment:</p>
<pre><code class="hljs language-html"><span class="hljs-comment">&lt;!-- note to self (level 3): jngxbea{i13j_f0hep3_o3s0e3_l0h_u4px}  ·  rot13, obviously --&gt;</span>
</code></pre><p>It even tells you the cipher. ROT13 shifts every letter 13 places, and applying it twice gets you back where you started:</p>
<pre><code class="hljs language-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">&#x27;jngxbea{i13j_f0hep3_o3s0e3_l0h_u4px}&#x27;</span> | <span class="hljs-built_in">tr</span> <span class="hljs-string">&#x27;A-Za-z&#x27;</span> <span class="hljs-string">&#x27;N-ZA-Mn-za-m&#x27;</span>
</code></pre><p>Digits and symbols are left alone, which is why <code>{</code>, <code>_</code> and the leetspeak numbers survive untouched.</p>
<details>
<summary>Show flag</summary><p><code>watkorn{v13w_s0urc3_b3f0r3_y0u_h4ck}</code></p>
</details><p><strong>Lesson:</strong> comments ship to production more often than you&#39;d think. On real web challenges (and real bug bounties), read the source, the JavaScript bundles and the HTML comments first.</p>
<h2>Level 4: Robots only (40 pts)</h2>
<p><em>&quot;Every well-behaved crawler reads one file before anything else. Be badly behaved.&quot;</em></p>
<p>That file is <code>/robots.txt</code>, a polite request to search engines about what not to index:</p>
<pre><code class="hljs language-bash">curl -s https://watkorn.me/robots.txt
</code></pre><pre><code class="hljs">User-agent: *
Disallow: /y3t1-l41r/
</code></pre><p>&quot;Please don&#39;t look at /y3t1-l41r/&quot; is basically an invitation. Visit <a href="https://watkorn.me/y3t1-l41r/">the yeti&#39;s lair</a> and you&#39;ll find a wall of bytes: <code>77 61 74 6b 6f 72 6e 7b …</code>. That&#39;s <strong>hex</strong>: every pair of characters is one byte, and <code>77 61 74</code> is <code>wat</code>. Convert it back:</p>
<pre><code class="hljs language-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">&#x27;77 61 74 6b 6f 72 6e 7b 72 30 62 30 74 73 5f 74 78 74 5f 31 73 5f 34 5f 74 72 33 34 73 75 72 33 5f 6d 34 70 7d&#x27;</span> | xxd -r -p
</code></pre><p>No <code>xxd</code>? Python works anywhere (and CyberChef&#39;s &quot;From Hex&quot; does too):</p>
<pre><code class="hljs language-bash">python3 -c <span class="hljs-string">&quot;print(bytes.fromhex(&#x27;77 61 74 6b 6f 72 6e 7b 72 30 62 30 74 73 5f 74 78 74 5f 31 73 5f 34 5f 74 72 33 34 73 75 72 33 5f 6d 34 70 7d&#x27;).decode())&quot;</span>
</code></pre><details>
<summary>Show flag</summary><p><code>watkorn{r0b0ts_txt_1s_4_tr34sur3_m4p}</code></p>
</details><p><strong>Lesson:</strong> <code>robots.txt</code> is <strong>not access control</strong>. It lists exactly the paths someone wanted to hide, which makes it one of the first files to check in any web challenge or recon.</p>
<h2>Level 5: Pixel secrets (50 pts)</h2>
<p><em>&quot;The yeti is an SVG. Open the file on its own and look past the pixels.&quot;</em></p>
<p>The pixel yeti isn&#39;t an image tag; it&#39;s drawn from an SVG sprite. In DevTools (<strong>F12 → Elements</strong>), inspect the yeti and you&#39;ll find something like:</p>
<pre><code class="hljs language-html"><span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/assets/yeti-XXXXXXXX.svg#yeti&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">use</span>&gt;</span>
</code></pre><p>(the part after <code>yeti-</code> is a content hash, so yours may differ). Open that SVG file directly in a new tab and view its source. SVG is just XML, and next to the drawing there&#39;s a <code>&lt;metadata&gt;</code> element the browser never renders:</p>
<pre><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">metadata</span>&gt;</span>yeti-says: d2F0a29ybntwMXgzbHNfYzRuX2gxZDNfc3Q0ZmZfdDAwfQ==<span class="hljs-tag">&lt;/<span class="hljs-name">metadata</span>&gt;</span>
</code></pre><p>The <code>==</code> padding at the end is a Base64 tell, again:</p>
<pre><code class="hljs language-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">&#x27;d2F0a29ybntwMXgzbHNfYzRuX2gxZDNfc3Q0ZmZfdDAwfQ==&#x27;</span> | <span class="hljs-built_in">base64</span> -d
</code></pre><p>Command-line route, no DevTools needed:</p>
<pre><code class="hljs language-bash">js=$(curl -s https://watkorn.me/ | grep -o <span class="hljs-string">&#x27;/assets/index-[^&quot;]*\.js&#x27;</span>)
svg=$(curl -s <span class="hljs-string">&quot;https://watkorn.me<span class="hljs-variable">$js</span>&quot;</span> | grep -o <span class="hljs-string">&#x27;/assets/yeti-[^&quot;`]*\.svg&#x27;</span> | <span class="hljs-built_in">head</span> -1)
curl -s <span class="hljs-string">&quot;https://watkorn.me<span class="hljs-variable">$svg</span>&quot;</span> | grep -o <span class="hljs-string">&#x27;yeti-says: [^&lt;]*&#x27;</span>
</code></pre><details>
<summary>Show flag</summary><p><code>watkorn{p1x3ls_c4n_h1d3_st4ff_t00}</code></p>
</details><p><strong>Lesson:</strong> images can carry data. SVGs are text files that can hold metadata, comments and even scripts. That&#39;s why real sites sanitise user-uploaded SVGs, and why steganography challenges love image files.</p>
<h2>How the checking works (and its limits)</h2>
<ul>
<li>The terminal hashes whatever you <code>submit</code> with SHA-256 in your browser (<code>crypto.subtle.digest</code>) and compares it against the five stored hashes. The hashes are public, but a hash can&#39;t be reversed back into the flag.</li>
<li>Your progress is stored in your browser&#39;s <code>localStorage</code>. Nothing is sent to a server, because there isn&#39;t one.</li>
<li>Honest limits: flags 1 and 2 have to live in the JavaScript, because the terminal prints them. And the whole site is <a href="https://github.com/watkorn/watkorn.me" target="_blank" rel="noopener noreferrer">open source</a>, so reading the repo is a valid, if slightly cheeky, strategy. For a warm-up CTF, that&#39;s a feature.</li>
</ul>
<h2>What this mini CTF teaches</h2>
<table>
<thead>
<tr>
<th>Level</th>
<th>Technique</th>
<th>Real-world version</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Enumerate first</td>
<td><code>ls</code>, <code>strings</code>, reading every file you&#39;re given</td>
</tr>
<tr>
<td>2</td>
<td>Hidden files + Base64</td>
<td>dotfiles, <code>.git/</code>, encoded config values</td>
</tr>
<tr>
<td>3</td>
<td>View source + ROT13</td>
<td>leaked comments, secrets in JS bundles</td>
</tr>
<tr>
<td>4</td>
<td>robots.txt + hex</td>
<td>recon on <code>robots.txt</code>, <code>sitemap.xml</code>, <code>.well-known/</code></td>
</tr>
<tr>
<td>5</td>
<td>File metadata</td>
<td>EXIF data, SVG/Office metadata, steganography</td>
</tr>
</tbody></table>
<p>Got all five? Screenshot your <a href="https://watkorn.me/achievements">achievements</a> and tag me. Next time I&#39;ll make them harder.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Preparing for CTF</title>
      <link>https://watkorn.me/blogs/preparing-for-ctf/</link>
      <guid isPermaLink="true">https://watkorn.me/blogs/preparing-for-ctf/</guid>
      <pubDate>Wed, 08 Oct 2025 00:00:00 GMT</pubDate>
      <description>A no-fluff starter kit for your first Capture The Flag: pick a category, set up your tools, practise, and survive the weekend.</description>
      <category>ctf</category>
      <category>beginner</category>
      <content:encoded><![CDATA[<p>Capture The Flag (CTF) competitions are the most fun way to learn security. Someone hides a string like <code>flag{...}</code> behind a broken web app, a weird binary or a suspicious PCAP, and you break things (legally) until it falls out. You&#39;ll fail a lot at first. That&#39;s the whole point.</p>
<p>This is the guide I wish I&#39;d had before my first one.</p>
<p><img src="https://watkorn.me/images/blogs/ctftime.png" alt="CTFtime, where you find upcoming CTFs" loading="lazy"></p>
<h2>First, what kind of CTF is it?</h2>
<ul>
<li><strong>Jeopardy.</strong> A board of challenges by category and points. Solve any in any order. This is 90% of CTFs and where you should start.</li>
<li><strong>Attack–Defense.</strong> Every team gets the same vulnerable services. Patch yours, exploit everyone else&#39;s. Chaotic, amazing, not for week one.</li>
<li><strong>King of the Hill.</strong> Take over a box and hold it. Great on TryHackMe once you&#39;re comfortable.</li>
</ul>
<p>Find events on <a href="https://ctftime.org/" target="_blank" rel="noopener noreferrer">CTFtime</a>. Look for ones tagged <em>beginner</em>, or with low &quot;weight&quot;.</p>
<h2>Pick a lane (then another)</h2>
<p>Nobody is good at everything. Start with one or two categories, then branch out.</p>
<table>
<thead>
<tr>
<th>Category</th>
<th>What it is</th>
<th>Learn first</th>
</tr>
</thead>
<tbody><tr>
<td><strong>web</strong></td>
<td>Break web apps</td>
<td>HTTP, cookies, SQLi, XSS, SSTI, IDOR, reading JS</td>
</tr>
<tr>
<td><strong>pwn</strong></td>
<td>Exploit binaries for a shell</td>
<td>C, stack layout, buffer overflows, ROP, <code>checksec</code></td>
</tr>
<tr>
<td><strong>rev</strong></td>
<td>Figure out what a program does</td>
<td>x86-64 basics, Ghidra, <code>strace</code>/<code>ltrace</code>, patching</td>
</tr>
<tr>
<td><strong>crypto</strong></td>
<td>Break bad cryptography</td>
<td>XOR, RSA mistakes, padding, encodings vs encryption</td>
</tr>
<tr>
<td><strong>forensics</strong></td>
<td>Dig through files, memory, traffic</td>
<td>file formats, Wireshark, Volatility, steganography</td>
</tr>
<tr>
<td><strong>misc / OSINT</strong></td>
<td>Everything else</td>
<td>Linux-fu, scripting, search skills</td>
</tr>
</tbody></table>
<p>If you don&#39;t know where to start: <strong>web</strong> or <strong>forensics</strong>. You get quick wins without needing assembly first.</p>
<h2>Set up your toolkit</h2>
<p>A Linux VM (Kali, Parrot or plain Ubuntu) keeps everything in one place and your host clean. Core tools:</p>
<ul>
<li><strong>Everywhere:</strong> Python 3, <a href="https://gchq.github.io/CyberChef/" target="_blank" rel="noopener noreferrer">CyberChef</a>, <code>file</code>, <code>strings</code>, a good text editor</li>
<li><strong>Web:</strong> Burp Suite Community, browser DevTools, <code>ffuf</code>, <code>curl</code></li>
<li><strong>Pwn / rev:</strong> <code>pwntools</code>, GDB + <a href="https://github.com/pwndbg/pwndbg" target="_blank" rel="noopener noreferrer">pwndbg</a> or GEF, Ghidra, <code>checksec</code></li>
<li><strong>Forensics:</strong> Wireshark, <code>binwalk</code>, <code>exiftool</code>, Volatility 3</li>
<li><strong>Crypto / cracking:</strong> <code>hashcat</code>, John the Ripper, SageMath or plain Python</li>
</ul>
<pre><code class="hljs language-bash"><span class="hljs-built_in">sudo</span> apt install -y python3-pip gdb binwalk exiftool wireshark john hashcat
pip install pwntools
git <span class="hljs-built_in">clone</span> https://github.com/pwndbg/pwndbg &amp;&amp; <span class="hljs-built_in">cd</span> pwndbg &amp;&amp; ./setup.sh
</code></pre><h2>Practise before the weekend</h2>
<ul>
<li><a href="https://picoctf.org/" target="_blank" rel="noopener noreferrer">picoCTF</a>: the best place to start. Challenges go from gentle to genuinely hard.</li>
<li><a href="https://overthewire.org/wargames/bandit/" target="_blank" rel="noopener noreferrer">OverTheWire: Bandit</a>: Linux basics, one level at a time.</li>
<li><a href="https://tryhackme.com/" target="_blank" rel="noopener noreferrer">TryHackMe</a>: guided rooms and learning paths.</li>
<li><a href="https://www.hackthebox.com/" target="_blank" rel="noopener noreferrer">Hack The Box</a>: realistic machines, plus a &quot;Challenges&quot; section in CTF style.</li>
<li><a href="https://pwn.college/" target="_blank" rel="noopener noreferrer">pwn.college</a>: the free university course for pwn and rev.</li>
<li><a href="https://cryptohack.org/" target="_blank" rel="noopener noreferrer">CryptoHack</a>: crypto, taught through puzzles.</li>
</ul>
<p>Aim for something small every day rather than one huge weekend. Ten solved easy challenges beat one hard one you gave up on.</p>
<h2>The first 10 minutes of any challenge</h2>
<p>Before anything clever, run the boring stuff. It solves more challenges than you&#39;d think.</p>
<pre><code class="hljs language-bash">file chall                      <span class="hljs-comment"># what is this, really?</span>
strings -n 8 chall | less       <span class="hljs-comment"># readable text, sometimes the flag itself</span>
exiftool image.png              <span class="hljs-comment"># metadata</span>
binwalk -e firmware.bin         <span class="hljs-comment"># files hidden inside files</span>
checksec --file=./chall         <span class="hljs-comment"># which protections does this binary have?</span>
</code></pre><p>For web challenges: read the page source, open DevTools, check <code>/robots.txt</code>, look at cookies, and watch every request in Burp.</p>
<h2>During the CTF</h2>
<ul>
<li><strong>Read every challenge first.</strong> Sort by number of solves; the most-solved ones are usually the easiest.</li>
<li><strong>Timebox.</strong> If you&#39;ve made no progress in 45–60 minutes, switch challenges and come back later.</li>
<li><strong>Write everything down.</strong> What you tried, what failed, and every weird thing you noticed. Future-you will thank you.</li>
<li><strong>Read the rules.</strong> Don&#39;t attack the infrastructure, don&#39;t brute-force the flag submission, don&#39;t share flags.</li>
<li><strong>Sleep and eat.</strong> Seriously. Tired brains don&#39;t find off-by-one bugs.</li>
</ul>
<h2>Play with a team</h2>
<ul>
<li>One channel or thread per challenge. Post what you&#39;ve tried.</li>
<li>&quot;Claim&quot; a challenge so two people don&#39;t silently do the same thing.</li>
<li>Share notes in one place (Obsidian, HedgeDoc or Notion) so nothing lives only in your head.</li>
<li>Pair up: someone strong in rev plus someone strong in pwn is a very good combo.</li>
</ul>
<h2>After the CTF (the part everyone skips)</h2>
<p>This is where most of the learning actually happens:</p>
<ol>
<li><strong>Read other teams&#39; writeups</strong> for the challenges you didn&#39;t solve. CTFtime links them on each event page.</li>
<li><strong>Write your own writeups</strong>, even for easy ones. Explaining a solve is how it sticks. (On this site, it&#39;s <code>npm run new-post -- --writeup &quot;Challenge name&quot;</code>.)</li>
<li><strong>Turn repeated tricks into cheat sheets.</strong> Payloads, one-liners, Python snippets.</li>
</ol>
<h2>Quick checklist</h2>
<ul>
<li class="task"><label><input type="checkbox" disabled> Picked 1–2 categories to focus on</label></li>
<li class="task"><label><input type="checkbox" disabled> VM with the core tools installed</label></li>
<li class="task"><label><input type="checkbox" disabled> Solved 10+ picoCTF or TryHackMe challenges</label></li>
<li class="task"><label><input type="checkbox" disabled> Found an upcoming beginner CTF on CTFtime</label></li>
<li class="task"><label><input type="checkbox" disabled> Notes app and team channel ready</label></li>
<li class="task"><label><input type="checkbox" disabled> Plan to write at least one writeup afterwards</label></li>
</ul>
<p>Want a warm-up right now? The <a href="https://watkorn.me/">terminal on the home page</a> has five flags hidden around this site. Check your progress on the <a href="https://watkorn.me/achievements">achievements page</a>. Good luck, and have fun breaking things.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
