<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>0xb105</title>
      <link>https://blog.0xb105.com</link>
      <description>Security research, CTF writeups, Linux kernel patches, CVE analysis, and open-source side projects by Catherine Li.</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://blog.0xb105.com/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 02 May 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>CPCTF 2026 &#x2F; Buffer Visualizer — Anatomy of an Adjacent-Field Stack Overflow</title>
          <pubDate>Sat, 02 May 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://blog.0xb105.com/ctf/cpctf-2026/buffer-visualizer/</link>
          <guid>https://blog.0xb105.com/ctf/cpctf-2026/buffer-visualizer/</guid>
          <description xml:base="https://blog.0xb105.com/ctf/cpctf-2026/buffer-visualizer/">&lt;blockquote&gt;
&lt;p&gt;隣のあいつを書き換えよう！ — &lt;em&gt;Overwrite the one next door!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That tagline is the entire point of the challenge, and it is also the entire point of every adjacent-field stack overflow that has ever shown up in a real-world advisory. CPCTF 2026’s &lt;strong&gt;Buffer Visualizer&lt;&#x2F;strong&gt; is a deliberately gentle introduction to the bug class — the binary literally draws the memory layout for you between every read — but the underlying primitive is the same one that powered Morris (1988), Code Red (2001), and a long tail of CVEs that are still landing in 2026 against C codebases that never got rewritten.&lt;&#x2F;p&gt;
&lt;p&gt;This post walks the challenge end-to-end and uses it as a coat-hook to hang a more comprehensive tutorial on:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;how local variables and structs are actually laid out on the x86-64 SysV stack,&lt;&#x2F;li&gt;
&lt;li&gt;why &lt;code&gt;read(2)&lt;&#x2F;code&gt; is not &lt;code&gt;gets(3)&lt;&#x2F;code&gt; but is still dangerous in the same way,&lt;&#x2F;li&gt;
&lt;li&gt;the small but important difference between &lt;em&gt;overflowing into a return address&lt;&#x2F;em&gt; (classic &lt;code&gt;ret2win&lt;&#x2F;code&gt;) and &lt;em&gt;overflowing into an adjacent field&lt;&#x2F;em&gt; (this challenge),&lt;&#x2F;li&gt;
&lt;li&gt;what every mitigation in the modern hardening stack — stack canaries, NX, ASLR, &lt;code&gt;FORTIFY_SOURCE&lt;&#x2F;code&gt;, &lt;code&gt;-D_FORTIFY_SOURCE=3&lt;&#x2F;code&gt;, ASan — would have done, and why this binary was built with them all turned off,&lt;&#x2F;li&gt;
&lt;li&gt;how to write the same program in 2026 without the bug.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;the-challenge&quot;&gt;The challenge&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Field&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Category&lt;&#x2F;td&gt;&lt;td&gt;Pwn&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Difficulty&lt;&#x2F;td&gt;&lt;td&gt;Lv.2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Score&lt;&#x2F;td&gt;&lt;td&gt;50.00&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Author&lt;&#x2F;td&gt;&lt;td&gt;quarantineee&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Hint&lt;&#x2F;td&gt;&lt;td&gt;“Try entering 16 or more characters. How does &lt;code&gt;target&lt;&#x2F;code&gt;’s value change?”&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Attachments: &lt;code&gt;visualizer.c&lt;&#x2F;code&gt;, the compiled &lt;code&gt;visualizer&lt;&#x2F;code&gt; binary, and a per-user remote instance.&lt;&#x2F;p&gt;
&lt;p&gt;The full source — short enough to fit on one screen — is what makes this a teaching challenge:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; gcc -fno-stack-protector -o visualizer visualizer.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;string.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;unistd.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;lt;stdlib.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; Task {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    char&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; buffer&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    char&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; target&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; print_flag&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;You have successfully performed a buffer overflow!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    system&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;cat flag.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    exit&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; print_visualizer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span&gt; Task &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;--- Memory ---&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;| buffer ---------------------- | target ------ |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    unsigned char *&lt;&#x2F;span&gt;&lt;span&gt;ptr &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;unsigned char *&lt;&#x2F;span&gt;&lt;span&gt;)t;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;; i &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span&gt;; i&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        char&lt;&#x2F;span&gt;&lt;span&gt; c &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; ptr&lt;&#x2F;span&gt;&lt;span&gt;[i];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; %c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, (c &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; c &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 126&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; c &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;--------------&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    struct&lt;&#x2F;span&gt;&lt;span&gt; Task t;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    memset&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;.&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    strcpy&lt;&#x2F;span&gt;&lt;span&gt;(t.target,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;GUEST&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    setvbuf&lt;&#x2F;span&gt;&lt;span&gt;(stdout,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; NULL&lt;&#x2F;span&gt;&lt;span&gt;, _IONBF,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Goal: Overwrite target with &amp;#39;ADMIN&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        print_visualizer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;t);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;        printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Input: &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        int&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; t.buffer[n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) t.buffer[n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strcmp&lt;&#x2F;span&gt;&lt;span&gt;(t.target,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;ADMIN&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            print_visualizer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;t);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            print_flag&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;            printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;Current target value: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;%s\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, t.target);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Three details matter and the rest is decoration:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;struct Task&lt;&#x2F;code&gt; packs a 16-byte &lt;code&gt;buffer&lt;&#x2F;code&gt; immediately followed by an 8-byte &lt;code&gt;target&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read(0, t.buffer, 32)&lt;&#x2F;code&gt; writes up to &lt;strong&gt;32 bytes&lt;&#x2F;strong&gt; into a &lt;strong&gt;16-byte&lt;&#x2F;strong&gt; field. The compiler doesn’t care; &lt;code&gt;read&lt;&#x2F;code&gt; doesn’t care; the kernel doesn’t care.&lt;&#x2F;li&gt;
&lt;li&gt;The win condition is &lt;code&gt;strcmp(t.target, &quot;ADMIN&quot;) == 0&lt;&#x2F;code&gt;, not control-flow hijack. We need &lt;code&gt;target&lt;&#x2F;code&gt; to literally contain &lt;code&gt;A&lt;&#x2F;code&gt;, &lt;code&gt;D&lt;&#x2F;code&gt;, &lt;code&gt;M&lt;&#x2F;code&gt;, &lt;code&gt;I&lt;&#x2F;code&gt;, &lt;code&gt;N&lt;&#x2F;code&gt;, &lt;code&gt;\0&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;That is the whole bug. Everything else in this post is making sure the reader actually sees &lt;em&gt;why&lt;&#x2F;em&gt; it works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;background-where-local-structs-live&quot;&gt;Background: where local structs live&lt;&#x2F;h2&gt;
&lt;p&gt;When &lt;code&gt;main&lt;&#x2F;code&gt; is entered, the x86-64 System V ABI (the calling convention every mainstream Linux compiler obeys) hands &lt;code&gt;main&lt;&#x2F;code&gt; a stack frame that grows downward. &lt;code&gt;gcc&lt;&#x2F;code&gt; reserves space for &lt;code&gt;struct Task t&lt;&#x2F;code&gt; — exactly 24 bytes — somewhere inside that frame. Compiled at &lt;code&gt;-O0&lt;&#x2F;code&gt; with &lt;code&gt;-fno-stack-protector&lt;&#x2F;code&gt;, the layout is the source order, with &lt;code&gt;buffer&lt;&#x2F;code&gt; at the lower address and &lt;code&gt;target&lt;&#x2F;code&gt; immediately above it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    higher addresses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---------------------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | saved RBP                 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | return address            |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---------------------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[7]               |   &amp;lt;- t + 23&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[6]               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[5]               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[4]   &amp;#39;T&amp;#39;         |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[3]   &amp;#39;S&amp;#39;         |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[2]   &amp;#39;E&amp;#39;         |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[1]   &amp;#39;U&amp;#39;         |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.target[0]   &amp;#39;G&amp;#39;         |   &amp;lt;- t + 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---------------------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.buffer[15]              |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | ...                       |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.buffer[1]               |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    | t.buffer[0]               |   &amp;lt;- t + 0   (this is &amp;amp;t)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    +---------------------------+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lower addresses (stack grows here)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;C structs are laid out in &lt;strong&gt;declaration order&lt;&#x2F;strong&gt;, with each field’s offset rounded up to its natural alignment. &lt;code&gt;char&lt;&#x2F;code&gt; has alignment 1, so the layout is dense: &lt;code&gt;buffer&lt;&#x2F;code&gt; occupies offsets &lt;code&gt;[0..16)&lt;&#x2F;code&gt;, &lt;code&gt;target&lt;&#x2F;code&gt; occupies &lt;code&gt;[16..24)&lt;&#x2F;code&gt;. There is no padding between them and there is no canary between them, because &lt;code&gt;gcc -fno-stack-protector&lt;&#x2F;code&gt; was used at build time.&lt;&#x2F;p&gt;
&lt;p&gt;Anything that walks past &lt;code&gt;&amp;amp;t.buffer[15]&lt;&#x2F;code&gt; walks straight into &lt;code&gt;t.target[0]&lt;&#x2F;code&gt;. The compiler’s bounds knowledge ends at the type system, and the type system stops at the field. &lt;code&gt;read(2)&lt;&#x2F;code&gt; doesn’t know about either.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-read-2-is-not-gets-3-but-acts-like-it-here&quot;&gt;Why read(2) is not gets(3) but acts like it here&lt;&#x2F;h2&gt;
&lt;p&gt;Old pwn challenges love &lt;code&gt;gets(3)&lt;&#x2F;code&gt; because it has no length argument and was deprecated for that reason. Modern code reaches for &lt;code&gt;read(2)&lt;&#x2F;code&gt; because &lt;em&gt;it does have a length&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ssize_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; fd&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; void *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;buf&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; size_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; count&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The trap is that &lt;code&gt;count&lt;&#x2F;code&gt; is the buffer the &lt;strong&gt;programmer believes they are filling&lt;&#x2F;strong&gt;, not the one C actually allocated. Here:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;t.buffer&lt;&#x2F;code&gt; is 16 bytes. &lt;code&gt;count&lt;&#x2F;code&gt; is 32. &lt;code&gt;read&lt;&#x2F;code&gt; will faithfully ask the kernel for up to 32 bytes and write them, in order, starting at &lt;code&gt;&amp;amp;t.buffer[0]&lt;&#x2F;code&gt;. Bytes 0–15 land in &lt;code&gt;buffer&lt;&#x2F;code&gt;. Bytes 16–23 land in &lt;code&gt;target&lt;&#x2F;code&gt;. Byte 24 onwards would land in saved RBP, the return address, and so on — but we don’t need to go that far for this challenge.&lt;&#x2F;p&gt;
&lt;p&gt;This is the core lesson the challenge is actually teaching: &lt;em&gt;the size argument to &lt;code&gt;read&lt;&#x2F;code&gt;, &lt;code&gt;recv&lt;&#x2F;code&gt;, &lt;code&gt;memcpy&lt;&#x2F;code&gt;, &lt;code&gt;snprintf&lt;&#x2F;code&gt;, &lt;code&gt;fread&lt;&#x2F;code&gt;, and friends is a contract you have to enforce yourself.&lt;&#x2F;em&gt; The compiler will not check it, the linker will not check it, and the kernel will not check it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;crafting-the-payload&quot;&gt;Crafting the payload&lt;&#x2F;h2&gt;
&lt;p&gt;The win condition is &lt;code&gt;strcmp(t.target, &quot;ADMIN&quot;) == 0&lt;&#x2F;code&gt;. &lt;code&gt;strcmp&lt;&#x2F;code&gt; reads from &lt;code&gt;t.target[0]&lt;&#x2F;code&gt; until it hits a &lt;code&gt;\0&lt;&#x2F;code&gt;. So we need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;bytes 0–15: anything, just to fill &lt;code&gt;buffer&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;bytes 16–20: &lt;code&gt;A&lt;&#x2F;code&gt;, &lt;code&gt;D&lt;&#x2F;code&gt;, &lt;code&gt;M&lt;&#x2F;code&gt;, &lt;code&gt;I&lt;&#x2F;code&gt;, &lt;code&gt;N&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;byte 21: &lt;code&gt;\0&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The straightforward 22-byte payload would be &lt;code&gt;&quot;X&quot; * 16 + &quot;ADMIN\0&quot;&lt;&#x2F;code&gt;. But we are typing into a TTY-shaped &lt;code&gt;read(0, ...)&lt;&#x2F;code&gt;, and sending a literal NUL byte from the shell is awkward. The trick the challenge nudges you toward — and the part that makes this writeup actually interesting — is the post-read fixup:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 32&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span&gt;[n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;) t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span&gt;[n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the input ends with &lt;code&gt;\n&lt;&#x2F;code&gt;, the program rewrites that final byte to &lt;code&gt;\0&lt;&#x2F;code&gt;. So if our payload is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;A&amp;quot; * 16 + &amp;quot;ADMIN&amp;quot; + &amp;quot;\n&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;— that’s 22 bytes — &lt;code&gt;read&lt;&#x2F;code&gt; returns &lt;code&gt;n = 22&lt;&#x2F;code&gt;, the last byte is &lt;code&gt;\n&lt;&#x2F;code&gt; at offset 21, the fixup overwrites it with &lt;code&gt;\0&lt;&#x2F;code&gt;, and we end up with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;buffer  = &amp;quot;AAAAAAAAAAAAAAAA&amp;quot;   (16 bytes, no terminator inside the field)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;target  = &amp;quot;ADMIN\0&amp;quot;            (5 chars + terminator at offset 21)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;strcmp(t.target, &quot;ADMIN&quot;)&lt;&#x2F;code&gt; returns &lt;code&gt;0&lt;&#x2F;code&gt;. &lt;code&gt;print_flag&lt;&#x2F;code&gt; runs.&lt;&#x2F;p&gt;
&lt;p&gt;The memory diagram in transition:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;before: . . . . . . . . . . . . . . . .  G U E S T . . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;after:  A A A A A A A A A A A A A A A A  A D M I N \0 . .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                         ^^^^^^^^^^^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                         our overflow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is a subtler win path. If our input were 21 bytes — &lt;code&gt;&quot;A&quot; * 16 + &quot;ADMI&quot;&lt;&#x2F;code&gt; followed by &lt;code&gt;N\n&lt;&#x2F;code&gt; would still be 22; &lt;em&gt;exactly&lt;&#x2F;em&gt; &lt;code&gt;&quot;A&quot; * 16 + &quot;ADMIN&quot;&lt;&#x2F;code&gt; with no newline is 21 bytes — &lt;code&gt;read&lt;&#x2F;code&gt; returns &lt;code&gt;n = 21&lt;&#x2F;code&gt;, the last byte is &lt;code&gt;N&lt;&#x2F;code&gt; (not &lt;code&gt;\n&lt;&#x2F;code&gt;), the fixup is skipped, and &lt;code&gt;target&lt;&#x2F;code&gt; becomes &lt;code&gt;ADMIN&lt;&#x2F;code&gt; followed by &lt;em&gt;whatever the stack already held&lt;&#x2F;em&gt; at offset 21. If that byte happened to be &lt;code&gt;\0&lt;&#x2F;code&gt; (it is, because &lt;code&gt;strcpy(t.target, &quot;GUEST&quot;)&lt;&#x2F;code&gt; wrote &lt;code&gt;G&lt;&#x2F;code&gt;,&lt;code&gt;U&lt;&#x2F;code&gt;,&lt;code&gt;E&lt;&#x2F;code&gt;,&lt;code&gt;S&lt;&#x2F;code&gt;,&lt;code&gt;T&lt;&#x2F;code&gt;,&lt;code&gt;\0&lt;&#x2F;code&gt; at offsets 16–21), the strcmp succeeds without needing the fixup at all. The fixup path is the &lt;em&gt;intended&lt;&#x2F;em&gt; solution because it works regardless of residual stack contents; the no-fixup path is fragile across compilers.&lt;&#x2F;p&gt;
&lt;p&gt;This is the part of pwn that nobody tells you up front: &lt;strong&gt;payloads are about the program’s state machine, not just the bytes&lt;&#x2F;strong&gt;. Two payloads that look almost identical can have completely different reliability profiles depending on what you assume about uninitialized memory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hitting-it-remotely&quot;&gt;Hitting it remotely&lt;&#x2F;h2&gt;
&lt;p&gt;The challenge runs as a per-user network instance. The supplied solver:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; socket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;HOST&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;133.88.122.244&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 30788&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PAYLOAD&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; = b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;A&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; + b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;ADMIN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; None&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;    with&lt;&#x2F;span&gt;&lt;span&gt; socket.create_connection((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;HOST&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; PORT&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; timeout&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span&gt; sock:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sock.recv(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;4096&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;              # consume the welcome banner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sock.sendall(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;PAYLOAD&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        # 22 bytes, single send&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        chunks&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sock.settimeout(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;        while&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; True&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            try&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; sock.recv(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;4096&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            except&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; TimeoutError&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;            if not&lt;&#x2F;span&gt;&lt;span&gt; data:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;                break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            chunks.append(data)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.join(chunks).decode(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;latin1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;replace&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; end&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Three things worth noting for anyone writing their first pwn solver:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why &lt;code&gt;latin1&lt;&#x2F;code&gt; decode.&lt;&#x2F;strong&gt; The remote prints arbitrary bytes (the visualizer dumps memory). UTF-8 will throw on invalid sequences; &lt;code&gt;latin1&lt;&#x2F;code&gt; is a 1:1 byte-to-codepoint map so it never raises and you see exactly what the binary sent.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Why a single &lt;code&gt;sendall&lt;&#x2F;code&gt;.&lt;&#x2F;strong&gt; Because &lt;code&gt;read(2)&lt;&#x2F;code&gt; will gladly stitch together multiple TCP packets, but it can also return early if the kernel hands back a short read. A single &lt;code&gt;sendall&lt;&#x2F;code&gt; of 22 bytes is the minimum surface area for a flake.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Why the timeout loop.&lt;&#x2F;strong&gt; The remote calls &lt;code&gt;exit(0)&lt;&#x2F;code&gt; after &lt;code&gt;print_flag&lt;&#x2F;code&gt;, so the socket closes when we win. Reading until close is the simplest synchronization.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Run it, see the flag:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPCTF{y0u_4r3_PWN_h4ck3r}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-every-modern-mitigation-would-have-done&quot;&gt;What every modern mitigation would have done&lt;&#x2F;h2&gt;
&lt;p&gt;The build line at the top of the source — &lt;code&gt;gcc -fno-stack-protector&lt;&#x2F;code&gt; — quietly disables one of the four standard stack-overflow defenses. Worth running through all of them, since “what does each mitigation block” is the actual interview question this challenge is rehearsing.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stack-canary-fstack-protector-strong&quot;&gt;Stack canary (&lt;code&gt;-fstack-protector-strong&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;Default in modern gcc&#x2F;clang for any function with a stack buffer. The compiler inserts a random word between the local variables and the saved frame pointer at function entry, and checks it before &lt;code&gt;ret&lt;&#x2F;code&gt;. If we overflowed past &lt;code&gt;t&lt;&#x2F;code&gt; into the canary, &lt;code&gt;__stack_chk_fail&lt;&#x2F;code&gt; would &lt;code&gt;abort()&lt;&#x2F;code&gt; the process before &lt;code&gt;print_flag&lt;&#x2F;code&gt; could ever be called.&lt;&#x2F;p&gt;
&lt;p&gt;This challenge bypasses the canary by &lt;strong&gt;not needing to reach it&lt;&#x2F;strong&gt;. We only walk 6 bytes past &lt;code&gt;buffer&lt;&#x2F;code&gt;, into &lt;code&gt;target&lt;&#x2F;code&gt;. The canary lives further up, near the saved frame pointer. Stack canaries protect &lt;em&gt;return addresses&lt;&#x2F;em&gt;, not &lt;em&gt;adjacent struct fields&lt;&#x2F;em&gt;. This is the single most important nuance of the canary mitigation and the reason adjacent-field overflows are quietly common in real CVEs even on hardened binaries.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nx-wl-z-noexecstack&quot;&gt;NX (&lt;code&gt;-Wl,-z,noexecstack&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;The stack is mapped non-executable. Shellcode written into the buffer can’t be run. Irrelevant here because we don’t write shellcode and don’t redirect execution — &lt;code&gt;print_flag&lt;&#x2F;code&gt; is already in the binary.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aslr-pie&quot;&gt;ASLR + PIE&lt;&#x2F;h3&gt;
&lt;p&gt;The address of &lt;code&gt;print_flag&lt;&#x2F;code&gt; is randomized per run. Irrelevant here because we don’t need to know &lt;code&gt;print_flag&lt;&#x2F;code&gt;’s address — the legitimate code path calls it for us once &lt;code&gt;strcmp&lt;&#x2F;code&gt; returns &lt;code&gt;0&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fortify-source&quot;&gt;&lt;code&gt;FORTIFY_SOURCE&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Compiled with &lt;code&gt;-D_FORTIFY_SOURCE=2&lt;&#x2F;code&gt; (default on most distros under &lt;code&gt;-O2&lt;&#x2F;code&gt;), glibc swaps &lt;code&gt;memcpy&lt;&#x2F;code&gt;, &lt;code&gt;strcpy&lt;&#x2F;code&gt;, &lt;code&gt;snprintf&lt;&#x2F;code&gt;, &lt;code&gt;read&lt;&#x2F;code&gt;, etc. for &lt;code&gt;__*_chk&lt;&#x2F;code&gt; variants when the destination size is known at compile time. For &lt;code&gt;read(0, t.buffer, 32)&lt;&#x2F;code&gt; with &lt;code&gt;t.buffer&lt;&#x2F;code&gt; of size 16, glibc’s &lt;code&gt;__read_chk&lt;&#x2F;code&gt; would &lt;code&gt;__chk_fail()&lt;&#x2F;code&gt; at runtime.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;-D_FORTIFY_SOURCE=3&lt;&#x2F;code&gt; (gcc 12+, glibc 2.34+) extends this to many cases the compiler used to miss. Either level kills this exact bug.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;addresssanitizer-fsanitize-address&quot;&gt;AddressSanitizer (&lt;code&gt;-fsanitize=address&lt;&#x2F;code&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;A debug-time mitigation. ASan would catch the out-of-bounds write the moment &lt;code&gt;read&lt;&#x2F;code&gt; writes past &lt;code&gt;&amp;amp;t.buffer[15]&lt;&#x2F;code&gt; and print a beautiful report. It’s the right tool for catching this class of bug in CI before it ever ships.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;putting-it-together&quot;&gt;Putting it together&lt;&#x2F;h3&gt;
&lt;p&gt;The build line tells the whole story:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;gcc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; -fno-stack-protector -o&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; visualizer visualizer.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No canary (explicit), no PIE (default off without &lt;code&gt;-pie&lt;&#x2F;code&gt;), no fortification (no &lt;code&gt;-D_FORTIFY_SOURCE&lt;&#x2F;code&gt; and no &lt;code&gt;-O2&lt;&#x2F;code&gt;), no ASan, no warnings (no &lt;code&gt;-Wall&lt;&#x2F;code&gt;). It is a CTF binary built to be exploitable. A real production binary built with &lt;code&gt;gcc -O2 -Wall -Wextra -fstack-protector-strong -D_FORTIFY_SOURCE=2 -pie -Wl,-z,now,-z,relro,-z,noexecstack&lt;&#x2F;code&gt; would block this exact payload at runtime via &lt;code&gt;FORTIFY_SOURCE&lt;&#x2F;code&gt;, and would catch it at build time if the developer also enabled &lt;code&gt;-fanalyzer&lt;&#x2F;code&gt; (gcc 14+).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-write-this-in-2026-without-the-bug&quot;&gt;How to write this in 2026 without the bug&lt;&#x2F;h2&gt;
&lt;p&gt;The fix is one character — &lt;code&gt;32&lt;&#x2F;code&gt; becomes &lt;code&gt;sizeof(t.buffer)&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But “use sizeof” is a &lt;strong&gt;rule of thumb that fails the moment someone changes the type&lt;&#x2F;strong&gt;. The deeper fixes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Option 1: bounded read with explicit length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;char&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt; input&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer)];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;ssize_t&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt; read&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, input,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(input));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* handle *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;size_t&lt;&#x2F;span&gt;&lt;span&gt; to_copy &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;size_t&lt;&#x2F;span&gt;&lt;span&gt;)n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;&amp;lt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;size_t&lt;&#x2F;span&gt;&lt;span&gt;)n &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;: sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;memcpy&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer, input, to_copy);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span&gt;[to_copy]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Option 2: fgets — bounded by construction, always NUL-terminates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;fgets&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; sizeof&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer), stdin)) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt; &#x2F;* handle EOF *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FFAB70;&quot;&gt;buffer&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B392F0;&quot;&gt;strcspn&lt;&#x2F;span&gt;&lt;span&gt;(t.buffer,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F97583;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #79B8FF;&quot;&gt;\0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9ECBFF;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Option 3: don&amp;#39;t write C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; Rewrite in Rust, where the compiler refuses to compile a slice index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;&#x2F;&#x2F; that escapes its container, and where String &#x2F; Vec carry their own length.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first two are tactical fixes; the third is the strategic one. Linux kernel (since 2022), Android system services, parts of Chrome and Firefox, and a growing share of new infrastructure code at every major cloud are migrating exactly these patterns to memory-safe languages because the cost-per-CVE math finally tipped over. CISA’s 2023 &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cisa.gov&#x2F;resources-tools&#x2F;resources&#x2F;case-memory-safe-roadmaps&quot;&gt;The Case for Memory Safe Roadmaps&lt;&#x2F;a&gt; is the policy-level statement of the same conclusion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;defensive-takeaways&quot;&gt;Defensive takeaways&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bounds are programmer responsibility in C.&lt;&#x2F;strong&gt; No tool in the standard toolchain checks that &lt;code&gt;read(fd, buf, n)&lt;&#x2F;code&gt;’s &lt;code&gt;n&lt;&#x2F;code&gt; matches &lt;code&gt;buf&lt;&#x2F;code&gt;’s actual size. Habits — &lt;code&gt;sizeof(buf)&lt;&#x2F;code&gt;, never magic numbers — are the only defense at the source level.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Stack canaries do not protect adjacent fields.&lt;&#x2F;strong&gt; They protect return addresses. CVE patterns like Heartbleed (CVE-2014-0160) and many integer-truncation OOB-writes live happily inside a single stack frame without ever touching the canary.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;FORTIFY_SOURCE&lt;&#x2F;code&gt; is free.&lt;&#x2F;strong&gt; Turn it on. Anything caught by &lt;code&gt;__*_chk&lt;&#x2F;code&gt; at runtime is a bug you didn’t ship.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ASan in CI is non-negotiable.&lt;&#x2F;strong&gt; Cost is one extra CI lane; benefit is every category of memory-safety bug in your test corpus surfacing before code review.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Track the difference between control-flow hijack and data-only attacks.&lt;&#x2F;strong&gt; The latter is what this challenge is. They are reliably under-appreciated by junior reviewers because the demo does not pop a shell — but a one-bit privilege escalation (&lt;code&gt;isAdmin = false → true&lt;&#x2F;code&gt;) is often more valuable to an attacker than a shell.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gcc.gnu.org&#x2F;onlinedocs&#x2F;gcc&#x2F;Instrumentation-Options.html&quot;&gt;GCC manual — &lt;code&gt;-fstack-protector*&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;libc&#x2F;manual&#x2F;html_node&#x2F;Source-Fortification.html&quot;&gt;glibc — &lt;code&gt;_FORTIFY_SOURCE&lt;&#x2F;code&gt; levels&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cisa.gov&#x2F;resources-tools&#x2F;resources&#x2F;case-memory-safe-roadmaps&quot;&gt;CISA — The Case for Memory Safe Roadmaps (2023)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;read.2.html&quot;&gt;Linux man-pages — &lt;code&gt;read(2)&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;930736&#x2F;&quot;&gt;LWN — How memory-safe languages reach the Linux kernel&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Aleph One, &lt;em&gt;Smashing The Stack For Fun And Profit&lt;&#x2F;em&gt;, Phrack 49 (1996) — the original tutorial; still the clearest explanation of the call stack at the byte level.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;flag&quot;&gt;Flag&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPCTF{y0u_4r3_PWN_h4ck3r}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
    </channel>
</rss>
